@swaggerexpert/jsonpath 3.0.0 → 3.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 +33 -4
- package/SECURITY.md +3 -1
- package/cjs/apg-lite.cjs +28 -28
- package/cjs/compile.cjs +50 -0
- package/cjs/errors/JSONPathCompileError.cjs +8 -0
- package/cjs/escape.cjs +59 -0
- package/cjs/index.cjs +13 -1
- package/cjs/parse/index.cjs +2 -1
- package/cjs/parse/trace/Expectations.cjs +10 -0
- package/cjs/parse/trace/Trace.cjs +35 -0
- package/cjs/parse/translators/ASTTranslator/decoders.cjs +72 -5
- package/cjs/parse/translators/ASTTranslator/index.cjs +1 -2
- package/cjs/parse/translators/ASTTranslator/transformers.cjs +3 -2
- package/es/compile.mjs +45 -0
- package/es/errors/JSONPathCompileError.mjs +3 -0
- package/es/escape.mjs +55 -0
- package/es/index.mjs +7 -1
- package/es/parse/index.mjs +2 -1
- package/es/parse/trace/Expectations.mjs +6 -0
- package/es/parse/trace/Trace.mjs +30 -0
- package/es/parse/translators/ASTTranslator/decoders.mjs +69 -3
- package/es/parse/translators/ASTTranslator/transformers.mjs +3 -2
- package/package.json +22 -14
- package/types/index.d.ts +9 -4
package/README.md
CHANGED
|
@@ -43,6 +43,8 @@ The development of this library contributed to the identification and formal sub
|
|
|
43
43
|
- [Statistics](#statistics)
|
|
44
44
|
- [Tracing](#tracing)
|
|
45
45
|
- [Validation](#validation)
|
|
46
|
+
- [Compilation](#compilation)
|
|
47
|
+
- [Escaping](#escaping)
|
|
46
48
|
- [Errors](#errors)
|
|
47
49
|
- [Grammar](#grammar)
|
|
48
50
|
- [More about JSONPath](#more-about-jsonpath)
|
|
@@ -200,10 +202,11 @@ const { result, trace } = parse('$fdfadfd', { trace: true });
|
|
|
200
202
|
|
|
201
203
|
result.success; // returns false
|
|
202
204
|
trace.displayTrace(); // returns trace information
|
|
205
|
+
trace.inferExpectations(); // returns parser expectations
|
|
203
206
|
```
|
|
204
207
|
|
|
205
|
-
By combining information from `result` and `trace`,
|
|
206
|
-
and generate
|
|
208
|
+
By combining information from `result` and `trace`, you can analyze the parsing process in detail
|
|
209
|
+
and generate messages like: `'Syntax error at position 1, expected "[", ".", ".."'`. Please see this
|
|
207
210
|
[test file](https://github.com/swaggerexpert/jsonpath/blob/main/test/parse/trace.js) for more information how to achieve that.
|
|
208
211
|
|
|
209
212
|
#### Validation
|
|
@@ -226,13 +229,39 @@ test("$['a']", { normalized: true }); // => true
|
|
|
226
229
|
test('$.store.book[0].title', { normalized: true }); // => false
|
|
227
230
|
```
|
|
228
231
|
|
|
232
|
+
#### Compilation
|
|
233
|
+
|
|
234
|
+
Compilation is the process of transforming a list of selectors into a [Normalized Path](https://www.rfc-editor.org/rfc/rfc9535#name-normalized-paths).
|
|
235
|
+
During compilation, name selectors are automatically escaped before being compiled.
|
|
236
|
+
|
|
237
|
+
```js
|
|
238
|
+
import { compile } from '@swaggerexpert/jsonpath';
|
|
239
|
+
|
|
240
|
+
compile(['store', 'book', 0, 'title']); // => "$['store']['book'][0]['title']"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
#### Escaping
|
|
244
|
+
|
|
245
|
+
Certain characters within name selectors in Normalized Paths require escaping.
|
|
246
|
+
The apostrophe (`'`) and backslash (`\`) characters must be escaped.
|
|
247
|
+
Control characters (U+0000 through U+001F) are escaped using specific escape sequences
|
|
248
|
+
(`\b`, `\t`, `\n`, `\f`, `\r`) or Unicode escape sequences (`\uXXXX`).
|
|
249
|
+
|
|
250
|
+
```js
|
|
251
|
+
import { escape } from '@swaggerexpert/jsonpath';
|
|
252
|
+
|
|
253
|
+
escape("it's"); // => "it\\'s"
|
|
254
|
+
escape('back\\slash'); // => "back\\\\slash"
|
|
255
|
+
escape('line\nfeed'); // => "line\\nfeed"
|
|
256
|
+
```
|
|
257
|
+
|
|
229
258
|
#### Errors
|
|
230
259
|
|
|
231
260
|
`@swaggerexpert/jsonpath` provides a structured error class hierarchy,
|
|
232
|
-
enabling precise error handling across JSONPath operations, including parsing.
|
|
261
|
+
enabling precise error handling across JSONPath operations, including parsing and compilation.
|
|
233
262
|
|
|
234
263
|
```js
|
|
235
|
-
import { JSONPathError, JSONPathParseError } from '@swaggerexpert/jsonpath';
|
|
264
|
+
import { JSONPathError, JSONPathParseError, JSONPathCompileError } from '@swaggerexpert/jsonpath';
|
|
236
265
|
```
|
|
237
266
|
|
|
238
267
|
**JSONPathError** is the base class for all JSONPath errors.
|
package/SECURITY.md
CHANGED
|
@@ -6,7 +6,9 @@ If you believe you've found an exploitable security issue in @swaggerexpert/json
|
|
|
6
6
|
|
|
7
7
|
| Version | Supported |
|
|
8
8
|
|---------|--------------------|
|
|
9
|
-
| ^1.0.0 | :
|
|
9
|
+
| ^1.0.0 | :x: |
|
|
10
|
+
| ^2.0.0 | :x: |
|
|
11
|
+
| ^3.0.0 | :white_check_mark: |
|
|
10
12
|
|
|
11
13
|
## Reporting a Vulnerability
|
|
12
14
|
|
package/cjs/apg-lite.cjs
CHANGED
|
@@ -2,31 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
4
|
exports.utilities = exports.identifiers = exports.Trace = exports.Stats = exports.Parser = exports.Ast = void 0;
|
|
5
|
-
/* *************************************************************************************
|
|
6
|
-
* copyright: Copyright (c) 2023 Lowell D. Thomas, all rights reserved
|
|
7
|
-
* license: BSD-2-Clause (https://opensource.org/licenses/BSD-2-Clause)
|
|
8
|
-
*
|
|
9
|
-
* Redistribution and use in source and binary forms, with or without
|
|
10
|
-
* modification, are permitted provided that the following conditions are met:
|
|
11
|
-
*
|
|
12
|
-
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
13
|
-
* list of conditions and the following disclaimer.
|
|
14
|
-
*
|
|
15
|
-
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
16
|
-
* this list of conditions and the following disclaimer in the documentation
|
|
17
|
-
* and/or other materials provided with the distribution.
|
|
18
|
-
*
|
|
19
|
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
-
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
-
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
-
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
-
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
-
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
|
-
*
|
|
5
|
+
/* *************************************************************************************
|
|
6
|
+
* copyright: Copyright (c) 2023 Lowell D. Thomas, all rights reserved
|
|
7
|
+
* license: BSD-2-Clause (https://opensource.org/licenses/BSD-2-Clause)
|
|
8
|
+
*
|
|
9
|
+
* Redistribution and use in source and binary forms, with or without
|
|
10
|
+
* modification, are permitted provided that the following conditions are met:
|
|
11
|
+
*
|
|
12
|
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
13
|
+
* list of conditions and the following disclaimer.
|
|
14
|
+
*
|
|
15
|
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
16
|
+
* this list of conditions and the following disclaimer in the documentation
|
|
17
|
+
* and/or other materials provided with the distribution.
|
|
18
|
+
*
|
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
|
+
*
|
|
30
30
|
* ********************************************************************************* */
|
|
31
31
|
|
|
32
32
|
const Parser = exports.Parser = function fnparser() {
|
|
@@ -665,7 +665,7 @@ const Ast = exports.Ast = function fnast() {
|
|
|
665
665
|
a.ruleDefined = index => !!nodeCallbacks[index];
|
|
666
666
|
/* AST node UDT callbacks - called by the parser's `UDT` operator */
|
|
667
667
|
a.udtDefined = index => !!nodeCallbacks[rules.length + index];
|
|
668
|
-
/* called by the parser's `RNM` & `UDT` operators
|
|
668
|
+
/* called by the parser's `RNM` & `UDT` operators
|
|
669
669
|
builds a record for the downward traversal of the node */
|
|
670
670
|
a.down = (callbackIndex, name) => {
|
|
671
671
|
const thisIndex = records.length;
|
|
@@ -963,8 +963,8 @@ const Stats = exports.Stats = function fnstats() {
|
|
|
963
963
|
out += displayRow('TOTAL', totals.match, totals.empty, totals.nomatch, totals.total);
|
|
964
964
|
return out;
|
|
965
965
|
};
|
|
966
|
-
/*
|
|
967
|
-
Display rule/udt
|
|
966
|
+
/*
|
|
967
|
+
Display rule/udt
|
|
968
968
|
*/
|
|
969
969
|
this.displayHits = type => {
|
|
970
970
|
let out = '';
|
package/cjs/compile.cjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
var _escape = _interopRequireDefault(require("./escape.cjs"));
|
|
6
|
+
var _JSONPathCompileError = _interopRequireDefault(require("./errors/JSONPathCompileError.cjs"));
|
|
7
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
+
/**
|
|
9
|
+
* Compiles an array of selectors into a normalized JSONPath.
|
|
10
|
+
* Follows RFC 9535 Section 2.7 normalized path format.
|
|
11
|
+
*
|
|
12
|
+
* @param {Array<string|number>} selectors - Array of name selectors (strings) or index selectors (numbers)
|
|
13
|
+
* @returns {string} A normalized JSONPath string
|
|
14
|
+
* @throws {JSONPathCompileError} If selectors is not an array or contains invalid selector types
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* compile(['a', 'b', 1]) // returns "$['a']['b'][1]"
|
|
18
|
+
* compile([]) // returns "$"
|
|
19
|
+
* compile(['foo', 0, 'bar']) // returns "$['foo'][0]['bar']"
|
|
20
|
+
*/
|
|
21
|
+
const compile = selectors => {
|
|
22
|
+
if (!Array.isArray(selectors)) {
|
|
23
|
+
throw new _JSONPathCompileError.default(`Selectors must be an array, got: ${typeof selectors}`, {
|
|
24
|
+
selectors
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const segments = selectors.map(selector => {
|
|
29
|
+
if (typeof selector === 'string') {
|
|
30
|
+
// Name selector: escape and wrap in single quotes
|
|
31
|
+
return `['${(0, _escape.default)(selector)}']`;
|
|
32
|
+
}
|
|
33
|
+
if (typeof selector === 'number') {
|
|
34
|
+
// Index selector: must be a non-negative safe integer (RFC 9535 Section 2.1)
|
|
35
|
+
if (!Number.isSafeInteger(selector) || selector < 0) {
|
|
36
|
+
throw new TypeError(`Index selector must be a non-negative safe integer, got: ${selector}`);
|
|
37
|
+
}
|
|
38
|
+
return `[${selector}]`;
|
|
39
|
+
}
|
|
40
|
+
throw new TypeError(`Selector must be a string or non-negative integer, got: ${typeof selector}`);
|
|
41
|
+
});
|
|
42
|
+
return `$${segments.join('')}`;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
throw new _JSONPathCompileError.default('Failed to compile normalized JSONPath', {
|
|
45
|
+
cause: error,
|
|
46
|
+
selectors
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var _default = exports.default = compile;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
var _JSONPathError = _interopRequireDefault(require("./JSONPathError.cjs"));
|
|
6
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
class JSONPathCompileError extends _JSONPathError.default {}
|
|
8
|
+
var _default = exports.default = JSONPathCompileError;
|
package/cjs/escape.cjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
/**
|
|
6
|
+
* Escapes a string for use in a normalized JSONPath name selector.
|
|
7
|
+
* Follows RFC 9535 Section 2.7 escaping rules for single-quoted strings.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} selector - The string to escape
|
|
10
|
+
* @returns {string} The escaped string (without surrounding quotes)
|
|
11
|
+
*/
|
|
12
|
+
const escape = selector => {
|
|
13
|
+
if (typeof selector !== 'string') {
|
|
14
|
+
throw new TypeError('Selector must be a string');
|
|
15
|
+
}
|
|
16
|
+
let escaped = '';
|
|
17
|
+
for (const char of selector) {
|
|
18
|
+
const codePoint = char.codePointAt(0);
|
|
19
|
+
switch (codePoint) {
|
|
20
|
+
case 0x08:
|
|
21
|
+
// backspace
|
|
22
|
+
escaped += '\\b';
|
|
23
|
+
break;
|
|
24
|
+
case 0x09:
|
|
25
|
+
// horizontal tab
|
|
26
|
+
escaped += '\\t';
|
|
27
|
+
break;
|
|
28
|
+
case 0x0a:
|
|
29
|
+
// line feed
|
|
30
|
+
escaped += '\\n';
|
|
31
|
+
break;
|
|
32
|
+
case 0x0c:
|
|
33
|
+
// form feed
|
|
34
|
+
escaped += '\\f';
|
|
35
|
+
break;
|
|
36
|
+
case 0x0d:
|
|
37
|
+
// carriage return
|
|
38
|
+
escaped += '\\r';
|
|
39
|
+
break;
|
|
40
|
+
case 0x27:
|
|
41
|
+
// apostrophe '
|
|
42
|
+
escaped += "\\'";
|
|
43
|
+
break;
|
|
44
|
+
case 0x5c:
|
|
45
|
+
// backslash \
|
|
46
|
+
escaped += '\\\\';
|
|
47
|
+
break;
|
|
48
|
+
default:
|
|
49
|
+
// Other control characters (U+0000-U+001F except those handled above)
|
|
50
|
+
if (codePoint <= 0x1f) {
|
|
51
|
+
escaped += `\\u${codePoint.toString(16).padStart(4, '0')}`;
|
|
52
|
+
} else {
|
|
53
|
+
escaped += char;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return escaped;
|
|
58
|
+
};
|
|
59
|
+
var _default = exports.default = escape;
|
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 = exports.ASTTranslator = void 0;
|
|
4
|
+
exports.test = exports.parse = exports.escape = exports.compile = exports.XMLTranslator = exports.Trace = exports.JSONPathParseError = exports.JSONPathError = exports.JSONPathCompileError = 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"));
|
|
@@ -14,6 +14,18 @@ var _index2 = _interopRequireDefault(require("./parse/translators/ASTTranslator/
|
|
|
14
14
|
exports.ASTTranslator = _index2.default;
|
|
15
15
|
var _XMLTranslator = _interopRequireDefault(require("./parse/translators/XMLTranslator.cjs"));
|
|
16
16
|
exports.XMLTranslator = _XMLTranslator.default;
|
|
17
|
+
var _Trace = _interopRequireDefault(require("./parse/trace/Trace.cjs"));
|
|
18
|
+
exports.Trace = _Trace.default;
|
|
17
19
|
var _index3 = _interopRequireDefault(require("./test/index.cjs"));
|
|
18
20
|
exports.test = _index3.default;
|
|
21
|
+
var _compile = _interopRequireDefault(require("./compile.cjs"));
|
|
22
|
+
exports.compile = _compile.default;
|
|
23
|
+
var _escape = _interopRequireDefault(require("./escape.cjs"));
|
|
24
|
+
exports.escape = _escape.default;
|
|
25
|
+
var _JSONPathError = _interopRequireDefault(require("./errors/JSONPathError.cjs"));
|
|
26
|
+
exports.JSONPathError = _JSONPathError.default;
|
|
27
|
+
var _JSONPathParseError = _interopRequireDefault(require("./errors/JSONPathParseError.cjs"));
|
|
28
|
+
exports.JSONPathParseError = _JSONPathParseError.default;
|
|
29
|
+
var _JSONPathCompileError = _interopRequireDefault(require("./errors/JSONPathCompileError.cjs"));
|
|
30
|
+
exports.JSONPathCompileError = _JSONPathCompileError.default;
|
|
19
31
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
package/cjs/parse/index.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
4
|
exports.default = void 0;
|
|
5
5
|
var _apgLite = require("../apg-lite.cjs");
|
|
6
|
+
var _Trace = _interopRequireDefault(require("./trace/Trace.cjs"));
|
|
6
7
|
var _grammar = _interopRequireDefault(require("../grammar.cjs"));
|
|
7
8
|
var _index = _interopRequireDefault(require("./translators/ASTTranslator/index.cjs"));
|
|
8
9
|
var _JSONPathParseError = _interopRequireDefault(require("../errors/JSONPathParseError.cjs"));
|
|
@@ -21,7 +22,7 @@ const parse = (jsonPath, {
|
|
|
21
22
|
const parser = new _apgLite.Parser();
|
|
22
23
|
if (translator) parser.ast = translator;
|
|
23
24
|
if (stats) parser.stats = new _apgLite.Stats();
|
|
24
|
-
if (trace) parser.trace = new
|
|
25
|
+
if (trace) parser.trace = new _Trace.default();
|
|
25
26
|
const startRule = normalized ? 'normalized-path' : 'jsonpath-query';
|
|
26
27
|
const result = parser.parse(grammar, startRule, jsonPath);
|
|
27
28
|
return {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
var _apgLite = require("../../apg-lite.cjs");
|
|
6
|
+
var _Expectations = _interopRequireDefault(require("./Expectations.cjs"));
|
|
7
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
+
class Trace extends _apgLite.Trace {
|
|
9
|
+
inferExpectations() {
|
|
10
|
+
const lines = this.displayTrace().split('\n');
|
|
11
|
+
const expectations = new Set();
|
|
12
|
+
let lastMatchedIndex = -1;
|
|
13
|
+
for (let i = 0; i < lines.length; i++) {
|
|
14
|
+
const line = lines[i];
|
|
15
|
+
|
|
16
|
+
// capture the max match line (first one that ends in a single character match)
|
|
17
|
+
if (line.includes('M|')) {
|
|
18
|
+
const textMatch = line.match(/]'(.*)'$/);
|
|
19
|
+
if (textMatch && textMatch[1]) {
|
|
20
|
+
lastMatchedIndex = i;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// collect terminal failures after the deepest successful match
|
|
25
|
+
if (i > lastMatchedIndex) {
|
|
26
|
+
const terminalFailMatch = line.match(/N\|\[TLS\(([^)]+)\)]/);
|
|
27
|
+
if (terminalFailMatch) {
|
|
28
|
+
expectations.add(terminalFailMatch[1]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return new _Expectations.default(...expectations);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
var _default = exports.default = Trace;
|
|
@@ -1,13 +1,80 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
|
-
exports.
|
|
5
|
-
const
|
|
6
|
-
return
|
|
4
|
+
exports.decodeSingleQuotedString = exports.decodeJSONValue = exports.decodeInteger = exports.decodeDoubleQuotedString = void 0;
|
|
5
|
+
const decodeDoubleQuotedString = str => {
|
|
6
|
+
return decodeJSONValue(`"${str}"`);
|
|
7
7
|
};
|
|
8
|
-
exports.
|
|
8
|
+
exports.decodeDoubleQuotedString = decodeDoubleQuotedString;
|
|
9
|
+
const decodeSingleQuotedString = str => {
|
|
10
|
+
// Decode single-quoted string escape sequences into raw text, then let JSON.stringify
|
|
11
|
+
// produce a correctly escaped double-quoted JSON string.
|
|
12
|
+
let decoded = '';
|
|
13
|
+
for (let i = 0; i < str.length; i++) {
|
|
14
|
+
const ch = str[i];
|
|
15
|
+
if (ch === '\\') {
|
|
16
|
+
i++;
|
|
17
|
+
if (i >= str.length) {
|
|
18
|
+
// Trailing backslash, treat it as a literal backslash
|
|
19
|
+
decoded += '\\';
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
const esc = str[i];
|
|
23
|
+
switch (esc) {
|
|
24
|
+
case 'n':
|
|
25
|
+
decoded += '\n';
|
|
26
|
+
break;
|
|
27
|
+
case 'r':
|
|
28
|
+
decoded += '\r';
|
|
29
|
+
break;
|
|
30
|
+
case 't':
|
|
31
|
+
decoded += '\t';
|
|
32
|
+
break;
|
|
33
|
+
case 'b':
|
|
34
|
+
decoded += '\b';
|
|
35
|
+
break;
|
|
36
|
+
case 'f':
|
|
37
|
+
decoded += '\f';
|
|
38
|
+
break;
|
|
39
|
+
case '/':
|
|
40
|
+
decoded += '/';
|
|
41
|
+
break;
|
|
42
|
+
case '\\':
|
|
43
|
+
decoded += '\\';
|
|
44
|
+
break;
|
|
45
|
+
case "'":
|
|
46
|
+
decoded += "'";
|
|
47
|
+
break;
|
|
48
|
+
case '"':
|
|
49
|
+
decoded += '"';
|
|
50
|
+
break;
|
|
51
|
+
case 'u':
|
|
52
|
+
{
|
|
53
|
+
// Unicode escape \uXXXX - grammar guarantees exactly 4 hex digits
|
|
54
|
+
const hex = str.slice(i + 1, i + 5);
|
|
55
|
+
decoded += String.fromCharCode(parseInt(hex, 16));
|
|
56
|
+
i += 4;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
default:
|
|
60
|
+
// Unrecognized escape, keep the escaped character literally
|
|
61
|
+
decoded += esc;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
decoded += ch;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Use JSON.stringify to produce a valid JSON string literal
|
|
69
|
+
return decodeJSONValue(JSON.stringify(decoded));
|
|
70
|
+
};
|
|
71
|
+
exports.decodeSingleQuotedString = decodeSingleQuotedString;
|
|
9
72
|
const decodeInteger = str => {
|
|
10
|
-
|
|
73
|
+
const value = parseInt(str, 10);
|
|
74
|
+
if (!Number.isSafeInteger(value)) {
|
|
75
|
+
throw new RangeError(`Integer value out of safe range [-(2^53)+1, (2^53)-1], got: ${str}`);
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
11
78
|
};
|
|
12
79
|
exports.decodeInteger = decodeInteger;
|
|
13
80
|
const decodeJSONValue = str => {
|
|
@@ -4,8 +4,7 @@ exports.__esModule = true;
|
|
|
4
4
|
exports.default = void 0;
|
|
5
5
|
var _CSTOptimizedTranslator = _interopRequireDefault(require("../CSTOptimizedTranslator.cjs"));
|
|
6
6
|
var _transformers = _interopRequireWildcard(require("./transformers.cjs"));
|
|
7
|
-
function
|
|
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; }
|
|
7
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
9
8
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
9
|
class ASTTranslator extends _CSTOptimizedTranslator.default {
|
|
11
10
|
getTree() {
|
|
@@ -73,9 +73,10 @@ const transformers = {
|
|
|
73
73
|
const quoted = node.children.find(({
|
|
74
74
|
type
|
|
75
75
|
}) => ['double-quoted', 'single-quoted'].includes(type));
|
|
76
|
+
const decodeString = isSingleQuoted ? _decoders.decodeSingleQuotedString : _decoders.decodeDoubleQuotedString;
|
|
76
77
|
return {
|
|
77
78
|
type: 'StringLiteral',
|
|
78
|
-
value: quoted ?
|
|
79
|
+
value: quoted ? decodeString(quoted.text) : '',
|
|
79
80
|
format: isSingleQuoted ? 'single-quoted' : 'double-quoted'
|
|
80
81
|
};
|
|
81
82
|
},
|
|
@@ -396,7 +397,7 @@ const transformers = {
|
|
|
396
397
|
}) => type === 'normal-single-quoted');
|
|
397
398
|
return {
|
|
398
399
|
type: 'NameSelector',
|
|
399
|
-
value: child ? (0, _decoders.
|
|
400
|
+
value: child ? (0, _decoders.decodeSingleQuotedString)(child.text) : '',
|
|
400
401
|
format: 'single-quoted'
|
|
401
402
|
};
|
|
402
403
|
},
|
package/es/compile.mjs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import escape from "./escape.mjs";
|
|
2
|
+
import JSONPathCompileError from "./errors/JSONPathCompileError.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Compiles an array of selectors into a normalized JSONPath.
|
|
5
|
+
* Follows RFC 9535 Section 2.7 normalized path format.
|
|
6
|
+
*
|
|
7
|
+
* @param {Array<string|number>} selectors - Array of name selectors (strings) or index selectors (numbers)
|
|
8
|
+
* @returns {string} A normalized JSONPath string
|
|
9
|
+
* @throws {JSONPathCompileError} If selectors is not an array or contains invalid selector types
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* compile(['a', 'b', 1]) // returns "$['a']['b'][1]"
|
|
13
|
+
* compile([]) // returns "$"
|
|
14
|
+
* compile(['foo', 0, 'bar']) // returns "$['foo'][0]['bar']"
|
|
15
|
+
*/
|
|
16
|
+
const compile = selectors => {
|
|
17
|
+
if (!Array.isArray(selectors)) {
|
|
18
|
+
throw new JSONPathCompileError(`Selectors must be an array, got: ${typeof selectors}`, {
|
|
19
|
+
selectors
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const segments = selectors.map(selector => {
|
|
24
|
+
if (typeof selector === 'string') {
|
|
25
|
+
// Name selector: escape and wrap in single quotes
|
|
26
|
+
return `['${escape(selector)}']`;
|
|
27
|
+
}
|
|
28
|
+
if (typeof selector === 'number') {
|
|
29
|
+
// Index selector: must be a non-negative safe integer (RFC 9535 Section 2.1)
|
|
30
|
+
if (!Number.isSafeInteger(selector) || selector < 0) {
|
|
31
|
+
throw new TypeError(`Index selector must be a non-negative safe integer, got: ${selector}`);
|
|
32
|
+
}
|
|
33
|
+
return `[${selector}]`;
|
|
34
|
+
}
|
|
35
|
+
throw new TypeError(`Selector must be a string or non-negative integer, got: ${typeof selector}`);
|
|
36
|
+
});
|
|
37
|
+
return `$${segments.join('')}`;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
throw new JSONPathCompileError('Failed to compile normalized JSONPath', {
|
|
40
|
+
cause: error,
|
|
41
|
+
selectors
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export default compile;
|
package/es/escape.mjs
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escapes a string for use in a normalized JSONPath name selector.
|
|
3
|
+
* Follows RFC 9535 Section 2.7 escaping rules for single-quoted strings.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} selector - The string to escape
|
|
6
|
+
* @returns {string} The escaped string (without surrounding quotes)
|
|
7
|
+
*/
|
|
8
|
+
const escape = selector => {
|
|
9
|
+
if (typeof selector !== 'string') {
|
|
10
|
+
throw new TypeError('Selector must be a string');
|
|
11
|
+
}
|
|
12
|
+
let escaped = '';
|
|
13
|
+
for (const char of selector) {
|
|
14
|
+
const codePoint = char.codePointAt(0);
|
|
15
|
+
switch (codePoint) {
|
|
16
|
+
case 0x08:
|
|
17
|
+
// backspace
|
|
18
|
+
escaped += '\\b';
|
|
19
|
+
break;
|
|
20
|
+
case 0x09:
|
|
21
|
+
// horizontal tab
|
|
22
|
+
escaped += '\\t';
|
|
23
|
+
break;
|
|
24
|
+
case 0x0a:
|
|
25
|
+
// line feed
|
|
26
|
+
escaped += '\\n';
|
|
27
|
+
break;
|
|
28
|
+
case 0x0c:
|
|
29
|
+
// form feed
|
|
30
|
+
escaped += '\\f';
|
|
31
|
+
break;
|
|
32
|
+
case 0x0d:
|
|
33
|
+
// carriage return
|
|
34
|
+
escaped += '\\r';
|
|
35
|
+
break;
|
|
36
|
+
case 0x27:
|
|
37
|
+
// apostrophe '
|
|
38
|
+
escaped += "\\'";
|
|
39
|
+
break;
|
|
40
|
+
case 0x5c:
|
|
41
|
+
// backslash \
|
|
42
|
+
escaped += '\\\\';
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
// Other control characters (U+0000-U+001F except those handled above)
|
|
46
|
+
if (codePoint <= 0x1f) {
|
|
47
|
+
escaped += `\\u${codePoint.toString(16).padStart(4, '0')}`;
|
|
48
|
+
} else {
|
|
49
|
+
escaped += char;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return escaped;
|
|
54
|
+
};
|
|
55
|
+
export default escape;
|
package/es/index.mjs
CHANGED
|
@@ -4,4 +4,10 @@ export { default as CSTTranslator } from "./parse/translators/CSTTranslator.mjs"
|
|
|
4
4
|
export { default as CSTOptimizedTranslator } from "./parse/translators/CSTOptimizedTranslator.mjs";
|
|
5
5
|
export { default as ASTTranslator } from "./parse/translators/ASTTranslator/index.mjs";
|
|
6
6
|
export { default as XMLTranslator } from "./parse/translators/XMLTranslator.mjs";
|
|
7
|
-
export { default as
|
|
7
|
+
export { default as Trace } from "./parse/trace/Trace.mjs";
|
|
8
|
+
export { default as test } from "./test/index.mjs";
|
|
9
|
+
export { default as compile } from "./compile.mjs";
|
|
10
|
+
export { default as escape } from "./escape.mjs";
|
|
11
|
+
export { default as JSONPathError } from "./errors/JSONPathError.mjs";
|
|
12
|
+
export { default as JSONPathParseError } from "./errors/JSONPathParseError.mjs";
|
|
13
|
+
export { default as JSONPathCompileError } from "./errors/JSONPathCompileError.mjs";
|
package/es/parse/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Parser, Stats
|
|
1
|
+
import { Parser, Stats } from 'apg-lite';
|
|
2
|
+
import Trace from "./trace/Trace.mjs";
|
|
2
3
|
import Grammar from "../grammar.mjs";
|
|
3
4
|
import ASTTranslator from "./translators/ASTTranslator/index.mjs";
|
|
4
5
|
import JSONPathParseError from "../errors/JSONPathParseError.mjs";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Trace as BaseTrace } from 'apg-lite';
|
|
2
|
+
import Expectations from "./Expectations.mjs";
|
|
3
|
+
class Trace extends BaseTrace {
|
|
4
|
+
inferExpectations() {
|
|
5
|
+
const lines = this.displayTrace().split('\n');
|
|
6
|
+
const expectations = new Set();
|
|
7
|
+
let lastMatchedIndex = -1;
|
|
8
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9
|
+
const line = lines[i];
|
|
10
|
+
|
|
11
|
+
// capture the max match line (first one that ends in a single character match)
|
|
12
|
+
if (line.includes('M|')) {
|
|
13
|
+
const textMatch = line.match(/]'(.*)'$/);
|
|
14
|
+
if (textMatch && textMatch[1]) {
|
|
15
|
+
lastMatchedIndex = i;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// collect terminal failures after the deepest successful match
|
|
20
|
+
if (i > lastMatchedIndex) {
|
|
21
|
+
const terminalFailMatch = line.match(/N\|\[TLS\(([^)]+)\)]/);
|
|
22
|
+
if (terminalFailMatch) {
|
|
23
|
+
expectations.add(terminalFailMatch[1]);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return new Expectations(...expectations);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export default Trace;
|
|
@@ -1,8 +1,74 @@
|
|
|
1
|
-
export const
|
|
2
|
-
return
|
|
1
|
+
export const decodeDoubleQuotedString = str => {
|
|
2
|
+
return decodeJSONValue(`"${str}"`);
|
|
3
|
+
};
|
|
4
|
+
export const decodeSingleQuotedString = str => {
|
|
5
|
+
// Decode single-quoted string escape sequences into raw text, then let JSON.stringify
|
|
6
|
+
// produce a correctly escaped double-quoted JSON string.
|
|
7
|
+
let decoded = '';
|
|
8
|
+
for (let i = 0; i < str.length; i++) {
|
|
9
|
+
const ch = str[i];
|
|
10
|
+
if (ch === '\\') {
|
|
11
|
+
i++;
|
|
12
|
+
if (i >= str.length) {
|
|
13
|
+
// Trailing backslash, treat it as a literal backslash
|
|
14
|
+
decoded += '\\';
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
const esc = str[i];
|
|
18
|
+
switch (esc) {
|
|
19
|
+
case 'n':
|
|
20
|
+
decoded += '\n';
|
|
21
|
+
break;
|
|
22
|
+
case 'r':
|
|
23
|
+
decoded += '\r';
|
|
24
|
+
break;
|
|
25
|
+
case 't':
|
|
26
|
+
decoded += '\t';
|
|
27
|
+
break;
|
|
28
|
+
case 'b':
|
|
29
|
+
decoded += '\b';
|
|
30
|
+
break;
|
|
31
|
+
case 'f':
|
|
32
|
+
decoded += '\f';
|
|
33
|
+
break;
|
|
34
|
+
case '/':
|
|
35
|
+
decoded += '/';
|
|
36
|
+
break;
|
|
37
|
+
case '\\':
|
|
38
|
+
decoded += '\\';
|
|
39
|
+
break;
|
|
40
|
+
case "'":
|
|
41
|
+
decoded += "'";
|
|
42
|
+
break;
|
|
43
|
+
case '"':
|
|
44
|
+
decoded += '"';
|
|
45
|
+
break;
|
|
46
|
+
case 'u':
|
|
47
|
+
{
|
|
48
|
+
// Unicode escape \uXXXX - grammar guarantees exactly 4 hex digits
|
|
49
|
+
const hex = str.slice(i + 1, i + 5);
|
|
50
|
+
decoded += String.fromCharCode(parseInt(hex, 16));
|
|
51
|
+
i += 4;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
default:
|
|
55
|
+
// Unrecognized escape, keep the escaped character literally
|
|
56
|
+
decoded += esc;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
decoded += ch;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Use JSON.stringify to produce a valid JSON string literal
|
|
64
|
+
return decodeJSONValue(JSON.stringify(decoded));
|
|
3
65
|
};
|
|
4
66
|
export const decodeInteger = str => {
|
|
5
|
-
|
|
67
|
+
const value = parseInt(str, 10);
|
|
68
|
+
if (!Number.isSafeInteger(value)) {
|
|
69
|
+
throw new RangeError(`Integer value out of safe range [-(2^53)+1, (2^53)-1], got: ${str}`);
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
6
72
|
};
|
|
7
73
|
export const decodeJSONValue = str => {
|
|
8
74
|
return JSON.parse(str);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import JSONPathParseError from "../../../errors/JSONPathParseError.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { decodeSingleQuotedString, decodeDoubleQuotedString, decodeInteger, decodeJSONValue } from "./decoders.mjs";
|
|
3
3
|
export const transformCSTtoAST = (node, transformerMap, ctx = {
|
|
4
4
|
parent: null,
|
|
5
5
|
path: []
|
|
@@ -67,6 +67,7 @@ const transformers = {
|
|
|
67
67
|
const quoted = node.children.find(({
|
|
68
68
|
type
|
|
69
69
|
}) => ['double-quoted', 'single-quoted'].includes(type));
|
|
70
|
+
const decodeString = isSingleQuoted ? decodeSingleQuotedString : decodeDoubleQuotedString;
|
|
70
71
|
return {
|
|
71
72
|
type: 'StringLiteral',
|
|
72
73
|
value: quoted ? decodeString(quoted.text) : '',
|
|
@@ -390,7 +391,7 @@ const transformers = {
|
|
|
390
391
|
}) => type === 'normal-single-quoted');
|
|
391
392
|
return {
|
|
392
393
|
type: 'NameSelector',
|
|
393
|
-
value: child ?
|
|
394
|
+
value: child ? decodeSingleQuotedString(child.text) : '',
|
|
394
395
|
format: 'single-quoted'
|
|
395
396
|
};
|
|
396
397
|
},
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swaggerexpert/jsonpath",
|
|
3
3
|
"publishConfig": {
|
|
4
|
-
"access": "public"
|
|
4
|
+
"access": "public",
|
|
5
|
+
"registry": "https://registry.npmjs.org",
|
|
6
|
+
"provenance": true
|
|
5
7
|
},
|
|
6
|
-
"version": "3.
|
|
7
|
-
"description": "
|
|
8
|
+
"version": "3.1.0",
|
|
9
|
+
"description": "RFC 9535 implementation of JSONPath",
|
|
8
10
|
"main": "./cjs/index.cjs",
|
|
9
11
|
"types": "./types/index.d.ts",
|
|
10
12
|
"exports": {
|
|
@@ -60,22 +62,28 @@
|
|
|
60
62
|
"SECURITY.md"
|
|
61
63
|
],
|
|
62
64
|
"dependencies": {
|
|
63
|
-
"apg-lite": "^1.0.
|
|
65
|
+
"apg-lite": "^1.0.5"
|
|
64
66
|
},
|
|
65
67
|
"devDependencies": {
|
|
66
|
-
"@babel/cli": "=7.
|
|
67
|
-
"@babel/core": "=7.
|
|
68
|
-
"@babel/preset-env": "=7.
|
|
69
|
-
"@commitlint/cli": "=
|
|
70
|
-
"@commitlint/config-conventional": "=
|
|
68
|
+
"@babel/cli": "=7.28.6",
|
|
69
|
+
"@babel/core": "=7.28.6",
|
|
70
|
+
"@babel/preset-env": "=7.28.6",
|
|
71
|
+
"@commitlint/cli": "=20.3.1",
|
|
72
|
+
"@commitlint/config-conventional": "=20.3.1",
|
|
73
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
74
|
+
"@semantic-release/git": "^10.0.1",
|
|
75
|
+
"@semantic-release/github": "^12.0.2",
|
|
76
|
+
"@semantic-release/npm": "^13.1.3",
|
|
77
|
+
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
71
78
|
"apg-js": "^4.4.0",
|
|
72
79
|
"babel-plugin-module-resolver": "^5.0.2",
|
|
73
|
-
"chai": "=
|
|
74
|
-
"cross-env": "^
|
|
80
|
+
"chai": "=6.2.2",
|
|
81
|
+
"cross-env": "^10.0.0",
|
|
75
82
|
"husky": "=9.1.7",
|
|
76
|
-
"mocha": "=11.
|
|
77
|
-
"mocha-expect-snapshot": "^
|
|
83
|
+
"mocha": "=11.7.5",
|
|
84
|
+
"mocha-expect-snapshot": "^8.0.0",
|
|
78
85
|
"npm-watch": "^0.13.0",
|
|
79
|
-
"prettier": "^3.5.2"
|
|
86
|
+
"prettier": "^3.5.2",
|
|
87
|
+
"semantic-release": "^25.0.2"
|
|
80
88
|
}
|
|
81
89
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -20,6 +20,9 @@ export declare class CSTOptimizedTranslator implements CSTTranslator {
|
|
|
20
20
|
constructor(options?: { collapsibleTypes?: string[] });
|
|
21
21
|
getTree(): CSTTree;
|
|
22
22
|
}
|
|
23
|
+
export declare class ASTTranslator implements Translator<ASTTree> {
|
|
24
|
+
getTree(): ASTTree;
|
|
25
|
+
}
|
|
23
26
|
export declare class XMLTranslator implements Translator<XMLTree> {
|
|
24
27
|
getTree(): XMLTree;
|
|
25
28
|
}
|
|
@@ -35,7 +38,7 @@ export interface ParseResult<TTree = ASTTree> {
|
|
|
35
38
|
readonly maxTreeDepth: number
|
|
36
39
|
readonly nodeHits: number;
|
|
37
40
|
};
|
|
38
|
-
readonly tree
|
|
41
|
+
readonly tree?: TTree;
|
|
39
42
|
readonly stats?: Stats;
|
|
40
43
|
readonly trace?: Trace;
|
|
41
44
|
}
|
|
@@ -92,6 +95,8 @@ export interface NameSelectorASTNode extends ASTNode {
|
|
|
92
95
|
value: string;
|
|
93
96
|
format: 'single-quoted' | 'double-quoted' | 'shorthand';
|
|
94
97
|
}
|
|
98
|
+
type NameSelectorShorthandASTNode = NameSelectorASTNode & { format: 'shorthand' };
|
|
99
|
+
type NameSelectorQuotedASTNode = NameSelectorASTNode & { format: 'single-quoted' | 'double-quoted' };
|
|
95
100
|
// https://www.rfc-editor.org/rfc/rfc9535#section-2.3.2.1
|
|
96
101
|
export interface WildcardSelectorASTNode extends ASTNode {
|
|
97
102
|
type: 'WildcardSelector';
|
|
@@ -166,7 +171,7 @@ export interface FunctionExprASTNode extends ASTNode {
|
|
|
166
171
|
// https://www.rfc-editor.org/rfc/rfc9535#section-2.5.1.1
|
|
167
172
|
export interface ChildSegmentASTNode extends ASTNode {
|
|
168
173
|
type: 'ChildSegment';
|
|
169
|
-
selector: BracketedSelectionASTNode | WildcardSelectorASTNode |
|
|
174
|
+
selector: BracketedSelectionASTNode | WildcardSelectorASTNode | NameSelectorShorthandASTNode;
|
|
170
175
|
}
|
|
171
176
|
export interface BracketedSelectionASTNode extends ASTNode {
|
|
172
177
|
type: 'BracketedSelection';
|
|
@@ -174,11 +179,11 @@ export interface BracketedSelectionASTNode extends ASTNode {
|
|
|
174
179
|
}
|
|
175
180
|
export interface DescendantSegmentASTNode extends ASTNode {
|
|
176
181
|
type: 'DescendantSegment';
|
|
177
|
-
selector: BracketedSelectionASTNode | WildcardSelectorASTNode |
|
|
182
|
+
selector: BracketedSelectionASTNode | WildcardSelectorASTNode | NameSelectorShorthandASTNode;
|
|
178
183
|
}
|
|
179
184
|
// union types
|
|
180
185
|
export type SelectorASTNode =
|
|
181
|
-
|
|
|
186
|
+
| NameSelectorQuotedASTNode
|
|
182
187
|
| WildcardSelectorASTNode
|
|
183
188
|
| SliceSelectorASTNode
|
|
184
189
|
| IndexSelectorASTNode
|