@jmespath-community/jmespath 1.1.5 → 1.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 +107 -72
- package/dist/jmespath.esm.js +87 -69
- package/dist/jmespath.esm.min.js +1 -1
- package/dist/jmespath.esm.min.js.map +1 -1
- package/dist/jmespath.umd.js +87 -69
- package/dist/jmespath.umd.min.js +1 -1
- package/dist/jmespath.umd.min.js.map +1 -1
- package/dist/lib/bin/jp.js +127 -0
- package/dist/lib/bin/jp.js.map +1 -0
- package/dist/lib/package.json +70 -0
- package/dist/lib/{AST.type.js.map → src/AST.type.js.map} +1 -1
- package/dist/lib/{JSON.type.js.map → src/JSON.type.js.map} +1 -1
- package/dist/lib/{Lexer.js → src/Lexer.js} +2 -1
- package/dist/lib/src/Lexer.js.map +1 -0
- package/dist/lib/{Lexer.type.js → src/Lexer.type.js} +1 -0
- package/dist/lib/src/Lexer.type.js.map +1 -0
- package/dist/lib/{Parser.js → src/Parser.js} +17 -8
- package/dist/lib/src/Parser.js.map +1 -0
- package/dist/lib/{Parser.type.js.map → src/Parser.type.js.map} +1 -1
- package/dist/lib/{Runtime.js → src/Runtime.js} +1 -1
- package/dist/lib/src/Runtime.js.map +1 -0
- package/dist/lib/src/Scope.js.map +1 -0
- package/dist/lib/{TreeInterpreter.js → src/TreeInterpreter.js} +12 -5
- package/dist/lib/src/TreeInterpreter.js.map +1 -0
- package/dist/lib/{index.js → src/index.js} +2 -4
- package/dist/lib/src/index.js.map +1 -0
- package/dist/lib/{utils → src/utils}/index.js +12 -11
- package/dist/lib/src/utils/index.js.map +1 -0
- package/dist/lib/src/utils/strings.js.map +1 -0
- package/dist/lib/{utils → src/utils}/text.js +1 -0
- package/dist/lib/src/utils/text.js.map +1 -0
- package/dist/types/bin/jp.d.ts +2 -0
- package/dist/types/{AST.type.d.ts → src/AST.type.d.ts} +7 -1
- package/dist/types/{Lexer.type.d.ts → src/Lexer.type.d.ts} +2 -1
- package/dist/types/{Runtime.d.ts → src/Runtime.d.ts} +1 -1
- package/dist/types/{index.d.ts → src/index.d.ts} +3 -3
- package/package.json +4 -1
- package/dist/lib/Lexer.js.map +0 -1
- package/dist/lib/Lexer.type.js.map +0 -1
- package/dist/lib/Parser.js.map +0 -1
- package/dist/lib/Runtime.js.map +0 -1
- package/dist/lib/Scope.js.map +0 -1
- package/dist/lib/TreeInterpreter.js.map +0 -1
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/utils/index.js.map +0 -1
- package/dist/lib/utils/strings.js.map +0 -1
- package/dist/lib/utils/text.js.map +0 -1
- /package/dist/lib/{AST.type.js → src/AST.type.js} +0 -0
- /package/dist/lib/{JSON.type.js → src/JSON.type.js} +0 -0
- /package/dist/lib/{Parser.type.js → src/Parser.type.js} +0 -0
- /package/dist/lib/{Scope.js → src/Scope.js} +0 -0
- /package/dist/lib/{utils → src/utils}/strings.js +0 -0
- /package/dist/types/{JSON.type.d.ts → src/JSON.type.d.ts} +0 -0
- /package/dist/types/{Lexer.d.ts → src/Lexer.d.ts} +0 -0
- /package/dist/types/{Parser.d.ts → src/Parser.d.ts} +0 -0
- /package/dist/types/{Parser.type.d.ts → src/Parser.type.d.ts} +0 -0
- /package/dist/types/{Scope.d.ts → src/Scope.d.ts} +0 -0
- /package/dist/types/{TreeInterpreter.d.ts → src/TreeInterpreter.d.ts} +0 -0
- /package/dist/types/{utils → src/utils}/index.d.ts +0 -0
- /package/dist/types/{utils → src/utils}/strings.d.ts +0 -0
- /package/dist/types/{utils → src/utils}/text.d.ts +0 -0
package/README.md
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
# @jmespath-community/jmespath
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
@jmespath-community/jmespath is a **TypeScript** implementation of the [JMESPath](https://jmespath.site/) spec.
|
|
7
6
|
|
|
8
7
|
JMESPath is a query language for JSON. It will take a JSON document
|
|
@@ -20,12 +19,9 @@ npm install @jmespath-community/jmespath
|
|
|
20
19
|
### `search(data: JSONValue, expression: string): JSONValue`
|
|
21
20
|
|
|
22
21
|
```javascript
|
|
23
|
-
import { search } from
|
|
22
|
+
import { search } from "@jmespath-community/jmespath";
|
|
24
23
|
|
|
25
|
-
search(
|
|
26
|
-
{foo: {bar: {baz: [0, 1, 2, 3, 4]}}},
|
|
27
|
-
"foo.bar.baz[2]"
|
|
28
|
-
);
|
|
24
|
+
search({ foo: { bar: { baz: [0, 1, 2, 3, 4] } } }, "foo.bar.baz[2]");
|
|
29
25
|
|
|
30
26
|
// OUTPUTS: 2
|
|
31
27
|
```
|
|
@@ -35,50 +31,42 @@ In the example we gave the `search` function input data of
|
|
|
35
31
|
expression `foo.bar.baz[2]`, and the `search` function evaluated
|
|
36
32
|
the expression against the input data to produce the result `2`.
|
|
37
33
|
|
|
38
|
-
The JMESPath language can do
|
|
39
|
-
from a list.
|
|
34
|
+
The JMESPath language can do _a lot_ more than select an element
|
|
35
|
+
from a list. Here are a few more examples:
|
|
40
36
|
|
|
41
37
|
```javascript
|
|
42
|
-
import { search } from
|
|
38
|
+
import { search } from "@jmespath-community/jmespath";
|
|
43
39
|
|
|
44
40
|
/* --- EXAMPLE 1 --- */
|
|
45
41
|
|
|
46
42
|
let JSON_DOCUMENT = {
|
|
47
43
|
foo: {
|
|
48
44
|
bar: {
|
|
49
|
-
baz: [0, 1, 2, 3, 4]
|
|
50
|
-
}
|
|
51
|
-
}
|
|
45
|
+
baz: [0, 1, 2, 3, 4],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
52
48
|
};
|
|
53
49
|
|
|
54
50
|
search(JSON_DOCUMENT, "foo.bar");
|
|
55
51
|
// OUTPUTS: { baz: [ 0, 1, 2, 3, 4 ] }
|
|
56
52
|
|
|
57
|
-
|
|
58
53
|
/* --- EXAMPLE 2 --- */
|
|
59
54
|
|
|
60
55
|
JSON_DOCUMENT = {
|
|
61
|
-
|
|
62
|
-
{
|
|
63
|
-
{
|
|
64
|
-
]
|
|
56
|
+
foo: [
|
|
57
|
+
{ first: "a", last: "b" },
|
|
58
|
+
{ first: "c", last: "d" },
|
|
59
|
+
],
|
|
65
60
|
};
|
|
66
61
|
|
|
67
|
-
search(JSON_DOCUMENT, "foo[*].first")
|
|
62
|
+
search(JSON_DOCUMENT, "foo[*].first");
|
|
68
63
|
// OUTPUTS: [ 'a', 'c' ]
|
|
69
64
|
|
|
70
|
-
|
|
71
65
|
/* --- EXAMPLE 3 --- */
|
|
72
66
|
|
|
73
67
|
JSON_DOCUMENT = {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
{"age": 25},
|
|
77
|
-
{"age": 30},
|
|
78
|
-
{"age": 35},
|
|
79
|
-
{"age": 40}
|
|
80
|
-
]
|
|
81
|
-
}
|
|
68
|
+
foo: [{ age: 20 }, { age: 25 }, { age: 30 }, { age: 35 }, { age: 40 }],
|
|
69
|
+
};
|
|
82
70
|
|
|
83
71
|
search(JSON_DOCUMENT, "foo[?age > `30`]");
|
|
84
72
|
// OUTPUTS: [ { age: 35 }, { age: 40 } ]
|
|
@@ -86,91 +74,138 @@ search(JSON_DOCUMENT, "foo[?age > `30`]");
|
|
|
86
74
|
|
|
87
75
|
### `compile(expression: string): ExpressionNodeTree`
|
|
88
76
|
|
|
89
|
-
You can precompile all your expressions ready for use later on.
|
|
77
|
+
You can precompile all your expressions ready for use later on. The `compile`
|
|
90
78
|
function takes a JMESPath expression and returns an abstract syntax tree that
|
|
91
79
|
can be used by the TreeInterpreter function
|
|
92
80
|
|
|
93
81
|
```javascript
|
|
94
|
-
import { compile, TreeInterpreter } from
|
|
82
|
+
import { compile, TreeInterpreter } from "@jmespath-community/jmespath";
|
|
95
83
|
|
|
96
|
-
const ast = compile(
|
|
84
|
+
const ast = compile("foo.bar");
|
|
97
85
|
|
|
98
|
-
TreeInterpreter.search(ast, {foo: {bar:
|
|
86
|
+
TreeInterpreter.search(ast, { foo: { bar: "BAZ" } });
|
|
99
87
|
// RETURNS: "BAZ"
|
|
100
|
-
|
|
101
88
|
```
|
|
102
89
|
|
|
103
90
|
---
|
|
91
|
+
|
|
104
92
|
## EXTENSIONS TO ORIGINAL SPEC
|
|
105
93
|
|
|
106
94
|
1. ### Register you own custom functions
|
|
107
95
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Extend the list of built in JMESpath expressions with your own functions.
|
|
111
|
-
|
|
112
|
-
```javascript
|
|
113
|
-
import {search, registerFunction, TYPE_NUMBER} from '@jmespath-community/jmespath'
|
|
114
|
-
|
|
96
|
+
#### `registerFunction(functionName: string, customFunction: RuntimeFunction, signature: InputSignature[]): void`
|
|
115
97
|
|
|
116
|
-
|
|
117
|
-
// THROWS ERROR: Error: Unknown function: divide()
|
|
98
|
+
Extend the list of built in JMESpath expressions with your own functions.
|
|
118
99
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
(resolvedArgs) => { // CUSTOM FUNCTION
|
|
122
|
-
const [dividend, divisor] = resolvedArgs;
|
|
123
|
-
return dividend / divisor;
|
|
124
|
-
},
|
|
125
|
-
[{ types: [TYPE_NUMBER] }, { types: [TYPE_NUMBER] }] //SIGNATURE
|
|
126
|
-
);
|
|
100
|
+
```javascript
|
|
101
|
+
import { search, registerFunction, TYPE_NUMBER } from "@jmespath-community/jmespath";
|
|
127
102
|
|
|
128
|
-
|
|
129
|
-
|
|
103
|
+
search({ foo: 60, bar: 10 }, "divide(foo, bar)");
|
|
104
|
+
// THROWS ERROR: Error: Unknown function: divide()
|
|
130
105
|
|
|
131
|
-
|
|
106
|
+
registerFunction(
|
|
107
|
+
"divide", // FUNCTION NAME
|
|
108
|
+
(resolvedArgs) => {
|
|
109
|
+
// CUSTOM FUNCTION
|
|
110
|
+
const [dividend, divisor] = resolvedArgs;
|
|
111
|
+
return dividend / divisor;
|
|
112
|
+
},
|
|
113
|
+
[{ types: [TYPE_NUMBER] }, { types: [TYPE_NUMBER] }], //SIGNATURE
|
|
114
|
+
);
|
|
132
115
|
|
|
133
|
-
|
|
116
|
+
search({ foo: 60, bar: 10 }, "divide(foo, bar)");
|
|
117
|
+
// OUTPUTS: 6
|
|
118
|
+
```
|
|
134
119
|
|
|
120
|
+
Optional arguments are supported by setting `{..., optional: true}` in argument signatures
|
|
135
121
|
|
|
136
|
-
|
|
122
|
+
```javascript
|
|
123
|
+
registerFunction(
|
|
124
|
+
"divide",
|
|
125
|
+
(resolvedArgs) => {
|
|
126
|
+
const [dividend, divisor] = resolvedArgs;
|
|
127
|
+
return dividend / divisor ?? 1; //OPTIONAL DIVISOR THAT DEFAULTS TO 1
|
|
128
|
+
},
|
|
129
|
+
[{ types: [TYPE_NUMBER] }, { types: [TYPE_NUMBER], optional: true }], //SIGNATURE
|
|
130
|
+
);
|
|
137
131
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const [dividend, divisor] = resolvedArgs;
|
|
142
|
-
return dividend / divisor ?? 1; //OPTIONAL DIVISOR THAT DEFAULTS TO 1
|
|
143
|
-
},
|
|
144
|
-
[{ types: [TYPE_NUMBER] }, { types: [TYPE_NUMBER], optional: true }] //SIGNATURE
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
search({ foo: 60, bar: 10 }, 'divide(foo)');
|
|
148
|
-
// OUTPUTS: 60
|
|
149
|
-
|
|
150
|
-
```
|
|
132
|
+
search({ foo: 60, bar: 10 }, "divide(foo)");
|
|
133
|
+
// OUTPUTS: 60
|
|
134
|
+
```
|
|
151
135
|
|
|
152
136
|
2. ### Root value access with `$` symbol
|
|
153
137
|
|
|
154
138
|
```javascript
|
|
155
|
-
|
|
156
|
-
search({foo: {bar: 999}, baz: [1, 2, 3]}, '$.baz[*].[@, $.foo.bar]')
|
|
139
|
+
search({ foo: { bar: 999 }, baz: [1, 2, 3] }, "$.baz[*].[@, $.foo.bar]");
|
|
157
140
|
|
|
158
141
|
// OUTPUTS:
|
|
159
142
|
// [ [ 1, 999 ], [ 2, 999 ], [ 3, 999 ] ]
|
|
160
143
|
```
|
|
161
144
|
|
|
162
|
-
|
|
163
145
|
## More Resources
|
|
164
146
|
|
|
165
147
|
The example above only show a small amount of what
|
|
166
148
|
a JMESPath expression can do. If you want to take a
|
|
167
|
-
tour of the language, the
|
|
149
|
+
tour of the language, the _best_ place to go is the
|
|
168
150
|
[JMESPath Tutorial](http://jmespath.site/main#tutorial).
|
|
169
151
|
|
|
170
152
|
One of the best things about JMESPath is that it is
|
|
171
153
|
implemented in many different programming languages including
|
|
172
|
-
python, ruby, php, lua, etc.
|
|
154
|
+
python, ruby, php, lua, etc. To see a complete list of libraries,
|
|
173
155
|
check out the [JMESPath libraries page](http://jmespath.site/main#libraries).
|
|
174
156
|
|
|
175
157
|
And finally, the full JMESPath specification can be found
|
|
176
158
|
on the [JMESPath site](https://jmespath.site/main/#specification).
|
|
159
|
+
|
|
160
|
+
## Experimental Features
|
|
161
|
+
|
|
162
|
+
### Ternary Operations (`? :`)
|
|
163
|
+
|
|
164
|
+
**Supported Version:** 1.1.6
|
|
165
|
+
|
|
166
|
+
Experimental support for [ternary operations](https://github.com/jmespath-community/jmespath.spec/discussions/179) has been added, allowing for conditional logic within your JMESPath expressions. The syntax is `condition ? value_if_true : value_if_false`.
|
|
167
|
+
|
|
168
|
+
- **Condition:** The expression before the `?`. JMESPath determines truthiness based on the evaluated value:
|
|
169
|
+
- `true` is truthy.
|
|
170
|
+
- Any non-empty object, array, or string is truthy.
|
|
171
|
+
- Any non-zero number is truthy.
|
|
172
|
+
- `false`, `null`, empty objects `{}`, empty arrays `[]`, and empty strings `''` are falsy.
|
|
173
|
+
- **Value if true:** The expression between the `?` and `:`. This is evaluated and returned if the condition is truthy.
|
|
174
|
+
- **Value if false:** The expression after the `:`. This is evaluated and returned if the condition is falsy.
|
|
175
|
+
|
|
176
|
+
**Examples:**
|
|
177
|
+
|
|
178
|
+
Basic usage:
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
search({ is_active: true, user: "Alice" }, "is_active ? user : 'Guest'");
|
|
182
|
+
// OUTPUTS: "Alice"
|
|
183
|
+
|
|
184
|
+
search({ is_active: false, user: "Bob" }, "is_active ? user : 'Guest'");
|
|
185
|
+
// OUTPUTS: "Guest"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Truthiness with different types:
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
search({ data: [1, 2] }, "data ? 'has_data' : 'no_data'");
|
|
192
|
+
// OUTPUTS: "has_data"
|
|
193
|
+
|
|
194
|
+
search({ data: [] }, "data ? 'has_data' : 'no_data'");
|
|
195
|
+
// OUTPUTS: "no_data"
|
|
196
|
+
|
|
197
|
+
search({ count: 5 }, "count ? 'count_present' : 'no_count'");
|
|
198
|
+
// OUTPUTS: "count_present"
|
|
199
|
+
|
|
200
|
+
search({ count: 0 }, "count ? 'count_present' : 'no_count'");
|
|
201
|
+
// OUTPUTS: "no_count"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Nested Ternaries:
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
search({ a: true, b: false, val1: 10, val2: 20, val3: 30 }, "a ? (b ? val1 : val2) : val3");
|
|
208
|
+
// OUTPUTS: 20
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
This feature is currently experimental and its syntax or behavior might change in future releases.
|
package/dist/jmespath.esm.js
CHANGED
|
@@ -1,3 +1,46 @@
|
|
|
1
|
+
var Token;
|
|
2
|
+
(function (Token) {
|
|
3
|
+
Token["TOK_EOF"] = "EOF";
|
|
4
|
+
Token["TOK_VARIABLE"] = "Variable";
|
|
5
|
+
Token["TOK_ASSIGN"] = "Assign";
|
|
6
|
+
Token["TOK_UNQUOTEDIDENTIFIER"] = "UnquotedIdentifier";
|
|
7
|
+
Token["TOK_QUOTEDIDENTIFIER"] = "QuotedIdentifier";
|
|
8
|
+
Token["TOK_RBRACKET"] = "Rbracket";
|
|
9
|
+
Token["TOK_RPAREN"] = "Rparen";
|
|
10
|
+
Token["TOK_COMMA"] = "Comma";
|
|
11
|
+
Token["TOK_COLON"] = "Colon";
|
|
12
|
+
Token["TOK_RBRACE"] = "Rbrace";
|
|
13
|
+
Token["TOK_NUMBER"] = "Number";
|
|
14
|
+
Token["TOK_CURRENT"] = "Current";
|
|
15
|
+
Token["TOK_ROOT"] = "Root";
|
|
16
|
+
Token["TOK_EXPREF"] = "Expref";
|
|
17
|
+
Token["TOK_PIPE"] = "Pipe";
|
|
18
|
+
Token["TOK_OR"] = "Or";
|
|
19
|
+
Token["TOK_AND"] = "And";
|
|
20
|
+
Token["TOK_EQ"] = "EQ";
|
|
21
|
+
Token["TOK_GT"] = "GT";
|
|
22
|
+
Token["TOK_LT"] = "LT";
|
|
23
|
+
Token["TOK_GTE"] = "GTE";
|
|
24
|
+
Token["TOK_LTE"] = "LTE";
|
|
25
|
+
Token["TOK_NE"] = "NE";
|
|
26
|
+
Token["TOK_PLUS"] = "Plus";
|
|
27
|
+
Token["TOK_MINUS"] = "Minus";
|
|
28
|
+
Token["TOK_MULTIPLY"] = "Multiply";
|
|
29
|
+
Token["TOK_DIVIDE"] = "Divide";
|
|
30
|
+
Token["TOK_MODULO"] = "Modulo";
|
|
31
|
+
Token["TOK_DIV"] = "Div";
|
|
32
|
+
Token["TOK_FLATTEN"] = "Flatten";
|
|
33
|
+
Token["TOK_STAR"] = "Star";
|
|
34
|
+
Token["TOK_FILTER"] = "Filter";
|
|
35
|
+
Token["TOK_DOT"] = "Dot";
|
|
36
|
+
Token["TOK_NOT"] = "Not";
|
|
37
|
+
Token["TOK_LBRACE"] = "Lbrace";
|
|
38
|
+
Token["TOK_LBRACKET"] = "Lbracket";
|
|
39
|
+
Token["TOK_LPAREN"] = "Lparen";
|
|
40
|
+
Token["TOK_LITERAL"] = "Literal";
|
|
41
|
+
Token["TOK_QUESTION"] = "Question";
|
|
42
|
+
})(Token || (Token = {}));
|
|
43
|
+
|
|
1
44
|
const isObject = (obj) => {
|
|
2
45
|
return obj !== null && Object.prototype.toString.call(obj) === '[object Object]';
|
|
3
46
|
};
|
|
@@ -36,31 +79,32 @@ const strictDeepEqual = (first, second) => {
|
|
|
36
79
|
return false;
|
|
37
80
|
};
|
|
38
81
|
const isFalse = (obj) => {
|
|
82
|
+
// falsey values
|
|
83
|
+
if (obj === null || obj === undefined || obj === false) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
if (typeof obj === 'string') {
|
|
87
|
+
return obj === '';
|
|
88
|
+
}
|
|
39
89
|
if (typeof obj === 'object') {
|
|
40
|
-
if (obj === null) {
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
90
|
if (Array.isArray(obj)) {
|
|
44
91
|
return obj.length === 0;
|
|
45
92
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return false;
|
|
93
|
+
if (obj === null) {
|
|
94
|
+
return true;
|
|
49
95
|
}
|
|
50
|
-
|
|
96
|
+
// check if object is empty
|
|
97
|
+
return Object.keys(obj).length === 0;
|
|
51
98
|
}
|
|
52
|
-
return
|
|
99
|
+
return false;
|
|
53
100
|
};
|
|
54
101
|
const isAlpha = (ch) => {
|
|
55
|
-
// tslint:disable-next-line: strict-comparisons
|
|
56
102
|
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '_';
|
|
57
103
|
};
|
|
58
104
|
const isNum = (ch) => {
|
|
59
|
-
// tslint:disable-next-line: strict-comparisons
|
|
60
105
|
return (ch >= '0' && ch <= '9') || ch === '-';
|
|
61
106
|
};
|
|
62
107
|
const isAlphaNum = (ch) => {
|
|
63
|
-
// tslint:disable-next-line: strict-comparisons
|
|
64
108
|
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch === '_';
|
|
65
109
|
};
|
|
66
110
|
const ensureInteger = (value) => {
|
|
@@ -201,48 +245,6 @@ const trimImpl = (subject, regExper, chars) => {
|
|
|
201
245
|
};
|
|
202
246
|
const upper = (subject) => subject.toUpperCase();
|
|
203
247
|
|
|
204
|
-
var Token;
|
|
205
|
-
(function (Token) {
|
|
206
|
-
Token["TOK_EOF"] = "EOF";
|
|
207
|
-
Token["TOK_VARIABLE"] = "Variable";
|
|
208
|
-
Token["TOK_ASSIGN"] = "Assign";
|
|
209
|
-
Token["TOK_UNQUOTEDIDENTIFIER"] = "UnquotedIdentifier";
|
|
210
|
-
Token["TOK_QUOTEDIDENTIFIER"] = "QuotedIdentifier";
|
|
211
|
-
Token["TOK_RBRACKET"] = "Rbracket";
|
|
212
|
-
Token["TOK_RPAREN"] = "Rparen";
|
|
213
|
-
Token["TOK_COMMA"] = "Comma";
|
|
214
|
-
Token["TOK_COLON"] = "Colon";
|
|
215
|
-
Token["TOK_RBRACE"] = "Rbrace";
|
|
216
|
-
Token["TOK_NUMBER"] = "Number";
|
|
217
|
-
Token["TOK_CURRENT"] = "Current";
|
|
218
|
-
Token["TOK_ROOT"] = "Root";
|
|
219
|
-
Token["TOK_EXPREF"] = "Expref";
|
|
220
|
-
Token["TOK_PIPE"] = "Pipe";
|
|
221
|
-
Token["TOK_OR"] = "Or";
|
|
222
|
-
Token["TOK_AND"] = "And";
|
|
223
|
-
Token["TOK_EQ"] = "EQ";
|
|
224
|
-
Token["TOK_GT"] = "GT";
|
|
225
|
-
Token["TOK_LT"] = "LT";
|
|
226
|
-
Token["TOK_GTE"] = "GTE";
|
|
227
|
-
Token["TOK_LTE"] = "LTE";
|
|
228
|
-
Token["TOK_NE"] = "NE";
|
|
229
|
-
Token["TOK_PLUS"] = "Plus";
|
|
230
|
-
Token["TOK_MINUS"] = "Minus";
|
|
231
|
-
Token["TOK_MULTIPLY"] = "Multiply";
|
|
232
|
-
Token["TOK_DIVIDE"] = "Divide";
|
|
233
|
-
Token["TOK_MODULO"] = "Modulo";
|
|
234
|
-
Token["TOK_DIV"] = "Div";
|
|
235
|
-
Token["TOK_FLATTEN"] = "Flatten";
|
|
236
|
-
Token["TOK_STAR"] = "Star";
|
|
237
|
-
Token["TOK_FILTER"] = "Filter";
|
|
238
|
-
Token["TOK_DOT"] = "Dot";
|
|
239
|
-
Token["TOK_NOT"] = "Not";
|
|
240
|
-
Token["TOK_LBRACE"] = "Lbrace";
|
|
241
|
-
Token["TOK_LBRACKET"] = "Lbracket";
|
|
242
|
-
Token["TOK_LPAREN"] = "Lparen";
|
|
243
|
-
Token["TOK_LITERAL"] = "Literal";
|
|
244
|
-
})(Token || (Token = {}));
|
|
245
|
-
|
|
246
248
|
const basicTokens = {
|
|
247
249
|
'(': Token.TOK_LPAREN,
|
|
248
250
|
')': Token.TOK_RPAREN,
|
|
@@ -256,6 +258,7 @@ const basicTokens = {
|
|
|
256
258
|
'}': Token.TOK_RBRACE,
|
|
257
259
|
'+': Token.TOK_PLUS,
|
|
258
260
|
'%': Token.TOK_MODULO,
|
|
261
|
+
'?': Token.TOK_QUESTION,
|
|
259
262
|
'\u2212': Token.TOK_MINUS,
|
|
260
263
|
'\u00d7': Token.TOK_MULTIPLY,
|
|
261
264
|
'\u00f7': Token.TOK_DIVIDE,
|
|
@@ -577,8 +580,9 @@ const bindingPower = {
|
|
|
577
580
|
[Token.TOK_ROOT]: 0,
|
|
578
581
|
[Token.TOK_ASSIGN]: 1,
|
|
579
582
|
[Token.TOK_PIPE]: 1,
|
|
580
|
-
[Token.
|
|
581
|
-
[Token.
|
|
583
|
+
[Token.TOK_QUESTION]: 2,
|
|
584
|
+
[Token.TOK_OR]: 3,
|
|
585
|
+
[Token.TOK_AND]: 4,
|
|
582
586
|
[Token.TOK_EQ]: 5,
|
|
583
587
|
[Token.TOK_GT]: 5,
|
|
584
588
|
[Token.TOK_LT]: 5,
|
|
@@ -685,8 +689,7 @@ class TokenParser {
|
|
|
685
689
|
}
|
|
686
690
|
case Token.TOK_STAR: {
|
|
687
691
|
const left = { type: 'Identity' };
|
|
688
|
-
|
|
689
|
-
return { type: 'ValueProjection', left, right };
|
|
692
|
+
return { type: 'ValueProjection', left, right: this.parseProjectionRHS(bindingPower.Star) };
|
|
690
693
|
}
|
|
691
694
|
case Token.TOK_FILTER:
|
|
692
695
|
return this.led(token.type, { type: 'Identity' });
|
|
@@ -726,11 +729,9 @@ class TokenParser {
|
|
|
726
729
|
return { type: 'ExpressionReference', child };
|
|
727
730
|
}
|
|
728
731
|
case Token.TOK_LPAREN: {
|
|
729
|
-
const
|
|
730
|
-
let expression = this.expression(0);
|
|
731
|
-
args.push(expression);
|
|
732
|
+
const expression = this.expression(0);
|
|
732
733
|
this.match(Token.TOK_RPAREN);
|
|
733
|
-
return
|
|
734
|
+
return expression;
|
|
734
735
|
}
|
|
735
736
|
default:
|
|
736
737
|
this.errorToken(token);
|
|
@@ -738,6 +739,17 @@ class TokenParser {
|
|
|
738
739
|
}
|
|
739
740
|
led(tokenName, left) {
|
|
740
741
|
switch (tokenName) {
|
|
742
|
+
case Token.TOK_QUESTION: {
|
|
743
|
+
const trueExpr = this.expression(0);
|
|
744
|
+
this.match(Token.TOK_COLON);
|
|
745
|
+
const falseExpr = this.expression(0);
|
|
746
|
+
return {
|
|
747
|
+
type: 'Ternary',
|
|
748
|
+
condition: left,
|
|
749
|
+
trueExpr,
|
|
750
|
+
falseExpr,
|
|
751
|
+
};
|
|
752
|
+
}
|
|
741
753
|
case Token.TOK_DOT: {
|
|
742
754
|
const rbp = bindingPower.Dot;
|
|
743
755
|
if (this.lookahead(0) !== Token.TOK_STAR) {
|
|
@@ -1047,6 +1059,7 @@ class Text {
|
|
|
1047
1059
|
}
|
|
1048
1060
|
get codePoints() {
|
|
1049
1061
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1062
|
+
// biome-ignore lint: lint/style/noNonNullAssertion
|
|
1050
1063
|
const array = [...this._text].map(s => s.codePointAt(0));
|
|
1051
1064
|
return array;
|
|
1052
1065
|
}
|
|
@@ -2016,13 +2029,20 @@ class TreeInterpreter$1 {
|
|
|
2016
2029
|
visit(node, value) {
|
|
2017
2030
|
var _a, _b, _c;
|
|
2018
2031
|
switch (node.type) {
|
|
2032
|
+
case 'Ternary': {
|
|
2033
|
+
const condition = this.visit(node.condition, value);
|
|
2034
|
+
if (!isFalse(condition)) {
|
|
2035
|
+
return this.visit(node.trueExpr, value);
|
|
2036
|
+
}
|
|
2037
|
+
return this.visit(node.falseExpr, value);
|
|
2038
|
+
}
|
|
2019
2039
|
case 'Field':
|
|
2020
2040
|
const identifier = node.name;
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
result = (_a = value[identifier]) !== null && _a !== void 0 ? _a : null;
|
|
2041
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
2042
|
+
return null;
|
|
2024
2043
|
}
|
|
2025
|
-
return
|
|
2044
|
+
// return the value of the field
|
|
2045
|
+
return (_a = value[identifier]) !== null && _a !== void 0 ? _a : null;
|
|
2026
2046
|
case 'LetExpression': {
|
|
2027
2047
|
const { bindings, expression } = node;
|
|
2028
2048
|
let scope = {};
|
|
@@ -2049,7 +2069,7 @@ class TreeInterpreter$1 {
|
|
|
2049
2069
|
return this.visit(node.right, this.visit(node.left, value));
|
|
2050
2070
|
case 'Subexpression': {
|
|
2051
2071
|
const result = this.visit(node.left, value);
|
|
2052
|
-
return result != null ? (_b = this.visit(node.right, result)) !== null && _b !== void 0 ? _b : null : null;
|
|
2072
|
+
return result != null ? ((_b = this.visit(node.right, result)) !== null && _b !== void 0 ? _b : null) : null;
|
|
2053
2073
|
}
|
|
2054
2074
|
case 'Index': {
|
|
2055
2075
|
if (!Array.isArray(value)) {
|
|
@@ -2317,9 +2337,7 @@ function compile(expression, options) {
|
|
|
2317
2337
|
function tokenize(expression, options) {
|
|
2318
2338
|
return Lexer.tokenize(expression, options);
|
|
2319
2339
|
}
|
|
2320
|
-
const registerFunction = (functionName,
|
|
2321
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2322
|
-
customFunction, signature) => {
|
|
2340
|
+
const registerFunction = (functionName, customFunction, signature) => {
|
|
2323
2341
|
TreeInterpreterInstance.runtime.registerFunction(functionName, customFunction, signature);
|
|
2324
2342
|
};
|
|
2325
2343
|
function search(data, expression, options) {
|