Skip to content

Commit 76c4cfd

Browse files
authored
feat(jmespath): add abstract syntax tree definition (#2213)
1 parent cd01ecf commit 76c4cfd

File tree

1 file changed

+299
-0
lines changed

1 file changed

+299
-0
lines changed

packages/jmespath/src/ast.ts

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
import type { JSONValue } from '@aws-lambda-powertools/commons/types';
2+
import type { Node } from './types.js';
3+
4+
/**
5+
* AST node representing a comparator expression.
6+
*
7+
* A comparator expression is a binary expression that compares two values.
8+
*
9+
* @param name The name of the comparator
10+
* @param first The left-hand side of the comparator
11+
* @param second The right-hand side of the comparator
12+
*/
13+
const comparator = (name: string, first: Node, second: Node): Node => ({
14+
type: 'comparator',
15+
children: [first, second],
16+
value: name,
17+
});
18+
19+
/**
20+
* AST node representing the current node.
21+
*
22+
* The current node is a reference to the current value being processed.
23+
* In JMESPath, the current node is represented by the `@` symbol.
24+
*/
25+
const currentNode = (): Node => ({
26+
type: 'current',
27+
children: [],
28+
});
29+
30+
/**
31+
* AST node representing an expression reference.
32+
*
33+
* An expression reference is a reference to another expression.
34+
* In JMESPath, an expression reference is represented by the `&` symbol.
35+
*
36+
* @param expression The expression to reference
37+
*/
38+
const expref = (expression: Node): Node => ({
39+
type: 'expref',
40+
children: [expression],
41+
});
42+
43+
/**
44+
* AST node representing a function expression.
45+
*
46+
* A function expression is a reference to a function and its arguments.
47+
* The JMESPath specification defines a set of built-in functions that can
48+
* be used in expressions like `length(@)`, `map(@, &foo)`, etc.
49+
*
50+
* Custom functions can be added by extending the `Functions` class.
51+
*
52+
* @param name The name of the function
53+
* @param args The arguments to the function
54+
*/
55+
const functionExpression = (name: string, args: Node[]): Node => ({
56+
type: 'function_expression',
57+
children: args,
58+
value: name,
59+
});
60+
61+
/**
62+
* AST node representing a field reference.
63+
*
64+
* A field reference is a reference to a field in an object.
65+
*/
66+
const field = (name: JSONValue): Node => ({
67+
type: 'field',
68+
children: [],
69+
value: name,
70+
});
71+
72+
/**
73+
* AST node representing a filter projection.
74+
*
75+
* A filter projection is a binary expression that filters the left-hand side
76+
* based on the right-hand side.
77+
*
78+
* In JMESPath, a filter projection is represented by the `[]` operator.
79+
* For example, `people[?age > 18]` filters the `people` array based on the
80+
* `age` field.
81+
*
82+
* @param left The left-hand side of the filter projection
83+
* @param right The right-hand side of the filter projection
84+
* @param comparator The comparator to use for the filter
85+
*/
86+
const filterProjection = (left: Node, right: Node, comparator: Node): Node => ({
87+
type: 'filter_projection',
88+
children: [left, right, comparator],
89+
});
90+
91+
/**
92+
* AST node representing a flatten expression.
93+
*
94+
* A flatten expression is a unary expression that flattens an array of arrays
95+
* into a single array.
96+
*
97+
* In JMESPath, a flatten expression is represented by the `[]` operator.
98+
* For example, `people[].name` flattens the `people` array and returns the
99+
* `name` field of each object in the array.
100+
*
101+
* @param node The node to flatten
102+
*/
103+
const flatten = (node: Node): Node => ({
104+
type: 'flatten',
105+
children: [node],
106+
});
107+
108+
/**
109+
* AST node representing an identity expression.
110+
*/
111+
const identity = (): Node => ({ type: 'identity', children: [] });
112+
113+
/**
114+
* AST node representing an index reference.
115+
*
116+
* An index reference is a reference to an index in an array.
117+
* For example, `people[0]` references the first element in the `people` array.
118+
*
119+
* @param index The index to reference
120+
*/
121+
const index = (index: JSONValue): Node => ({
122+
type: 'index',
123+
value: index,
124+
children: [],
125+
});
126+
127+
/**
128+
* AST node representing an index expression.
129+
*
130+
* An index expression holds the index and the children of the expression.
131+
*
132+
* @param children The children of the index expression
133+
*/
134+
const indexExpression = (children: Node[]): Node => ({
135+
type: 'index_expression',
136+
children: children,
137+
});
138+
139+
/**
140+
* AST node representing a key-value pair.
141+
*
142+
* @param keyName The name of the key
143+
* @param node The value of the key
144+
*/
145+
const keyValPair = (keyName: JSONValue, node: Node): Node => ({
146+
type: 'key_val_pair',
147+
children: [node],
148+
value: keyName,
149+
});
150+
151+
/**
152+
* AST node representing a literal value.
153+
*
154+
* A literal value is a value that is not a reference to another node.
155+
*
156+
* @param literalValue The value of the literal
157+
*/
158+
const literal = (literalValue: JSONValue): Node => ({
159+
type: 'literal',
160+
value: literalValue,
161+
children: [],
162+
});
163+
164+
/**
165+
* AST node representing a multi-select object.
166+
*
167+
* A multi-select object is a reference to multiple nodes in an object.
168+
*
169+
* @param nodes
170+
*/
171+
const multiSelectObject = (nodes: Node[]): Node => ({
172+
type: 'multi_select_object',
173+
children: nodes,
174+
});
175+
176+
/**
177+
* AST node representing a multi-select list.
178+
*
179+
* @param nodes
180+
*/
181+
const multiSelectList = (nodes: Node[]): Node => ({
182+
type: 'multi_select_list',
183+
children: nodes,
184+
});
185+
186+
/**
187+
* AST node representing an or expression.
188+
*
189+
* @param left The left-hand side of the or expression
190+
* @param right The right-hand side of the or expression
191+
*/
192+
const orExpression = (left: Node, right: Node): Node => ({
193+
type: 'or_expression',
194+
children: [left, right],
195+
});
196+
197+
/**
198+
* AST node representing an and expression.
199+
*
200+
* @param left The left-hand side of the and expression
201+
* @param right The right-hand side of the and expression
202+
*/
203+
const andExpression = (left: Node, right: Node): Node => ({
204+
type: 'and_expression',
205+
children: [left, right],
206+
});
207+
208+
/**
209+
* AST node representing a not expression.
210+
*
211+
* @param left The left-hand side of the not expression
212+
* @param right The right-hand side of the not expression
213+
*/
214+
const notExpression = (expr: Node): Node => ({
215+
type: 'not_expression',
216+
children: [expr],
217+
});
218+
219+
/**
220+
* AST node representing a pipe expression.
221+
*
222+
* @param left The left-hand side of the pipe expression
223+
* @param right The right-hand side of the pipe expression
224+
*/
225+
const pipe = (left: Node, right: Node): Node => ({
226+
type: 'pipe',
227+
children: [left, right],
228+
});
229+
230+
/**
231+
* AST node representing a projection.
232+
*
233+
* @param left The left-hand side of the projection
234+
* @param right The right-hand side of the projection
235+
*/
236+
const projection = (left: Node, right: Node): Node => ({
237+
type: 'projection',
238+
children: [left, right],
239+
});
240+
241+
/**
242+
* AST node representing a subexpression.
243+
*
244+
* @param children The children of the subexpression
245+
*/
246+
const subexpression = (children: Node[]): Node => ({
247+
type: 'subexpression',
248+
children: children,
249+
});
250+
251+
/**
252+
* AST node representing a slice.
253+
*
254+
* A slice is a reference to a range of values in an array.
255+
*
256+
* @param start The start of the slice
257+
* @param end The end of the slice
258+
* @param step The step of the slice
259+
*/
260+
const slice = (start: JSONValue, end: JSONValue, step: JSONValue): Node => ({
261+
type: 'slice',
262+
children: [start as Node, end as Node, step as Node],
263+
});
264+
265+
/**
266+
* AST node representing a value projection.
267+
*
268+
* @param left The left-hand side of the value projection
269+
* @param right The right-hand side of the value projection
270+
*/
271+
const valueProjection = (left: Node, right: Node): Node => ({
272+
type: 'value_projection',
273+
children: [left, right],
274+
});
275+
276+
export {
277+
andExpression,
278+
comparator,
279+
currentNode,
280+
expref,
281+
field,
282+
filterProjection,
283+
flatten,
284+
functionExpression,
285+
identity,
286+
index,
287+
indexExpression,
288+
keyValPair,
289+
literal,
290+
multiSelectObject,
291+
multiSelectList,
292+
notExpression,
293+
orExpression,
294+
pipe,
295+
projection,
296+
slice,
297+
subexpression,
298+
valueProjection,
299+
};

0 commit comments

Comments
 (0)