@jmespath-community/jmespath 1.2.0 → 1.4.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.
Files changed (71) hide show
  1. package/README.md +228 -12
  2. package/dist/cli.cjs +2816 -0
  3. package/dist/cli.cjs.map +1 -0
  4. package/dist/cli.d.cts +2 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.mjs +2794 -0
  7. package/dist/cli.mjs.map +1 -0
  8. package/dist/index.cjs +2699 -0
  9. package/dist/index.cjs.map +1 -0
  10. package/dist/index.d.cts +464 -0
  11. package/dist/index.d.ts +464 -0
  12. package/dist/index.esm.js +2707 -0
  13. package/dist/index.esm.js.map +1 -0
  14. package/dist/index.esm.min.js +6 -0
  15. package/dist/index.esm.min.js.map +1 -0
  16. package/dist/index.mjs +2697 -0
  17. package/dist/index.mjs.map +1 -0
  18. package/dist/index.umd.js +2712 -0
  19. package/dist/index.umd.js.map +1 -0
  20. package/dist/index.umd.min.js +6 -0
  21. package/dist/index.umd.min.js.map +1 -0
  22. package/package.json +68 -11
  23. package/dist/jmespath.esm.js +0 -2369
  24. package/dist/jmespath.esm.min.js +0 -2
  25. package/dist/jmespath.esm.min.js.map +0 -1
  26. package/dist/jmespath.umd.js +0 -2398
  27. package/dist/jmespath.umd.min.js +0 -2
  28. package/dist/jmespath.umd.min.js.map +0 -1
  29. package/dist/lib/bin/jp.js +0 -127
  30. package/dist/lib/bin/jp.js.map +0 -1
  31. package/dist/lib/package.json +0 -70
  32. package/dist/lib/src/AST.type.js +0 -3
  33. package/dist/lib/src/AST.type.js.map +0 -1
  34. package/dist/lib/src/JSON.type.js +0 -3
  35. package/dist/lib/src/JSON.type.js.map +0 -1
  36. package/dist/lib/src/Lexer.js +0 -327
  37. package/dist/lib/src/Lexer.js.map +0 -1
  38. package/dist/lib/src/Lexer.type.js +0 -46
  39. package/dist/lib/src/Lexer.type.js.map +0 -1
  40. package/dist/lib/src/Parser.js +0 -468
  41. package/dist/lib/src/Parser.js.map +0 -1
  42. package/dist/lib/src/Parser.type.js +0 -3
  43. package/dist/lib/src/Parser.type.js.map +0 -1
  44. package/dist/lib/src/Runtime.js +0 -924
  45. package/dist/lib/src/Runtime.js.map +0 -1
  46. package/dist/lib/src/Scope.js +0 -29
  47. package/dist/lib/src/Scope.js.map +0 -1
  48. package/dist/lib/src/TreeInterpreter.js +0 -319
  49. package/dist/lib/src/TreeInterpreter.js.map +0 -1
  50. package/dist/lib/src/index.js +0 -65
  51. package/dist/lib/src/index.js.map +0 -1
  52. package/dist/lib/src/utils/index.js +0 -145
  53. package/dist/lib/src/utils/index.js.map +0 -1
  54. package/dist/lib/src/utils/strings.js +0 -92
  55. package/dist/lib/src/utils/strings.js.map +0 -1
  56. package/dist/lib/src/utils/text.js +0 -45
  57. package/dist/lib/src/utils/text.js.map +0 -1
  58. package/dist/types/bin/jp.d.ts +0 -2
  59. package/dist/types/src/AST.type.d.ts +0 -104
  60. package/dist/types/src/JSON.type.d.ts +0 -10
  61. package/dist/types/src/Lexer.d.ts +0 -19
  62. package/dist/types/src/Lexer.type.d.ts +0 -51
  63. package/dist/types/src/Parser.d.ts +0 -33
  64. package/dist/types/src/Parser.type.d.ts +0 -4
  65. package/dist/types/src/Runtime.d.ts +0 -87
  66. package/dist/types/src/Scope.d.ts +0 -8
  67. package/dist/types/src/TreeInterpreter.d.ts +0 -22
  68. package/dist/types/src/index.d.ts +0 -45
  69. package/dist/types/src/utils/index.d.ts +0 -16
  70. package/dist/types/src/utils/strings.d.ts +0 -11
  71. package/dist/types/src/utils/text.d.ts +0 -11
