json-p3 0.2.0 → 0.3.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 +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/json-p3.cjs.js +288 -59
- package/dist/json-p3.esm.js +288 -60
- package/dist/json-p3.iife.js +288 -59
- package/dist/json-p3.iife.min.js +1 -1
- package/dist/json-p3.iife.min.js.map +1 -1
- package/dist/path/environment.d.ts +35 -10
- package/dist/path/index.d.ts +18 -0
- package/dist/path/node.d.ts +1 -4
- package/dist/path/parse.d.ts +4 -0
- package/dist/path/path.d.ts +6 -0
- package/dist/path/selectors.d.ts +25 -9
- package/dist/path/types.d.ts +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,6 +39,7 @@ console.log(nodes.values()); // [ 'John', 'Sally', 'Jane' ]
|
|
|
39
39
|
|
|
40
40
|
- Docs: https://jg-rp.github.io/json-p3/
|
|
41
41
|
- Install: https://jg-rp.github.io/json-p3/#install
|
|
42
|
+
- JSONPath playground: https://jg-rp.github.io/json-p3/playground
|
|
42
43
|
- JSONPath syntax: https://jg-rp.github.io/json-p3/guides/jsonpath-syntax
|
|
43
44
|
- API reference: https://jg-rp.github.io/json-p3/api
|
|
44
45
|
- Change log: https://github.com/jg-rp/json-p3/blob/main/CHANGELOG.md
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const version = "__VERSION__";
|
|
2
2
|
export * as jsonpath from "./path";
|
|
3
|
-
export { DEFAULT_ENVIRONMENT, FunctionExpressionType, JSONPath, JSONPathEnvironment, JSONPathError, JSONPathIndexError, JSONPathLexerError, JSONPathNode, JSONPathNodeList, JSONPathSyntaxError, JSONPathTypeError, JSONPathRecursionLimitError, Token, TokenKind, Nothing, query, compile, } from "./path";
|
|
3
|
+
export { DEFAULT_ENVIRONMENT, FunctionExpressionType, JSONPath, JSONPathEnvironment, JSONPathError, JSONPathIndexError, JSONPathLexerError, JSONPathNode, JSONPathNodeList, JSONPathSyntaxError, JSONPathTypeError, JSONPathRecursionLimitError, Token, TokenKind, Nothing, lazyQuery, query, compile, } from "./path";
|
|
4
4
|
export type { JSONPathEnvironmentOptions, FilterFunction } from "./path";
|
|
5
5
|
export * as jsonpointer from "./pointer";
|
|
6
6
|
export { JSONPointer, RelativeJSONPointer, resolve, UNDEFINED, } from "./pointer";
|
package/dist/json-p3.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* json-p3 version 0.
|
|
2
|
+
* json-p3 version 0.3.0
|
|
3
3
|
* https://github.com/jg-rp/json-p3
|
|
4
4
|
*
|
|
5
5
|
* MIT License
|
|
@@ -645,10 +645,6 @@ var index$3 = /*#__PURE__*/Object.freeze({
|
|
|
645
645
|
* The pair of a JSON value and its location found in the target JSON value.
|
|
646
646
|
*/
|
|
647
647
|
class JSONPathNode {
|
|
648
|
-
/**
|
|
649
|
-
* The normalized path to this node in the target JSON value.
|
|
650
|
-
*/
|
|
651
|
-
|
|
652
648
|
/**
|
|
653
649
|
* @param value - The JSON value found at _location_.
|
|
654
650
|
* @param location - The parts of a normalized path to _value_.
|
|
@@ -658,9 +654,12 @@ class JSONPathNode {
|
|
|
658
654
|
this.value = value;
|
|
659
655
|
this.location = location;
|
|
660
656
|
this.root = root;
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
657
|
+
}
|
|
658
|
+
get path() {
|
|
659
|
+
return (
|
|
660
|
+
// eslint-disable-next-line prefer-template
|
|
661
|
+
"$" + this.location.map(s => isString(s) ? `['${s}']` : `[${s}]`).join("")
|
|
662
|
+
);
|
|
664
663
|
}
|
|
665
664
|
|
|
666
665
|
/**
|
|
@@ -912,7 +911,7 @@ class JSONPathQuery extends FilterExpression {
|
|
|
912
911
|
}
|
|
913
912
|
class RelativeQuery extends JSONPathQuery {
|
|
914
913
|
evaluate(context) {
|
|
915
|
-
return this.path.query(context.currentValue);
|
|
914
|
+
return context.lazy ? new JSONPathNodeList(Array.from(this.path.lazyQuery(context.currentValue))) : this.path.query(context.currentValue);
|
|
916
915
|
}
|
|
917
916
|
toString() {
|
|
918
917
|
return `@${this.path.toString().slice(1)}`;
|
|
@@ -920,7 +919,7 @@ class RelativeQuery extends JSONPathQuery {
|
|
|
920
919
|
}
|
|
921
920
|
class RootQuery extends JSONPathQuery {
|
|
922
921
|
evaluate(context) {
|
|
923
|
-
return this.path.query(context.rootValue);
|
|
922
|
+
return context.lazy ? new JSONPathNodeList(Array.from(this.path.lazyQuery(context.rootValue))) : this.path.query(context.rootValue);
|
|
924
923
|
}
|
|
925
924
|
toString() {
|
|
926
925
|
return this.path.toString();
|
|
@@ -1722,6 +1721,10 @@ class JSONPathSelector {
|
|
|
1722
1721
|
this.token = token;
|
|
1723
1722
|
}
|
|
1724
1723
|
|
|
1724
|
+
/**
|
|
1725
|
+
* @param nodes - Nodes matched by preceding selectors.
|
|
1726
|
+
*/
|
|
1727
|
+
|
|
1725
1728
|
/**
|
|
1726
1729
|
* @param nodes - Nodes matched by preceding selectors.
|
|
1727
1730
|
*/
|
|
@@ -1749,7 +1752,14 @@ class NameSelector extends JSONPathSelector {
|
|
|
1749
1752
|
rv.push(new JSONPathNode(node.value[this.name], node.location.concat(this.name), node.root));
|
|
1750
1753
|
}
|
|
1751
1754
|
}
|
|
1752
|
-
return
|
|
1755
|
+
return rv;
|
|
1756
|
+
}
|
|
1757
|
+
*lazyResolve(nodes) {
|
|
1758
|
+
for (const node of nodes) {
|
|
1759
|
+
if (hasStringKey(node.value, this.name)) {
|
|
1760
|
+
yield new JSONPathNode(node.value[this.name], node.location.concat(this.name), node.root);
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1753
1763
|
}
|
|
1754
1764
|
toString() {
|
|
1755
1765
|
return this.shorthand ? `['${this.name}']` : `'${this.name}'`;
|
|
@@ -1779,7 +1789,17 @@ class IndexSelector extends JSONPathSelector {
|
|
|
1779
1789
|
}
|
|
1780
1790
|
}
|
|
1781
1791
|
}
|
|
1782
|
-
return
|
|
1792
|
+
return rv;
|
|
1793
|
+
}
|
|
1794
|
+
*lazyResolve(nodes) {
|
|
1795
|
+
for (const node of nodes) {
|
|
1796
|
+
if (isArray(node.value)) {
|
|
1797
|
+
const normIndex = this.normalizedIndex(node.value.length);
|
|
1798
|
+
if (normIndex in node.value) {
|
|
1799
|
+
yield new JSONPathNode(node.value[normIndex], node.location.concat(normIndex), node.root);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1783
1803
|
}
|
|
1784
1804
|
toString() {
|
|
1785
1805
|
return String(this.index);
|
|
@@ -1807,7 +1827,15 @@ class SliceSelector extends JSONPathSelector {
|
|
|
1807
1827
|
rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
|
|
1808
1828
|
}
|
|
1809
1829
|
}
|
|
1810
|
-
return
|
|
1830
|
+
return rv;
|
|
1831
|
+
}
|
|
1832
|
+
*lazyResolve(nodes) {
|
|
1833
|
+
for (const node of nodes) {
|
|
1834
|
+
if (!isArray(node.value)) continue;
|
|
1835
|
+
for (const [i, value] of this.slice(node.value, this.start, this.stop, this.step)) {
|
|
1836
|
+
yield new JSONPathNode(value, node.location.concat(i), node.root);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1811
1839
|
}
|
|
1812
1840
|
toString() {
|
|
1813
1841
|
const start = this.start ? this.start : "";
|
|
@@ -1890,22 +1918,92 @@ class WildcardSelector extends JSONPathSelector {
|
|
|
1890
1918
|
}
|
|
1891
1919
|
}
|
|
1892
1920
|
}
|
|
1893
|
-
return
|
|
1921
|
+
return rv;
|
|
1922
|
+
}
|
|
1923
|
+
*lazyResolve(nodes) {
|
|
1924
|
+
for (const node of nodes) {
|
|
1925
|
+
if (node.value instanceof String) continue;
|
|
1926
|
+
if (isArray(node.value)) {
|
|
1927
|
+
for (let i = 0; i < node.value.length; i++) {
|
|
1928
|
+
yield new JSONPathNode(node.value[i], node.location.concat(i), node.root);
|
|
1929
|
+
}
|
|
1930
|
+
} else if (isObject(node.value)) {
|
|
1931
|
+
for (const [key, value] of Object.entries(node.value)) {
|
|
1932
|
+
yield new JSONPathNode(value, node.location.concat(key), node.root);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1894
1936
|
}
|
|
1895
1937
|
toString() {
|
|
1896
1938
|
return this.shorthand ? "[*]" : "*";
|
|
1897
1939
|
}
|
|
1898
1940
|
}
|
|
1899
1941
|
class RecursiveDescentSegment extends JSONPathSelector {
|
|
1942
|
+
constructor(environment, token, selector) {
|
|
1943
|
+
super(environment, token);
|
|
1944
|
+
this.environment = environment;
|
|
1945
|
+
this.token = token;
|
|
1946
|
+
this.selector = selector;
|
|
1947
|
+
}
|
|
1900
1948
|
resolve(nodes) {
|
|
1901
1949
|
const rv = [];
|
|
1902
1950
|
for (const node of nodes) {
|
|
1903
|
-
rv.push(node
|
|
1951
|
+
rv.push(node);
|
|
1952
|
+
for (const _node of this.visit(node)) {
|
|
1953
|
+
rv.push(_node);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
return this.selector.resolve(rv);
|
|
1957
|
+
}
|
|
1958
|
+
*lazyResolve(nodes) {
|
|
1959
|
+
yield* this.selector.lazyResolve(this._lazyResolve(nodes));
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
1963
|
+
*_lazyResolve(nodes) {
|
|
1964
|
+
for (const _node of nodes) {
|
|
1965
|
+
const stack = [{
|
|
1966
|
+
node: _node,
|
|
1967
|
+
depth: 0
|
|
1968
|
+
}];
|
|
1969
|
+
yield _node;
|
|
1970
|
+
while (stack.length) {
|
|
1971
|
+
const {
|
|
1972
|
+
node: currentNode,
|
|
1973
|
+
depth
|
|
1974
|
+
} = stack.pop();
|
|
1975
|
+
if (depth >= this.environment.maxRecursionDepth) {
|
|
1976
|
+
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
1977
|
+
}
|
|
1978
|
+
if (currentNode.value instanceof String) continue;
|
|
1979
|
+
if (isArray(currentNode.value)) {
|
|
1980
|
+
for (let i = 0; i < currentNode.value.length; i++) {
|
|
1981
|
+
const __node = new JSONPathNode(currentNode.value[i], currentNode.location.concat(i), currentNode.root);
|
|
1982
|
+
yield __node;
|
|
1983
|
+
if (isObject(__node.value)) {
|
|
1984
|
+
stack.push({
|
|
1985
|
+
node: __node,
|
|
1986
|
+
depth: depth + 1
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
} else if (isObject(currentNode.value)) {
|
|
1991
|
+
for (const [key, value] of Object.entries(currentNode.value)) {
|
|
1992
|
+
const __node = new JSONPathNode(value, currentNode.location.concat(key), currentNode.root);
|
|
1993
|
+
yield __node;
|
|
1994
|
+
if (isObject(__node.value)) {
|
|
1995
|
+
stack.push({
|
|
1996
|
+
node: __node,
|
|
1997
|
+
depth: depth + 1
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
1904
2003
|
}
|
|
1905
|
-
return new JSONPathNodeList(rv);
|
|
1906
2004
|
}
|
|
1907
2005
|
toString() {
|
|
1908
|
-
return
|
|
2006
|
+
return `..${this.selector.toString()}`;
|
|
1909
2007
|
}
|
|
1910
2008
|
visit(node) {
|
|
1911
2009
|
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
@@ -1913,19 +2011,25 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
1913
2011
|
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
1914
2012
|
}
|
|
1915
2013
|
const rv = [];
|
|
1916
|
-
if (node.value instanceof String) return
|
|
2014
|
+
if (node.value instanceof String) return rv;
|
|
1917
2015
|
if (isArray(node.value)) {
|
|
1918
2016
|
for (let i = 0; i < node.value.length; i++) {
|
|
1919
2017
|
const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
|
|
1920
|
-
rv.push(_node
|
|
2018
|
+
rv.push(_node);
|
|
2019
|
+
for (const __node of this.visit(_node, depth + 1)) {
|
|
2020
|
+
rv.push(__node);
|
|
2021
|
+
}
|
|
1921
2022
|
}
|
|
1922
2023
|
} else if (isObject(node.value)) {
|
|
1923
2024
|
for (const [key, value] of Object.entries(node.value)) {
|
|
1924
2025
|
const _node = new JSONPathNode(value, node.location.concat(key), node.root);
|
|
1925
|
-
rv.push(_node
|
|
2026
|
+
rv.push(_node);
|
|
2027
|
+
for (const __node of this.visit(_node, depth + 1)) {
|
|
2028
|
+
rv.push(__node);
|
|
2029
|
+
}
|
|
1926
2030
|
}
|
|
1927
2031
|
}
|
|
1928
|
-
return
|
|
2032
|
+
return rv;
|
|
1929
2033
|
}
|
|
1930
2034
|
}
|
|
1931
2035
|
class FilterSelector extends JSONPathSelector {
|
|
@@ -1966,7 +2070,40 @@ class FilterSelector extends JSONPathSelector {
|
|
|
1966
2070
|
}
|
|
1967
2071
|
}
|
|
1968
2072
|
}
|
|
1969
|
-
return
|
|
2073
|
+
return rv;
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
2077
|
+
*lazyResolve(nodes) {
|
|
2078
|
+
for (const node of nodes) {
|
|
2079
|
+
if (node.value instanceof String) continue;
|
|
2080
|
+
if (isArray(node.value)) {
|
|
2081
|
+
for (let i = 0; i < node.value.length; i++) {
|
|
2082
|
+
const value = node.value[i];
|
|
2083
|
+
const filterContext = {
|
|
2084
|
+
environment: this.environment,
|
|
2085
|
+
currentValue: value,
|
|
2086
|
+
rootValue: node.root,
|
|
2087
|
+
lazy: true
|
|
2088
|
+
};
|
|
2089
|
+
if (this.expression.evaluate(filterContext)) {
|
|
2090
|
+
yield new JSONPathNode(value, node.location.concat(i), node.root);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
} else if (isObject(node.value)) {
|
|
2094
|
+
for (const [key, value] of Object.entries(node.value)) {
|
|
2095
|
+
const filterContext = {
|
|
2096
|
+
environment: this.environment,
|
|
2097
|
+
currentValue: value,
|
|
2098
|
+
rootValue: node.root,
|
|
2099
|
+
lazy: true
|
|
2100
|
+
};
|
|
2101
|
+
if (this.expression.evaluate(filterContext)) {
|
|
2102
|
+
yield new JSONPathNode(value, node.location.concat(key), node.root);
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
1970
2107
|
}
|
|
1971
2108
|
toString() {
|
|
1972
2109
|
return `?${this.expression.toString()}`;
|
|
@@ -1983,10 +2120,19 @@ class BracketedSelection extends JSONPathSelector {
|
|
|
1983
2120
|
const rv = [];
|
|
1984
2121
|
for (const node of nodes) {
|
|
1985
2122
|
for (const item of this.items) {
|
|
1986
|
-
|
|
2123
|
+
for (const _node of item.resolve([node])) {
|
|
2124
|
+
rv.push(_node);
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
return rv;
|
|
2129
|
+
}
|
|
2130
|
+
*lazyResolve(nodes) {
|
|
2131
|
+
for (const node of nodes) {
|
|
2132
|
+
for (const item of this.items) {
|
|
2133
|
+
yield* item.lazyResolve([node]);
|
|
1987
2134
|
}
|
|
1988
2135
|
}
|
|
1989
|
-
return new JSONPathNodeList(rv);
|
|
1990
2136
|
}
|
|
1991
2137
|
toString() {
|
|
1992
2138
|
return `[${this.items.map(itm => itm.toString()).join(", ")}]`;
|
|
@@ -2025,10 +2171,23 @@ class JSONPath {
|
|
|
2025
2171
|
* @returns
|
|
2026
2172
|
*/
|
|
2027
2173
|
query(value) {
|
|
2028
|
-
let nodes =
|
|
2174
|
+
let nodes = [new JSONPathNode(value, [], value)];
|
|
2029
2175
|
for (const selector of this.selectors) {
|
|
2030
2176
|
nodes = selector.resolve(nodes);
|
|
2031
2177
|
}
|
|
2178
|
+
return new JSONPathNodeList(nodes);
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
/**
|
|
2182
|
+
*
|
|
2183
|
+
* @param value -
|
|
2184
|
+
* @returns
|
|
2185
|
+
*/
|
|
2186
|
+
lazyQuery(value) {
|
|
2187
|
+
let nodes = [new JSONPathNode(value, [], value)][Symbol.iterator]();
|
|
2188
|
+
for (const selector of this.selectors) {
|
|
2189
|
+
nodes = selector.lazyResolve(nodes);
|
|
2190
|
+
}
|
|
2032
2191
|
return nodes;
|
|
2033
2192
|
}
|
|
2034
2193
|
|
|
@@ -2041,7 +2200,10 @@ class JSONPath {
|
|
|
2041
2200
|
* there are no matches.
|
|
2042
2201
|
*/
|
|
2043
2202
|
match(value) {
|
|
2044
|
-
|
|
2203
|
+
const it = this.lazyQuery(value);
|
|
2204
|
+
const rv = it.next();
|
|
2205
|
+
if (rv.done) return undefined;
|
|
2206
|
+
return rv.value;
|
|
2045
2207
|
}
|
|
2046
2208
|
|
|
2047
2209
|
/**
|
|
@@ -2061,13 +2223,17 @@ class JSONPath {
|
|
|
2061
2223
|
}
|
|
2062
2224
|
|
|
2063
2225
|
const PRECEDENCE_LOWEST = 1;
|
|
2064
|
-
const PRECEDENCE_LOGICALRIGHT = 3;
|
|
2065
2226
|
const PRECEDENCE_LOGICAL_AND = 4;
|
|
2066
2227
|
const PRECEDENCE_LOGICAL_OR = 5;
|
|
2067
2228
|
const PRECEDENCE_COMPARISON = 6;
|
|
2068
|
-
const
|
|
2229
|
+
const PRECEDENCE_PREFIX = 7;
|
|
2230
|
+
const PRECEDENCES = new Map([[TokenKind.AND, PRECEDENCE_LOGICAL_AND], [TokenKind.EQ, PRECEDENCE_COMPARISON], [TokenKind.GE, PRECEDENCE_COMPARISON], [TokenKind.GT, PRECEDENCE_COMPARISON], [TokenKind.LE, PRECEDENCE_COMPARISON], [TokenKind.LT, PRECEDENCE_COMPARISON], [TokenKind.NE, PRECEDENCE_COMPARISON], [TokenKind.NOT, PRECEDENCE_PREFIX], [TokenKind.OR, PRECEDENCE_LOGICAL_OR], [TokenKind.RPAREN, PRECEDENCE_LOWEST]]);
|
|
2069
2231
|
const BINARY_OPERATORS = new Map([[TokenKind.AND, "&&"], [TokenKind.EQ, "=="], [TokenKind.GE, ">="], [TokenKind.GT, ">"], [TokenKind.LE, "<="], [TokenKind.LT, "<"], [TokenKind.NE, "!="], [TokenKind.OR, "||"]]);
|
|
2070
2232
|
const COMPARISON_OPERATORS = new Set(["==", ">=", ">", "<=", "<", "!="]);
|
|
2233
|
+
|
|
2234
|
+
/**
|
|
2235
|
+
* JSONPath token stream parser.
|
|
2236
|
+
*/
|
|
2071
2237
|
class Parser {
|
|
2072
2238
|
constructor(environment) {
|
|
2073
2239
|
this.environment = environment;
|
|
@@ -2084,30 +2250,41 @@ class Parser {
|
|
|
2084
2250
|
parsePath(stream) {
|
|
2085
2251
|
let inFilter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
2086
2252
|
const selectors = [];
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
break;
|
|
2095
|
-
case TokenKind.DDOT:
|
|
2096
|
-
selectors.push(new RecursiveDescentSegment(this.environment, stream.current));
|
|
2097
|
-
break;
|
|
2098
|
-
case TokenKind.LBRACKET:
|
|
2099
|
-
selectors.push(this.parseBracketedSelection(stream));
|
|
2100
|
-
break;
|
|
2101
|
-
default:
|
|
2102
|
-
if (inFilter) {
|
|
2103
|
-
stream.backup();
|
|
2104
|
-
}
|
|
2105
|
-
break loop;
|
|
2253
|
+
for (;;) {
|
|
2254
|
+
const selector = this.parseSegment(stream);
|
|
2255
|
+
if (!selector) {
|
|
2256
|
+
if (inFilter) {
|
|
2257
|
+
stream.backup();
|
|
2258
|
+
}
|
|
2259
|
+
break;
|
|
2106
2260
|
}
|
|
2261
|
+
selectors.push(selector);
|
|
2107
2262
|
stream.next();
|
|
2108
2263
|
}
|
|
2109
2264
|
return selectors;
|
|
2110
2265
|
}
|
|
2266
|
+
parseSegment(stream) {
|
|
2267
|
+
switch (stream.current.kind) {
|
|
2268
|
+
case TokenKind.NAME:
|
|
2269
|
+
return new NameSelector(this.environment, stream.current, stream.current.value, true);
|
|
2270
|
+
case TokenKind.WILD:
|
|
2271
|
+
return new WildcardSelector(this.environment, stream.current, true);
|
|
2272
|
+
case TokenKind.DDOT:
|
|
2273
|
+
{
|
|
2274
|
+
const segmentToken = stream.current;
|
|
2275
|
+
stream.next();
|
|
2276
|
+
const selector = this.parseSegment(stream);
|
|
2277
|
+
if (!selector) {
|
|
2278
|
+
throw new JSONPathSyntaxError("bald descendant segment", stream.current);
|
|
2279
|
+
}
|
|
2280
|
+
return new RecursiveDescentSegment(this.environment, segmentToken, selector);
|
|
2281
|
+
}
|
|
2282
|
+
case TokenKind.LBRACKET:
|
|
2283
|
+
return this.parseBracketedSelection(stream);
|
|
2284
|
+
default:
|
|
2285
|
+
return null;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2111
2288
|
parseIndex(stream) {
|
|
2112
2289
|
if (stream.current.value.length > 1 && stream.current.value.startsWith("0") || stream.current.value.startsWith("-0")) {
|
|
2113
2290
|
throw new JSONPathSyntaxError("leading zero in index selector", stream.current);
|
|
@@ -2228,7 +2405,7 @@ class Parser {
|
|
|
2228
2405
|
parsePrefixExpression(stream) {
|
|
2229
2406
|
stream.expect(TokenKind.NOT);
|
|
2230
2407
|
stream.next();
|
|
2231
|
-
return new PrefixExpression(stream.current, "!", this.parseFilterExpression(stream,
|
|
2408
|
+
return new PrefixExpression(stream.current, "!", this.parseFilterExpression(stream, PRECEDENCE_PREFIX));
|
|
2232
2409
|
}
|
|
2233
2410
|
parseInfixExpression(stream, left) {
|
|
2234
2411
|
const tok = stream.next();
|
|
@@ -2350,7 +2527,10 @@ class Parser {
|
|
|
2350
2527
|
*/
|
|
2351
2528
|
|
|
2352
2529
|
/**
|
|
2530
|
+
* A configuration object from which JSONPath queries can be evaluated.
|
|
2353
2531
|
*
|
|
2532
|
+
* An environment is where you'd register custom function extensions or set
|
|
2533
|
+
* the maximum recursion depth limit, for example.
|
|
2354
2534
|
*/
|
|
2355
2535
|
class JSONPathEnvironment {
|
|
2356
2536
|
/**
|
|
@@ -2383,8 +2563,7 @@ class JSONPathEnvironment {
|
|
|
2383
2563
|
*/
|
|
2384
2564
|
functionRegister = new Map();
|
|
2385
2565
|
/**
|
|
2386
|
-
*
|
|
2387
|
-
* @param options -
|
|
2566
|
+
* @param options - Environment configuration options.
|
|
2388
2567
|
*/
|
|
2389
2568
|
constructor() {
|
|
2390
2569
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -2397,9 +2576,8 @@ class JSONPathEnvironment {
|
|
|
2397
2576
|
}
|
|
2398
2577
|
|
|
2399
2578
|
/**
|
|
2400
|
-
*
|
|
2401
|
-
* @
|
|
2402
|
-
* @returns
|
|
2579
|
+
* @param path - A JSONPath query to parse.
|
|
2580
|
+
* @returns A new {@link JSONPath} object, bound to this environment.
|
|
2403
2581
|
*/
|
|
2404
2582
|
compile(path) {
|
|
2405
2583
|
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(path))));
|
|
@@ -2407,14 +2585,28 @@ class JSONPathEnvironment {
|
|
|
2407
2585
|
|
|
2408
2586
|
/**
|
|
2409
2587
|
*
|
|
2410
|
-
* @param path -
|
|
2411
|
-
* @param value -
|
|
2412
|
-
* @returns
|
|
2588
|
+
* @param path - A JSONPath query to parse and evaluate against _value_.
|
|
2589
|
+
* @param value - Data to which _path_ will be applied.
|
|
2590
|
+
* @returns The {@link JSONPathNodeList} resulting from applying _path_
|
|
2591
|
+
* to _value_.
|
|
2413
2592
|
*/
|
|
2414
2593
|
query(path, value) {
|
|
2415
2594
|
return this.compile(path).query(value);
|
|
2416
2595
|
}
|
|
2417
2596
|
|
|
2597
|
+
/**
|
|
2598
|
+
* A lazy version of {@link query} which is faster and more memory
|
|
2599
|
+
* efficient when querying some large datasets.
|
|
2600
|
+
*
|
|
2601
|
+
* @param path - A JSONPath query to parse and evaluate against _value_.
|
|
2602
|
+
* @param value - Data to which _path_ will be applied.
|
|
2603
|
+
* @returns A sequence of {@link JSONPathNode} objects resulting from
|
|
2604
|
+
* applying _path_ to _value_.
|
|
2605
|
+
*/
|
|
2606
|
+
lazyQuery(path, value) {
|
|
2607
|
+
return this.compile(path).lazyQuery(value);
|
|
2608
|
+
}
|
|
2609
|
+
|
|
2418
2610
|
/**
|
|
2419
2611
|
* Return a {@link JSONPathNode} instance for the first object found in
|
|
2420
2612
|
* _value_ matching _path_.
|
|
@@ -2427,6 +2619,11 @@ class JSONPathEnvironment {
|
|
|
2427
2619
|
match(path, value) {
|
|
2428
2620
|
return this.compile(path).match(value);
|
|
2429
2621
|
}
|
|
2622
|
+
|
|
2623
|
+
/**
|
|
2624
|
+
* A hook for setting up the function register. You are encouraged to
|
|
2625
|
+
* override this method in classes extending `JSONPathEnvironment`.
|
|
2626
|
+
*/
|
|
2430
2627
|
setupFilterFunctions() {
|
|
2431
2628
|
this.functionRegister.set("count", new Count());
|
|
2432
2629
|
this.functionRegister.set("length", new Length());
|
|
@@ -2436,9 +2633,18 @@ class JSONPathEnvironment {
|
|
|
2436
2633
|
}
|
|
2437
2634
|
|
|
2438
2635
|
/**
|
|
2636
|
+
* Check the well-typedness of a function's arguments at compile-time.
|
|
2637
|
+
*
|
|
2638
|
+
* This method is called by the {@link Parser} when parsing function calls.
|
|
2639
|
+
* It is expected to throw a {@link JSONPathTypeError} if the function's
|
|
2640
|
+
* parameters are not well-typed.
|
|
2641
|
+
*
|
|
2642
|
+
* Override this if you want to deviate from the JSONPath Spec's function
|
|
2643
|
+
* extension type system.
|
|
2439
2644
|
*
|
|
2440
|
-
* @param token -
|
|
2441
|
-
*
|
|
2645
|
+
* @param token - The {@link Token} starting the function call. `Token.value`
|
|
2646
|
+
* will contain the name of the function.
|
|
2647
|
+
* @param args - One {@link FilterExpression} for each argument.
|
|
2442
2648
|
*/
|
|
2443
2649
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
2444
2650
|
checkWellTypedness(token, args) {
|
|
@@ -2505,6 +2711,27 @@ function query(path, value) {
|
|
|
2505
2711
|
return DEFAULT_ENVIRONMENT.query(path, value);
|
|
2506
2712
|
}
|
|
2507
2713
|
|
|
2714
|
+
/**
|
|
2715
|
+
* Lazily query JSON value _value_ with JSONPath expression _path_.
|
|
2716
|
+
* Lazy queries can be faster and more memory efficient when querying
|
|
2717
|
+
* large datasets, especially when using recursive decent selectors.
|
|
2718
|
+
*
|
|
2719
|
+
* @param path - A JSONPath expression/query.
|
|
2720
|
+
* @param value - The JSON-like value the JSONPath query is applied to.
|
|
2721
|
+
* @returns A sequence of {@link JSONPathNode} objects resulting from
|
|
2722
|
+
* applying _path_ to _value_.
|
|
2723
|
+
*
|
|
2724
|
+
* @throws {@link JSONPathSyntaxError}
|
|
2725
|
+
* If the path does not conform to standard syntax.
|
|
2726
|
+
*
|
|
2727
|
+
* @throws {@link JSONPathTypeError}
|
|
2728
|
+
* If filter function arguments are invalid, or filter expression are
|
|
2729
|
+
* used in an invalid way.
|
|
2730
|
+
*/
|
|
2731
|
+
function lazyQuery(path, value) {
|
|
2732
|
+
return DEFAULT_ENVIRONMENT.lazyQuery(path, value);
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2508
2735
|
/**
|
|
2509
2736
|
* Compile JSONPath _path_ for later use.
|
|
2510
2737
|
* @param path - A JSONPath expression/query.
|
|
@@ -2554,6 +2781,7 @@ var index$1 = /*#__PURE__*/Object.freeze({
|
|
|
2554
2781
|
compile: compile,
|
|
2555
2782
|
expressions: expression,
|
|
2556
2783
|
functions: index$2,
|
|
2784
|
+
lazyQuery: lazyQuery,
|
|
2557
2785
|
match: match,
|
|
2558
2786
|
query: query,
|
|
2559
2787
|
selectors: selectors
|
|
@@ -3039,7 +3267,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
3039
3267
|
apply: apply
|
|
3040
3268
|
});
|
|
3041
3269
|
|
|
3042
|
-
const version = "0.
|
|
3270
|
+
const version = "0.3.0";
|
|
3043
3271
|
|
|
3044
3272
|
exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
|
|
3045
3273
|
exports.FunctionExpressionType = FunctionExpressionType;
|
|
@@ -3067,6 +3295,7 @@ exports.compile = compile;
|
|
|
3067
3295
|
exports.jsonpatch = index;
|
|
3068
3296
|
exports.jsonpath = index$1;
|
|
3069
3297
|
exports.jsonpointer = index$3;
|
|
3298
|
+
exports.lazyQuery = lazyQuery;
|
|
3070
3299
|
exports.query = query;
|
|
3071
3300
|
exports.resolve = resolve;
|
|
3072
3301
|
exports.version = version;
|