@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 +28 -24
- package/cjs/index.cjs +5 -3
- package/cjs/parse/callbacks/cst.cjs +8 -5
- package/cjs/parse/index.cjs +3 -4
- package/cjs/parse/translators/ASTTranslator/decoders.cjs +16 -0
- package/cjs/parse/translators/ASTTranslator/index.cjs +16 -0
- package/cjs/parse/translators/ASTTranslator/transformers.cjs +410 -0
- package/cjs/parse/translators/CSTOptimizedTranslator.cjs +8 -2
- package/es/index.mjs +1 -0
- package/es/parse/callbacks/cst.mjs +8 -5
- package/es/parse/index.mjs +3 -4
- package/es/parse/translators/ASTTranslator/decoders.mjs +9 -0
- package/es/parse/translators/ASTTranslator/index.mjs +9 -0
- package/es/parse/translators/ASTTranslator/transformers.mjs +404 -0
- package/es/parse/translators/CSTOptimizedTranslator.mjs +8 -2
- package/package.json +1 -1
- package/types/index.d.ts +154 -1
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
import { utilities, identifiers } from 'apg-lite';
|
|
2
2
|
import JSONPathParseError from "../../errors/JSONPathParseError.mjs";
|
|
3
|
-
const cst =
|
|
3
|
+
const cst = nodeType => {
|
|
4
4
|
return (state, chars, phraseIndex, phraseLength, data) => {
|
|
5
|
+
var _data$options, _data$options2;
|
|
5
6
|
if (!(typeof data === 'object' && data !== null && !Array.isArray(data))) {
|
|
6
7
|
throw new JSONPathParseError("parser's user data must be an object");
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
// drop the empty nodes
|
|
10
|
-
if (phraseLength === 0)
|
|
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
|
+
}
|
|
11
14
|
if (state === identifiers.SEM_PRE) {
|
|
12
15
|
const node = {
|
|
13
|
-
type:
|
|
16
|
+
type: nodeType,
|
|
14
17
|
text: utilities.charsToString(chars, phraseIndex, phraseLength),
|
|
15
18
|
start: phraseIndex,
|
|
16
19
|
length: phraseLength,
|
|
17
20
|
children: []
|
|
18
21
|
};
|
|
19
22
|
if (data.stack.length > 0) {
|
|
20
|
-
var _data$
|
|
23
|
+
var _data$options3, _data$options4;
|
|
21
24
|
const parent = data.stack[data.stack.length - 1];
|
|
22
25
|
const prevSibling = parent.children[parent.children.length - 1];
|
|
23
26
|
const isTextNodeWithinTextNode = parent.type === 'text' && node.type === 'text';
|
|
24
|
-
const shouldCollapse = ((_data$
|
|
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;
|
|
25
28
|
if (shouldCollapse) {
|
|
26
29
|
prevSibling.text += node.text;
|
|
27
30
|
prevSibling.length += node.length;
|
package/es/parse/index.mjs
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import { Parser, Stats, Trace } from 'apg-lite';
|
|
2
2
|
import Grammar from "../grammar.mjs";
|
|
3
|
-
import
|
|
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
|
|
10
|
+
translator = new ASTTranslator()
|
|
11
11
|
} = {}) => {
|
|
12
12
|
if (typeof jsonPath !== 'string') {
|
|
13
13
|
throw new TypeError('JSONPath must be a string');
|
|
14
14
|
}
|
|
15
15
|
try {
|
|
16
|
-
var _parser$ast;
|
|
17
16
|
const parser = new Parser();
|
|
18
17
|
if (translator) parser.ast = translator;
|
|
19
18
|
if (stats) parser.stats = new Stats();
|
|
@@ -22,7 +21,7 @@ const parse = (jsonPath, {
|
|
|
22
21
|
const result = parser.parse(grammar, startRule, jsonPath);
|
|
23
22
|
return {
|
|
24
23
|
result,
|
|
25
|
-
tree: result.success
|
|
24
|
+
tree: result.success && translator ? parser.ast.getTree() : undefined,
|
|
26
25
|
stats: parser.stats,
|
|
27
26
|
trace: parser.trace
|
|
28
27
|
};
|
|
@@ -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;
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import CSTTranslator from "./CSTTranslator.mjs";
|
|
2
2
|
class CSTOptimizedTranslator extends CSTTranslator {
|
|
3
3
|
collapsibleTypes = ['single-quoted', 'double-quoted', 'normal-single-quoted'];
|
|
4
|
+
droppableTypes = ['text', 'segments', 'singular-query-segments'];
|
|
4
5
|
constructor({
|
|
5
|
-
collapsibleTypes
|
|
6
|
+
collapsibleTypes,
|
|
7
|
+
droppableTypes
|
|
6
8
|
} = {}) {
|
|
7
9
|
super();
|
|
8
10
|
if (Array.isArray(collapsibleTypes)) {
|
|
9
11
|
this.collapsibleTypes = collapsibleTypes;
|
|
10
12
|
}
|
|
13
|
+
if (Array.isArray(droppableTypes)) {
|
|
14
|
+
this.droppableTypes = droppableTypes;
|
|
15
|
+
}
|
|
11
16
|
}
|
|
12
17
|
getTree() {
|
|
13
18
|
const options = {
|
|
14
19
|
optimize: true,
|
|
15
|
-
collapsibleTypes: this.collapsibleTypes
|
|
20
|
+
collapsibleTypes: this.collapsibleTypes,
|
|
21
|
+
droppableTypes: this.droppableTypes
|
|
16
22
|
};
|
|
17
23
|
const data = {
|
|
18
24
|
stack: [],
|
package/package.json
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export declare class XMLTranslator implements Translator<XMLTree> {
|
|
|
24
24
|
getTree(): XMLTree;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export interface ParseResult<TTree =
|
|
27
|
+
export interface ParseResult<TTree = ASTTree> {
|
|
28
28
|
readonly result: {
|
|
29
29
|
readonly success: boolean;
|
|
30
30
|
readonly state: number;
|
|
@@ -54,6 +54,159 @@ export interface CSTTree {
|
|
|
54
54
|
|
|
55
55
|
export type XMLTree = string;
|
|
56
56
|
|
|
57
|
+
/* AST Tree start */
|
|
58
|
+
export interface ASTTree {
|
|
59
|
+
readonly root: JSONPathQueryASTNode;
|
|
60
|
+
}
|
|
61
|
+
export interface ASTNode {
|
|
62
|
+
readonly type:
|
|
63
|
+
| 'JSONPathQuery'
|
|
64
|
+
| 'NameSelector'
|
|
65
|
+
| 'WildcardSelector'
|
|
66
|
+
| 'IndexSelector'
|
|
67
|
+
| 'SliceSelector'
|
|
68
|
+
| 'FilterSelector'
|
|
69
|
+
| 'LogicalOrExpr'
|
|
70
|
+
| 'LogicalAndExpr'
|
|
71
|
+
| 'LogicalNotExpr'
|
|
72
|
+
| 'TestExpr'
|
|
73
|
+
| 'FilterQuery'
|
|
74
|
+
| 'RelQuery'
|
|
75
|
+
| 'ComparisonExpr'
|
|
76
|
+
| 'Literal'
|
|
77
|
+
| 'RelSingularQuery'
|
|
78
|
+
| 'AbsSingularQuery'
|
|
79
|
+
| 'FunctionExpr'
|
|
80
|
+
| 'ChildSegment'
|
|
81
|
+
| 'DescendantSegment'
|
|
82
|
+
| 'BracketedSelection';
|
|
83
|
+
}
|
|
84
|
+
// https://www.rfc-editor.org/rfc/rfc9535#section-2.1.1
|
|
85
|
+
export interface JSONPathQueryASTNode extends ASTNode {
|
|
86
|
+
readonly type: 'JSONPathQuery';
|
|
87
|
+
segments: SegmentASTNode[];
|
|
88
|
+
}
|
|
89
|
+
// https://www.rfc-editor.org/rfc/rfc9535#section-2.3.1.1
|
|
90
|
+
export interface NameSelectorASTNode extends ASTNode {
|
|
91
|
+
type: 'NameSelector';
|
|
92
|
+
value: string;
|
|
93
|
+
format: 'single-quoted' | 'double-quoted' | 'shorthand';
|
|
94
|
+
}
|
|
95
|
+
// https://www.rfc-editor.org/rfc/rfc9535#section-2.3.2.1
|
|
96
|
+
export interface WildcardSelectorASTNode extends ASTNode {
|
|
97
|
+
type: 'WildcardSelector';
|
|
98
|
+
}
|
|
99
|
+
// https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths
|
|
100
|
+
export interface IndexSelectorASTNode extends ASTNode {
|
|
101
|
+
type: 'IndexSelector';
|
|
102
|
+
value: number;
|
|
103
|
+
}
|
|
104
|
+
// https://www.rfc-editor.org/rfc/rfc9535#section-2.3.4.1
|
|
105
|
+
export interface SliceSelectorASTNode extends ASTNode {
|
|
106
|
+
type: 'SliceSelector';
|
|
107
|
+
start: number | null;
|
|
108
|
+
end: number | null ;
|
|
109
|
+
step: number | null;
|
|
110
|
+
}
|
|
111
|
+
// https://www.rfc-editor.org/rfc/rfc9535#section-2.3.5.1
|
|
112
|
+
export interface FilterSelectorASTNode extends ASTNode {
|
|
113
|
+
type: 'FilterSelector';
|
|
114
|
+
expression: LogicalExprASTNode;
|
|
115
|
+
}
|
|
116
|
+
export interface LogicalOrExprASTNode extends ASTNode {
|
|
117
|
+
type: 'LogicalOrExpr';
|
|
118
|
+
left: LogicalExprASTNode;
|
|
119
|
+
right: LogicalExprASTNode;
|
|
120
|
+
}
|
|
121
|
+
export interface LogicalAndExprASTNode extends ASTNode {
|
|
122
|
+
type: 'LogicalAndExpr';
|
|
123
|
+
left: LogicalExprASTNode;
|
|
124
|
+
right: LogicalExprASTNode;
|
|
125
|
+
}
|
|
126
|
+
export interface LogicalNotExprASTNode extends ASTNode {
|
|
127
|
+
type: 'LogicalNotExpr';
|
|
128
|
+
expression: LogicalExprASTNode;
|
|
129
|
+
}
|
|
130
|
+
export interface TestExprASTNode extends ASTNode {
|
|
131
|
+
type: 'TestExpr';
|
|
132
|
+
expression: FilterQueryASTNode | FunctionExprASTNode;
|
|
133
|
+
}
|
|
134
|
+
export interface FilterQueryASTNode extends ASTNode {
|
|
135
|
+
type: 'FilterQuery';
|
|
136
|
+
query: RelQueryASTNode | JSONPathQueryASTNode;
|
|
137
|
+
}
|
|
138
|
+
export interface RelQueryASTNode extends ASTNode {
|
|
139
|
+
type: 'RelQuery';
|
|
140
|
+
segments: SegmentASTNode[];
|
|
141
|
+
}
|
|
142
|
+
export interface ComparisonExprASTNode extends ASTNode {
|
|
143
|
+
type: 'ComparisonExpr';
|
|
144
|
+
left: ComparableASTNode;
|
|
145
|
+
operator: '==' | '!=' | '<=' | '>=' | '<' | '>';
|
|
146
|
+
right: ComparableASTNode;
|
|
147
|
+
}
|
|
148
|
+
export interface LiteralASTNode extends ASTNode {
|
|
149
|
+
type: 'Literal';
|
|
150
|
+
value: string | number | boolean | null;
|
|
151
|
+
}
|
|
152
|
+
export interface RelSingularQueryASTNode extends ASTNode {
|
|
153
|
+
type: 'RelSingularQuery';
|
|
154
|
+
segments: SingularQuerySegmentASTNode[];
|
|
155
|
+
}
|
|
156
|
+
export interface AbsSingularQueryASTNode extends ASTNode {
|
|
157
|
+
type: 'AbsSingularQuery';
|
|
158
|
+
segments: SingularQuerySegmentASTNode[];
|
|
159
|
+
}
|
|
160
|
+
// https://www.rfc-editor.org/rfc/rfc9535#section-2.4
|
|
161
|
+
export interface FunctionExprASTNode extends ASTNode {
|
|
162
|
+
type: 'FunctionExpr';
|
|
163
|
+
name: string;
|
|
164
|
+
arguments: FunctionArgumentASTNode[];
|
|
165
|
+
}
|
|
166
|
+
// https://www.rfc-editor.org/rfc/rfc9535#section-2.5.1.1
|
|
167
|
+
export interface ChildSegmentASTNode extends ASTNode {
|
|
168
|
+
type: 'ChildSegment';
|
|
169
|
+
selector: BracketedSelectionASTNode | WildcardSelectorASTNode | NameSelectorASTNode;
|
|
170
|
+
}
|
|
171
|
+
export interface BracketedSelectionASTNode extends ASTNode {
|
|
172
|
+
type: 'BracketedSelection';
|
|
173
|
+
selectors: SelectorASTNode[];
|
|
174
|
+
}
|
|
175
|
+
export interface DescendantSegmentASTNode extends ASTNode {
|
|
176
|
+
type: 'DescendantSegment';
|
|
177
|
+
selector: BracketedSelectionASTNode | WildcardSelectorASTNode | NameSelectorASTNode;
|
|
178
|
+
}
|
|
179
|
+
// union types
|
|
180
|
+
export type SelectorASTNode =
|
|
181
|
+
| NameSelectorASTNode
|
|
182
|
+
| WildcardSelectorASTNode
|
|
183
|
+
| SliceSelectorASTNode
|
|
184
|
+
| IndexSelectorASTNode
|
|
185
|
+
| FilterQueryASTNode;
|
|
186
|
+
export type LogicalExprASTNode =
|
|
187
|
+
| LogicalOrExprASTNode
|
|
188
|
+
| LogicalAndExprASTNode
|
|
189
|
+
| LogicalNotExprASTNode
|
|
190
|
+
| TestExprASTNode
|
|
191
|
+
| ComparisonExprASTNode;
|
|
192
|
+
export type ComparableASTNode =
|
|
193
|
+
| RelSingularQueryASTNode
|
|
194
|
+
| AbsSingularQueryASTNode
|
|
195
|
+
| FunctionExprASTNode
|
|
196
|
+
| LiteralASTNode;
|
|
197
|
+
export type SegmentASTNode =
|
|
198
|
+
| ChildSegmentASTNode
|
|
199
|
+
| DescendantSegmentASTNode;
|
|
200
|
+
export type FunctionArgumentASTNode =
|
|
201
|
+
| LogicalExprASTNode
|
|
202
|
+
| FilterQueryASTNode
|
|
203
|
+
| FunctionExprASTNode
|
|
204
|
+
| LiteralASTNode;
|
|
205
|
+
export type SingularQuerySegmentASTNode =
|
|
206
|
+
| NameSelectorASTNode
|
|
207
|
+
| IndexSelectorASTNode;
|
|
208
|
+
/* AST Tree end */
|
|
209
|
+
|
|
57
210
|
export interface Stats {
|
|
58
211
|
displayStats(): string;
|
|
59
212
|
displayHits(): string;
|