package/README.md CHANGED
@@ -8,29 +8,91 @@ JMESPath is a query language for JSON. It will take a JSON document
8
8
  as input and transform it into another JSON document
9
9
  given a JMESPath expression.
10
10
 
11
- ## INSTALLATION
12
-
13
- ```
11
+ ## Table of Contents
12
+
13
+ - [Installation](#installation)
14
+ - [Usage](#usage)
15
+ - [ESM (Node.js)](#esm-nodejs)
16
+ - [CommonJS (Node.js)](#commonjs-nodejs)
17
+ - [Browser (UMD)](#browser-umd)
18
+ - [API](#api)
19
+ - [`search(data, expression, options)`](#searchdata-d-expression-string-options-options-t)
20
+ - [`searchStream(source, expression, options)`](#searchstreamsource-expression-options-asyncgenerator)
21
+ - [`compile(expression)`](#compileexpression-string-expressionnodetree)
22
+ - [`compileQuery(expression, options)`](#compilequeryexpression-string-options-options-compiledquery)
23
+ - [`validate(expression, options)`](#validateexpression-string-options-options-validationresult)
24
+ - [Extensions](#extensions-to-original-spec)
25
+ - [More Resources](#more-resources)
26
+ - [Experimental Features](#experimental-features)
27
+
28
+ ## Installation
29
+
30
+ ```bash
14
31
  npm install @jmespath-community/jmespath
15
32
  ```
16
33
 
17
- ## USAGE
34
+ ## Usage
18
35
 
19
- ### `search(data: JSONValue, expression: string): JSONValue`
36
+ ### ESM (Node.js)
20
37
 
21
38
  ```javascript
22
39
  import { search } from "@jmespath-community/jmespath";
23
40
 
24
- search({ foo: { bar: { baz: [0, 1, 2, 3, 4] } } }, "foo.bar.baz[2]");
41
+ const data = { foo: { bar: { baz: [0, 1, 2, 3, 4] } } };
42
+ const result = search(data, "foo.bar.baz[2]");
25
43
 
26
- // OUTPUTS: 2
44
+ console.log(result);
45
+ // Outputs: 2
27
46
  ```
28
47
 
48
+ ### CommonJS (Node.js)
49
+
50
+ ```javascript
51
+ const { search } = require("@jmespath-community/jmespath");
52
+
53
+ const data = { foo: { bar: { baz: [0, 1, 2, 3, 4] } } };
54
+ const result = search(data, "foo.bar.baz[2]");
55
+
56
+ console.log(result);
57
+ // Outputs: 2
58
+ ```
59
+
60
+ ### Browser (UMD)
61
+
62
+ You can include the UMD build directly in your HTML file. The library will be available under the `jmespath` global variable.
63
+
64
+ ```html
65
+ <script src="https://unpkg.com/@jmespath-community/jmespath/dist/index.umd.min.js"></script>
66
+ <script>
67
+ const data = { foo: { bar: { baz: [0, 1, 2, 3, 4] } } };
68
+ const result = jmespath.search(data, "foo.bar.baz[2]");
69
+ console.log(result);
70
+ // Outputs: 2
71
+ </script>
72
+ ```
73
+
74
+ ## API
75
+
76
+ ### `search<T = JSONValue, D = unknown>(data: D, expression: string, options?: Options): T`
77
+
29
78
  In the example we gave the `search` function input data of
30
79
  `{foo: {bar: {baz: [0, 1, 2, 3, 4]}}}` as well as the JMESPath
31
80
  expression `foo.bar.baz[2]`, and the `search` function evaluated
32
81
  the expression against the input data to produce the result `2`.
33
82
 
83
+ Accepts custom TypeScript interfaces directly without casting:
84
+
85
+ ```typescript
86
+ interface User {
87
+ name: string;
88
+ age: number;
89
+ }
90
+
91
+ const user: User = { name: "Alice", age: 30 };
92
+ const name = search<string>(user, "name");
93
+ // name is typed as string
94
+ ```
95
+
34
96
  The JMESPath language can do _a lot_ more than select an element
35
97
  from a list. Here are a few more examples:
36
98
 
@@ -72,6 +134,61 @@ search(JSON_DOCUMENT, "foo[?age > `30`]");
72
134
  // OUTPUTS: [ { age: 35 }, { age: 40 } ]
73
135
  ```
