@swaggerexpert/jsonpath 3.2.2 → 3.2.4

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.
Files changed (38) hide show
  1. package/cjs/apg-lite.cjs +1221 -0
  2. package/cjs/compile.cjs +50 -0
  3. package/cjs/errors/JSONPathCompileError.cjs +8 -0
  4. package/cjs/errors/JSONPathError.cjs +44 -0
  5. package/cjs/errors/JSONPathParseError.cjs +8 -0
  6. package/cjs/escape.cjs +59 -0
  7. package/cjs/grammar.cjs +2839 -0
  8. package/cjs/index.cjs +31 -0
  9. package/cjs/parse/callbacks/cst.cjs +49 -0
  10. package/cjs/parse/index.cjs +41 -0
  11. package/cjs/parse/trace/Expectations.cjs +10 -0
  12. package/cjs/parse/trace/Trace.cjs +35 -0
  13. package/cjs/parse/translators/ASTTranslator/decoders.cjs +83 -0
  14. package/cjs/parse/translators/ASTTranslator/index.cjs +15 -0
  15. package/cjs/parse/translators/ASTTranslator/transformers.cjs +411 -0
  16. package/cjs/parse/translators/CSTOptimizedTranslator.cjs +39 -0
  17. package/cjs/parse/translators/CSTTranslator.cjs +118 -0
  18. package/cjs/parse/translators/XMLTranslator.cjs +12 -0
  19. package/cjs/test/index.cjs +25 -0
  20. package/es/compile.mjs +45 -0
  21. package/es/errors/JSONPathCompileError.mjs +3 -0
  22. package/es/errors/JSONPathError.mjs +40 -0
  23. package/es/errors/JSONPathParseError.mjs +3 -0
  24. package/es/escape.mjs +55 -0
  25. package/es/grammar.mjs +2835 -0
  26. package/es/index.mjs +13 -0
  27. package/es/parse/callbacks/cst.mjs +44 -0
  28. package/es/parse/index.mjs +36 -0
  29. package/es/parse/trace/Expectations.mjs +6 -0
  30. package/es/parse/trace/Trace.mjs +30 -0
  31. package/es/parse/translators/ASTTranslator/decoders.mjs +75 -0
  32. package/es/parse/translators/ASTTranslator/index.mjs +9 -0
  33. package/es/parse/translators/ASTTranslator/transformers.mjs +405 -0
  34. package/es/parse/translators/CSTOptimizedTranslator.mjs +34 -0
  35. package/es/parse/translators/CSTTranslator.mjs +113 -0
  36. package/es/parse/translators/XMLTranslator.mjs +7 -0
  37. package/es/test/index.mjs +20 -0
  38. package/package.json +1 -1
