json-p3 0.1.0 → 0.2.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 +26 -211
- package/dist/index.d.ts +2 -2
- package/dist/json-p3.cjs.js +279 -45
- package/dist/json-p3.esm.js +277 -46
- package/dist/json-p3.iife.js +279 -45
- package/dist/json-p3.iife.min.js +1 -1
- package/dist/json-p3.iife.min.js.map +1 -1
- package/dist/patch/patch.d.ts +4 -0
- package/dist/path/environment.d.ts +56 -10
- package/dist/path/errors.d.ts +8 -0
- package/dist/path/expression.d.ts +1 -0
- package/dist/path/index.d.ts +12 -2
- package/dist/path/path.d.ts +10 -1
- package/dist/path/selectors.d.ts +0 -1
- package/dist/pointer/errors.d.ts +15 -0
- package/dist/pointer/index.d.ts +1 -1
- package/dist/pointer/pointer.d.ts +31 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +2 -2
package/dist/json-p3.iife.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* json-p3 version 0.
|
|
2
|
+
* json-p3 version 0.2.0
|
|
3
3
|
* https://github.com/jg-rp/json-p3
|
|
4
4
|
*
|
|
5
5
|
* MIT License
|
|
@@ -125,6 +125,20 @@ var json_p3 = (function (exports) {
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Error thrown when the maximum recursion depth is reached.
|
|
130
|
+
*/
|
|
131
|
+
class JSONPathRecursionLimitError extends JSONPathError {
|
|
132
|
+
constructor(message, token) {
|
|
133
|
+
super(message, token);
|
|
134
|
+
this.message = message;
|
|
135
|
+
this.token = token;
|
|
136
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
137
|
+
this.name = "JSONPathRecursionLimitError";
|
|
138
|
+
this.message = withErrorContext(message, token);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
128
142
|
/**
|
|
129
143
|
* Common types and type predicates.
|
|
130
144
|
*/
|
|
@@ -233,6 +247,10 @@ var json_p3 = (function (exports) {
|
|
|
233
247
|
this.name = "JSONPointerError";
|
|
234
248
|
}
|
|
235
249
|
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Base class for JSON Pointer resolution errors.
|
|
253
|
+
*/
|
|
236
254
|
class JSONPointerResolutionError extends JSONPointerError {
|
|
237
255
|
constructor(message) {
|
|
238
256
|
super(message);
|
|
@@ -241,6 +259,10 @@ var json_p3 = (function (exports) {
|
|
|
241
259
|
this.name = "JSONPointerResolutionError";
|
|
242
260
|
}
|
|
243
261
|
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Error thrown due to an out of range index when resolving a JSON Pointer.
|
|
265
|
+
*/
|
|
244
266
|
class JSONPointerIndexError extends JSONPointerResolutionError {
|
|
245
267
|
constructor(message) {
|
|
246
268
|
super(message);
|
|
@@ -249,6 +271,10 @@ var json_p3 = (function (exports) {
|
|
|
249
271
|
this.name = "JSONPointerIndexError";
|
|
250
272
|
}
|
|
251
273
|
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Error thrown due to a missing property when resolving a JSON Pointer.
|
|
277
|
+
*/
|
|
252
278
|
class JSONPointerKeyError extends JSONPointerResolutionError {
|
|
253
279
|
constructor(message) {
|
|
254
280
|
super(message);
|
|
@@ -257,6 +283,10 @@ var json_p3 = (function (exports) {
|
|
|
257
283
|
this.name = "JSONPointerKeyError";
|
|
258
284
|
}
|
|
259
285
|
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Error thrown due to invalid JSON Pointer syntax.
|
|
289
|
+
*/
|
|
260
290
|
class JSONPointerSyntaxError extends JSONPointerError {
|
|
261
291
|
constructor(message) {
|
|
262
292
|
super(message);
|
|
@@ -265,6 +295,10 @@ var json_p3 = (function (exports) {
|
|
|
265
295
|
this.name = "JSONPointerSyntaxError";
|
|
266
296
|
}
|
|
267
297
|
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Error thrown when trying to resolve a property or index against a primitive value.
|
|
301
|
+
*/
|
|
268
302
|
class JSONPointerTypeError extends JSONPointerResolutionError {
|
|
269
303
|
constructor(message) {
|
|
270
304
|
super(message);
|
|
@@ -324,8 +358,6 @@ var json_p3 = (function (exports) {
|
|
|
324
358
|
}
|
|
325
359
|
}
|
|
326
360
|
|
|
327
|
-
// TODO: add `resolveWithFallback` to handle explicit `undefined`
|
|
328
|
-
|
|
329
361
|
/**
|
|
330
362
|
*
|
|
331
363
|
* @param value -
|
|
@@ -364,6 +396,8 @@ var json_p3 = (function (exports) {
|
|
|
364
396
|
}
|
|
365
397
|
return pointer.split("/").map(token => token.replaceAll("~1", "/").replaceAll("~0", "~")).slice(1);
|
|
366
398
|
}
|
|
399
|
+
|
|
400
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
367
401
|
getItem(val, token, idx) {
|
|
368
402
|
// NOTE:
|
|
369
403
|
// - string primitives "have own" indices and `length`.
|
|
@@ -373,12 +407,23 @@ var json_p3 = (function (exports) {
|
|
|
373
407
|
if (isArray(val)) {
|
|
374
408
|
if (token !== "length" && Object.hasOwn(val, token)) {
|
|
375
409
|
return val[Number(token)];
|
|
410
|
+
} else if (token.startsWith("#")) {
|
|
411
|
+
// handle non-standard '#' from relative json pointer
|
|
412
|
+
const maybeIndex = token.slice(1);
|
|
413
|
+
if (RE_INT.test(maybeIndex) && Object.hasOwn(val, maybeIndex)) {
|
|
414
|
+
return Number(maybeIndex);
|
|
415
|
+
} else {
|
|
416
|
+
throw new JSONPointerIndexError(`index out of range '${JSONPointer.encode(this.tokens.slice(0, idx + 1))}'`);
|
|
417
|
+
}
|
|
376
418
|
} else {
|
|
377
419
|
throw new JSONPointerIndexError(`index out of range '${JSONPointer.encode(this.tokens.slice(0, idx + 1))}'`);
|
|
378
420
|
}
|
|
379
421
|
} else if (isObject(val)) {
|
|
380
422
|
if (Object.hasOwn(val, token)) {
|
|
381
423
|
return val[token];
|
|
424
|
+
} else if (token.startsWith("#") && Object.hasOwn(val, token.slice(1))) {
|
|
425
|
+
// handle non-standard '#' from relative json pointer
|
|
426
|
+
return token.slice(1);
|
|
382
427
|
} else {
|
|
383
428
|
throw new JSONPointerKeyError(`no such property '${JSONPointer.encode(this.tokens.slice(0, idx + 1))}'`);
|
|
384
429
|
}
|
|
@@ -398,10 +443,12 @@ var json_p3 = (function (exports) {
|
|
|
398
443
|
|
|
399
444
|
/**
|
|
400
445
|
* Join this pointer with _tokens_.
|
|
446
|
+
*
|
|
401
447
|
* @param tokens - JSON Pointer strings, possibly without leading slashes.
|
|
402
448
|
* If a token or "part" does have a leading slash, the previous pointer is
|
|
403
449
|
* ignored and a new `JSONPointer` is created, then processing of the
|
|
404
450
|
* remaining tokens continues.
|
|
451
|
+
*
|
|
405
452
|
* @returns A new JSON Pointer that is the concatenation of all tokens or
|
|
406
453
|
* "parts".
|
|
407
454
|
*/
|
|
@@ -451,8 +498,111 @@ var json_p3 = (function (exports) {
|
|
|
451
498
|
}
|
|
452
499
|
return new JSONPointer(JSONPointer.encode(this.tokens.slice(0, this.tokens.length - 1)));
|
|
453
500
|
}
|
|
501
|
+
to(rel) {
|
|
502
|
+
const relativePointer = isString(rel) ? new RelativeJSONPointer(rel) : rel;
|
|
503
|
+
return relativePointer.to(this);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const RE_RELATIVE_POINTER = /(?<ORIGIN>\d+)(?<INDEX_G>(?<SIGN>[+-])(?<INDEX>\d))?(?<POINTER>.*)/s;
|
|
507
|
+
const RE_INT = /(0|[1-9][0-9]*)/;
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* A relative JSON Pointer.
|
|
511
|
+
*
|
|
512
|
+
* See https://www.ietf.org/id/draft-hha-relative-json-pointer-00.html
|
|
513
|
+
*/
|
|
514
|
+
class RelativeJSONPointer {
|
|
515
|
+
/**
|
|
516
|
+
*
|
|
517
|
+
* @param rel -
|
|
518
|
+
*/
|
|
519
|
+
constructor(rel) {
|
|
520
|
+
[this.origin, this.index, this.pointer] = this.parse(rel);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
*
|
|
525
|
+
* @returns
|
|
526
|
+
*/
|
|
527
|
+
toString() {
|
|
528
|
+
const sign = this.index > 0 ? "+" : "";
|
|
529
|
+
const index = this.index === 0 ? "" : `${sign}${this.index}`;
|
|
530
|
+
return `${this.origin}${index}${this.pointer}`;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
*
|
|
535
|
+
* @param pointer -
|
|
536
|
+
*/
|
|
537
|
+
to(pointer) {
|
|
538
|
+
const p = isString(pointer) ? new JSONPointer(pointer) : pointer;
|
|
539
|
+
|
|
540
|
+
// move to origin
|
|
541
|
+
if (this.origin > p.tokens.length) {
|
|
542
|
+
throw new JSONPointerIndexError(`origin (${this.origin}) exceeds root (${p.tokens.length})`);
|
|
543
|
+
}
|
|
544
|
+
const tokens = this.origin < 1 ? p.tokens.slice() : p.tokens.slice(0, -this.origin);
|
|
545
|
+
|
|
546
|
+
// array index offset
|
|
547
|
+
if (this.index && tokens.length && this.isIntLike(tokens.at(-1))) {
|
|
548
|
+
const newIndex = Number(tokens.at(-1)) + this.index;
|
|
549
|
+
if (newIndex < 0) {
|
|
550
|
+
throw new JSONPointerIndexError(`index offset out of range (${newIndex})`);
|
|
551
|
+
}
|
|
552
|
+
tokens[tokens.length - 1] = String(newIndex);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// pointer or index/property
|
|
556
|
+
if (this.pointer instanceof JSONPointer) {
|
|
557
|
+
tokens.push(...this.pointer.tokens);
|
|
558
|
+
} else {
|
|
559
|
+
tokens[tokens.length - 1] = `#${tokens[tokens.length - 1]}`;
|
|
560
|
+
}
|
|
561
|
+
return new JSONPointer(JSONPointer.encode(tokens));
|
|
562
|
+
}
|
|
563
|
+
parse(rel) {
|
|
564
|
+
const match = RE_RELATIVE_POINTER.exec(rel);
|
|
565
|
+
if (!match || !match.groups) {
|
|
566
|
+
throw new JSONPointerSyntaxError("failed to parse relative pointer");
|
|
567
|
+
}
|
|
454
568
|
|
|
455
|
-
|
|
569
|
+
// steps to move
|
|
570
|
+
const origin = this.parseInt(match.groups.ORIGIN);
|
|
571
|
+
|
|
572
|
+
// optional index manipulation
|
|
573
|
+
let index = 0;
|
|
574
|
+
if (match.groups["INDEX_G"]) {
|
|
575
|
+
index = this.parseInt(match.groups.INDEX);
|
|
576
|
+
if (index === 0) {
|
|
577
|
+
throw new JSONPointerSyntaxError("index offset can't be zero");
|
|
578
|
+
}
|
|
579
|
+
if (match.groups.SIGN === "-") {
|
|
580
|
+
index = -index;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// pointer or '#'. an empty string is OK.
|
|
585
|
+
if (match.groups.POINTER === "#") {
|
|
586
|
+
return [origin, index, "#"];
|
|
587
|
+
}
|
|
588
|
+
return [origin, index, new JSONPointer(match.groups.POINTER)];
|
|
589
|
+
}
|
|
590
|
+
parseInt(s) {
|
|
591
|
+
if (s.startsWith("0") && s.length > 1) {
|
|
592
|
+
throw new JSONPointerSyntaxError("unexpected leading zero");
|
|
593
|
+
}
|
|
594
|
+
if (RE_INT.test(s)) {
|
|
595
|
+
return Number(s);
|
|
596
|
+
}
|
|
597
|
+
throw new JSONPointerSyntaxError(`expected an integer, found '${s}'`);
|
|
598
|
+
}
|
|
599
|
+
isIntLike(value) {
|
|
600
|
+
if (value === undefined || isNumber(value)) {
|
|
601
|
+
return true;
|
|
602
|
+
} else {
|
|
603
|
+
return RE_INT.test(value);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
456
606
|
}
|
|
457
607
|
|
|
458
608
|
/**
|
|
@@ -487,6 +637,7 @@ var json_p3 = (function (exports) {
|
|
|
487
637
|
JSONPointerResolutionError: JSONPointerResolutionError,
|
|
488
638
|
JSONPointerSyntaxError: JSONPointerSyntaxError,
|
|
489
639
|
JSONPointerTypeError: JSONPointerTypeError,
|
|
640
|
+
RelativeJSONPointer: RelativeJSONPointer,
|
|
490
641
|
UNDEFINED: UNDEFINED,
|
|
491
642
|
resolve: resolve
|
|
492
643
|
});
|
|
@@ -784,7 +935,7 @@ var json_p3 = (function (exports) {
|
|
|
784
935
|
this.args = args;
|
|
785
936
|
}
|
|
786
937
|
evaluate(context) {
|
|
787
|
-
const func = context.environment.
|
|
938
|
+
const func = context.environment.functionRegister.get(this.name);
|
|
788
939
|
if (!func) {
|
|
789
940
|
throw new UndefinedFilterFunctionError(`filter function '${this.name}' is undefined`, this.token);
|
|
790
941
|
}
|
|
@@ -804,13 +955,6 @@ var json_p3 = (function (exports) {
|
|
|
804
955
|
if (value instanceof JSONPathNodeList && value.empty()) return false;
|
|
805
956
|
return !(typeof value === "boolean" && value === false);
|
|
806
957
|
}
|
|
807
|
-
|
|
808
|
-
/**
|
|
809
|
-
*
|
|
810
|
-
* @param left -
|
|
811
|
-
* @param operator -
|
|
812
|
-
* @param right -
|
|
813
|
-
*/
|
|
814
958
|
function compare(left, operator, right) {
|
|
815
959
|
switch (operator) {
|
|
816
960
|
case "==":
|
|
@@ -864,7 +1008,8 @@ var json_p3 = (function (exports) {
|
|
|
864
1008
|
PrefixExpression: PrefixExpression,
|
|
865
1009
|
RelativeQuery: RelativeQuery,
|
|
866
1010
|
RootQuery: RootQuery,
|
|
867
|
-
StringLiteral: StringLiteral
|
|
1011
|
+
StringLiteral: StringLiteral,
|
|
1012
|
+
compare: compare
|
|
868
1013
|
});
|
|
869
1014
|
|
|
870
1015
|
class Count {
|
|
@@ -1095,7 +1240,7 @@ var json_p3 = (function (exports) {
|
|
|
1095
1240
|
|
|
1096
1241
|
// These regular expressions are to be used with Lexer.acceptMatchRun(),
|
|
1097
1242
|
// which expects the sticky flag to be set.
|
|
1098
|
-
const exponentPattern = /e[+-]
|
|
1243
|
+
const exponentPattern = /e[+-]?\d+/y;
|
|
1099
1244
|
const functionNamePattern = /[a-z][a-z_0-9]*/y;
|
|
1100
1245
|
const indexPattern = /-?\d+/y;
|
|
1101
1246
|
const intPattern = /-?[0-9]+/y;
|
|
@@ -1388,6 +1533,10 @@ var json_p3 = (function (exports) {
|
|
|
1388
1533
|
case "":
|
|
1389
1534
|
case "]":
|
|
1390
1535
|
l.filterLevel -= 1;
|
|
1536
|
+
if (l.parenStack.length === 1) {
|
|
1537
|
+
l.error("unbalanced parentheses");
|
|
1538
|
+
return null;
|
|
1539
|
+
}
|
|
1391
1540
|
l.backup();
|
|
1392
1541
|
return lexInsideBracketedSelection;
|
|
1393
1542
|
case ",":
|
|
@@ -1617,7 +1766,7 @@ var json_p3 = (function (exports) {
|
|
|
1617
1766
|
this.environment = environment;
|
|
1618
1767
|
this.token = token;
|
|
1619
1768
|
this.index = index;
|
|
1620
|
-
if (index < this.environment.
|
|
1769
|
+
if (index < this.environment.minIntIndex || index > this.environment.maxIntIndex) {
|
|
1621
1770
|
throw new JSONPathIndexError("index out of range", this.token);
|
|
1622
1771
|
}
|
|
1623
1772
|
}
|
|
@@ -1672,15 +1821,11 @@ var json_p3 = (function (exports) {
|
|
|
1672
1821
|
indices[_key] = arguments[_key];
|
|
1673
1822
|
}
|
|
1674
1823
|
for (const index of indices) {
|
|
1675
|
-
if (index !== undefined && (index < this.environment.
|
|
1824
|
+
if (index !== undefined && (index < this.environment.minIntIndex || index > this.environment.maxIntIndex)) {
|
|
1676
1825
|
throw new JSONPathIndexError("index out of range", this.token);
|
|
1677
1826
|
}
|
|
1678
1827
|
}
|
|
1679
1828
|
}
|
|
1680
|
-
normalizedIndex(length, index) {
|
|
1681
|
-
if (index < 0 && length >= Math.abs(index)) return Math.min(length + index, length - 1);
|
|
1682
|
-
return Math.min(index, length - 1);
|
|
1683
|
-
}
|
|
1684
1829
|
|
|
1685
1830
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
1686
1831
|
slice(arr, start, stop, step) {
|
|
@@ -1764,17 +1909,21 @@ var json_p3 = (function (exports) {
|
|
|
1764
1909
|
return "..";
|
|
1765
1910
|
}
|
|
1766
1911
|
visit(node) {
|
|
1912
|
+
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
1913
|
+
if (depth >= this.environment.maxRecursionDepth) {
|
|
1914
|
+
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
1915
|
+
}
|
|
1767
1916
|
const rv = [];
|
|
1768
1917
|
if (node.value instanceof String) return new JSONPathNodeList(rv);
|
|
1769
1918
|
if (isArray(node.value)) {
|
|
1770
1919
|
for (let i = 0; i < node.value.length; i++) {
|
|
1771
1920
|
const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
|
|
1772
|
-
rv.push(_node, ...this.visit(_node));
|
|
1921
|
+
rv.push(_node, ...this.visit(_node, depth + 1));
|
|
1773
1922
|
}
|
|
1774
1923
|
} else if (isObject(node.value)) {
|
|
1775
1924
|
for (const [key, value] of Object.entries(node.value)) {
|
|
1776
1925
|
const _node = new JSONPathNode(value, node.location.concat(key), node.root);
|
|
1777
|
-
rv.push(_node, ...this.visit(_node));
|
|
1926
|
+
rv.push(_node, ...this.visit(_node, depth + 1));
|
|
1778
1927
|
}
|
|
1779
1928
|
}
|
|
1780
1929
|
return new JSONPathNodeList(rv);
|
|
@@ -1884,6 +2033,18 @@ var json_p3 = (function (exports) {
|
|
|
1884
2033
|
return nodes;
|
|
1885
2034
|
}
|
|
1886
2035
|
|
|
2036
|
+
/**
|
|
2037
|
+
* Return a {@link JSONPathNode} instance for the first object found in
|
|
2038
|
+
* _value_ matching this query.
|
|
2039
|
+
*
|
|
2040
|
+
* @param value - JSON-like data to which this query will be applied.
|
|
2041
|
+
* @returns The first node in _value_ matching this query, or `undefined` if
|
|
2042
|
+
* there are no matches.
|
|
2043
|
+
*/
|
|
2044
|
+
match(value) {
|
|
2045
|
+
return this.query(value).nodes.at(0);
|
|
2046
|
+
}
|
|
2047
|
+
|
|
1887
2048
|
/**
|
|
1888
2049
|
*
|
|
1889
2050
|
*/
|
|
@@ -2045,7 +2206,7 @@ var json_p3 = (function (exports) {
|
|
|
2045
2206
|
const tok = stream.next();
|
|
2046
2207
|
const expr = this.parseFilterExpression(stream);
|
|
2047
2208
|
if (expr instanceof FunctionExtension) {
|
|
2048
|
-
const func = this.environment.
|
|
2209
|
+
const func = this.environment.functionRegister.get(expr.name);
|
|
2049
2210
|
if (func && func.returnType === FunctionExpressionType.ValueType) {
|
|
2050
2211
|
throw new JSONPathTypeError(`result of ${expr.name}() must be compared`, expr.token);
|
|
2051
2212
|
}
|
|
@@ -2115,7 +2276,16 @@ var json_p3 = (function (exports) {
|
|
|
2115
2276
|
if (!func) {
|
|
2116
2277
|
throw new JSONPathSyntaxError(`unexpected '${stream.current.value}'`, stream.current);
|
|
2117
2278
|
}
|
|
2118
|
-
|
|
2279
|
+
let expr = func.bind(this)(stream);
|
|
2280
|
+
|
|
2281
|
+
// Could be a comparison/logical expression
|
|
2282
|
+
let peekKind = stream.peek.kind;
|
|
2283
|
+
while (BINARY_OPERATORS.has(peekKind)) {
|
|
2284
|
+
stream.next();
|
|
2285
|
+
expr = this.parseInfixExpression(stream, expr);
|
|
2286
|
+
peekKind = stream.peek.kind;
|
|
2287
|
+
}
|
|
2288
|
+
args.push(expr);
|
|
2119
2289
|
if (stream.peek.kind !== TokenKind.RPAREN) {
|
|
2120
2290
|
if (stream.peek.kind === TokenKind.RBRACKET) break;
|
|
2121
2291
|
stream.expectPeek(TokenKind.COMMA);
|
|
@@ -2123,6 +2293,7 @@ var json_p3 = (function (exports) {
|
|
|
2123
2293
|
}
|
|
2124
2294
|
stream.next();
|
|
2125
2295
|
}
|
|
2296
|
+
stream.expect(TokenKind.RPAREN);
|
|
2126
2297
|
return new FunctionExtension(tok, tok.value, this.environment.checkWellTypedness(tok, args));
|
|
2127
2298
|
}
|
|
2128
2299
|
parseFilterExpression(stream) {
|
|
@@ -2167,7 +2338,7 @@ var json_p3 = (function (exports) {
|
|
|
2167
2338
|
}
|
|
2168
2339
|
throwForNonComparableFunction(expr) {
|
|
2169
2340
|
if (!(expr instanceof FunctionExtension)) return;
|
|
2170
|
-
const func = this.environment.
|
|
2341
|
+
const func = this.environment.functionRegister.get(expr.name);
|
|
2171
2342
|
if (func && func.returnType !== FunctionExpressionType.ValueType) {
|
|
2172
2343
|
throw new JSONPathTypeError(`result of ${expr.name}() is not comparable`, expr.token);
|
|
2173
2344
|
}
|
|
@@ -2175,30 +2346,53 @@ var json_p3 = (function (exports) {
|
|
|
2175
2346
|
}
|
|
2176
2347
|
|
|
2177
2348
|
/**
|
|
2178
|
-
*
|
|
2349
|
+
* JSONPath environment options. The defaults are in compliance with JSONPath
|
|
2350
|
+
* standards.
|
|
2179
2351
|
*/
|
|
2180
2352
|
|
|
2181
|
-
const defaultOptions = {
|
|
2182
|
-
strict: true,
|
|
2183
|
-
maxIntIndex: Math.pow(2, 53) - 1,
|
|
2184
|
-
minIntIndex: -Math.pow(2, 53) - 1
|
|
2185
|
-
};
|
|
2186
|
-
|
|
2187
2353
|
/**
|
|
2188
2354
|
*
|
|
2189
2355
|
*/
|
|
2190
2356
|
class JSONPathEnvironment {
|
|
2191
2357
|
/**
|
|
2358
|
+
* Indicates if the environment should to be strict about its compliance with
|
|
2359
|
+
* JSONPath standards.
|
|
2192
2360
|
*
|
|
2361
|
+
* Defaults to `true`. Setting `strict` to `false` currently has no effect.
|
|
2362
|
+
* If/when we add non-standard features, the environment's strictness will
|
|
2363
|
+
* control their availability.
|
|
2364
|
+
*/
|
|
2365
|
+
|
|
2366
|
+
/**
|
|
2367
|
+
* The maximum number allowed when indexing or slicing an array. Defaults to
|
|
2368
|
+
* 2**53 -1.
|
|
2369
|
+
*/
|
|
2370
|
+
|
|
2371
|
+
/**
|
|
2372
|
+
* The minimum number allowed when indexing or slicing an array. Defaults to
|
|
2373
|
+
* -(2**53) -1.
|
|
2374
|
+
*/
|
|
2375
|
+
|
|
2376
|
+
/**
|
|
2377
|
+
* The maximum number of objects and/or arrays the recursive descent selector
|
|
2378
|
+
* can visit before a `JSONPathRecursionLimitError` is thrown.
|
|
2379
|
+
*/
|
|
2380
|
+
|
|
2381
|
+
/**
|
|
2382
|
+
* A map of function names to objects implementing the {@link FilterFunction}
|
|
2383
|
+
* interface. You are free to set or delete custom filter functions directly.
|
|
2193
2384
|
*/
|
|
2194
|
-
|
|
2385
|
+
functionRegister = new Map();
|
|
2195
2386
|
/**
|
|
2196
2387
|
*
|
|
2197
2388
|
* @param options -
|
|
2198
2389
|
*/
|
|
2199
2390
|
constructor() {
|
|
2200
|
-
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] :
|
|
2201
|
-
this.
|
|
2391
|
+
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
2392
|
+
this.strict = options.strict ?? true;
|
|
2393
|
+
this.maxIntIndex = options.maxIntIndex ?? Math.pow(2, 53) - 1;
|
|
2394
|
+
this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
|
|
2395
|
+
this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
|
|
2202
2396
|
this.parser = new Parser(this);
|
|
2203
2397
|
this.setupFilterFunctions();
|
|
2204
2398
|
}
|
|
@@ -2221,12 +2415,25 @@ var json_p3 = (function (exports) {
|
|
|
2221
2415
|
query(path, value) {
|
|
2222
2416
|
return this.compile(path).query(value);
|
|
2223
2417
|
}
|
|
2418
|
+
|
|
2419
|
+
/**
|
|
2420
|
+
* Return a {@link JSONPathNode} instance for the first object found in
|
|
2421
|
+
* _value_ matching _path_.
|
|
2422
|
+
*
|
|
2423
|
+
* @param path - A JSONPath query.
|
|
2424
|
+
* @param value - JSON-like data to which the query _path_ will be applied.
|
|
2425
|
+
* @returns The first node in _value_ matching _path_, or `undefined` if
|
|
2426
|
+
* there are no matches.
|
|
2427
|
+
*/
|
|
2428
|
+
match(path, value) {
|
|
2429
|
+
return this.compile(path).match(value);
|
|
2430
|
+
}
|
|
2224
2431
|
setupFilterFunctions() {
|
|
2225
|
-
this.
|
|
2226
|
-
this.
|
|
2227
|
-
this.
|
|
2228
|
-
this.
|
|
2229
|
-
this.
|
|
2432
|
+
this.functionRegister.set("count", new Count());
|
|
2433
|
+
this.functionRegister.set("length", new Length());
|
|
2434
|
+
this.functionRegister.set("search", new Search());
|
|
2435
|
+
this.functionRegister.set("match", new Match());
|
|
2436
|
+
this.functionRegister.set("value", new Value());
|
|
2230
2437
|
}
|
|
2231
2438
|
|
|
2232
2439
|
/**
|
|
@@ -2236,7 +2443,7 @@ var json_p3 = (function (exports) {
|
|
|
2236
2443
|
*/
|
|
2237
2444
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
2238
2445
|
checkWellTypedness(token, args) {
|
|
2239
|
-
const func = this.
|
|
2446
|
+
const func = this.functionRegister.get(token.value);
|
|
2240
2447
|
if (!func) {
|
|
2241
2448
|
throw new UndefinedFilterFunctionError(`no such function '${token.value}'`, token);
|
|
2242
2449
|
}
|
|
@@ -2250,17 +2457,17 @@ var json_p3 = (function (exports) {
|
|
|
2250
2457
|
for (const [typ, arg, idx] of func.argTypes.map((t, i) => [t, args[i], i])) {
|
|
2251
2458
|
switch (typ) {
|
|
2252
2459
|
case FunctionExpressionType.ValueType:
|
|
2253
|
-
if (!(arg instanceof FilterExpressionLiteral || arg instanceof JSONPathQuery && arg.path.singularQuery())) {
|
|
2460
|
+
if (!(arg instanceof FilterExpressionLiteral || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
|
|
2254
2461
|
throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of ValueType`, arg.token);
|
|
2255
2462
|
}
|
|
2256
2463
|
break;
|
|
2257
2464
|
case FunctionExpressionType.LogicalType:
|
|
2258
|
-
if (!(arg instanceof
|
|
2465
|
+
if (!(arg instanceof JSONPathQuery || arg instanceof InfixExpression)) {
|
|
2259
2466
|
throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of LogicalType`, arg.token);
|
|
2260
2467
|
}
|
|
2261
2468
|
break;
|
|
2262
2469
|
case FunctionExpressionType.NodesType:
|
|
2263
|
-
if (!(arg instanceof JSONPathQuery)) {
|
|
2470
|
+
if (!(arg instanceof JSONPathQuery || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.NodesType)) {
|
|
2264
2471
|
throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of NodesType`, arg.token);
|
|
2265
2472
|
}
|
|
2266
2473
|
}
|
|
@@ -2315,6 +2522,19 @@ var json_p3 = (function (exports) {
|
|
|
2315
2522
|
return DEFAULT_ENVIRONMENT.compile(path);
|
|
2316
2523
|
}
|
|
2317
2524
|
|
|
2525
|
+
/**
|
|
2526
|
+
* Return a {@link JSONPathNode} instance for the first object found in
|
|
2527
|
+
* _value_ matching _path_.
|
|
2528
|
+
*
|
|
2529
|
+
* @param path - A JSONPath query.
|
|
2530
|
+
* @param value - JSON-like data to which the query _path_ will be applied.
|
|
2531
|
+
* @returns The first node in _value_ matching _path_, or `undefined` if
|
|
2532
|
+
* there are no matches.
|
|
2533
|
+
*/
|
|
2534
|
+
function match(path, value) {
|
|
2535
|
+
return DEFAULT_ENVIRONMENT.match(path, value);
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2318
2538
|
var index$1 = /*#__PURE__*/Object.freeze({
|
|
2319
2539
|
__proto__: null,
|
|
2320
2540
|
DEFAULT_ENVIRONMENT: DEFAULT_ENVIRONMENT,
|
|
@@ -2326,6 +2546,7 @@ var json_p3 = (function (exports) {
|
|
|
2326
2546
|
JSONPathLexerError: JSONPathLexerError,
|
|
2327
2547
|
JSONPathNode: JSONPathNode,
|
|
2328
2548
|
JSONPathNodeList: JSONPathNodeList,
|
|
2549
|
+
JSONPathRecursionLimitError: JSONPathRecursionLimitError,
|
|
2329
2550
|
JSONPathSyntaxError: JSONPathSyntaxError,
|
|
2330
2551
|
JSONPathTypeError: JSONPathTypeError,
|
|
2331
2552
|
Nothing: Nothing,
|
|
@@ -2334,6 +2555,7 @@ var json_p3 = (function (exports) {
|
|
|
2334
2555
|
compile: compile,
|
|
2335
2556
|
expressions: expression,
|
|
2336
2557
|
functions: index$2,
|
|
2558
|
+
match: match,
|
|
2337
2559
|
query: query,
|
|
2338
2560
|
selectors: selectors
|
|
2339
2561
|
});
|
|
@@ -2634,6 +2856,15 @@ var json_p3 = (function (exports) {
|
|
|
2634
2856
|
}
|
|
2635
2857
|
}
|
|
2636
2858
|
|
|
2859
|
+
/**
|
|
2860
|
+
* @returns an iterator over ops in this patch.
|
|
2861
|
+
*/
|
|
2862
|
+
*[Symbol.iterator]() {
|
|
2863
|
+
for (const op of this.ops) {
|
|
2864
|
+
yield op.toObject();
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2637
2868
|
/**
|
|
2638
2869
|
*
|
|
2639
2870
|
* @param path -
|
|
@@ -2809,8 +3040,9 @@ var json_p3 = (function (exports) {
|
|
|
2809
3040
|
apply: apply
|
|
2810
3041
|
});
|
|
2811
3042
|
|
|
2812
|
-
const version = "0.
|
|
3043
|
+
const version = "0.2.0";
|
|
2813
3044
|
|
|
3045
|
+
exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
|
|
2814
3046
|
exports.FunctionExpressionType = FunctionExpressionType;
|
|
2815
3047
|
exports.JSONPatch = JSONPatch;
|
|
2816
3048
|
exports.JSONPatchError = JSONPatchError;
|
|
@@ -2822,10 +3054,12 @@ var json_p3 = (function (exports) {
|
|
|
2822
3054
|
exports.JSONPathLexerError = JSONPathLexerError;
|
|
2823
3055
|
exports.JSONPathNode = JSONPathNode;
|
|
2824
3056
|
exports.JSONPathNodeList = JSONPathNodeList;
|
|
3057
|
+
exports.JSONPathRecursionLimitError = JSONPathRecursionLimitError;
|
|
2825
3058
|
exports.JSONPathSyntaxError = JSONPathSyntaxError;
|
|
2826
3059
|
exports.JSONPathTypeError = JSONPathTypeError;
|
|
2827
3060
|
exports.JSONPointer = JSONPointer;
|
|
2828
3061
|
exports.Nothing = Nothing;
|
|
3062
|
+
exports.RelativeJSONPointer = RelativeJSONPointer;
|
|
2829
3063
|
exports.Token = Token;
|
|
2830
3064
|
exports.TokenKind = TokenKind;
|
|
2831
3065
|
exports.UNDEFINED = UNDEFINED;
|