@swaggerexpert/jsonpath 1.2.1 → 2.1.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
@@ -34,8 +34,10 @@ The development of this library contributed to the identification and formal sub
34
34
  - [Installation](#installation)
35
35
  - [Usage](#usage)
36
36
  - [Parsing](#parsing)
37
- - [Concrete Syntax Tree (CST)](#concrete-syntax-tree-cst)
38
- - [Interpreting Parse result as XML](#interpreting-parse-result-as-xml)
37
+ - [Normalized paths](#normalized-paths)
38
+ - [Translators](#translators)
39
+ - [CST](#cst-translator)
40
+ - [XML](#xml-translator)
39
41
  - [Statistics](#statistics)
40
42
  - [Tracing](#tracing)
41
43
  - [Errors](#errors)
@@ -69,231 +71,92 @@ import { parse } from '@swaggerexpert/jsonpath';
69
71
  const parseResult = parse('$.store.book[0].title');
70
72
  ```
71
73
 
72
- or
73
-
74
- ```js
75
- import { parse, JSONPathQueryCST } from '@swaggerexpert/jsonpath';
76
-
77
- const parseResult = parse('$.store.book[0].title', { ast: new JSONPathQueryCST() });
78
- ```
79
-
80
74
  **parseResult** variable has the following shape:
81
75
 
82
76
  ```
83
77
  {
84
- result: {
85
- success: true,
86
- state: 101,
87
- stateName: 'MATCH',
88
- length: 21,
89
- matched: 21,
90
- maxMatched: 21,
91
- maxTreeDepth: 21,
92
- nodeHits: 298
93
- },
94
- ast: <JSONPathQueryCST>,
95
- computed: {
96
- stack: [],
97
- root: {
98
- type: 'jsonpath-query',
99
- text: '$.store.book[0].title',
100
- start: 0,
101
- length: 21,
102
- children: [
103
- {
104
- type: 'root-identifier',
105
- text: '$',
106
- start: 0,
107
- length: 1,
108
- children: []
109
- },
110
- {
111
- type: 'segments',
112
- text: '.store.book[0].title',
113
- start: 1,
114
- length: 20,
115
- children: [
116
- {
117
- type: 'segment',
118
- text: '.store',
119
- start: 1,
120
- length: 6,
121
- children: [
122
- {
123
- type: 'child-segment',
124
- text: '.store',
125
- start: 1,
126
- length: 6,
127
- children: [
128
- {
129
- type: 'text',
130
- text: '.',
131
- start: 1,
132
- length: 1,
133
- children: []
134
- },
135
- {
136
- type: 'member-name-shorthand',
137
- text: 'store',
138
- start: 2,
139
- length: 5,
140
- children: []
141
- }
142
- ]
143
- }
144
- ]
145
- },
146
- {
147
- type: 'segment',
148
- text: '.book',
149
- start: 7,
150
- length: 5,
151
- children: [
152
- {
153
- type: 'child-segment',
154
- text: '.book',
155
- start: 7,
156
- length: 5,
157
- children: [
158
- {
159
- type: 'text',
160
- text: '.',
161
- start: 7,
162
- length: 1,
163
- children: []
164
- },
165
- {
166
- type: 'member-name-shorthand',
167
- text: 'book',
168
- start: 8,
169
- length: 4,
170
- children: []
171
- }
172
- ]
173
- }
174
- ]
175
- },
176
- {
177
- type: 'segment',
178
- text: '[0]',
179
- start: 12,
180
- length: 3,
181
- children: [
182
- {
183
- type: 'child-segment',
184
- text: '[0]',
185
- start: 12,
186
- length: 3,
187
- children: [
188
- {
189
- type: 'bracketed-selection',
190
- text: '[0]',
191
- start: 12,
192
- length: 3,
193
- children: [
194
- {
195
- type: 'text',
196
- text: '[',
197
- start: 12,
198
- length: 1,
199
- children: []
200
- },
201
- {
202
- type: 'selector',
203
- text: '0',
204
- start: 13,
205
- length: 1,
206
- children: [
207
- {
208
- type: 'index-selector',
209
- text: '0',
210
- start: 13,
211
- length: 1,
212
- children: []
213
- }
214
- ]
215
- },
216
- {
217
- type: 'text',
218
- text: ']',
219
- start: 14,
220
- length: 1,
221
- children: []
222
- }
223
- ]
224
- }
225
- ]
226
- }
227
- ]
228
- },
229
- {
230
- type: 'segment',
231
- text: '.title',
232
- start: 15,
233
- length: 6,
234
- children: [
235
- {
236
- type: 'child-segment',
237
- text: '.title',
238
- start: 15,
239
- length: 6,
240
- children: [
241
- {
242
- type: 'text',
243
- text: '.',
244
- start: 15,
245
- length: 1,
246
- children: []
247
- },
248
- {
249
- type: 'member-name-shorthand',
250
- text: 'title',
251
- start: 16,
252
- length: 5,
253
- children: []
254
- }
255
- ]
256
- }
257
- ]
258
- }
259
- ]
260
- }
261
- ]
262
- }
263
- }
78
+ result: <ParseResult['result]>,
79
+ tree: <ParseResult['tree']>,
80
+ stats: <ParseResult['stats']>,
81
+ trace: <ParseResult['trace']>,
264
82
  }
265
83
  ```
266
84
 
267
- ###### Concrete Syntax Tree (CST)
85
+ [TypeScript typings](https://github.com/swaggerexpert/jsonpath/blob/main/types/index.d.ts) are available for all fields attached to parse result object returned by the `parse` function.
86
+
87
+
88
+ ##### Normalized paths
89
+
90
+ [comment]: <> (SPDX-FileCopyrightText: Copyright &#40;c&#41; 2024 IETF Trust and the persons identified as the document authors. All rights reserved.)
91
+ [comment]: <> (SPDX-License-Identifier: BSD-3-Clause)
92
+
93
+ [Normalized Path](https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths) is a JSONPath query with restricted syntax.
94
+ A Normalized Path represents the identity of a node in a specific value.
95
+ There is precisely one Normalized Path identifying any particular node in a value.
96
+ Normalized Paths provide a predictable format that simplifies testing and post-processing of nodelists, e.g., to remove duplicate nodes.
97
+ Normalized Paths use the canonical bracket notation, rather than dot notation.
98
+ Single quotes are used in Normalized Paths to delimit string member names. This reduces the number of characters that need escaping when Normalized Paths appear in strings delimited by double quotes.
99
+
100
+ Parsing in normalized path mode can be enabled by setting `normalized` option to `true`.
101
+
102
+ ```js
103
+ import { parse } from '@swaggerexpert/jsonpath';
104
+
105
+ parse("$['a']", { normalized: true });
106
+ parse("$[1]", { normalized: true });
107
+ parse("$[2]", { normalized: true });
108
+ parse("$['a']['b'][1]", { normalized: true });
109
+ parse("$['\\u000b']", { normalized: true });
110
+ ```
111
+
112
+ ##### Translators
113
+
114
+ `@swaggerexpert/jsonpath` provides several translators to convert the parse result into different tree representations.
115
+
116
+ ###### CST translator
268
117
 
269
- [Concrete Syntax Tree](https://en.wikipedia.org/wiki/Parse_tree) (Parse tree) is available on parse result via `computed` field.
270
- Instance of `JSONPathQueryCST` needs to be assigned to `ast` option in `parse` function (default behavior).
118
+ [Concrete Syntax Tree](https://en.wikipedia.org/wiki/Parse_tree) (Parse tree) representation is available on parse result
119
+ by default or when instance of `CSTTranslator` is provided via a `translator` option to the `parse` function.
271
120
  CST is suitable to be consumed by other tools like IDEs, editors, etc...
272
121
 
273
122
  ```js
274
123
  import { parse } from '@swaggerexpert/jsonpath';
275
124
 
276
- const { computed: CST } = parse('$.store.book[0].title');
125
+ const { tree: CST } = parse('$.store.book[0].title');
277
126
  ```
278
127
 
279
128
  or
280
129
 
281
130
  ```js
282
- import { parse, JSONPathQueryCST } from '@swaggerexpert/jsonpath';
131
+ import { parse, CSTTranslator } from '@swaggerexpert/jsonpath';
283
132
 
284
- const { computed: CST } = parse('$.store.book[0].title', { ast: new JSONPathQueryCST() });
133
+ const { tree: CST } = parse('$.store.book[0].title', { translator: new CSTTranslator() });
285
134
  ```
286
135
 
287
- ###### Interpreting Parse result as XML
136
+ CST tree has the following shape:
137
+
138
+ ```ts
139
+ interface CSTTree {
140
+ readonly root: CSTNode;
141
+ }
142
+ interface CSTNode {
143
+ readonly type: string,
144
+ readonly text: string,
145
+ readonly start: number,
146
+ readonly length: number,
147
+ readonly children: CSTNode[],
148
+ }
149
+ ```
150
+
151
+ ###### XML translator
288
152
 
289
153
  ```js
290
- import { parse } from '@swaggerexpert/jsonpath';
154
+ import { parse, XMLTranslator } from '@swaggerexpert/jsonpath';
291
155
 
292
- const parseResult = parse('$.store.book[0].title');
293
- const xml = parseResult.ast.toXml();
156
+ const { tree: XML } = parse('$.store.book[0].title', { translator: new XMLTranslator() });
294
157
  ```
295
158
 
296
- ###### Statistics
159
+ ##### Statistics
297
160
 
298
161
  `parse` function returns additional statistical information about the parsing process.
299
162
  Collection of the statistics can be enabled by setting `stats` option to `true`.
@@ -307,7 +170,7 @@ stats.displayStats(); // returns operator stats
307
170
  stats.displayHits(); // returns rules grouped by hit count
308
171
  ```
309
172
 
310
- ###### Tracing
173
+ ##### Tracing
311
174
 
312
175
  `parse` function returns additional tracing information about the parsing process.
313
176
  Tracing can be enabled by setting `trace` option to `true`. Tracing is essential
package/cjs/grammar.cjs CHANGED
@@ -16,9 +16,9 @@ function grammar() {
16
16
  // ALT = 41
17
17
  // CAT = 60
18
18
  // REP = 32
19
- // RNM = 174
20
- // TLS = 66
21
- // TBS = 30
19
+ // RNM = 178
20
+ // TLS = 64
21
+ // TBS = 28
22
22
  // TRG = 20
23
23
  // --- SABNF superset opcodes
24
24
  // UDT = 0
@@ -2247,17 +2247,17 @@ function grammar() {
2247
2247
  children: [1, 2, 3]
2248
2248
  }; // CAT
2249
2249
  this.rules[69].opcodes[1] = {
2250
- type: 7,
2251
- string: [91]
2252
- }; // TLS
2250
+ type: 4,
2251
+ index: 80
2252
+ }; // RNM(left-bracket)
2253
2253
  this.rules[69].opcodes[2] = {
2254
2254
  type: 4,
2255
2255
  index: 70
2256
2256
  }; // RNM(normal-selector)
2257
2257
  this.rules[69].opcodes[3] = {
2258
- type: 7,
2259
- string: [93]
2260
- }; // TLS
2258
+ type: 4,
2259
+ index: 81
2260
+ }; // RNM(right-bracket)
2261
2261
 
2262
2262
  /* normal-selector */
2263
2263
  this.rules[70].opcodes = [];
@@ -2281,9 +2281,9 @@ function grammar() {
2281
2281
  children: [1, 2, 4]
2282
2282
  }; // CAT
2283
2283
  this.rules[71].opcodes[1] = {
2284
- type: 6,
2285
- string: [39]
2286
- }; // TBS
2284
+ type: 4,
2285
+ index: 87
2286
+ }; // RNM(squote)
2287
2287
  this.rules[71].opcodes[2] = {
2288
2288
  type: 3,
2289
2289
  min: 0,
@@ -2294,9 +2294,9 @@ function grammar() {
2294
2294
  index: 72
2295
2295
  }; // RNM(normal-single-quoted)
2296
2296
  this.rules[71].opcodes[4] = {
2297
- type: 6,
2298
- string: [39]
2299
- }; // TBS
2297
+ type: 4,
2298
+ index: 87
2299
+ }; // RNM(squote)
2300
2300
 
2301
2301
  /* normal-single-quoted */
2302
2302
  this.rules[72].opcodes = [];
@@ -2784,9 +2784,9 @@ function grammar() {
2784
2784
  str += "\n";
2785
2785
  str += "; https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths\n";
2786
2786
  str += "normalized-path = root-identifier *(normal-index-segment)\n";
2787
- str += "normal-index-segment = \"[\" normal-selector \"]\"\n";
2787
+ str += "normal-index-segment = left-bracket normal-selector right-bracket ; MODIFICATION: surrogate text rule used\n";
2788
2788
  str += "normal-selector = normal-name-selector / normal-index-selector\n";
2789
- str += "normal-name-selector = %x27 *normal-single-quoted %x27 ; 'string'\n";
2789
+ str += "normal-name-selector = squote *normal-single-quoted squote ; 'string', MODIFICATION: surrogate text rule used\n";
2790
2790
  str += "normal-single-quoted = normal-unescaped /\n";
2791
2791
  str += " ESC normal-escapable\n";
2792
2792
  str += "normal-unescaped = ; omit %x0-1F control codes\n";
package/cjs/index.cjs CHANGED
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
- exports.translateEvaluator = exports.parse = exports.JSONPathQueryCST = exports.Grammar = void 0;
4
+ exports.parse = exports.XMLTranslator = exports.Grammar = exports.CSTTranslator = 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"));
8
8
  exports.parse = _index.default;
9
- var _JSONPathQueryCST = _interopRequireDefault(require("./parse/ast/JSONPathQueryCST.cjs"));
10
- exports.JSONPathQueryCST = _JSONPathQueryCST.default;
11
- var _translate = _interopRequireDefault(require("./parse/evaluators/translate.cjs"));
12
- exports.translateEvaluator = _translate.default;
9
+ var _CSTTranslator = _interopRequireDefault(require("./parse/translators/CSTTranslator.cjs"));
10
+ exports.CSTTranslator = _CSTTranslator.default;
11
+ var _XMLTranslator = _interopRequireDefault(require("./parse/translators/XMLTranslator.cjs"));
12
+ exports.XMLTranslator = _XMLTranslator.default;
13
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -10,10 +10,6 @@ const cst = ruleName => {
10
10
  if (!(typeof data === 'object' && data !== null && !Array.isArray(data))) {
11
11
  throw new _JSONPathParseError.default("parser's user data must be an object");
12
12
  }
13
- if (!data.stack) {
14
- data.stack = [];
15
- data.root = null;
16
- }
17
13
 
18
14
  // drop the empty nodes
19
15
  if (phraseLength === 0) return;
@@ -4,35 +4,33 @@ 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 _translate = _interopRequireDefault(require("./evaluators/translate.cjs"));
8
- var _JSONPathQueryCST = _interopRequireDefault(require("./ast/JSONPathQueryCST.cjs"));
7
+ var _CSTTranslator = _interopRequireDefault(require("./translators/CSTTranslator.cjs"));
9
8
  var _JSONPathParseError = _interopRequireDefault(require("../errors/JSONPathParseError.cjs"));
10
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
10
  const grammar = new _grammar.default();
12
11
  const parse = (jsonPath, {
13
- ast = new _JSONPathQueryCST.default(),
12
+ normalized = false,
14
13
  stats = false,
15
14
  trace = false,
16
- evaluator = _translate.default
15
+ translator = new _CSTTranslator.default(),
16
+ test = 3
17
17
  } = {}) => {
18
18
  if (typeof jsonPath !== 'string') {
19
19
  throw new TypeError('JSONPath must be a string');
20
20
  }
21
21
  try {
22
+ var _parser$ast;
22
23
  const parser = new _apgLite.Parser();
23
- parser.ast = ast;
24
+ if (translator) parser.ast = translator;
24
25
  if (stats) parser.stats = new _apgLite.Stats();
25
26
  if (trace) parser.trace = new _apgLite.Trace();
26
- const result = parser.parse(grammar, 'jsonpath-query', jsonPath);
27
- const computed = evaluator(ast, {
28
- result
29
- });
27
+ const startRule = normalized ? 'normalized-path' : 'jsonpath-query';
28
+ const result = parser.parse(grammar, startRule, jsonPath);
30
29
  return {
31
30
  result,
32
- ast,
31
+ tree: (_parser$ast = parser.ast) == null ? void 0 : _parser$ast.getTree(),
33
32
  stats: parser.stats,
34
- trace: parser.trace,
35
- computed
33
+ trace: parser.trace
36
34
  };
37
35
  } catch (error) {
38
36
  throw new _JSONPathParseError.default('Unexpected error during JSONPath parsing', {
@@ -5,7 +5,7 @@ exports.default = void 0;
5
5
  var _apgLite = require("../../apg-lite.cjs");
6
6
  var _cst = _interopRequireDefault(require("../callbacks/cst.cjs"));
7
7
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
8
- class JSONPathQueryCST extends _apgLite.Ast {
8
+ class CSTTranslator extends _apgLite.Ast {
9
9
  constructor() {
10
10
  super();
11
11
 
@@ -82,6 +82,14 @@ class JSONPathQueryCST extends _apgLite.Ast {
82
82
  // https://www.rfc-editor.org/rfc/rfc9535#section-2.5.2.1
83
83
  this.callbacks['descendant-segment'] = (0, _cst.default)('descendant-segment');
84
84
 
85
+ // https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths
86
+ this.callbacks['normalized-path'] = (0, _cst.default)('normalized-path');
87
+ this.callbacks['normal-index-segment'] = (0, _cst.default)('normal-index-segment');
88
+ this.callbacks['normal-selector'] = (0, _cst.default)('normal-selector');
89
+ this.callbacks['normal-name-selector'] = (0, _cst.default)('normal-name-selector');
90
+ this.callbacks['normal-index-selector'] = (0, _cst.default)('normal-index-selector');
91
+ this.callbacks['normal-single-quoted'] = (0, _cst.default)('normal-single-quoted');
92
+
85
93
  // Surrogate named rules
86
94
  this.callbacks['dot-prefix'] = (0, _cst.default)('text');
87
95
  this.callbacks['double-dot-prefix'] = (0, _cst.default)('text');
@@ -97,5 +105,14 @@ class JSONPathQueryCST extends _apgLite.Ast {
97
105
  this.callbacks['left-paren'] = (0, _cst.default)('text');
98
106
  this.callbacks['right-paren'] = (0, _cst.default)('text');
99
107
  }
108
+ getTree() {
109
+ const data = {
110
+ stack: [],
111
+ root: null
112
+ };
113
+ this.translate(data);
114
+ delete data.stack;
115
+ return data;
116
+ }
100
117
  }
101
- var _default = exports.default = JSONPathQueryCST;
118
+ var _default = exports.default = CSTTranslator;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+ var _CSTTranslator = _interopRequireDefault(require("./CSTTranslator.cjs"));
6
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
7
+ class XMLTranslator extends _CSTTranslator.default {
8
+ getTree() {
9
+ return this.toXml();
10
+ }
11
+ }
12
+ var _default = exports.default = XMLTranslator;
package/es/grammar.mjs CHANGED
@@ -12,9 +12,9 @@ export default function grammar() {
12
12
  // ALT = 41
13
13
  // CAT = 60
14
14
  // REP = 32
15
- // RNM = 174
16
- // TLS = 66
17
- // TBS = 30
15
+ // RNM = 178
16
+ // TLS = 64
17
+ // TBS = 28
18
18
  // TRG = 20
19
19
  // --- SABNF superset opcodes
20
20
  // UDT = 0
@@ -2243,17 +2243,17 @@ export default function grammar() {
2243
2243
  children: [1, 2, 3]
2244
2244
  }; // CAT
2245
2245
  this.rules[69].opcodes[1] = {
2246
- type: 7,
2247
- string: [91]
2248
- }; // TLS
2246
+ type: 4,
2247
+ index: 80
2248
+ }; // RNM(left-bracket)
2249
2249
  this.rules[69].opcodes[2] = {
2250
2250
  type: 4,
2251
2251
  index: 70
2252
2252
  }; // RNM(normal-selector)
2253
2253
  this.rules[69].opcodes[3] = {
2254
- type: 7,
2255
- string: [93]
2256
- }; // TLS
2254
+ type: 4,
2255
+ index: 81
2256
+ }; // RNM(right-bracket)
2257
2257
 
2258
2258
  /* normal-selector */
2259
2259
  this.rules[70].opcodes = [];
@@ -2277,9 +2277,9 @@ export default function grammar() {
2277
2277
  children: [1, 2, 4]
2278
2278
  }; // CAT
2279
2279
  this.rules[71].opcodes[1] = {
2280
- type: 6,
2281
- string: [39]
2282
- }; // TBS
2280
+ type: 4,
2281
+ index: 87
2282
+ }; // RNM(squote)
2283
2283
  this.rules[71].opcodes[2] = {
2284
2284
  type: 3,
2285
2285
  min: 0,
@@ -2290,9 +2290,9 @@ export default function grammar() {
2290
2290
  index: 72
2291
2291
  }; // RNM(normal-single-quoted)
2292
2292
  this.rules[71].opcodes[4] = {
2293
- type: 6,
2294
- string: [39]
2295
- }; // TBS
2293
+ type: 4,
2294
+ index: 87
2295
+ }; // RNM(squote)
2296
2296
 
2297
2297
  /* normal-single-quoted */
2298
2298
  this.rules[72].opcodes = [];
@@ -2780,9 +2780,9 @@ export default function grammar() {
2780
2780
  str += "\n";
2781
2781
  str += "; https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths\n";
2782
2782
  str += "normalized-path = root-identifier *(normal-index-segment)\n";
2783
- str += "normal-index-segment = \"[\" normal-selector \"]\"\n";
2783
+ str += "normal-index-segment = left-bracket normal-selector right-bracket ; MODIFICATION: surrogate text rule used\n";
2784
2784
  str += "normal-selector = normal-name-selector / normal-index-selector\n";
2785
- str += "normal-name-selector = %x27 *normal-single-quoted %x27 ; 'string'\n";
2785
+ str += "normal-name-selector = squote *normal-single-quoted squote ; 'string', MODIFICATION: surrogate text rule used\n";
2786
2786
  str += "normal-single-quoted = normal-unescaped /\n";
2787
2787
  str += " ESC normal-escapable\n";
2788
2788
  str += "normal-unescaped = ; omit %x0-1F control codes\n";
package/es/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  export { default as Grammar } from "./grammar.mjs";
2
2
  export { default as parse } from "./parse/index.mjs";
3
- export { default as JSONPathQueryCST } from "./parse/ast/JSONPathQueryCST.mjs";
4
- export { default as translateEvaluator } from "./parse/evaluators/translate.mjs";
3
+ export { default as CSTTranslator } from "./parse/translators/CSTTranslator.mjs";
4
+ export { default as XMLTranslator } from "./parse/translators/XMLTranslator.mjs";
@@ -5,10 +5,6 @@ const cst = ruleName => {
5
5
  if (!(typeof data === 'object' && data !== null && !Array.isArray(data))) {
6
6
  throw new JSONPathParseError("parser's user data must be an object");
7
7
  }
8
- if (!data.stack) {
9
- data.stack = [];
10
- data.root = null;
11
- }
12
8
 
13
9
  // drop the empty nodes
14
10
  if (phraseLength === 0) return;
@@ -1,33 +1,31 @@
1
1
  import { Parser, Stats, Trace } from 'apg-lite';
2
2
  import Grammar from "../grammar.mjs";
3
- import translateEvaluator from "./evaluators/translate.mjs";
4
- import JSONPathQueryCST from "./ast/JSONPathQueryCST.mjs";
3
+ import CSTTranslator from "./translators/CSTTranslator.mjs";
5
4
  import JSONPathParseError from "../errors/JSONPathParseError.mjs";
6
5
  const grammar = new Grammar();
7
6
  const parse = (jsonPath, {
8
- ast = new JSONPathQueryCST(),
7
+ normalized = false,
9
8
  stats = false,
10
9
  trace = false,
11
- evaluator = translateEvaluator
10
+ translator = new CSTTranslator(),
11
+ test = 3
12
12
  } = {}) => {
13
13
  if (typeof jsonPath !== 'string') {
14
14
  throw new TypeError('JSONPath must be a string');
15
15
  }
16
16
  try {
17
+ var _parser$ast;
17
18
  const parser = new Parser();
18
- parser.ast = ast;
19
+ if (translator) parser.ast = translator;
19
20
  if (stats) parser.stats = new Stats();
20
21
  if (trace) parser.trace = new Trace();
21
- const result = parser.parse(grammar, 'jsonpath-query', jsonPath);
22
- const computed = evaluator(ast, {
23
- result
24
- });
22
+ const startRule = normalized ? 'normalized-path' : 'jsonpath-query';
23
+ const result = parser.parse(grammar, startRule, jsonPath);
25
24
  return {
26
25
  result,
27
- ast,
26
+ tree: (_parser$ast = parser.ast) === null || _parser$ast === void 0 ? void 0 : _parser$ast.getTree(),
28
27
  stats: parser.stats,
29
- trace: parser.trace,
30
- computed
28
+ trace: parser.trace
31
29
  };
32
30
  } catch (error) {
33
31
  throw new JSONPathParseError('Unexpected error during JSONPath parsing', {
@@ -1,6 +1,6 @@
1
1
  import { Ast as AST } from 'apg-lite';
2
2
  import cstCallback from "../callbacks/cst.mjs";
3
- class JSONPathQueryCST extends AST {
3
+ class CSTTranslator extends AST {
4
4
  constructor() {
5
5
  super();
6
6
 
@@ -77,6 +77,14 @@ class JSONPathQueryCST extends AST {
77
77
  // https://www.rfc-editor.org/rfc/rfc9535#section-2.5.2.1
78
78
  this.callbacks['descendant-segment'] = cstCallback('descendant-segment');
79
79
 
80
+ // https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths
81
+ this.callbacks['normalized-path'] = cstCallback('normalized-path');
82
+ this.callbacks['normal-index-segment'] = cstCallback('normal-index-segment');
83
+ this.callbacks['normal-selector'] = cstCallback('normal-selector');
84
+ this.callbacks['normal-name-selector'] = cstCallback('normal-name-selector');
85
+ this.callbacks['normal-index-selector'] = cstCallback('normal-index-selector');
86
+ this.callbacks['normal-single-quoted'] = cstCallback('normal-single-quoted');
87
+
80
88
  // Surrogate named rules
81
89
  this.callbacks['dot-prefix'] = cstCallback('text');
82
90
  this.callbacks['double-dot-prefix'] = cstCallback('text');
@@ -92,5 +100,14 @@ class JSONPathQueryCST extends AST {
92
100
  this.callbacks['left-paren'] = cstCallback('text');
93
101
  this.callbacks['right-paren'] = cstCallback('text');
94
102
  }
103
+ getTree() {
104
+ const data = {
105
+ stack: [],
106
+ root: null
107
+ };
108
+ this.translate(data);
109
+ delete data.stack;
110
+ return data;
111
+ }
95
112
  }
96
- export default JSONPathQueryCST;
113
+ export default CSTTranslator;
@@ -0,0 +1,7 @@
1
+ import CSTTranslator from "./CSTTranslator.mjs";
2
+ class XMLTranslator extends CSTTranslator {
3
+ getTree() {
4
+ return this.toXml();
5
+ }
6
+ }
7
+ export default XMLTranslator;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.2.1",
6
+ "version": "2.1.0",
7
7
  "description": "RCF 9535 implementation of JSONPath",
8
8
  "main": "./cjs/index.cjs",
9
9
  "types": "./types/index.d.ts",
package/types/index.d.ts CHANGED
@@ -4,22 +4,34 @@
4
4
  export function parse(jsonpath: string, options?: ParseOptions): ParseResult;
5
5
 
6
6
  export interface ParseOptions {
7
- readonly ast?: AST;
7
+ readonly normalized?: boolean;
8
8
  readonly stats?: boolean;
9
9
  readonly trace?: boolean;
10
+ readonly translator?: Translator | null;
10
11
  }
11
12
 
12
- export interface AST {
13
- readonly translate: (parts: Record<string, CSTNode>) => Record<string, CSTNode>;
14
- readonly toXml: () => string;
13
+ export interface Translator<TTree = unknown> {
14
+ getTree(): TTree;
15
+ }
16
+ export declare class CSTTranslator implements Translator<CSTTree> {
17
+ getTree(): CSTTree;
18
+ }
19
+ export declare class XMLTranslator implements Translator<XMLTree> {
20
+ getTree(): XMLTree;
15
21
  }
16
22
 
17
- export interface ParseResult {
23
+ export interface ParseResult<TTree = unknown> {
18
24
  readonly result: {
19
25
  readonly success: boolean;
26
+ readonly state: number;
27
+ readonly stateName: string;
28
+ readonly length: number;
29
+ readonly matched: number;
30
+ readonly maxMatched: number;
31
+ readonly maxTreeDepth: number
32
+ readonly nodeHits: number;
20
33
  };
21
- readonly ast: AST;
22
- readonly computed: Record<string, CSTNode>;
34
+ readonly tree: TTree;
23
35
  readonly stats?: Stats;
24
36
  readonly trace?: Trace;
25
37
  }
@@ -32,6 +44,12 @@ export interface CSTNode {
32
44
  readonly children: CSTNode[],
33
45
  }
34
46
 
47
+ export interface CSTTree {
48
+ readonly root: CSTNode;
49
+ }
50
+
51
+ export type XMLTree = string;
52
+
35
53
  export interface Stats {
36
54
  displayStats(): string;
37
55
  displayHits(): string;
@@ -1,13 +0,0 @@
1
- "use strict";
2
-
3
- exports.__esModule = true;
4
- exports.default = void 0;
5
- const translateEvaluator = (ast, {
6
- result
7
- }) => {
8
- if (!result.success) return null;
9
- const parts = {};
10
- ast.translate(parts);
11
- return parts;
12
- };
13
- var _default = exports.default = translateEvaluator;
@@ -1,9 +0,0 @@
1
- const translateEvaluator = (ast, {
2
- result
3
- }) => {
4
- if (!result.success) return null;
5
- const parts = {};
6
- ast.translate(parts);
7
- return parts;
8
- };
9
- export default translateEvaluator;