package/es/index.mjs ADDED
@@ -0,0 +1,13 @@
1
+ export { default as Grammar } from "./grammar.mjs";
2
+ export { default as parse } from "./parse/index.mjs";
3
+ export { default as CSTTranslator } from "./parse/translators/CSTTranslator.mjs";
4
+ export { default as CSTOptimizedTranslator } from "./parse/translators/CSTOptimizedTranslator.mjs";
5
+ export { default as ASTTranslator } from "./parse/translators/ASTTranslator/index.mjs";
6
+ export { default as XMLTranslator } from "./parse/translators/XMLTranslator.mjs";
7
+ export { default as Trace } from "./parse/trace/Trace.mjs";
8
+ export { default as test } from "./test/index.mjs";
9
+ export { default as compile } from "./compile.mjs";
10
+ export { default as escape } from "./escape.mjs";
11
+ export { default as JSONPathError } from "./errors/JSONPathError.mjs";
12
+ export { default as JSONPathParseError } from "./errors/JSONPathParseError.mjs";
13
+ export { default as JSONPathCompileError } from "./errors/JSONPathCompileError.mjs";
@@ -0,0 +1,44 @@
1
+ import { utilities, identifiers } from 'apg-lite';
2
+ import JSONPathParseError from "../../errors/JSONPathParseError.mjs";
3
+ const cst = nodeType => {
4
+ return (state, chars, phraseIndex, phraseLength, data) => {
5
+ var _data$options, _data$options2;
6
+ if (!(typeof data === 'object' && data !== null && !Array.isArray(data))) {
7
+ throw new JSONPathParseError("parser's user data must be an object");
8
+ }
9
+
10
+ // drop the empty nodes
11
+ if ((_data$options = data.options) !== null && _data$options !== void 0 && _data$options.optimize && phraseLength === 0 && (_data$options2 = data.options) !== null && _data$options2 !== void 0 && (_data$options2 = _data$options2.droppableTypes) !== null && _data$options2 !== void 0 && _data$options2.includes(nodeType)) {
12
+ return;
13
+ }
14
+ if (state === identifiers.SEM_PRE) {
15
+ const node = {
16
+ type: nodeType,
17
+ text: utilities.charsToString(chars, phraseIndex, phraseLength),
18
+ start: phraseIndex,
19
+ length: phraseLength,
20
+ children: []
21
+ };
22
+ if (data.stack.length > 0) {
23
+ var _data$options3, _data$options4;
24
+ const parent = data.stack[data.stack.length - 1];
25
+ const prevSibling = parent.children[parent.children.length - 1];
26
+ const isTextNodeWithinTextNode = parent.type === 'text' && node.type === 'text';
27
+ const shouldCollapse = ((_data$options3 = data.options) === null || _data$options3 === void 0 ? void 0 : _data$options3.optimize) && ((_data$options4 = data.options) === null || _data$options4 === void 0 || (_data$options4 = _data$options4.collapsibleTypes) === null || _data$options4 === void 0 ? void 0 : _data$options4.includes(node.type)) && (prevSibling === null || prevSibling === void 0 ? void 0 : prevSibling.type) === node.type;
28
+ if (shouldCollapse) {
29
+ prevSibling.text += node.text;
30
+ prevSibling.length += node.length;
31
+ } else if (!isTextNodeWithinTextNode) {
32
+ parent.children.push(node);
33
+ }
34
+ } else {
35
+ data.root = node;
36
+ }
37
+ data.stack.push(node);
38
+ }
39
+ if (state === identifiers.SEM_POST) {
40
+ data.stack.pop();
41
+ }
42
+ };
43
+ };
44
+ export default cst;
@@ -0,0 +1,36 @@
1
+ import { Parser, Stats } from 'apg-lite';
2
+ import Trace from "./trace/Trace.mjs";
3
+ import Grammar from "../grammar.mjs";
4
+ import ASTTranslator from "./translators/ASTTranslator/index.mjs";
5
+ import JSONPathParseError from "../errors/JSONPathParseError.mjs";
6
+ const grammar = new Grammar();
7
+ const parse = (jsonPath, {
8
+ normalized = false,
9
+ stats = false,
10
+ trace = false,
11
+ translator = new ASTTranslator()
12
+ } = {}) => {
13
+ if (typeof jsonPath !== 'string') {
14
+ throw new TypeError('JSONPath must be a string');
15
+ }
16
+ try {
17
+ const parser = new Parser();
18
+ if (translator) parser.ast = translator;
19
+ if (stats) parser.stats = new Stats();
20
+ if (trace) parser.trace = new Trace();
21
+ const startRule = normalized ? 'normalized-path' : 'jsonpath-query';
22
+ const result = parser.parse(grammar, startRule, jsonPath);
23
+ return {
24
+ result,
25
+ tree: result.success && translator ? parser.ast.getTree() : undefined,
26
+ stats: parser.stats,
27
+ trace: parser.trace
28
+ };
29
+ } catch (error) {
30
+ throw new JSONPathParseError('Unexpected error during JSONPath parsing', {
31
+ cause: error,
32
+ jsonPath
33
+ });
34
+ }
35
+ };
36
+ export default parse;
@@ -0,0 +1,6 @@
1
+ class Expectations extends Array {
2
+ toString() {
3
+ return this.map(c => `"${String(c)}"`).join(', ');
4
+ }
5
+ }
6
+ export default Expectations;
@@ -0,0 +1,30 @@
1
+ import { Trace as BaseTrace } from 'apg-lite';
2
+ import Expectations from "./Expectations.mjs";
3
+ class Trace extends BaseTrace {
4
+ inferExpectations() {
5
+ const lines = this.displayTrace().split('\n');
6
+ const expectations = new Set();
7
+ let lastMatchedIndex = -1;
8
+ for (let i = 0; i < lines.length; i++) {
9
+ const line = lines[i];
10
+
11
+ // capture the max match line (first one that ends in a single character match)
12
+ if (line.includes('M|')) {
13
+ const textMatch = line.match(/]'(.*)'$/);
14
+ if (textMatch && textMatch[1]) {
15
+ lastMatchedIndex = i;
16
+ }
17
+ }
18
+
19
+ // collect terminal failures after the deepest successful match
20
+ if (i > lastMatchedIndex) {
21
+ const terminalFailMatch = line.match(/N\|\[TLS\(([^)]+)\)]/);
22
+ if (terminalFailMatch) {
23
+ expectations.add(terminalFailMatch[1]);
24
+ }
25
+ }
26
+ }
27
+ return new Expectations(...expectations);
28
+ }
29
+ }
30
+ export default Trace;
@@ -0,0 +1,75 @@
1
+ export const decodeDoubleQuotedString = str => {
2
+ return decodeJSONValue(`"${str}"`);
3
+ };
4
+ export const decodeSingleQuotedString = str => {
5
+ // Decode single-quoted string escape sequences into raw text, then let JSON.stringify
6
+ // produce a correctly escaped double-quoted JSON string.
7
+ let decoded = '';
8
+ for (let i = 0; i < str.length; i++) {
9
+ const ch = str[i];
10
+ if (ch === '\\') {
11
+ i++;
12
+ if (i >= str.length) {
13
+ // Trailing backslash, treat it as a literal backslash
14
+ decoded += '\\';
15
+ break;
16
+ }
17
+ const esc = str[i];
18
+ switch (esc) {
19
+ case 'n':
20
+ decoded += '\n';
21
+ break;
22
+ case 'r':
23
+ decoded += '\r';
24
+ break;
25
+ case 't':
26
+ decoded += '\t';
27
+ break;
28
+ case 'b':
29
+ decoded += '\b';
30
+ break;
31
+ case 'f':
32
+ decoded += '\f';
33
+ break;
34
+ case '/':
35
+ decoded += '/';
36
+ break;
37
+ case '\\':
38
+ decoded += '\\';
39
+ break;
40
+ case "'":
41
+ decoded += "'";
42
+ break;
43
+ case '"':
44
+ decoded += '"';
45
+ break;
46
+ case 'u':
47
+ {
48
+ // Unicode escape \uXXXX - grammar guarantees exactly 4 hex digits
49
+ const hex = str.slice(i + 1, i + 5);
50
+ decoded += String.fromCharCode(parseInt(hex, 16));
51
+ i += 4;
52
+ break;
53
+ }
54
+ default:
55
+ // Unrecognized escape, keep the escaped character literally
56
+ decoded += esc;
57
+ break;
58
+ }
59
+ } else {
60
+ decoded += ch;
61
+ }
62
+ }
63
+ // Use JSON.stringify to produce a valid JSON string literal
64
+ return decodeJSONValue(JSON.stringify(decoded));
65
+ };
66
+ export const decodeInteger = str => {
67
+ const value = parseInt(str, 10);
68
+ if (!Number.isSafeInteger(value)) {
69
+ throw new RangeError(`Integer value out of safe range [-(2^53)+1, (2^53)-1], got: ${str}`);
70
+ }
71
+ return value;
72
+ };
73
+ export const decodeJSONValue = str => {
74
+ return JSON.parse(str);
75
+ };
@@ -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,405 @@
1
+ import JSONPathParseError from "../../../errors/JSONPathParseError.mjs";
2
+ import { decodeSingleQuotedString, decodeDoubleQuotedString, 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
+ const decodeString = isSingleQuoted ? decodeSingleQuotedString : decodeDoubleQuotedString;
71
+ return {
72
+ type: 'StringLiteral',
73
+ value: quoted ? decodeString(quoted.text) : '',
74
+ format: isSingleQuoted ? 'single-quoted' : 'double-quoted'
75
+ };
76
+ },
77
+ /**
78
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.2.1
79
+ */
80
+ ['wildcard-selector']() {
81
+ return {
82
+ type: 'WildcardSelector'
83
+ };
84
+ },
85
+ /**
86
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.3.1
87
+ */
88
+ ['index-selector'](node) {
89
+ return {
90
+ type: 'IndexSelector',
91
+ value: decodeInteger(node.text)
92
+ };
93
+ },
94
+ /**
95
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.4.1
96
+ */
97
+ ['slice-selector'](node) {
98
+ const start = node.children.find(({
99
+ type
100
+ }) => type === 'start');
101
+ const end = node.children.find(({
102
+ type
103
+ }) => type === 'end');
104
+ const step = node.children.find(({
105
+ type
106
+ }) => type === 'step');
107
+ return {
108
+ type: 'SliceSelector',
109
+ start: start ? decodeInteger(start.text) : null,
110
+ end: end ? decodeInteger(end.text) : null,
111
+ step: step ? decodeInteger(step.text) : null
112
+ };
113
+ },
114
+ /**
115
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.3.5.1
116
+ */
117
+ ['filter-selector'](node, ctx) {
118
+ const child = node.children.find(({
119
+ type
120
+ }) => type === 'logical-expr');
121
+ return {
122
+ type: 'FilterSelector',
123
+ expression: transformCSTtoAST(child, transformers, ctx)
124
+ };
125
+ },
126
+ ['logical-expr'](node, ctx) {
127
+ const child = node.children.find(({
128
+ type
129
+ }) => type === 'logical-or-expr');
130
+ return transformCSTtoAST(child, transformers, ctx);
131
+ },
132
+ ['logical-or-expr'](node, ctx) {
133
+ const logicalAndExprs = node.children.filter(({
134
+ type
135
+ }) => type === 'logical-and-expr');
136
+ if (logicalAndExprs.length === 1) {
137
+ return transformCSTtoAST(logicalAndExprs[0], transformers, ctx);
138
+ }
139
+
140
+ // fold left for left-associativity
141
+ let left = transformCSTtoAST(logicalAndExprs[0], transformers, ctx);
142
+ for (let i = 1; i < logicalAndExprs.length; i += 1) {
143
+ const right = transformCSTtoAST(logicalAndExprs[i], transformers, ctx);
144
+ left = {
145
+ type: 'LogicalOrExpr',
146
+ left,
147
+ right
148
+ };
149
+ }
150
+ },
151
+ ['logical-and-expr'](node, ctx) {
152
+ const basicExprs = node.children.filter(({
153
+ type
154
+ }) => type === 'basic-expr');
155
+ if (basicExprs.length === 1) {
156
+ return transformCSTtoAST(basicExprs[0], transformers, ctx);
157
+ }
158
+ let left = transformCSTtoAST(basicExprs[0], transformers, ctx);
159
+ for (let i = 1; i < basicExprs.length; i += 1) {
160
+ const right = transformCSTtoAST(basicExprs[i], transformers, ctx);
161
+ left = {
162
+ type: 'LogicalAndExpr',
163
+ left,
164
+ right
165
+ };
166
+ }
167
+ return left;
168
+ },
169
+ ['basic-expr'](node, ctx) {
170
+ const child = node.children.find(({
171
+ type
172
+ }) => ['paren-expr', 'comparison-expr', 'test-expr'].includes(type));
173
+ return transformCSTtoAST(child, transformers, ctx);
174
+ },
175
+ ['paren-expr'](node, ctx) {
176
+ const isNegated = node.children.some(child => child.type === 'logical-not-op');
177
+ const logicalExprCSTNode = node.children.find(child => child.type === 'logical-expr');
178
+ const logicalExpressionASTNode = transformCSTtoAST(logicalExprCSTNode, transformers, ctx);
179
+ if (isNegated) {
180
+ return {
181
+ type: 'LogicalNotExpr',
182
+ expression: logicalExpressionASTNode
183
+ };
184
+ }
185
+ return logicalExpressionASTNode;
186
+ },
187
+ ['test-expr'](node, ctx) {
188
+ const isNegated = node.children.some(({
189
+ type
190
+ }) => type === 'logical-not-op');
191
+ const expression = node.children.find(({
192
+ type
193
+ }) => ['filter-query', 'function-expr'].includes(type));
194
+ const testExpr = {
195
+ type: 'TestExpr',
196
+ expression: transformCSTtoAST(expression, transformers, ctx)
197
+ };
198
+ return isNegated ? {
199
+ type: 'LogicalNotExpr',
200
+ expression: testExpr
201
+ } : testExpr;
202
+ },
203
+ ['filter-query'](node, ctx) {
204
+ const child = node.children.find(({
205
+ type
206
+ }) => ['rel-query', 'jsonpath-query'].includes(type));
207
+ return {
208
+ type: 'FilterQuery',
209
+ query: transformCSTtoAST(child, transformers, ctx)
210
+ };
211
+ },
212
+ ['rel-query'](node, ctx) {
213
+ const segments = node.children.find(c => c.type === 'segments');
214
+ return {
215
+ type: 'RelQuery',
216
+ segments: segments ? segments.children.filter(n => n.type === 'segment').map(segNode => transformCSTtoAST(segNode, transformers, ctx)) : []
217
+ };
218
+ },
219
+ ['comparison-expr'](node, ctx) {
220
+ const children = node.children.filter(({
221
+ type
222
+ }) => ['comparable', 'comparison-op'].includes(type));
223
+ const [left, op, right] = children;
224
+ return {
225
+ type: 'ComparisonExpr',
226
+ left: transformCSTtoAST(left, transformers, ctx),
227
+ op: op.text,
228
+ right: transformCSTtoAST(right, transformers, ctx)
229
+ };
230
+ },
231
+ ['literal'](node, ctx) {
232
+ const child = node.children.find(({
233
+ type
234
+ }) => ['number', 'string-literal', 'true', 'false', 'null'].includes(type));
235
+ if (child.type === 'string-literal') {
236
+ const stringLiteralASTNode = transformCSTtoAST(child, transformers, ctx);
237
+ return {
238
+ type: 'Literal',
239
+ value: stringLiteralASTNode.value
240
+ };
241
+ }
242
+ return {
243
+ type: 'Literal',
244
+ value: decodeJSONValue(child.text)
245
+ };
246
+ },
247
+ ['comparable'](node, ctx) {
248
+ const child = node.children.find(({
249
+ type
250
+ }) => ['singular-query', 'function-expr', 'literal'].includes(type));
251
+ return transformCSTtoAST(child, transformers, ctx);
252
+ },
253
+ ['singular-query'](node, ctx) {
254
+ const child = node.children.find(({
255
+ type
256
+ }) => ['rel-singular-query', 'abs-singular-query'].includes(type));
257
+ return transformCSTtoAST(child, transformers, ctx);
258
+ },
259
+ ['rel-singular-query'](node, ctx) {
260
+ const segmentsNode = node.children.find(({
261
+ type
262
+ }) => type === 'singular-query-segments');
263
+ const segments = segmentsNode ? segmentsNode.children.filter(({
264
+ type
265
+ }) => ['name-segment', 'index-segment'].includes(type)).map(segNode => ({
266
+ type: 'SingularQuerySegment',
267
+ selector: transformCSTtoAST(segNode, transformers, ctx)
268
+ })) : [];
269
+ return {
270
+ type: 'RelSingularQuery',
271
+ segments
272
+ };
273
+ },
274
+ ['abs-singular-query'](node, ctx) {
275
+ const segmentsNode = node.children.find(({
276
+ type
277
+ }) => type === 'singular-query-segments');
278
+ const segments = segmentsNode ? segmentsNode.children.filter(({
279
+ type
280
+ }) => ['name-segment', 'index-segment'].includes(type)).map(segNode => ({
281
+ type: 'SingularQuerySegment',
282
+ selector: transformCSTtoAST(segNode, transformers, ctx)
283
+ })) : [];
284
+ return {
285
+ type: 'AbsSingularQuery',
286
+ segments
287
+ };
288
+ },
289
+ ['name-segment'](node, ctx) {
290
+ const child = node.children.find(({
291
+ type
292
+ }) => ['name-selector', 'member-name-shorthand'].includes(type));
293
+ return transformCSTtoAST(child, transformers, ctx);
294
+ },
295
+ ['index-segment'](node, ctx) {
296
+ const child = node.children.find(({
297
+ type
298
+ }) => type === 'index-selector');
299
+ return transformCSTtoAST(child, transformers, ctx);
300
+ },
301
+ /**
302
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.4
303
+ */
304
+ ['function-expr'](node, ctx) {
305
+ const name = node.children.find(({
306
+ type
307
+ }) => type === 'function-name');
308
+ const args = node.children.filter(({
309
+ type
310
+ }) => type === 'function-argument');
311
+ return {
312
+ type: 'FunctionExpr',
313
+ name: name.text,
314
+ arguments: args.map(arg => transformCSTtoAST(arg, transformers, ctx))
315
+ };
316
+ },
317
+ ['function-argument'](node, ctx) {
318
+ const child = node.children.find(({
319
+ type
320
+ }) => ['logical-expr', 'function-expr', 'filter-query', 'literal'].includes(type));
321
+ return transformCSTtoAST(child, transformers, ctx);
322
+ },
323
+ /**
324
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.5.1.1
325
+ */
326
+ ['child-segment'](node, ctx) {
327
+ const child = node.children.find(({
328
+ type
329
+ }) => ['bracketed-selection', 'wildcard-selector', 'member-name-shorthand'].includes(type));
330
+ return {
331
+ type: 'ChildSegment',
332
+ selector: transformCSTtoAST(child, transformers, ctx)
333
+ };
334
+ },
335
+ ['bracketed-selection'](node, ctx) {
336
+ return {
337
+ type: 'BracketedSelection',
338
+ selectors: node.children.filter(({
339
+ type
340
+ }) => type === 'selector').map(selectorNode => transformCSTtoAST(selectorNode, transformers, ctx))
341
+ };
342
+ },
343
+ ['member-name-shorthand'](node) {
344
+ return {
345
+ type: 'NameSelector',
346
+ value: node.text,
347
+ format: 'shorthand'
348
+ };
349
+ },
350
+ /**
351
+ * https://www.rfc-editor.org/rfc/rfc9535#section-2.5.2.1
352
+ */
353
+ ['descendant-segment'](node, ctx) {
354
+ const child = node.children.find(({
355
+ type
356
+ }) => ['bracketed-selection', 'wildcard-selector', 'member-name-shorthand'].includes(type));
357
+ return {
358
+ type: 'DescendantSegment',
359
+ selector: transformCSTtoAST(child, transformers, ctx)
360
+ };
361
+ },
362
+ /**
363
+ * https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths
364
+ */
365
+ ['normalized-path'](node, ctx) {
366
+ return {
367
+ type: 'JsonPathQuery',
368
+ segments: node.children.filter(({
369
+ type
370
+ }) => type === 'normal-index-segment').map(segNode => transformCSTtoAST(segNode, transformers, ctx))
371
+ };
372
+ },
373
+ ['normal-index-segment'](node, ctx) {
374
+ const child = node.children.find(({
375
+ type
376
+ }) => type === 'normal-selector');
377
+ return {
378
+ type: 'ChildSegment',
379
+ selector: transformCSTtoAST(child, transformers, ctx)
380
+ };
381
+ },
382
+ ['normal-selector'](node, ctx) {
383
+ const child = node.children.find(({
384
+ type
385
+ }) => ['normal-name-selector', 'normal-index-selector'].includes(type));
386
+ return transformCSTtoAST(child, transformers, ctx);
387
+ },
388
+ ['normal-name-selector'](node) {
389
+ const child = node.children.find(({
390
+ type
391
+ }) => type === 'normal-single-quoted');
392
+ return {
393
+ type: 'NameSelector',
394
+ value: child ? decodeSingleQuotedString(child.text) : '',
395
+ format: 'single-quoted'
396
+ };
397
+ },
398
+ ['normal-index-selector'](node) {
399
+ return {
400
+ type: 'IndexSelector',
401
+ value: decodeInteger(node.text)
402
+ };
403
+ }
404
+ };
405
+ export default transformers;
@@ -0,0 +1,34 @@
1
+ import CSTTranslator from "./CSTTranslator.mjs";
2
+ class CSTOptimizedTranslator extends CSTTranslator {
3
+ collapsibleTypes = ['single-quoted', 'double-quoted', 'normal-single-quoted'];
4
+ droppableTypes = ['text', 'segments', 'singular-query-segments'];
5
+ constructor({
6
+ collapsibleTypes,
7
+ droppableTypes
8
+ } = {}) {
9
+ super();
10
+ if (Array.isArray(collapsibleTypes)) {
11
+ this.collapsibleTypes = collapsibleTypes;
12
+ }
13
+ if (Array.isArray(droppableTypes)) {
14
+ this.droppableTypes = droppableTypes;
15
+ }
16
+ }
17
+ getTree() {
18
+ const options = {
19
+ optimize: true,
20
+ collapsibleTypes: this.collapsibleTypes,
21
+ droppableTypes: this.droppableTypes
22
+ };
23
+ const data = {
24
+ stack: [],
25
+ root: null,
26
+ options
27
+ };
28
+ this.translate(data);
29
+ delete data.stack;
30
+ delete data.options;
31
+ return data;
32
+ }
33
+ }
34
+ export default CSTOptimizedTranslator;