@jmespath-community/jmespath 1.1.5 → 1.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 +175 -68
- package/dist/cli.d.ts +2 -0
- package/dist/cli.mjs +2181 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.cjs +2118 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +412 -0
- package/dist/index.d.ts +412 -0
- package/dist/index.esm.js +2099 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.esm.min.js +2 -0
- package/dist/index.esm.min.js.map +1 -0
- package/dist/index.mjs +2089 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.js +2133 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/index.umd.min.js +2 -0
- package/dist/index.umd.min.js.map +1 -0
- package/package.json +30 -5
- package/dist/jmespath.esm.js +0 -2351
- package/dist/jmespath.esm.min.js +0 -2
- package/dist/jmespath.esm.min.js.map +0 -1
- package/dist/jmespath.umd.js +0 -2380
- package/dist/jmespath.umd.min.js +0 -2
- package/dist/jmespath.umd.min.js.map +0 -1
- package/dist/lib/AST.type.js +0 -3
- package/dist/lib/AST.type.js.map +0 -1
- package/dist/lib/JSON.type.js +0 -3
- package/dist/lib/JSON.type.js.map +0 -1
- package/dist/lib/Lexer.js +0 -326
- package/dist/lib/Lexer.js.map +0 -1
- package/dist/lib/Lexer.type.js +0 -45
- package/dist/lib/Lexer.type.js.map +0 -1
- package/dist/lib/Parser.js +0 -459
- package/dist/lib/Parser.js.map +0 -1
- package/dist/lib/Parser.type.js +0 -3
- package/dist/lib/Parser.type.js.map +0 -1
- package/dist/lib/Runtime.js +0 -924
- package/dist/lib/Runtime.js.map +0 -1
- package/dist/lib/Scope.js +0 -29
- package/dist/lib/Scope.js.map +0 -1
- package/dist/lib/TreeInterpreter.js +0 -312
- package/dist/lib/TreeInterpreter.js.map +0 -1
- package/dist/lib/index.js +0 -67
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/utils/index.js +0 -144
- package/dist/lib/utils/index.js.map +0 -1
- package/dist/lib/utils/strings.js +0 -92
- package/dist/lib/utils/strings.js.map +0 -1
- package/dist/lib/utils/text.js +0 -44
- package/dist/lib/utils/text.js.map +0 -1
- package/dist/types/AST.type.d.ts +0 -98
- package/dist/types/JSON.type.d.ts +0 -10
- package/dist/types/Lexer.d.ts +0 -19
- package/dist/types/Lexer.type.d.ts +0 -50
- package/dist/types/Parser.d.ts +0 -33
- package/dist/types/Parser.type.d.ts +0 -4
- package/dist/types/Runtime.d.ts +0 -87
- package/dist/types/Scope.d.ts +0 -8
- package/dist/types/TreeInterpreter.d.ts +0 -22
- package/dist/types/index.d.ts +0 -45
- package/dist/types/utils/index.d.ts +0 -16
- package/dist/types/utils/strings.d.ts +0 -11
- package/dist/types/utils/text.d.ts +0 -11
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,210 @@ 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
|
-
1. ### Register
|
|
94
|
+
1. ### Register your own custom functions
|
|
95
|
+
|
|
96
|
+
#### Enhanced Function Registry API
|
|
97
|
+
|
|
98
|
+
The library provides both backward-compatible and enhanced APIs for registering custom functions with improved developer experience, type safety, and flexible override behavior.
|
|
99
|
+
|
|
100
|
+
##### Basic Usage (Backward Compatible)
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
import { search, registerFunction, TYPE_NUMBER } from "@jmespath-community/jmespath";
|
|
104
|
+
|
|
105
|
+
search({ foo: 60, bar: 10 }, "divide(foo, bar)");
|
|
106
|
+
// THROWS ERROR: Error: Unknown function: divide()
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
registerFunction(
|
|
109
|
+
"divide", // FUNCTION NAME
|
|
110
|
+
(resolvedArgs) => {
|
|
111
|
+
// CUSTOM FUNCTION
|
|
112
|
+
const [dividend, divisor] = resolvedArgs;
|
|
113
|
+
return dividend / divisor;
|
|
114
|
+
},
|
|
115
|
+
[{ types: [TYPE_NUMBER] }, { types: [TYPE_NUMBER] }], //SIGNATURE
|
|
116
|
+
);
|
|
109
117
|
|
|
110
|
-
|
|
118
|
+
search({ foo: 60, bar: 10 }, "divide(foo, bar)");
|
|
119
|
+
// OUTPUTS: 6
|
|
120
|
+
```
|
|
111
121
|
|
|
112
|
-
|
|
113
|
-
import {search, registerFunction, TYPE_NUMBER} from '@jmespath-community/jmespath'
|
|
122
|
+
##### Enhanced Registry API with Type Safety
|
|
114
123
|
|
|
124
|
+
```typescript
|
|
125
|
+
import { register, search, TYPE_NUMBER } from "@jmespath-community/jmespath";
|
|
115
126
|
|
|
116
|
-
|
|
117
|
-
|
|
127
|
+
// TypeScript prevents registering built-in functions at compile time
|
|
128
|
+
// register('sum', myFunc, signature); // TypeScript error!
|
|
118
129
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
},
|
|
125
|
-
[{ types: [TYPE_NUMBER] }, { types: [TYPE_NUMBER] }] //SIGNATURE
|
|
126
|
-
);
|
|
130
|
+
// Enhanced registration with better error handling
|
|
131
|
+
const result = register('multiply', ([a, b]) => a * b, [
|
|
132
|
+
{ types: [TYPE_NUMBER] },
|
|
133
|
+
{ types: [TYPE_NUMBER] }
|
|
134
|
+
]);
|
|
127
135
|
|
|
128
|
-
|
|
129
|
-
|
|
136
|
+
if (result.success) {
|
|
137
|
+
console.log(result.message); // "Function multiply() registered successfully"
|
|
138
|
+
} else {
|
|
139
|
+
console.error(result.message); // Detailed error information
|
|
140
|
+
}
|
|
141
|
+
```
|
|
130
142
|
|
|
131
|
-
|
|
143
|
+
##### Override Existing Functions
|
|
132
144
|
|
|
133
|
-
|
|
145
|
+
```javascript
|
|
146
|
+
import { registerFunction, register } from "@jmespath-community/jmespath";
|
|
134
147
|
|
|
148
|
+
// Option 1: Using registerFunction with options
|
|
149
|
+
registerFunction('myFunc', () => 'first', []);
|
|
150
|
+
registerFunction('myFunc', () => 'second', [], { override: true, warn: true });
|
|
151
|
+
// Console: "Warning: Overriding existing function: myFunc()"
|
|
135
152
|
|
|
136
|
-
|
|
153
|
+
// Option 2: Using enhanced register API
|
|
154
|
+
const result = register('myFunc', () => 'third', [], { override: true });
|
|
155
|
+
console.log(result.message); // "Function myFunc() overridden successfully"
|
|
156
|
+
```
|
|
137
157
|
|
|
138
|
-
|
|
139
|
-
'divide',
|
|
140
|
-
(resolvedArgs) => {
|
|
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
|
-
);
|
|
158
|
+
##### Registry Management
|
|
146
159
|
|
|
147
|
-
|
|
148
|
-
|
|
160
|
+
```javascript
|
|
161
|
+
import {
|
|
162
|
+
isRegistered,
|
|
163
|
+
getRegisteredFunctions,
|
|
164
|
+
getCustomFunctions,
|
|
165
|
+
unregisterFunction,
|
|
166
|
+
clearCustomFunctions
|
|
167
|
+
} from "@jmespath-community/jmespath";
|
|
149
168
|
|
|
150
|
-
|
|
169
|
+
// Check if function exists
|
|
170
|
+
console.log(isRegistered('sum')); // true (built-in)
|
|
171
|
+
console.log(isRegistered('myFunc')); // true (if registered)
|
|
172
|
+
|
|
173
|
+
// Get all registered functions
|
|
174
|
+
const allFunctions = getRegisteredFunctions();
|
|
175
|
+
console.log(allFunctions); // ['abs', 'avg', 'ceil', ..., 'myFunc']
|
|
176
|
+
|
|
177
|
+
// Get only custom functions
|
|
178
|
+
const customFunctions = getCustomFunctions();
|
|
179
|
+
console.log(customFunctions); // ['myFunc', 'divide', ...]
|
|
180
|
+
|
|
181
|
+
// Unregister custom function (built-ins cannot be unregistered)
|
|
182
|
+
const removed = unregisterFunction('myFunc');
|
|
183
|
+
console.log(removed); // true if successful
|
|
184
|
+
|
|
185
|
+
// Clear all custom functions
|
|
186
|
+
clearCustomFunctions();
|
|
187
|
+
console.log(getCustomFunctions()); // []
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
##### Optional Arguments
|
|
191
|
+
|
|
192
|
+
Optional arguments are supported by setting `{..., optional: true}` in argument signatures
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
registerFunction(
|
|
196
|
+
"divide",
|
|
197
|
+
(resolvedArgs) => {
|
|
198
|
+
const [dividend, divisor] = resolvedArgs;
|
|
199
|
+
return dividend / (divisor ?? 1); //OPTIONAL DIVISOR THAT DEFAULTS TO 1
|
|
200
|
+
},
|
|
201
|
+
[{ types: [TYPE_NUMBER] }, { types: [TYPE_NUMBER], optional: true }], //SIGNATURE
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
search({ foo: 60, bar: 10 }, "divide(foo)");
|
|
205
|
+
// OUTPUTS: 60
|
|
206
|
+
```
|
|
151
207
|
|
|
152
208
|
2. ### Root value access with `$` symbol
|
|
153
209
|
|
|
154
210
|
```javascript
|
|
155
|
-
|
|
156
|
-
search({foo: {bar: 999}, baz: [1, 2, 3]}, '$.baz[*].[@, $.foo.bar]')
|
|
211
|
+
search({ foo: { bar: 999 }, baz: [1, 2, 3] }, "$.baz[*].[@, $.foo.bar]");
|
|
157
212
|
|
|
158
213
|
// OUTPUTS:
|
|
159
214
|
// [ [ 1, 999 ], [ 2, 999 ], [ 3, 999 ] ]
|
|
160
215
|
```
|
|
161
216
|
|
|
162
|
-
|
|
163
217
|
## More Resources
|
|
164
218
|
|
|
165
219
|
The example above only show a small amount of what
|
|
166
220
|
a JMESPath expression can do. If you want to take a
|
|
167
|
-
tour of the language, the
|
|
221
|
+
tour of the language, the _best_ place to go is the
|
|
168
222
|
[JMESPath Tutorial](http://jmespath.site/main#tutorial).
|
|
169
223
|
|
|
170
224
|
One of the best things about JMESPath is that it is
|
|
171
225
|
implemented in many different programming languages including
|
|
172
|
-
python, ruby, php, lua, etc.
|
|
226
|
+
python, ruby, php, lua, etc. To see a complete list of libraries,
|
|
173
227
|
check out the [JMESPath libraries page](http://jmespath.site/main#libraries).
|
|
174
228
|
|
|
175
229
|
And finally, the full JMESPath specification can be found
|
|
176
230
|
on the [JMESPath site](https://jmespath.site/main/#specification).
|
|
231
|
+
|
|
232
|
+
## Experimental Features
|
|
233
|
+
|
|
234
|
+
### Ternary Operations (`? :`)
|
|
235
|
+
|
|
236
|
+
**Supported Version:** 1.1.6
|
|
237
|
+
|
|
238
|
+
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`.
|
|
239
|
+
|
|
240
|
+
- **Condition:** The expression before the `?`. JMESPath determines truthiness based on the evaluated value:
|
|
241
|
+
- `true` is truthy.
|
|
242
|
+
- Any non-empty object, array, or string is truthy.
|
|
243
|
+
- Any non-zero number is truthy.
|
|
244
|
+
- `false`, `null`, empty objects `{}`, empty arrays `[]`, and empty strings `''` are falsy.
|
|
245
|
+
- **Value if true:** The expression between the `?` and `:`. This is evaluated and returned if the condition is truthy.
|
|
246
|
+
- **Value if false:** The expression after the `:`. This is evaluated and returned if the condition is falsy.
|
|
247
|
+
|
|
248
|
+
**Examples:**
|
|
249
|
+
|
|
250
|
+
Basic usage:
|
|
251
|
+
|
|
252
|
+
```javascript
|
|
253
|
+
search({ is_active: true, user: "Alice" }, "is_active ? user : 'Guest'");
|
|
254
|
+
// OUTPUTS: "Alice"
|
|
255
|
+
|
|
256
|
+
search({ is_active: false, user: "Bob" }, "is_active ? user : 'Guest'");
|
|
257
|
+
// OUTPUTS: "Guest"
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Truthiness with different types:
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
search({ data: [1, 2] }, "data ? 'has_data' : 'no_data'");
|
|
264
|
+
// OUTPUTS: "has_data"
|
|
265
|
+
|
|
266
|
+
search({ data: [] }, "data ? 'has_data' : 'no_data'");
|
|
267
|
+
// OUTPUTS: "no_data"
|
|
268
|
+
|
|
269
|
+
search({ count: 5 }, "count ? 'count_present' : 'no_count'");
|
|
270
|
+
// OUTPUTS: "count_present"
|
|
271
|
+
|
|
272
|
+
search({ count: 0 }, "count ? 'count_present' : 'no_count'");
|
|
273
|
+
// OUTPUTS: "no_count"
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Nested Ternaries:
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
search({ a: true, b: false, val1: 10, val2: 20, val3: 30 }, "a ? (b ? val1 : val2) : val3");
|
|
280
|
+
// OUTPUTS: 20
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
This feature is currently experimental and its syntax or behavior might change in future releases.
|
package/dist/cli.d.ts
ADDED