74
136
 
137
+ #### Automatic Type Inference
138
+
139
+ Literal path queries automatically infer property types without requiring manual type parameters or type assertions:
140
+
141
+ ```typescript
142
+ const user = {
143
+ profile: { name: "Alice", email: "alice@example.com" },
144
+ tags: ["admin", "dev"],
145
+ };
146
+
147
+ const name = search(user, "profile.name"); // inferred as string
148
+ const tag = search(user, "tags[0]"); // inferred as string
149
+ const tags = search(user, "tags[*]"); // inferred as string[]
150
+ ```
151
+
152
+ #### Runtime Security Options
153
+
154
+ Pass `options` to restrict execution limits on untrusted queries:
155
+
156
+ ```typescript
157
+ search(data, expression, {
158
+ maxDepth: 32, // expression and evaluation recursion limit
159
+ maxNodes: 128, // maximum AST node count
160
+ maxOutputSize: 1000, // maximum elements or characters in results
161
+ allowedFunctions: ['length', 'contains'], // allow-list specific built-ins
162
+ disallowedFunctions: ['custom_heavy'], // deny-list specific built-ins
163
+ timeoutMs: 100, // query execution time limit in ms
164
+ });
165
+ ```
166
+
167
+ ### `searchStream<T = JSONValue, D = unknown>(source: StreamSource<D>, expression: string | ExpressionNode, options?: StreamOptions): AsyncGenerator<T, void, unknown>`
168
+
169
+ Evaluates a JMESPath expression incrementally over an `AsyncIterable`, `ReadableStream`, or Node.js `stream.Readable`, yielding matching results without buffering large datasets in memory:
170
+
171
+ ```typescript
172
+ import jmespath from "@jmespath-community/jmespath";
173
+
174
+ async function* getEvents() {
175
+ yield { id: 1, level: "info", message: "connected" };
176
+ yield { id: 2, level: "error", message: "disk full" };
177
+ }
178
+
179
+ for await (const msg of jmespath.searchStream(getEvents(), "[?level == 'error'].message")) {
180
+ console.log(msg); // "disk full"
181
+ }
182
+ ```
183
+
184
+ Supports automatic NDJSON / JSON lines chunk decoding (`parseJson: 'auto'`), chunk flattening, precompiled ASTs, and early termination:
185
+
186
+ ```typescript
187
+ for await (const item of jmespath.searchStream(logStream, "[:10]", { limit: 10 })) {
188
+ console.log(item);
189
+ }
190
+ ```
191
+
75
192
  ### `compile(expression: string): ExpressionNodeTree`
76
193
 
77
194
  You can precompile all your expressions ready for use later on. The `compile`
@@ -83,19 +200,48 @@ import { compile, TreeInterpreter } from "@jmespath-community/jmespath";
83
200
 
84
201
  const ast = compile("foo.bar");
85
202
 
86
- TreeInterpreter.search(ast, { foo: { bar: "BAZ" } });
203
+ const result = TreeInterpreter.search(ast, { foo: { bar: "BAZ" } });
87
204
  // RETURNS: "BAZ"
88
205
  ```
89
206
 
207
+ ### `compileQuery<T = JSONValue, D = unknown>(expression: string, options?: Options): CompiledQuery<T, D>`
208
+
209
+ Precompiles an expression into a reusable, callable function:
210
+
211
+ ```typescript
212
+ import { compileQuery } from "@jmespath-community/jmespath";
213
+
214
+ const getName = compileQuery<string, { user: { name: string } }>("user.name");
215
+
216
+ const result = getName({ user: { name: "Alice" } });
217
+ // Outputs: "Alice"
218
+ ```
219
+
220
+ ### `validate(expression: string, options?: Options): ValidationResult`
221
+
222
+ Validates an expression without throwing exceptions, checking syntax and security options:
223
+
224
+ ```typescript
225
+ import { validate } from "@jmespath-community/jmespath";
226
+
227
+ const result = validate("foo.bar");
228
+ // { valid: true, ast: { type: 'Subexpression', ... } }
229
+
230
+ const invalid = validate("foo.", { maxNodes: 10 });
231
+ // { valid: false, error: 'Syntax error: ...' }
232
+ ```
233
+
90
234
  ---
91
235
 
92
236
  ## EXTENSIONS TO ORIGINAL SPEC
93
237
 
94
- 1. ### Register you own custom functions
238
+ 1. ### Register your own custom functions
95
239
 
96
- #### `registerFunction(functionName: string, customFunction: RuntimeFunction, signature: InputSignature[]): void`
240
+ #### Enhanced Function Registry API
97
241
 
98
- Extend the list of built in JMESpath expressions with your own functions.
242
+ The library provides both backward-compatible and enhanced APIs for registering custom functions with improved developer experience, type safety, and flexible override behavior.
243
+
244
+ ##### Basic Usage (Backward Compatible)
99
245
 
100
246
  ```javascript
