@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
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
|
-
|
|
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
|
|
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
|
|
16
|
-
exports.test =
|
|
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 =
|
|
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)
|
|
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:
|
|
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$
|
|
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$
|
|
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;
|
package/cjs/parse/index.cjs
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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";
|