@swaggerexpert/jsonpath 2.4.1 → 3.0.0

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,42 +119,22 @@ 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
 
155
135
  Same as CST, but optimizes the tree for more optimized representation. By default, it collapses
156
136
  fragmented `single-quoted`, `double-quoted` or `normal-single-quoted` nodes into a single node.
137
+ `text`, `segments` and `singular-query-segments` nodes, when empty, are removed from the tree.
157
138
 
158
139
  ```js
159
140
  import { parse, CSTOptimizedTranslator } from '@swaggerexpert/jsonpath';
@@ -161,6 +142,29 @@ import { parse, CSTOptimizedTranslator } from '@swaggerexpert/jsonpath';
161
142
  const { tree: CST } = parse('$.store.book[0].title', { translator: new CSTOptimizedTranslator() });
162
143
  ```
163
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
+
164
168
  ###### XML translator
165
169
 
166
170
  ```js
@@ -213,7 +217,7 @@ test('$.store.book[0].title'); // => true
213
217
  test('$$'); // => false
214
218
  ```
215
219
 
216
- Normalized paths can be validated by setting `normalized` option to `true`.
220
+ **Normalized paths** can be validated by setting `normalized` option to `true`.
217
221
 
218
222
  ```js
219
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 }; }
@@ -5,28 +5,31 @@ exports.default = void 0;
5
5
  var _apgLite = require("../../apg-lite.cjs");
6
6
  var _JSONPathParseError = _interopRequireDefault(require("../../errors/JSONPathParseError.cjs"));
7
7
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
8
- const cst = ruleName => {
8
+ const cst = nodeType => {
9
9
  return (state, chars, phraseIndex, phraseLength, data) => {
10
+ var _data$options, _data$options2;
10
11
  if (!(typeof data === 'object' && data !== null && !Array.isArray(data))) {
11
12
  throw new _JSONPathParseError.default("parser's user data must be an object");
12
13
  }
13
14
 
14
15
  // drop the empty nodes
15
- if (phraseLength === 0) return;
16
+ if ((_data$options = data.options) != null && _data$options.optimize && phraseLength === 0 && (_data$options2 = data.options) != null && (_data$options2 = _data$options2.droppableTypes) != null && _data$options2.includes(nodeType)) {
17
+ return;
18
+ }
16
19
  if (state === _apgLite.identifiers.SEM_PRE) {
17
20
  const node = {
18
- type: ruleName,
21
+ type: nodeType,
19
22
  text: _apgLite.utilities.charsToString(chars, phraseIndex, phraseLength),
20
23
  start: phraseIndex,
21
24
  length: phraseLength,
22
25
  children: []
23
26
  };
24
27
  if (data.stack.length > 0) {
25
- var _data$options, _data$options2;
28
+ var _data$options3, _data$options4;
26
29
  const parent = data.stack[data.stack.length - 1];
27
30
  const prevSibling = parent.children[parent.children.length - 1];
28
31
  const isTextNodeWithinTextNode = parent.type === 'text' && node.type === 'text';
29
- const shouldCollapse = ((_data$options = data.options) == null ? void 0 : _data$options.optimize) && ((_data$options2 = data.options) == null || (_data$options2 = _data$options2.collapsibleTypes) == null ? void 0 : _data$options2.includes(node.type)) && (prevSibling == null ? void 0 : prevSibling.type) === node.type;
32
+ const shouldCollapse = ((_data$options3 = data.options) == null ? void 0 : _data$options3.optimize) && ((_data$options4 = data.options) == null || (_data$options4 = _data$options4.collapsibleTypes) == null ? void 0 : _data$options4.includes(node.type)) && (prevSibling == null ? void 0 : prevSibling.type) === node.type;
30
33
  if (shouldCollapse) {
31
34
  prevSibling.text += node.text;
32
35
  prevSibling.length += node.length;
@@ -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,13 +12,12 @@ 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');
19
19
  }
20
20
  try {
21
- var _parser$ast;
22
21
  const parser = new _apgLite.Parser();
23
22
  if (translator) parser.ast = translator;
24
23
  if (stats) parser.stats = new _apgLite.Stats();
@@ -27,7 +26,7 @@ const parse = (jsonPath, {
27
26
  const result = parser.parse(grammar, startRule, jsonPath);
28
27
  return {
29
28
  result,
30
- tree: result.success ? (_parser$ast = parser.ast) == null ? void 0 : _parser$ast.getTree() : undefined,
29
+ tree: result.success && translator ? parser.ast.getTree() : undefined,
31
30
  stats: parser.stats,
32
31
  trace: parser.trace
33
32
  };
@@ -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;
@@ -6,18 +6,24 @@ var _CSTTranslator = _interopRequireDefault(require("./CSTTranslator.cjs"));
6
6
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
7
7
  class CSTOptimizedTranslator extends _CSTTranslator.default {
8
8
  collapsibleTypes = ['single-quoted', 'double-quoted', 'normal-single-quoted'];
9
+ droppableTypes = ['text', 'segments', 'singular-query-segments'];
9
10
  constructor({
10
- collapsibleTypes
11
+ collapsibleTypes,
12
+ droppableTypes
11
13
  } = {}) {
12
14
  super();
13
15
  if (Array.isArray(collapsibleTypes)) {
14
16
  this.collapsibleTypes = collapsibleTypes;
15
17
  }
18
+ if (Array.isArray(droppableTypes)) {
19
+ this.droppableTypes = droppableTypes;
20
+ }
16
21
  }
17
22
  getTree() {
18
23
  const options = {
19
24
  optimize: true,
20
- collapsibleTypes: this.collapsibleTypes
25
+ collapsibleTypes: this.collapsibleTypes,
26
+ droppableTypes: this.droppableTypes
21
27
  };
22
28
  const data = {
23
29
  stack: [],
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";