101
247
  import { search, registerFunction, TYPE_NUMBER } from "@jmespath-community/jmespath";
@@ -117,6 +263,76 @@ TreeInterpreter.search(ast, { foo: { bar: "BAZ" } });
117
263
  // OUTPUTS: 6
118
264
  ```
119
265
 
266
+ ##### Enhanced Registry API with Type Safety
267
+
268
+ ```typescript
269
+ import { register, search, TYPE_NUMBER } from "@jmespath-community/jmespath";
270
+
271
+ // TypeScript prevents registering built-in functions at compile time
272
+ // register('sum', myFunc, signature); // TypeScript error!
273
+
274
+ // Enhanced registration with better error handling
275
+ const result = register('multiply', ([a, b]) => a * b, [
276
+ { types: [TYPE_NUMBER] },
277
+ { types: [TYPE_NUMBER] }
278
+ ]);
279
+
280
+ if (result.success) {
281
+ console.log(result.message); // "Function multiply() registered successfully"
282
+ } else {
283
+ console.error(result.message); // Detailed error information
284
+ }
285
+ ```
286
+
287
+ ##### Override Existing Functions
288
+
289
+ ```javascript
290
+ import { registerFunction, register } from "@jmespath-community/jmespath";
291
+
292
+ // Option 1: Using registerFunction with options
293
+ registerFunction('myFunc', () => 'first', []);
294
+ registerFunction('myFunc', () => 'second', [], { override: true, warn: true });
295
+ // Console: "Warning: Overriding existing function: myFunc()"
296
+
297
+ // Option 2: Using enhanced register API
298
+ const result = register('myFunc', () => 'third', [], { override: true });
299
+ console.log(result.message); // "Function myFunc() overridden successfully"
300
+ ```
301
+
302
+ ##### Registry Management
303
+
304
+ ```javascript
305
+ import {
306
+ isRegistered,
307
+ getRegisteredFunctions,
308
+ getCustomFunctions,
309
+ unregisterFunction,
310
+ clearCustomFunctions
311
+ } from "@jmespath-community/jmespath";
312
+
313
+ // Check if function exists
314
+ console.log(isRegistered('sum')); // true (built-in)
315
+ console.log(isRegistered('myFunc')); // true (if registered)
316
+
317
+ // Get all registered functions
318
+ const allFunctions = getRegisteredFunctions();
319
+ console.log(allFunctions); // ['abs', 'avg', 'ceil', ..., 'myFunc']
320
+
321
+ // Get only custom functions
322
+ const customFunctions = getCustomFunctions();
323
+ console.log(customFunctions); // ['myFunc', 'divide', ...]
324
+
325
+ // Unregister custom function (built-ins cannot be unregistered)
326
+ const removed = unregisterFunction('myFunc');
327
+ console.log(removed); // true if successful
328
+
329
+ // Clear all custom functions
330
+ clearCustomFunctions();
331
+ console.log(getCustomFunctions()); // []
332
+ ```
333
+
334
+ ##### Optional Arguments
335
+
120
336
  Optional arguments are supported by setting `{..., optional: true}` in argument signatures
121
337
 
122
338
  ```javascript
@@ -124,7 +340,7 @@ TreeInterpreter.search(ast, { foo: { bar: "BAZ" } });
124
340
  "divide",
125
341
  (resolvedArgs) => {
126
342
  const [dividend, divisor] = resolvedArgs;
127
- return dividend / divisor ?? 1; //OPTIONAL DIVISOR THAT DEFAULTS TO 1
343
+ return dividend / (divisor ?? 1); //OPTIONAL DIVISOR THAT DEFAULTS TO 1
128
344
  },
129
345
  [{ types: [TYPE_NUMBER] }, { types: [TYPE_NUMBER], optional: true }], //SIGNATURE
130
346
  );