@swaggerexpert/jsonpath 2.5.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,6 +38,7 @@ The development of this library contributed to the identification and formal sub
38
38
  - [Translators](#translators)
39
39
  - [CST](#cst-translator)
40
40
  - [CST Optimized](#cst-optimized-translator)
41
+ - [AST](#ast-translator)
41
42
  - [XML](#xml-translator)
42
43
  - [Statistics](#statistics)
43
44
  - [Tracing](#tracing)
@@ -118,37 +119,16 @@ parse("$['\\u000b']", { normalized: true });
118
119
  ###### CST translator
119
120
 
120
121
  [Concrete Syntax Tree](https://en.wikipedia.org/wiki/Parse_tree) (Parse tree) representation is available on parse result
121
- by default or when instance of `CSTTranslator` is provided via a `translator` option to the `parse` function.
122
+ when instance of `CSTTranslator` is provided via a `translator` option to the `parse` function.
122
123
  CST is suitable to be consumed by other tools like IDEs, editors, etc...
123
124
 
124
- ```js
125
- import { parse } from '@swaggerexpert/jsonpath';
126
-
127
- const { tree: CST } = parse('$.store.book[0].title');
128
- ```
129
-
130
- or
131
-
132
125
  ```js
133
126
  import { parse, CSTTranslator } from '@swaggerexpert/jsonpath';
134
127
 
135
128
  const { tree: CST } = parse('$.store.book[0].title', { translator: new CSTTranslator() });
136
129
  ```
137
130
 
138
- CST tree has the following shape:
139
-
140
- ```ts
141
- interface CSTTree {
142
- readonly root: CSTNode;
143
- }
144
- interface CSTNode {
145
- readonly type: string,
146
- readonly text: string,
147
- readonly start: number,
148
- readonly length: number,
149
- readonly children: CSTNode[],
150
- }
151
- ```
131
+ CST tree has a shape documented by [TypeScript typings (CSTTree)](https://github.com/swaggerexpert/jsonpath/blob/main/types/index.d.ts).
152
132
 
153
133
  ###### CST Optimized translator
154
134
 
@@ -162,6 +142,29 @@ import { parse, CSTOptimizedTranslator } from '@swaggerexpert/jsonpath';
162
142
  const { tree: CST } = parse('$.store.book[0].title', { translator: new CSTOptimizedTranslator() });
163
143
  ```
164
144
 
145
+ ###### AST translator
146
+
147
+ **Default translator**. [Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) representation is available on parse result
148
+ by default or when instance of `ASTTranslator` is provided via a `translator` option to the `parse` function.
149
+ AST is suitable to be consumed by implementations that need to analyze the structure of the JSONPath expression
150
+ or for building a custom JSONPath evaluation engine.
151
+
152
+ ```js
153
+ import { parse } from '@swaggerexpert/jsonpath';
154
+
155
+ const { tree: AST } = parse('$.store.book[0].title');
156
+ ```
157
+
158
+ or
159
+
160
+ ```js
161
+ import { parse, ASTTranslator } from '@swaggerexpert/jsonpath';
162
+
163
+ const { tree: AST } = parse('$.store.book[0].title', { translator: new ASTTranslator() });
164
+ ```
165
+
166
+ AST tree has a shape documented by [TypeScript typings (ASTTree)](https://github.com/swaggerexpert/jsonpath/blob/main/types/index.d.ts).
167
+
165
168
  ###### XML translator
166
169
 
167
170
  ```js
@@ -214,7 +217,7 @@ test('$.store.book[0].title'); // => true
214
217
  test('$$'); // => false
215
218
  ```
216
219
 
217
- Normalized paths can be validated by setting `normalized` option to `true`.
220
+ **Normalized paths** can be validated by setting `normalized` option to `true`.
218
221
 
219
222
  ```js
220
223
  import { test } from '@swaggerexpert/jsonpath';
package/cjs/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
- exports.test = exports.parse = exports.XMLTranslator = exports.Grammar = exports.CSTTranslator = exports.CSTOptimizedTranslator = void 0;
4
+ exports.test = exports.parse = exports.XMLTranslator = exports.Grammar = exports.CSTTranslator = exports.CSTOptimizedTranslator = exports.ASTTranslator = void 0;
5
5
  var _grammar = _interopRequireDefault(require("./grammar.cjs"));
6
6
  exports.Grammar = _grammar.default;
7
7
  var _index = _interopRequireDefault(require("./parse/index.cjs"));
@@ -10,8 +10,10 @@ var _CSTTranslator = _interopRequireDefault(require("./parse/translators/CSTTran
10
10
  exports.CSTTranslator = _CSTTranslator.default;
11
11
  var _CSTOptimizedTranslator = _interopRequireDefault(require("./parse/translators/CSTOptimizedTranslator.cjs"));
12
12
  exports.CSTOptimizedTranslator = _CSTOptimizedTranslator.default;
13
+ var _index2 = _interopRequireDefault(require("./parse/translators/ASTTranslator/index.cjs"));
14
+ exports.ASTTranslator = _index2.default;
13
15
  var _XMLTranslator = _interopRequireDefault(require("./parse/translators/XMLTranslator.cjs"));
14
16
  exports.XMLTranslator = _XMLTranslator.default;
15
- var _index2 = _interopRequireDefault(require("./test/index.cjs"));
16
- exports.test = _index2.default;
17
+ var _index3 = _interopRequireDefault(require("./test/index.cjs"));
18
+ exports.test = _index3.default;
17
19
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -4,7 +4,7 @@ exports.__esModule = true;
4
4
  exports.default = void 0;
5
5
  var _apgLite = require("../apg-lite.cjs");
6
6
  var _grammar = _interopRequireDefault(require("../grammar.cjs"));
7
- var _CSTTranslator = _interopRequireDefault(require("./translators/CSTTranslator.cjs"));
7
+ var _index = _interopRequireDefault(require("./translators/ASTTranslator/index.cjs"));
8
8
  var _JSONPathParseError = _interopRequireDefault(require("../errors/JSONPathParseError.cjs"));
9
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
10
  const grammar = new _grammar.default();
@@ -12,7 +12,7 @@ const parse = (jsonPath, {
12
12
  normalized = false,
13
13
  stats = false,
14
14
  trace = false,
15
- translator = new _CSTTranslator.default()
15
+ translator = new _index.default()
16
16
  } = {}) => {
17
17
  if (typeof jsonPath !== 'string') {
18
18
  throw new TypeError('JSONPath must be a string');
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.decodeString = exports.decodeJSONValue = exports.decodeInteger = void 0;
5
+ const decodeString = str => {
6
+ return JSON.parse(`"${str.replace(/"/g, '\\"')}"`);
7
+ };
8
+ exports.decodeString = decodeString;
9
+ const decodeInteger = str => {
10
+ return parseInt(str, 10);
11
+ };
12
+ exports.decodeInteger = decodeInteger;
13
+ const decodeJSONValue = str => {
14
+ return JSON.parse(str);
15
+ };
16
+ exports.decodeJSONValue = decodeJSONValue;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ var _CSTOptimizedTranslator = _interopRequireDefault(require("../CSTOptimizedTranslator.cjs"));
6
+ var _transformers = _interopRequireWildcard(require("./transformers.cjs"));
7
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
8
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ class ASTTranslator extends _CSTOptimizedTranslator.default {
11
+ getTree() {
12
+ const cst = super.getTree();
13
+ return (0, _transformers.transformCSTtoAST)(cst.root, _transformers.default);
14
+ }
15
+ }
16
+ var _default = exports.default = ASTTranslator;
@@ -0,0 +1,410 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.transformCSTtoAST = exports.default = void 0;
5
+ var _JSONPathParseError = _interopRequireDefault(require("../../../errors/JSONPathParseError.cjs"));
6
+ var _decoders = require("./decoders.cjs");
7
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
8
+ const transformCSTtoAST = (node, transformerMap, ctx = {
9
+ parent: null,
10
+ path: []
11
+ }) => {
12
+ const transformer = transformerMap[node.type];
13
+ if (!transformer) {
14
+ throw new _JSONPathParseError.default(`No transformer for CST node type: ${node.type}`);
15
+ }
16
+ const nextCtx = {
17
+ parent: node,
18
+ path: [...ctx.path, node]
19
+ };
20
+ return transformer(node, nextCtx);
21
+ };
22
+ exports.transformCSTtoAST = transformCSTtoAST;
23
+ const transformers = {
24
+ /**
25
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.1.1
26
+ */
27
+ ['jsonpath-query'](node, ctx) {
28
+ const segments = node.children.find(c => c.type === 'segments');
29
+ return {
30
+ type: 'JsonPathQuery',
31
+ segments: segments ? segments.children.filter(({
32
+ type
33
+ }) => type === 'segment').map(segNode => transformCSTtoAST(segNode, transformers, ctx)) : []
34
+ };
35
+ },
36
+ /**
37
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.5
38
+ */
39
+ segment(node, ctx) {
40
+ const child = node.children.find(({
41
+ type
42
+ }) => ['child-segment', 'descendant-segment'].includes(type));
43
+ return transformCSTtoAST(child, transformers, ctx);
44
+ },
45
+ /**
46
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3
47
+ */
48
+ selector(node, ctx) {
49
+ const child = node.children.find(({
50
+ type
51
+ }) => ['name-selector', 'wildcard-selector', 'slice-selector', 'index-selector', 'filter-selector'].includes(type));
52
+ return transformCSTtoAST(child, transformers, ctx);
53
+ },
54
+ /**
55
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.1.1
56
+ */
57
+ ['name-selector'](node, ctx) {
58
+ const stringLiteralCSTNode = node.children.find(({
59
+ type
60
+ }) => type === 'string-literal');
61
+ const stringLiteralASTNode = transformCSTtoAST(stringLiteralCSTNode, transformers, ctx);
62
+ return {
63
+ type: 'NameSelector',
64
+ value: stringLiteralASTNode.value,
65
+ format: stringLiteralASTNode.format
66
+ };
67
+ },
68
+ ['string-literal'](node) {
69
+ const isSingleQuoted = node.children.find(({
70
+ type,
71
+ text
72
+ }) => type === 'text' && text === "'");
73
+ const quoted = node.children.find(({
74
+ type
75
+ }) => ['double-quoted', 'single-quoted'].includes(type));
76
+ return {
77
+ type: 'StringLiteral',
78
+ value: quoted ? (0, _decoders.decodeString)(quoted.text) : '',
79
+ format: isSingleQuoted ? 'single-quoted' : 'double-quoted'
80
+ };
81
+ },
82
+ /**
83
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.2.1
84
+ */
85
+ ['wildcard-selector']() {
86
+ return {
87
+ type: 'WildcardSelector'
88
+ };
89
+ },
90
+ /**
91
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.3.1
92
+ */
93
+ ['index-selector'](node) {
94
+ return {
95
+ type: 'IndexSelector',
96
+ value: (0, _decoders.decodeInteger)(node.text)
97
+ };
98
+ },
99
+ /**
100
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.4.1
101
+ */
102
+ ['slice-selector'](node) {
103
+ const start = node.children.find(({
104
+ type
105
+ }) => type === 'start');
106
+ const end = node.children.find(({
107
+ type
108
+ }) => type === 'end');
109
+ const step = node.children.find(({
110
+ type
111
+ }) => type === 'step');
112
+ return {
113
+ type: 'SliceSelector',
114
+ start: start ? (0, _decoders.decodeInteger)(start.text) : null,
115
+ end: end ? (0, _decoders.decodeInteger)(end.text) : null,
116
+ step: step ? (0, _decoders.decodeInteger)(step.text) : null
117
+ };
118
+ },
119
+ /**
120
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.5.1
121
+ */
122
+ ['filter-selector'](node, ctx) {
123
+ const child = node.children.find(({
124
+ type
125
+ }) => type === 'logical-expr');
126
+ return {
127
+ type: 'FilterSelector',
128
+ expression: transformCSTtoAST(child, transformers, ctx)
129
+ };
130
+ },
131
+ ['logical-expr'](node, ctx) {
132
+ const child = node.children.find(({
133
+ type
134
+ }) => type === 'logical-or-expr');
135
+ return transformCSTtoAST(child, transformers, ctx);
136
+ },
137
+ ['logical-or-expr'](node, ctx) {
138
+ const logicalAndExprs = node.children.filter(({
139
+ type
140
+ }) => type === 'logical-and-expr');
141
+ if (logicalAndExprs.length === 1) {
142
+ return transformCSTtoAST(logicalAndExprs[0], transformers, ctx);
143
+ }
144
+
145
+ // fold left for left-associativity
146
+ let left = transformCSTtoAST(logicalAndExprs[0], transformers, ctx);
147
+ for (let i = 1; i < logicalAndExprs.length; i += 1) {
148
+ const right = transformCSTtoAST(logicalAndExprs[i], transformers, ctx);
149
+ left = {
150
+ type: 'LogicalOrExpr',
151
+ left,
152
+ right
153
+ };
154
+ }
155
+ },
156
+ ['logical-and-expr'](node, ctx) {
157
+ const basicExprs = node.children.filter(({
158
+ type
159
+ }) => type === 'basic-expr');
160
+ if (basicExprs.length === 1) {
161
+ return transformCSTtoAST(basicExprs[0], transformers, ctx);
162
+ }
163
+ let left = transformCSTtoAST(basicExprs[0], transformers, ctx);
164
+ for (let i = 1; i < basicExprs.length; i += 1) {
165
+ const right = transformCSTtoAST(basicExprs[i], transformers, ctx);
166
+ left = {
167
+ type: 'LogicalAndExpr',
168
+ left,
169
+ right
170
+ };
171
+ }
172
+ return left;
173
+ },
174
+ ['basic-expr'](node, ctx) {
175
+ const child = node.children.find(({
176
+ type
177
+ }) => ['paren-expr', 'comparison-expr', 'test-expr'].includes(type));
178
+ return transformCSTtoAST(child, transformers, ctx);
179
+ },
180
+ ['paren-expr'](node, ctx) {
181
+ const isNegated = node.children.some(child => child.type === 'logical-not-op');
182
+ const logicalExprCSTNode = node.children.find(child => child.type === 'logical-expr');
183
+ const logicalExpressionASTNode = transformCSTtoAST(logicalExprCSTNode, transformers, ctx);
184
+ if (isNegated) {
185
+ return {
186
+ type: 'LogicalNotExpr',
187
+ expression: logicalExpressionASTNode
188
+ };
189
+ }
190
+ return logicalExpressionASTNode;
191
+ },
192
+ ['test-expr'](node, ctx) {
193
+ const isNegated = node.children.some(({
194
+ type
195
+ }) => type === 'logical-not-op');
196
+ const expression = node.children.find(({
197
+ type
198
+ }) => ['filter-query', 'function-expr'].includes(type));
199
+ const testExpr = {
200
+ type: 'TestExpr',
201
+ expression: transformCSTtoAST(expression, transformers, ctx)
202
+ };
203
+ return isNegated ? {
204
+ type: 'LogicalNotExpr',
205
+ expression: testExpr
206
+ } : testExpr;
207
+ },
208
+ ['filter-query'](node, ctx) {
209
+ const child = node.children.find(({
210
+ type
211
+ }) => ['rel-query', 'jsonpath-query'].includes(type));
212
+ return {
213
+ type: 'FilterQuery',
214
+ query: transformCSTtoAST(child, transformers, ctx)
215
+ };
216
+ },
217
+ ['rel-query'](node, ctx) {
218
+ const segments = node.children.find(c => c.type === 'segments');
219
+ return {
220
+ type: 'RelQuery',
221
+ segments: segments ? segments.children.filter(n => n.type === 'segment').map(segNode => transformCSTtoAST(segNode, transformers, ctx)) : []
222
+ };
223
+ },
224
+ ['comparison-expr'](node, ctx) {
225
+ const children = node.children.filter(({
226
+ type
227
+ }) => ['comparable', 'comparison-op'].includes(type));
228
+ const [left, op, right] = children;
229
+ return {
230
+ type: 'ComparisonExpr',
231
+ left: transformCSTtoAST(left, transformers, ctx),
232
+ op: op.text,
233
+ right: transformCSTtoAST(right, transformers, ctx)
234
+ };
235
+ },
236
+ ['literal'](node, ctx) {
237
+ const child = node.children.find(({
238
+ type
239
+ }) => ['number', 'string-literal', 'true', 'false', 'null'].includes(type));
240
+ if (child.type === 'string-literal') {
241
+ const stringLiteralASTNode = transformCSTtoAST(child, transformers, ctx);
242
+ return {
243
+ type: 'Literal',
244
+ value: stringLiteralASTNode.value
245
+ };
246
+ }
247
+ return {
248
+ type: 'Literal',
249
+ value: (0, _decoders.decodeJSONValue)(child.text)
250
+ };
251
+ },
252
+ ['comparable'](node, ctx) {
253
+ const child = node.children.find(({
254
+ type
255
+ }) => ['singular-query', 'function-expr', 'literal'].includes(type));
256
+ return transformCSTtoAST(child, transformers, ctx);
257
+ },
258
+ ['singular-query'](node, ctx) {
259
+ const child = node.children.find(({
260
+ type
261
+ }) => ['rel-singular-query', 'abs-singular-query'].includes(type));
262
+ return transformCSTtoAST(child, transformers, ctx);
263
+ },
264
+ ['rel-singular-query'](node, ctx) {
265
+ const segmentsNode = node.children.find(({
266
+ type
267
+ }) => type === 'singular-query-segments');
268
+ const segments = segmentsNode ? segmentsNode.children.filter(({
269
+ type
270
+ }) => ['name-segment', 'index-segment'].includes(type)).map(segNode => ({
271
+ type: 'SingularQuerySegment',
272
+ selector: transformCSTtoAST(segNode, transformers, ctx)
273
+ })) : [];
274
+ return {
275
+ type: 'RelSingularQuery',
276
+ segments
277
+ };
278
+ },
279
+ ['abs-singular-query'](node, ctx) {
280
+ const segmentsNode = node.children.find(({
281
+ type
282
+ }) => type === 'singular-query-segments');
283
+ const segments = segmentsNode ? segmentsNode.children.filter(({
284
+ type
285
+ }) => ['name-segment', 'index-segment'].includes(type)).map(segNode => ({
286
+ type: 'SingularQuerySegment',
287
+ selector: transformCSTtoAST(segNode, transformers, ctx)
288
+ })) : [];
289
+ return {
290
+ type: 'AbsSingularQuery',
291
+ segments
292
+ };
293
+ },
294
+ ['name-segment'](node, ctx) {
295
+ const child = node.children.find(({
296
+ type
297
+ }) => ['name-selector', 'member-name-shorthand'].includes(type));
298
+ return transformCSTtoAST(child, transformers, ctx);
299
+ },
300
+ ['index-segment'](node, ctx) {
301
+ const child = node.children.find(({
302
+ type
303
+ }) => type === 'index-selector');
304
+ return transformCSTtoAST(child, transformers, ctx);
305
+ },
306
+ /**
307
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.4
308
+ */
309
+ ['function-expr'](node, ctx) {
310
+ const name = node.children.find(({
311
+ type
312
+ }) => type === 'function-name');
313
+ const args = node.children.filter(({
314
+ type
315
+ }) => type === 'function-argument');
316
+ return {
317
+ type: 'FunctionExpr',
318
+ name: name.text,
319
+ arguments: args.map(arg => transformCSTtoAST(arg, transformers, ctx))
320
+ };
321
+ },
322
+ ['function-argument'](node, ctx) {
323
+ const child = node.children.find(({
324
+ type
325
+ }) => ['logical-expr', 'function-expr', 'filter-query', 'literal'].includes(type));
326
+ return transformCSTtoAST(child, transformers, ctx);
327
+ },
328
+ /**
329
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.5.1.1
330
+ */
331
+ ['child-segment'](node, ctx) {
332
+ const child = node.children.find(({
333
+ type
334
+ }) => ['bracketed-selection', 'wildcard-selector', 'member-name-shorthand'].includes(type));
335
+ return {
336
+ type: 'ChildSegment',
337
+ selector: transformCSTtoAST(child, transformers, ctx)
338
+ };
339
+ },
340
+ ['bracketed-selection'](node, ctx) {
341
+ return {
342
+ type: 'BracketedSelection',
343
+ selectors: node.children.filter(({
344
+ type
345
+ }) => type === 'selector').map(selectorNode => transformCSTtoAST(selectorNode, transformers, ctx))
346
+ };
347
+ },
348
+ ['member-name-shorthand'](node) {
349
+ return {
350
+ type: 'NameSelector',
351
+ value: node.text,
352
+ format: 'shorthand'
353
+ };
354
+ },
355
+ /**
356
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.5.2.1
357
+ */
358
+ ['descendant-segment'](node, ctx) {
359
+ const child = node.children.find(({
360
+ type
361
+ }) => ['bracketed-selection', 'wildcard-selector', 'member-name-shorthand'].includes(type));
362
+ return {
363
+ type: 'DescendantSegment',
364
+ selector: transformCSTtoAST(child, transformers, ctx)
365
+ };
366
+ },
367
+ /**
368
+ * https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths
369
+ */
370
+ ['normalized-path'](node, ctx) {
371
+ return {
372
+ type: 'JsonPathQuery',
373
+ segments: node.children.filter(({
374
+ type
375
+ }) => type === 'normal-index-segment').map(segNode => transformCSTtoAST(segNode, transformers, ctx))
376
+ };
377
+ },
378
+ ['normal-index-segment'](node, ctx) {
379
+ const child = node.children.find(({
380
+ type
381
+ }) => type === 'normal-selector');
382
+ return {
383
+ type: 'ChildSegment',
384
+ selector: transformCSTtoAST(child, transformers, ctx)
385
+ };
386
+ },
387
+ ['normal-selector'](node, ctx) {
388
+ const child = node.children.find(({
389
+ type
390
+ }) => ['normal-name-selector', 'normal-index-selector'].includes(type));
391
+ return transformCSTtoAST(child, transformers, ctx);
392
+ },
393
+ ['normal-name-selector'](node) {
394
+ const child = node.children.find(({
395
+ type
396
+ }) => type === 'normal-single-quoted');
397
+ return {
398
+ type: 'NameSelector',
399
+ value: child ? (0, _decoders.decodeString)(child.text) : '',
400
+ format: 'single-quoted'
401
+ };
402
+ },
403
+ ['normal-index-selector'](node) {
404
+ return {
405
+ type: 'IndexSelector',
406
+ value: (0, _decoders.decodeInteger)(node.text)
407
+ };
408
+ }
409
+ };
410
+ var _default = exports.default = transformers;
@@ -8,12 +8,16 @@ class CSTOptimizedTranslator extends _CSTTranslator.default {
8
8
  collapsibleTypes = ['single-quoted', 'double-quoted', 'normal-single-quoted'];
9
9
  droppableTypes = ['text', 'segments', 'singular-query-segments'];
10
10
  constructor({
11
- collapsibleTypes
11
+ collapsibleTypes,
12
+ droppableTypes
12
13
  } = {}) {
13
14
  super();
14
15
  if (Array.isArray(collapsibleTypes)) {
15
16
  this.collapsibleTypes = collapsibleTypes;
16
17
  }
18
+ if (Array.isArray(droppableTypes)) {
19
+ this.droppableTypes = droppableTypes;
20
+ }
17
21
  }
18
22
  getTree() {
19
23
  const options = {
package/es/index.mjs CHANGED
@@ -2,5 +2,6 @@ export { default as Grammar } from "./grammar.mjs";
2
2
  export { default as parse } from "./parse/index.mjs";
3
3
  export { default as CSTTranslator } from "./parse/translators/CSTTranslator.mjs";
4
4
  export { default as CSTOptimizedTranslator } from "./parse/translators/CSTOptimizedTranslator.mjs";
5
+ export { default as ASTTranslator } from "./parse/translators/ASTTranslator/index.mjs";
5
6
  export { default as XMLTranslator } from "./parse/translators/XMLTranslator.mjs";
6
7
  export { default as test } from "./test/index.mjs";
@@ -1,13 +1,13 @@
1
1
  import { Parser, Stats, Trace } from 'apg-lite';
2
2
  import Grammar from "../grammar.mjs";
3
- import CSTTranslator from "./translators/CSTTranslator.mjs";
3
+ import ASTTranslator from "./translators/ASTTranslator/index.mjs";
4
4
  import JSONPathParseError from "../errors/JSONPathParseError.mjs";
5
5
  const grammar = new Grammar();
6
6
  const parse = (jsonPath, {
7
7
  normalized = false,
8
8
  stats = false,
9
9
  trace = false,
10
- translator = new CSTTranslator()
10
+ translator = new ASTTranslator()
11
11
  } = {}) => {
12
12
  if (typeof jsonPath !== 'string') {
13
13
  throw new TypeError('JSONPath must be a string');
@@ -0,0 +1,9 @@
1
+ export const decodeString = str => {
2
+ return JSON.parse(`"${str.replace(/"/g, '\\"')}"`);
3
+ };
4
+ export const decodeInteger = str => {
5
+ return parseInt(str, 10);
6
+ };
7
+ export const decodeJSONValue = str => {
8
+ return JSON.parse(str);
9
+ };
@@ -0,0 +1,9 @@
1
+ import CSTOptimizedTranslator from "../CSTOptimizedTranslator.mjs";
2
+ import { transformCSTtoAST, default as transformers } from "./transformers.mjs";
3
+ class ASTTranslator extends CSTOptimizedTranslator {
4
+ getTree() {
5
+ const cst = super.getTree();
6
+ return transformCSTtoAST(cst.root, transformers);
7
+ }
8
+ }
9
+ export default ASTTranslator;
@@ -0,0 +1,404 @@
1
+ import JSONPathParseError from "../../../errors/JSONPathParseError.mjs";
2
+ import { decodeString, decodeInteger, decodeJSONValue } from "./decoders.mjs";
3
+ export const transformCSTtoAST = (node, transformerMap, ctx = {
4
+ parent: null,
5
+ path: []
6
+ }) => {
7
+ const transformer = transformerMap[node.type];
8
+ if (!transformer) {
9
+ throw new JSONPathParseError(`No transformer for CST node type: ${node.type}`);
10
+ }
11
+ const nextCtx = {
12
+ parent: node,
13
+ path: [...ctx.path, node]
14
+ };
15
+ return transformer(node, nextCtx);
16
+ };
17
+ const transformers = {
18
+ /**
19
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.1.1
20
+ */
21
+ ['jsonpath-query'](node, ctx) {
22
+ const segments = node.children.find(c => c.type === 'segments');
23
+ return {
24
+ type: 'JsonPathQuery',
25
+ segments: segments ? segments.children.filter(({
26
+ type
27
+ }) => type === 'segment').map(segNode => transformCSTtoAST(segNode, transformers, ctx)) : []
28
+ };
29
+ },
30
+ /**
31
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.5
32
+ */
33
+ segment(node, ctx) {
34
+ const child = node.children.find(({
35
+ type
36
+ }) => ['child-segment', 'descendant-segment'].includes(type));
37
+ return transformCSTtoAST(child, transformers, ctx);
38
+ },
39
+ /**
40
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3
41
+ */
42
+ selector(node, ctx) {
43
+ const child = node.children.find(({
44
+ type
45
+ }) => ['name-selector', 'wildcard-selector', 'slice-selector', 'index-selector', 'filter-selector'].includes(type));
46
+ return transformCSTtoAST(child, transformers, ctx);
47
+ },
48
+ /**
49
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.1.1
50
+ */
51
+ ['name-selector'](node, ctx) {
52
+ const stringLiteralCSTNode = node.children.find(({
53
+ type
54
+ }) => type === 'string-literal');
55
+ const stringLiteralASTNode = transformCSTtoAST(stringLiteralCSTNode, transformers, ctx);
56
+ return {
57
+ type: 'NameSelector',
58
+ value: stringLiteralASTNode.value,
59
+ format: stringLiteralASTNode.format
60
+ };
61
+ },
62
+ ['string-literal'](node) {
63
+ const isSingleQuoted = node.children.find(({
64
+ type,
65
+ text
66
+ }) => type === 'text' && text === "'");
67
+ const quoted = node.children.find(({
68
+ type
69
+ }) => ['double-quoted', 'single-quoted'].includes(type));
70
+ return {
71
+ type: 'StringLiteral',
72
+ value: quoted ? decodeString(quoted.text) : '',
73
+ format: isSingleQuoted ? 'single-quoted' : 'double-quoted'
74
+ };
75
+ },
76
+ /**
77
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.2.1
78
+ */
79
+ ['wildcard-selector']() {
80
+ return {
81
+ type: 'WildcardSelector'
82
+ };
83
+ },
84
+ /**
85
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.3.1
86
+ */
87
+ ['index-selector'](node) {
88
+ return {
89
+ type: 'IndexSelector',
90
+ value: decodeInteger(node.text)
91
+ };
92
+ },
93
+ /**
94
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.4.1
95
+ */
96
+ ['slice-selector'](node) {
97
+ const start = node.children.find(({
98
+ type
99
+ }) => type === 'start');
100
+ const end = node.children.find(({
101
+ type
102
+ }) => type === 'end');
103
+ const step = node.children.find(({
104
+ type
105
+ }) => type === 'step');
106
+ return {
107
+ type: 'SliceSelector',
108
+ start: start ? decodeInteger(start.text) : null,
109
+ end: end ? decodeInteger(end.text) : null,
110
+ step: step ? decodeInteger(step.text) : null
111
+ };
112
+ },
113
+ /**
114
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.5.1
115
+ */
116
+ ['filter-selector'](node, ctx) {
117
+ const child = node.children.find(({
118
+ type
119
+ }) => type === 'logical-expr');
120
+ return {
121
+ type: 'FilterSelector',
122
+ expression: transformCSTtoAST(child, transformers, ctx)
123
+ };
124
+ },
125
+ ['logical-expr'](node, ctx) {
126
+ const child = node.children.find(({
127
+ type
128
+ }) => type === 'logical-or-expr');
129
+ return transformCSTtoAST(child, transformers, ctx);
130
+ },
131
+ ['logical-or-expr'](node, ctx) {
132
+ const logicalAndExprs = node.children.filter(({
133
+ type
134
+ }) => type === 'logical-and-expr');
135
+ if (logicalAndExprs.length === 1) {
136
+ return transformCSTtoAST(logicalAndExprs[0], transformers, ctx);
137
+ }
138
+
139
+ // fold left for left-associativity
140
+ let left = transformCSTtoAST(logicalAndExprs[0], transformers, ctx);
141
+ for (let i = 1; i < logicalAndExprs.length; i += 1) {
142
+ const right = transformCSTtoAST(logicalAndExprs[i], transformers, ctx);
143
+ left = {
144
+ type: 'LogicalOrExpr',
145
+ left,
146
+ right
147
+ };
148
+ }
149
+ },
150
+ ['logical-and-expr'](node, ctx) {
151
+ const basicExprs = node.children.filter(({
152
+ type
153
+ }) => type === 'basic-expr');
154
+ if (basicExprs.length === 1) {
155
+ return transformCSTtoAST(basicExprs[0], transformers, ctx);
156
+ }
157
+ let left = transformCSTtoAST(basicExprs[0], transformers, ctx);
158
+ for (let i = 1; i < basicExprs.length; i += 1) {
159
+ const right = transformCSTtoAST(basicExprs[i], transformers, ctx);
160
+ left = {
161
+ type: 'LogicalAndExpr',
162
+ left,
163
+ right
164
+ };
165
+ }
166
+ return left;
167
+ },
168
+ ['basic-expr'](node, ctx) {
169
+ const child = node.children.find(({
170
+ type
171
+ }) => ['paren-expr', 'comparison-expr', 'test-expr'].includes(type));
172
+ return transformCSTtoAST(child, transformers, ctx);
173
+ },
174
+ ['paren-expr'](node, ctx) {
175
+ const isNegated = node.children.some(child => child.type === 'logical-not-op');
176
+ const logicalExprCSTNode = node.children.find(child => child.type === 'logical-expr');
177
+ const logicalExpressionASTNode = transformCSTtoAST(logicalExprCSTNode, transformers, ctx);
178
+ if (isNegated) {
179
+ return {
180
+ type: 'LogicalNotExpr',
181
+ expression: logicalExpressionASTNode
182
+ };
183
+ }
184
+ return logicalExpressionASTNode;
185
+ },
186
+ ['test-expr'](node, ctx) {
187
+ const isNegated = node.children.some(({
188
+ type
189
+ }) => type === 'logical-not-op');
190
+ const expression = node.children.find(({
191
+ type
192
+ }) => ['filter-query', 'function-expr'].includes(type));
193
+ const testExpr = {
194
+ type: 'TestExpr',
195
+ expression: transformCSTtoAST(expression, transformers, ctx)
196
+ };
197
+ return isNegated ? {
198
+ type: 'LogicalNotExpr',
199
+ expression: testExpr
200
+ } : testExpr;
201
+ },
202
+ ['filter-query'](node, ctx) {
203
+ const child = node.children.find(({
204
+ type
205
+ }) => ['rel-query', 'jsonpath-query'].includes(type));
206
+ return {
207
+ type: 'FilterQuery',
208
+ query: transformCSTtoAST(child, transformers, ctx)
209
+ };
210
+ },
211
+ ['rel-query'](node, ctx) {
212
+ const segments = node.children.find(c => c.type === 'segments');
213
+ return {
214
+ type: 'RelQuery',
215
+ segments: segments ? segments.children.filter(n => n.type === 'segment').map(segNode => transformCSTtoAST(segNode, transformers, ctx)) : []
216
+ };
217
+ },
218
+ ['comparison-expr'](node, ctx) {
219
+ const children = node.children.filter(({
220
+ type
221
+ }) => ['comparable', 'comparison-op'].includes(type));
222
+ const [left, op, right] = children;
223
+ return {
224
+ type: 'ComparisonExpr',
225
+ left: transformCSTtoAST(left, transformers, ctx),
226
+ op: op.text,
227
+ right: transformCSTtoAST(right, transformers, ctx)
228
+ };
229
+ },
230
+ ['literal'](node, ctx) {
231
+ const child = node.children.find(({
232
+ type
233
+ }) => ['number', 'string-literal', 'true', 'false', 'null'].includes(type));
234
+ if (child.type === 'string-literal') {
235
+ const stringLiteralASTNode = transformCSTtoAST(child, transformers, ctx);
236
+ return {
237
+ type: 'Literal',
238
+ value: stringLiteralASTNode.value
239
+ };
240
+ }
241
+ return {
242
+ type: 'Literal',
243
+ value: decodeJSONValue(child.text)
244
+ };
245
+ },
246
+ ['comparable'](node, ctx) {
247
+ const child = node.children.find(({
248
+ type
249
+ }) => ['singular-query', 'function-expr', 'literal'].includes(type));
250
+ return transformCSTtoAST(child, transformers, ctx);
251
+ },
252
+ ['singular-query'](node, ctx) {
253
+ const child = node.children.find(({
254
+ type
255
+ }) => ['rel-singular-query', 'abs-singular-query'].includes(type));
256
+ return transformCSTtoAST(child, transformers, ctx);
257
+ },
258
+ ['rel-singular-query'](node, ctx) {
259
+ const segmentsNode = node.children.find(({
260
+ type
261
+ }) => type === 'singular-query-segments');
262
+ const segments = segmentsNode ? segmentsNode.children.filter(({
263
+ type
264
+ }) => ['name-segment', 'index-segment'].includes(type)).map(segNode => ({
265
+ type: 'SingularQuerySegment',
266
+ selector: transformCSTtoAST(segNode, transformers, ctx)
267
+ })) : [];
268
+ return {
269
+ type: 'RelSingularQuery',
270
+ segments
271
+ };
272
+ },
273
+ ['abs-singular-query'](node, ctx) {
274
+ const segmentsNode = node.children.find(({
275
+ type
276
+ }) => type === 'singular-query-segments');
277
+ const segments = segmentsNode ? segmentsNode.children.filter(({
278
+ type
279
+ }) => ['name-segment', 'index-segment'].includes(type)).map(segNode => ({
280
+ type: 'SingularQuerySegment',
281
+ selector: transformCSTtoAST(segNode, transformers, ctx)
282
+ })) : [];
283
+ return {
284
+ type: 'AbsSingularQuery',
285
+ segments
286
+ };
287
+ },
288
+ ['name-segment'](node, ctx) {
289
+ const child = node.children.find(({
290
+ type
291
+ }) => ['name-selector', 'member-name-shorthand'].includes(type));
292
+ return transformCSTtoAST(child, transformers, ctx);
293
+ },
294
+ ['index-segment'](node, ctx) {
295
+ const child = node.children.find(({
296
+ type
297
+ }) => type === 'index-selector');
298
+ return transformCSTtoAST(child, transformers, ctx);
299
+ },
300
+ /**
301
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.4
302
+ */
303
+ ['function-expr'](node, ctx) {
304
+ const name = node.children.find(({
305
+ type
306
+ }) => type === 'function-name');
307
+ const args = node.children.filter(({
308
+ type
309
+ }) => type === 'function-argument');
310
+ return {
311
+ type: 'FunctionExpr',
312
+ name: name.text,
313
+ arguments: args.map(arg => transformCSTtoAST(arg, transformers, ctx))
314
+ };
315
+ },
316
+ ['function-argument'](node, ctx) {
317
+ const child = node.children.find(({
318
+ type
319
+ }) => ['logical-expr', 'function-expr', 'filter-query', 'literal'].includes(type));
320
+ return transformCSTtoAST(child, transformers, ctx);
321
+ },
322
+ /**
323
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.5.1.1
324
+ */
325
+ ['child-segment'](node, ctx) {
326
+ const child = node.children.find(({
327
+ type
328
+ }) => ['bracketed-selection', 'wildcard-selector', 'member-name-shorthand'].includes(type));
329
+ return {
330
+ type: 'ChildSegment',
331
+ selector: transformCSTtoAST(child, transformers, ctx)
332
+ };
333
+ },
334
+ ['bracketed-selection'](node, ctx) {
335
+ return {
336
+ type: 'BracketedSelection',
337
+ selectors: node.children.filter(({
338
+ type
339
+ }) => type === 'selector').map(selectorNode => transformCSTtoAST(selectorNode, transformers, ctx))
340
+ };
341
+ },
342
+ ['member-name-shorthand'](node) {
343
+ return {
344
+ type: 'NameSelector',
345
+ value: node.text,
346
+ format: 'shorthand'
347
+ };
348
+ },
349
+ /**
350
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.5.2.1
351
+ */
352
+ ['descendant-segment'](node, ctx) {
353
+ const child = node.children.find(({
354
+ type
355
+ }) => ['bracketed-selection', 'wildcard-selector', 'member-name-shorthand'].includes(type));
356
+ return {
357
+ type: 'DescendantSegment',
358
+ selector: transformCSTtoAST(child, transformers, ctx)
359
+ };
360
+ },
361
+ /**
362
+ * https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths
363
+ */
364
+ ['normalized-path'](node, ctx) {
365
+ return {
366
+ type: 'JsonPathQuery',
367
+ segments: node.children.filter(({
368
+ type
369
+ }) => type === 'normal-index-segment').map(segNode => transformCSTtoAST(segNode, transformers, ctx))
370
+ };
371
+ },
372
+ ['normal-index-segment'](node, ctx) {
373
+ const child = node.children.find(({
374
+ type
375
+ }) => type === 'normal-selector');
376
+ return {
377
+ type: 'ChildSegment',
378
+ selector: transformCSTtoAST(child, transformers, ctx)
379
+ };
380
+ },
381
+ ['normal-selector'](node, ctx) {
382
+ const child = node.children.find(({
383
+ type
384
+ }) => ['normal-name-selector', 'normal-index-selector'].includes(type));
385
+ return transformCSTtoAST(child, transformers, ctx);
386
+ },
387
+ ['normal-name-selector'](node) {
388
+ const child = node.children.find(({
389
+ type
390
+ }) => type === 'normal-single-quoted');
391
+ return {
392
+ type: 'NameSelector',
393
+ value: child ? decodeString(child.text) : '',
394
+ format: 'single-quoted'
395
+ };
396
+ },
397
+ ['normal-index-selector'](node) {
398
+ return {
399
+ type: 'IndexSelector',
400
+ value: decodeInteger(node.text)
401
+ };
402
+ }
403
+ };
404
+ export default transformers;
@@ -3,12 +3,16 @@ class CSTOptimizedTranslator extends CSTTranslator {
3
3
  collapsibleTypes = ['single-quoted', 'double-quoted', 'normal-single-quoted'];
4
4
  droppableTypes = ['text', 'segments', 'singular-query-segments'];
5
5
  constructor({
6
- collapsibleTypes
6
+ collapsibleTypes,
7
+ droppableTypes
7
8
  } = {}) {
8
9
  super();
9
10
  if (Array.isArray(collapsibleTypes)) {
10
11
  this.collapsibleTypes = collapsibleTypes;
11
12
  }
13
+ if (Array.isArray(droppableTypes)) {
14
+ this.droppableTypes = droppableTypes;
15
+ }
12
16
  }
13
17
  getTree() {
14
18
  const options = {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "2.5.0",
6
+ "version": "3.0.1",
7
7
  "description": "RCF 9535 implementation of JSONPath",
8
8
  "main": "./cjs/index.cjs",
9
9
  "types": "./types/index.d.ts",
package/types/index.d.ts CHANGED
@@ -20,11 +20,14 @@ export declare class CSTOptimizedTranslator implements CSTTranslator {
20
20
  constructor(options?: { collapsibleTypes?: string[] });
21
21
  getTree(): CSTTree;
22
22
  }
23
+ export declare class ASTTranslator implements Translator<ASTTree> {
24
+ getTree(): ASTTree;
25
+ }
23
26
  export declare class XMLTranslator implements Translator<XMLTree> {
24
27
  getTree(): XMLTree;
25
28
  }
26
29
 
27
- export interface ParseResult<TTree = unknown> {
30
+ export interface ParseResult<TTree = ASTTree> {
28
31
  readonly result: {
29
32
  readonly success: boolean;
30
33
  readonly state: number;
@@ -35,7 +38,7 @@ export interface ParseResult<TTree = unknown> {
35
38
  readonly maxTreeDepth: number
36
39
  readonly nodeHits: number;
37
40
  };
38
- readonly tree: TTree;
41
+ readonly tree?: TTree;
39
42
  readonly stats?: Stats;
40
43
  readonly trace?: Trace;
41
44
  }
@@ -54,6 +57,159 @@ export interface CSTTree {
54
57
 
55
58
  export type XMLTree = string;
56
59
 
60
+ /* AST Tree start */
61
+ export interface ASTTree {
62
+ readonly root: JSONPathQueryASTNode;
63
+ }
64
+ export interface ASTNode {
65
+ readonly type:
66
+ | 'JSONPathQuery'
67
+ | 'NameSelector'
68
+ | 'WildcardSelector'
69
+ | 'IndexSelector'
70
+ | 'SliceSelector'
71
+ | 'FilterSelector'
72
+ | 'LogicalOrExpr'
73
+ | 'LogicalAndExpr'
74
+ | 'LogicalNotExpr'
75
+ | 'TestExpr'
76
+ | 'FilterQuery'
77
+ | 'RelQuery'
78
+ | 'ComparisonExpr'
79
+ | 'Literal'
80
+ | 'RelSingularQuery'
81
+ | 'AbsSingularQuery'
82
+ | 'FunctionExpr'
83
+ | 'ChildSegment'
84
+ | 'DescendantSegment'
85
+ | 'BracketedSelection';
86
+ }
87
+ // https://www.rfc-editor.org/rfc/rfc9535#section-2.1.1
88
+ export interface JSONPathQueryASTNode extends ASTNode {
89
+ readonly type: 'JSONPathQuery';
90
+ segments: SegmentASTNode[];
91
+ }
92
+ // https://www.rfc-editor.org/rfc/rfc9535#section-2.3.1.1
93
+ export interface NameSelectorASTNode extends ASTNode {
94
+ type: 'NameSelector';
95
+ value: string;
96
+ format: 'single-quoted' | 'double-quoted' | 'shorthand';
97
+ }
98
+ // https://www.rfc-editor.org/rfc/rfc9535#section-2.3.2.1
99
+ export interface WildcardSelectorASTNode extends ASTNode {
100
+ type: 'WildcardSelector';
101
+ }
102
+ // https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths
103
+ export interface IndexSelectorASTNode extends ASTNode {
104
+ type: 'IndexSelector';
105
+ value: number;
106
+ }
107
+ // https://www.rfc-editor.org/rfc/rfc9535#section-2.3.4.1
108
+ export interface SliceSelectorASTNode extends ASTNode {
109
+ type: 'SliceSelector';
110
+ start: number | null;
111
+ end: number | null ;
112
+ step: number | null;
113
+ }
114
+ // https://www.rfc-editor.org/rfc/rfc9535#section-2.3.5.1
115
+ export interface FilterSelectorASTNode extends ASTNode {
116
+ type: 'FilterSelector';
117
+ expression: LogicalExprASTNode;
118
+ }
119
+ export interface LogicalOrExprASTNode extends ASTNode {
120
+ type: 'LogicalOrExpr';
121
+ left: LogicalExprASTNode;
122
+ right: LogicalExprASTNode;
123
+ }
124
+ export interface LogicalAndExprASTNode extends ASTNode {
125
+ type: 'LogicalAndExpr';
126
+ left: LogicalExprASTNode;
127
+ right: LogicalExprASTNode;
128
+ }
129
+ export interface LogicalNotExprASTNode extends ASTNode {
130
+ type: 'LogicalNotExpr';
131
+ expression: LogicalExprASTNode;
132
+ }
133
+ export interface TestExprASTNode extends ASTNode {
134
+ type: 'TestExpr';
135
+ expression: FilterQueryASTNode | FunctionExprASTNode;
136
+ }
137
+ export interface FilterQueryASTNode extends ASTNode {
138
+ type: 'FilterQuery';
139
+ query: RelQueryASTNode | JSONPathQueryASTNode;
140
+ }
141
+ export interface RelQueryASTNode extends ASTNode {
142
+ type: 'RelQuery';
143
+ segments: SegmentASTNode[];
144
+ }
145
+ export interface ComparisonExprASTNode extends ASTNode {
146
+ type: 'ComparisonExpr';
147
+ left: ComparableASTNode;
148
+ operator: '==' | '!=' | '<=' | '>=' | '<' | '>';
149
+ right: ComparableASTNode;
150
+ }
151
+ export interface LiteralASTNode extends ASTNode {
152
+ type: 'Literal';
153
+ value: string | number | boolean | null;
154
+ }
155
+ export interface RelSingularQueryASTNode extends ASTNode {
156
+ type: 'RelSingularQuery';
157
+ segments: SingularQuerySegmentASTNode[];
158
+ }
159
+ export interface AbsSingularQueryASTNode extends ASTNode {
160
+ type: 'AbsSingularQuery';
161
+ segments: SingularQuerySegmentASTNode[];
162
+ }
163
+ // https://www.rfc-editor.org/rfc/rfc9535#section-2.4
164
+ export interface FunctionExprASTNode extends ASTNode {
165
+ type: 'FunctionExpr';
166
+ name: string;
167
+ arguments: FunctionArgumentASTNode[];
168
+ }
169
+ // https://www.rfc-editor.org/rfc/rfc9535#section-2.5.1.1
170
+ export interface ChildSegmentASTNode extends ASTNode {
171
+ type: 'ChildSegment';
172
+ selector: BracketedSelectionASTNode | WildcardSelectorASTNode | NameSelectorASTNode;
173
+ }
174
+ export interface BracketedSelectionASTNode extends ASTNode {
175
+ type: 'BracketedSelection';
176
+ selectors: SelectorASTNode[];
177
+ }
178
+ export interface DescendantSegmentASTNode extends ASTNode {
179
+ type: 'DescendantSegment';
180
+ selector: BracketedSelectionASTNode | WildcardSelectorASTNode | NameSelectorASTNode;
181
+ }
182
+ // union types
183
+ export type SelectorASTNode =
184
+ | NameSelectorASTNode
185
+ | WildcardSelectorASTNode
186
+ | SliceSelectorASTNode
187
+ | IndexSelectorASTNode
188
+ | FilterQueryASTNode;
189
+ export type LogicalExprASTNode =
190
+ | LogicalOrExprASTNode
191
+ | LogicalAndExprASTNode
192
+ | LogicalNotExprASTNode
193
+ | TestExprASTNode
194
+ | ComparisonExprASTNode;
195
+ export type ComparableASTNode =
196
+ | RelSingularQueryASTNode
197
+ | AbsSingularQueryASTNode
198
+ | FunctionExprASTNode
199
+ | LiteralASTNode;
200
+ export type SegmentASTNode =
201
+ | ChildSegmentASTNode
202
+ | DescendantSegmentASTNode;
203
+ export type FunctionArgumentASTNode =
204
+ | LogicalExprASTNode
205
+ | FilterQueryASTNode
206
+ | FunctionExprASTNode
207
+ | LiteralASTNode;
208
+ export type SingularQuerySegmentASTNode =
209
+ | NameSelectorASTNode
210
+ | IndexSelectorASTNode;
211
+ /* AST Tree end */
212
+
57
213
  export interface Stats {
58
214
  displayStats(): string;
59
215
  displayHits(): string;