Skip to content

Commit 70a19c7

Browse files
authored
feat: introduce new public API (#8)
BREAKING CHANGE: new more flexible and extensible public API has been introduced
1 parent a1bd76c commit 70a19c7

File tree

15 files changed

+189
-333
lines changed

15 files changed

+189
-333
lines changed

README.md

Lines changed: 41 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ The development of this library contributed to the identification and formal sub
3434
- [Installation](#installation)
3535
- [Usage](#usage)
3636
- [Parsing](#parsing)
37-
- [Concrete Syntax Tree (CST)](#concrete-syntax-tree-cst)
38-
- [Interpreting Parse result as XML](#interpreting-parse-result-as-xml)
37+
- [Translators](#translators)
38+
- [CST](#cst-translator)
39+
- [XML](#xml-translator)
3940
- [Statistics](#statistics)
4041
- [Tracing](#tracing)
4142
- [Errors](#errors)
@@ -72,228 +73,72 @@ const parseResult = parse('$.store.book[0].title');
7273
or
7374

7475
```js
75-
import { parse, JSONPathQueryCST } from '@swaggerexpert/jsonpath';
76+
import { parse, CSTTranslator } from '@swaggerexpert/jsonpath';
7677

77-
const parseResult = parse('$.store.book[0].title', { ast: new JSONPathQueryCST() });
78+
const parseResult = parse('$.store.book[0].title', { translator: new CSTTranslator() });
7879
```
7980

8081
**parseResult** variable has the following shape:
8182

8283
```
8384
{
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-
}
85+
result: <ParseResult['result]>,
86+
tree: <ParseResult['tree']>,
87+
stats: <ParseResult['stats']>,
88+
trace: <ParseResult['trace']>,
26489
}
26590
```
26691

267-
###### 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.
26893

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).
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.
271102
CST is suitable to be consumed by other tools like IDEs, editors, etc...
272103

273104
```js
274105
import { parse } from '@swaggerexpert/jsonpath';
275106

276-
const { computed: CST } = parse('$.store.book[0].title');
107+
const { tree: CST } = parse('$.store.book[0].title');
277108
```
278109

279110
or
280111

281112
```js
282-
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+
```
283117

284-
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+
}
285131
```
286132

287-
###### Interpreting Parse result as XML
133+
###### XML translator
288134

289135
```js
290-
import { parse } from '@swaggerexpert/jsonpath';
136+
import { parse, XMLTranslator } from '@swaggerexpert/jsonpath';
291137

292-
const parseResult = parse('$.store.book[0].title');
293-
const xml = parseResult.ast.toXml();
138+
const { tree: XML } = parse('$.store.book[0].title', { translator: new XMLTranslator() });
294139
```
295140

296-
###### Statistics
141+
##### Statistics
297142

298143
`parse` function returns additional statistical information about the parsing process.
299144
Collection of the statistics can be enabled by setting `stats` option to `true`.
@@ -307,7 +152,7 @@ stats.displayStats(); // returns operator stats
307152
stats.displayHits(); // returns rules grouped by hit count
308153
```
309154

310-
###### Tracing
155+
##### Tracing
311156

312157
`parse` function returns additional tracing information about the parsing process.
313158
Tracing can be enabled by setting `trace` option to `true`. Tracing is essential

src/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export { default as Grammar } from './grammar.js';
22

33
export { default as parse } from './parse/index.js';
4-
export { default as JSONPathQueryCST } from './parse/ast/JSONPathQueryCST.js';
5-
export { default as translateEvaluator } from './parse/evaluators/translate.js';
4+
export { default as CSTTranslator } from './parse/translators/CSTTranslator.js';
5+
export { default as XMLTranslator } from './parse/translators/XMLTranslator.js';

src/parse/callbacks/cst.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@ const cst = (ruleName) => {
88
throw new JSONPathParseError("parser's user data must be an object");
99
}
1010

11-
if (!data.stack) {
12-
data.stack = [];
13-
data.root = null;
14-
}
15-
1611
// drop the empty nodes
1712
if (phraseLength === 0) return;
1813

src/parse/evaluators/translate.js

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/parse/index.js

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,34 @@
11
import { Parser, Stats, Trace } from 'apg-lite';
22

33
import Grammar from '../grammar.js';
4-
import translateEvaluator from './evaluators/translate.js';
5-
import JSONPathQueryCST from './ast/JSONPathQueryCST.js';
4+
import CSTTranslator from './translators/CSTTranslator.js';
65
import JSONPathParseError from '../errors/JSONPathParseError.js';
76

87
const grammar = new Grammar();
98

109
const parse = (
1110
jsonPath,
12-
{
13-
ast = new JSONPathQueryCST(),
14-
stats = false,
15-
trace = false,
16-
evaluator = translateEvaluator,
17-
} = {},
11+
{ translator = new CSTTranslator(), stats = false, trace = false } = {},
1812
) => {
1913
if (typeof jsonPath !== 'string') {
2014
throw new TypeError('JSONPath must be a string');
2115
}
2216

2317
try {
2418
const parser = new Parser();
25-
parser.ast = ast;
19+
20+
if (translator) parser.ast = translator;
2621
if (stats) parser.stats = new Stats();
2722
if (trace) parser.trace = new Trace();
2823

2924
const result = parser.parse(grammar, 'jsonpath-query', jsonPath);
30-
const computed = evaluator(ast, { result });
3125

32-
return { result, ast, stats: parser.stats, trace: parser.trace, computed };
26+
return {
27+
result,
28+
tree: parser.ast?.getTree(),
29+
stats: parser.stats,
30+
trace: parser.trace,
31+
};
3332
} catch (error) {
3433
throw new JSONPathParseError('Unexpected error during JSONPath parsing', {
3534
cause: error,
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Ast as AST } from 'apg-lite';
22

33
import cstCallback from '../callbacks/cst.js';
44

5-
class JSONPathQueryCST extends AST {
5+
class CSTTranslator extends AST {
66
constructor() {
77
super();
88

@@ -94,6 +94,13 @@ class JSONPathQueryCST extends AST {
9494
this.callbacks['left-paren'] = cstCallback('text');
9595
this.callbacks['right-paren'] = cstCallback('text');
9696
}
97+
98+
getTree() {
99+
const data = { stack: [], root: null };
100+
this.translate(data);
101+
delete data.stack;
102+
return data;
103+
}
97104
}
98105

99-
export default JSONPathQueryCST;
106+
export default CSTTranslator;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import CSTTranslator from './CSTTranslator.js';
2+
3+
class XMLTranslator extends CSTTranslator {
4+
getTree() {
5+
return this.toXml();
6+
}
7+
}
8+
9+
export default XMLTranslator;

0 commit comments

Comments
 (0)