@swaggerexpert/jsonpath 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,11 @@
9
9
 
10
10
  `@swaggerexpert/jsonpath` is a **parser** and **validator** for [RFC 9535](https://www.rfc-editor.org/rfc/rfc9535) Query Expressions for JSON - **JSONPath**.
11
11
 
12
- The development of this library contributed to the identification and formal submission of [Errata 8343](https://www.rfc-editor.org/errata/eid8343) against RFC 9535.
12
+ The development of this library contributed to the identification and formal submission of following **erratas** against the RFC 9535:
13
+ - [Errata ID: 8343](https://www.rfc-editor.org/errata/eid8343)
14
+ - [Errata ID: 8352](https://www.rfc-editor.org/errata/eid8352)
15
+ - [Errata ID: 8353](https://www.rfc-editor.org/errata/eid8353)
16
+ - [Errata ID: 8354](https://www.rfc-editor.org/errata/eid8354)
13
17
 
14
18
  <table>
15
19
  <tr>
@@ -30,8 +34,9 @@ The development of this library contributed to the identification and formal sub
30
34
  - [Installation](#installation)
31
35
  - [Usage](#usage)
32
36
  - [Parsing](#parsing)
33
- - [Concrete Syntax Tree (CST)](#concrete-syntax-tree-cst)
34
- - [Interpreting Parse result as XML](#interpreting-parse-result-as-xml)
37
+ - [Translators](#translators)
38
+ - [CST](#cst-translator)
39
+ - [XML](#xml-translator)
35
40
  - [Statistics](#statistics)
36
41
  - [Tracing](#tracing)
37
42
  - [Errors](#errors)
@@ -68,228 +73,72 @@ const parseResult = parse('$.store.book[0].title');
68
73
  or
69
74
 
70
75
  ```js
71
- import { parse, JSONPathQueryCST } from '@swaggerexpert/jsonpath';
76
+ import { parse, CSTTranslator } from '@swaggerexpert/jsonpath';
72
77
 
73
- const parseResult = parse('$.store.book[0].title', { ast: new JSONPathQueryCST() });
78
+ const parseResult = parse('$.store.book[0].title', { translator: new CSTTranslator() });
74
79
  ```
75
80
 
76
81
  **parseResult** variable has the following shape:
77
82
 
78
83
  ```
79
84
  {
80
- result: {
81
- success: true,
82
- state: 101,
83
- stateName: 'MATCH',
84
- length: 21,
85
- matched: 21,
86
- maxMatched: 21,
87
- maxTreeDepth: 21,
88
- nodeHits: 298
89
- },
90
- ast: <JSONPathQueryCST>,
91
- computed: {
92
- stack: [],
93
- root: {
94
- type: 'jsonpath-query',
95
- text: '$.store.book[0].title',
96
- start: 0,
97
- length: 21,
98
- children: [
99
- {
100
- type: 'root-identifier',
101
- text: '$',
102
- start: 0,
103
- length: 1,
104
- children: []
105
- },
106
- {
107
- type: 'segments',
108
- text: '.store.book[0].title',
109
- start: 1,
110
- length: 20,
111
- children: [
112
- {
113
- type: 'segment',
114
- text: '.store',
115
- start: 1,
116
- length: 6,
117
- children: [
118
- {
119
- type: 'child-segment',
120
- text: '.store',
121
- start: 1,
122
- length: 6,
123
- children: [
124
- {
125
- type: 'text',
126
- text: '.',
127
- start: 1,
128
- length: 1,
129
- children: []
130
- },
131
- {
132
- type: 'member-name-shorthand',
133
- text: 'store',
134
- start: 2,
135
- length: 5,
136
- children: []
137
- }
138
- ]
139
- }
140
- ]
141
- },
142
- {
143
- type: 'segment',
144
- text: '.book',
145
- start: 7,
146
- length: 5,
147
- children: [
148
- {
149
- type: 'child-segment',
150
- text: '.book',
151
- start: 7,
152
- length: 5,
153
- children: [
154
- {
155
- type: 'text',
156
- text: '.',
157
- start: 7,
158
- length: 1,
159
- children: []
160
- },
161
- {
162
- type: 'member-name-shorthand',
163
- text: 'book',
164
- start: 8,
165
- length: 4,
166
- children: []
167
- }
168
- ]
169
- }
170
- ]
171
- },
172
- {
173
- type: 'segment',
174
- text: '[0]',
175
- start: 12,
176
- length: 3,
177
- children: [
178
- {
179
- type: 'child-segment',
180
- text: '[0]',
181
- start: 12,
182
- length: 3,
183
- children: [
184
- {
185
- type: 'bracketed-selection',
186
- text: '[0]',
187
- start: 12,
188
- length: 3,
189
- children: [
190
- {
191
- type: 'text',
192
- text: '[',
193
- start: 12,
194
- length: 1,
195
- children: []
196
- },
197
- {
198
- type: 'selector',
199
- text: '0',
200
- start: 13,
201
- length: 1,
202
- children: [
203
- {
204
- type: 'index-selector',
205
- text: '0',
206
- start: 13,
207
- length: 1,
208
- children: []
209
- }
210
- ]
211
- },
212
- {
213
- type: 'text',
214
- text: ']',
215
- start: 14,
216
- length: 1,
217
- children: []
218
- }
219
- ]
220
- }
221
- ]
222
- }
223
- ]
224
- },
225
- {
226
- type: 'segment',
227
- text: '.title',
228
- start: 15,
229
- length: 6,
230
- children: [
231
- {
232
- type: 'child-segment',
233
- text: '.title',
234
- start: 15,
235
- length: 6,
236
- children: [
237
- {
238
- type: 'text',
239
- text: '.',
240
- start: 15,
241
- length: 1,
242
- children: []
243
- },
244
- {
245
- type: 'member-name-shorthand',
246
- text: 'title',
247
- start: 16,
248
- length: 5,
249
- children: []
250
- }
251
- ]
252
- }
253
- ]
254
- }
255
- ]
256
- }
257
- ]
258
- }
259
- }
85
+ result: <ParseResult['result]>,
86
+ tree: <ParseResult['tree']>,
87
+ stats: <ParseResult['stats']>,
88
+ trace: <ParseResult['trace']>,
260
89
  }
261
90
  ```
262
91
 
263
- ###### Concrete Syntax Tree (CST)
92
+ [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.
264
93
 
265
- [Concrete Syntax Tree](https://en.wikipedia.org/wiki/Parse_tree) (Parse tree) is available on parse result via `computed` field.
266
- Instance of `JSONPathQueryCST` needs to be assigned to `ast` option in `parse` function (default behavior).
94
+ ##### Translators
95
+
96
+ `@swaggerexpert/jsonpath` provides several translators to convert the parse result into different tree representations.
97
+
98
+ ###### CST translator
99
+
100
+ [Concrete Syntax Tree](https://en.wikipedia.org/wiki/Parse_tree) (Parse tree) representation is available on parse result
101
+ by default or when instance of `CSTTranslator` is provided via a `translator` option to the `parse` function.
267
102
  CST is suitable to be consumed by other tools like IDEs, editors, etc...
268
103
 
269
104
  ```js
270
105
  import { parse } from '@swaggerexpert/jsonpath';
271
106
 
272
- const { computed: CST } = parse('$.store.book[0].title');
107
+ const { tree: CST } = parse('$.store.book[0].title');
273
108
  ```
274
109
 
275
110
  or
276
111
 
277
112
  ```js
278
- import { parse, JSONPathQueryCST } from '@swaggerexpert/jsonpath';
113
+ import { parse, CSTTranslator } from '@swaggerexpert/jsonpath';
114
+
115
+ const { tree: CST } = parse('$.store.book[0].title', { translator: new CSTTranslator() });
116
+ ```
279
117
 
280
- const { computed: CST } = parse('$.store.book[0].title', { ast: new JSONPathQueryCST() });
118
+ CST tree has the following shape:
119
+
120
+ ```ts
121
+ interface CSTTree {
122
+ readonly root: CSTNode;
123
+ }
124
+ interface CSTNode {
125
+ readonly type: string,
126
+ readonly text: string,
127
+ readonly start: number,
128
+ readonly length: number,
129
+ readonly children: CSTNode[],
130
+ }
281
131
  ```
282
132
 
283
- ###### Interpreting Parse result as XML
133
+ ###### XML translator
284
134
 
285
135
  ```js
286
- import { parse } from '@swaggerexpert/jsonpath';
136
+ import { parse, XMLTranslator } from '@swaggerexpert/jsonpath';
287
137
 
288
- const parseResult = parse('$.store.book[0].title');
289
- const xml = parseResult.ast.toXml();
138
+ const { tree: XML } = parse('$.store.book[0].title', { translator: new XMLTranslator() });
290
139
  ```
291
140
 
292
- ###### Statistics
141
+ ##### Statistics
293
142
 
294
143
  `parse` function returns additional statistical information about the parsing process.
295
144
  Collection of the statistics can be enabled by setting `stats` option to `true`.
@@ -303,7 +152,7 @@ stats.displayStats(); // returns operator stats
303
152
  stats.displayHits(); // returns rules grouped by hit count
304
153
  ```
305
154
 
306
- ###### Tracing
155
+ ##### Tracing
307
156
 
308
157
  `parse` function returns additional tracing information about the parsing process.
309
158
  Tracing can be enabled by setting `trace` option to `true`. Tracing is essential
package/cjs/grammar.cjs CHANGED
@@ -2720,7 +2720,7 @@ function grammar() {
2720
2720
  str += "comparable = singular-query / ; singular query value\n";
2721
2721
  str += " function-expr / ; ValueType\n";
2722
2722
  str += " literal\n";
2723
- str += " ; MODIFICATION: https://www.rfc-editor.org/errata/eid8343\n";
2723
+ str += " ; MODIFICATION: https://www.rfc-editor.org/errata/eid8352\n";
2724
2724
  str += "comparison-op = \"==\" / \"!=\" /\n";
2725
2725
  str += " \"<=\" / \">=\" /\n";
2726
2726
  str += " \"<\" / \">\"\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,30 @@ 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
+ translator = new _CSTTranslator.default(),
14
13
  stats = false,
15
- trace = false,
16
- evaluator = _translate.default
14
+ trace = false
17
15
  } = {}) => {
18
16
  if (typeof jsonPath !== 'string') {
19
17
  throw new TypeError('JSONPath must be a string');
20
18
  }
21
19
  try {
20
+ var _parser$ast;
22
21
  const parser = new _apgLite.Parser();
23
- parser.ast = ast;
22
+ if (translator) parser.ast = translator;
24
23
  if (stats) parser.stats = new _apgLite.Stats();
25
24
  if (trace) parser.trace = new _apgLite.Trace();
26
25
  const result = parser.parse(grammar, 'jsonpath-query', jsonPath);
27
- const computed = evaluator(ast, {
28
- result
29
- });
30
26
  return {
31
27
  result,
32
- ast,
28
+ tree: (_parser$ast = parser.ast) == null ? void 0 : _parser$ast.getTree(),
33
29
  stats: parser.stats,
34
- trace: parser.trace,
35
- computed
30
+ trace: parser.trace
36
31
  };
37
32
  } catch (error) {
38
33
  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
 
@@ -97,5 +97,14 @@ class JSONPathQueryCST extends _apgLite.Ast {
97
97
  this.callbacks['left-paren'] = (0, _cst.default)('text');
98
98
  this.callbacks['right-paren'] = (0, _cst.default)('text');
99
99
  }
100
+ getTree() {
101
+ const data = {
102
+ stack: [],
103
+ root: null
104
+ };
105
+ this.translate(data);
106
+ delete data.stack;
107
+ return data;
108
+ }
100
109
  }
101
- var _default = exports.default = JSONPathQueryCST;
110
+ 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
@@ -2716,7 +2716,7 @@ export default function grammar() {
2716
2716
  str += "comparable = singular-query / ; singular query value\n";
2717
2717
  str += " function-expr / ; ValueType\n";
2718
2718
  str += " literal\n";
2719
- str += " ; MODIFICATION: https://www.rfc-editor.org/errata/eid8343\n";
2719
+ str += " ; MODIFICATION: https://www.rfc-editor.org/errata/eid8352\n";
2720
2720
  str += "comparison-op = \"==\" / \"!=\" /\n";
2721
2721
  str += " \"<=\" / \">=\" /\n";
2722
2722
  str += " \"<\" / \">\"\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,28 @@
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
+ translator = new CSTTranslator(),
9
8
  stats = false,
10
- trace = false,
11
- evaluator = translateEvaluator
9
+ trace = false
12
10
  } = {}) => {
13
11
  if (typeof jsonPath !== 'string') {
14
12
  throw new TypeError('JSONPath must be a string');
15
13
  }
16
14
  try {
15
+ var _parser$ast;
17
16
  const parser = new Parser();
18
- parser.ast = ast;
17
+ if (translator) parser.ast = translator;
19
18
  if (stats) parser.stats = new Stats();
20
19
  if (trace) parser.trace = new Trace();
21
20
  const result = parser.parse(grammar, 'jsonpath-query', jsonPath);
22
- const computed = evaluator(ast, {
23
- result
24
- });
25
21
  return {
26
22
  result,
27
- ast,
23
+ tree: (_parser$ast = parser.ast) === null || _parser$ast === void 0 ? void 0 : _parser$ast.getTree(),
28
24
  stats: parser.stats,
29
- trace: parser.trace,
30
- computed
25
+ trace: parser.trace
31
26
  };
32
27
  } catch (error) {
33
28
  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
 
@@ -92,5 +92,14 @@ class JSONPathQueryCST extends AST {
92
92
  this.callbacks['left-paren'] = cstCallback('text');
93
93
  this.callbacks['right-paren'] = cstCallback('text');
94
94
  }
95
+ getTree() {
96
+ const data = {
97
+ stack: [],
98
+ root: null
99
+ };
100
+ this.translate(data);
101
+ delete data.stack;
102
+ return data;
103
+ }
95
104
  }
96
- export default JSONPathQueryCST;
105
+ 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.0",
6
+ "version": "2.0.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,33 @@
4
4
  export function parse(jsonpath: string, options?: ParseOptions): ParseResult;
5
5
 
6
6
  export interface ParseOptions {
7
- readonly ast?: AST;
7
+ readonly translator?: Translator | null;
8
8
  readonly stats?: boolean;
9
9
  readonly trace?: boolean;
10
10
  }
11
11
 
12
- export interface AST {
13
- readonly translate: (parts: Record<string, CSTNode>) => Record<string, CSTNode>;
14
- readonly toXml: () => string;
12
+ export interface Translator<TTree = unknown> {
13
+ getTree(): TTree;
14
+ }
15
+ export declare class CSTTranslator implements Translator<CSTTree> {
16
+ getTree(): CSTTree;
17
+ }
18
+ export declare class XMLTranslator implements Translator<XMLTree> {
19
+ getTree(): XMLTree;
15
20
  }
16
21
 
17
- export interface ParseResult {
22
+ export interface ParseResult<TTree = unknown> {
18
23
  readonly result: {
19
24
  readonly success: boolean;
25
+ readonly state: number;
26
+ readonly stateName: string;
27
+ readonly length: number;
28
+ readonly matched: number;
29
+ readonly maxMatched: number;
30
+ readonly maxTreeDepth: number
31
+ readonly nodeHits: number;
20
32
  };
21
- readonly ast: AST;
22
- readonly computed: Record<string, CSTNode>;
33
+ readonly tree: TTree;
23
34
  readonly stats?: Stats;
24
35
  readonly trace?: Trace;
25
36
  }
@@ -32,6 +43,12 @@ export interface CSTNode {
32
43
  readonly children: CSTNode[],
33
44
  }
34
45
 
46
+ export interface CSTTree {
47
+ readonly root: CSTNode;
48
+ }
49
+
50
+ export type XMLTree = string;
51
+
35
52
  export interface Stats {
36
53
  displayStats(): string;
37
54
  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;