@stackone/expressions 0.18.0 → 0.19.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 CHANGED
@@ -65,8 +65,16 @@ evaluate("x + y", { x: 1, y: 2 }); // Returns 3
65
65
  - This exchanges performance for better error messages, useful for AI validation and self-repair.
66
66
 
67
67
  ```js
68
- evaluate("$.user.name", { user: { name: "John" } }, { incrementalJsonPath: true }); // Returns "John"
69
- evaluate("$.user.details.age", { user: { details: { name: "John" } } }, { incrementalJsonPath: true }); // Throws Error: "Key 'age' not found at '$.user.details'. Available keys: name"
68
+ evaluate(
69
+ "$.user.name",
70
+ { user: { name: "John" } },
71
+ { incrementalJsonPath: true }
72
+ ); // Returns "John"
73
+ evaluate(
74
+ "$.user.details.age",
75
+ { user: { details: { name: "John" } } },
76
+ { incrementalJsonPath: true }
77
+ ); // Throws Error: "Key 'age' not found at '$.user.details'. Available keys: name"
70
78
  ```
71
79
 
72
80
  ### isValidExpression(expression: string)
@@ -103,28 +111,28 @@ When the expression starts with `$`, it is treated as a JSON Path expression and
103
111
 
104
112
  #### JSON Path Syntax
105
113
 
106
- | JSON Path | Description |
107
- | --- | --- |
108
- | `$` | The root object |
109
- | `.` | Child operator |
110
- | `@` | The current object |
111
- | `*` | Wildcard. All elements in an array, or all properties of an object |
112
- | `..` | Recursive descent |
113
- | `[]` | Subscript operator |
114
- | `[,]` | Union operator (e.g., `$.a[b,c]` for multiple properties) |
115
- | `[start:end:step]` | Array slice operator |
116
- | `?(expression)` | Filter expression |
117
- | `()` | Script expression |
114
+ | JSON Path | Description |
115
+ | ------------------ | ------------------------------------------------------------------ |
116
+ | `$` | The root object |
117
+ | `.` | Child operator |
118
+ | `@` | The current object |
119
+ | `*` | Wildcard. All elements in an array, or all properties of an object |
120
+ | `..` | Recursive descent |
121
+ | `[]` | Subscript operator |
122
+ | `[,]` | Union operator (e.g., `$.a[b,c]` for multiple properties) |
123
+ | `[start:end:step]` | Array slice operator |
124
+ | `?(expression)` | Filter expression |
125
+ | `()` | Script expression |
118
126
 
119
127
  Examples:
120
128
 
121
129
  ```js
122
130
  // Given the context: { user: { name: "John", age: 30 }, "info/email": "info@email.com" }
123
- '$.user.name' // Returns "John"
124
- '$.user.age' // Returns 30
125
- '$.user[*]' // Returns ["John", 30]
126
- '$.user[name,age]' // Returns ["John", 30] (union operator)
127
- '$["info/email"]' // Returns "info@email.com"
131
+ "$.user.name"; // Returns "John"
132
+ "$.user.age"; // Returns 30
133
+ "$.user[*]"; // Returns ["John", 30]
134
+ "$.user[name,age]"; // Returns ["John", 30] (union operator)
135
+ '$["info/email"]'; // Returns "info@email.com"
128
136
  ```
129
137
 
130
138
  For more information on JSON Path syntax, refer to the [JSONPath Plus documentation](https://github.com/s3u/JSONPath) and the original [JSON Path specification](https://goessner.net/articles/JsonPath/).
@@ -135,39 +143,39 @@ This kind of expression is enclosed in double brackets `{{expression}}`. It supp
135
143
 
136
144
  #### Operators
137
145
 
138
- | Operator | Description |
139
- | --- | --- |
140
- | `!` | Logical NOT |
141
- | `+` | Addition, string concatenation |
142
- | `-` | Subtraction |
143
- | `*` | Multiplication |
144
- | `/` | Division |
145
- | `//` | Floor division |
146
- | `%` | Modulus |
147
- | `^` | Exponentiation |
148
- | `&&` | Logical AND |
149
- | `\|\|` | Logical OR |
150
- | `==` | Equal |
151
- | `!=` | Not equal |
152
- | `>` | Greater than |
153
- | `>=` | Greater than or equal |
154
- | `<` | Less than |
155
- | `<=` | Less than or equal |
156
- | `in` | Element of string or array |
157
- | `? :` | Ternary operator |
158
- | `??` | Nullish coalescing operator |
146
+ | Operator | Description |
147
+ | -------- | ------------------------------ |
148
+ | `!` | Logical NOT |
149
+ | `+` | Addition, string concatenation |
150
+ | `-` | Subtraction |
151
+ | `*` | Multiplication |
152
+ | `/` | Division |
153
+ | `//` | Floor division |
154
+ | `%` | Modulus |
155
+ | `^` | Exponentiation |
156
+ | `&&` | Logical AND |
157
+ | `\|\|` | Logical OR |
158
+ | `==` | Equal |
159
+ | `!=` | Not equal |
160
+ | `>` | Greater than |
161
+ | `>=` | Greater than or equal |
162
+ | `<` | Less than |
163
+ | `<=` | Less than or equal |
164
+ | `in` | Element of string or array |
165
+ | `? :` | Ternary operator |
166
+ | `??` | Nullish coalescing operator |
159
167
 
160
168
  Examples:
161
169
 
162
170
  ```js
163
171
  // Given the context: { x: 10, y: 5 }
164
- '{{x + y}}' // Returns 15
165
- '{{x * 2}}' // Returns 20
166
- '{{x > y}}' // Returns true
167
- '{{x == 10 ? "yes" : "no"}}' // Returns "yes"
168
- '{{x in [1, 2, 3]}}' // Returns false
169
- '{{x != y}}' // Returns true
170
- '{{x ?? y}}' // Returns 10
172
+ "{{x + y}}"; // Returns 15
173
+ "{{x * 2}}"; // Returns 20
174
+ "{{x > y}}"; // Returns true
175
+ '{{x == 10 ? "yes" : "no"}}'; // Returns "yes"
176
+ "{{x in [1, 2, 3]}}"; // Returns false
177
+ "{{x != y}}"; // Returns true
178
+ "{{x ?? y}}"; // Returns 10
171
179
  ```
172
180
 
173
181
  #### Identifiers
@@ -176,15 +184,15 @@ Identifiers can be used to reference variables in the context.
176
184
 
177
185
  ```js
178
186
  // Given the context:
179
- // {
187
+ // {
180
188
  // name: {
181
189
  // first: "John",
182
190
  // last: "Smith"
183
191
  // },
184
192
  // jobs: ["Developer", "Designer"]
185
193
  // }
186
- `{{name.first}}` // Returns "John"
187
- `{{jobs[1]}}` // Returns "Designer"
194
+ `{{name.first}}` // Returns "John"
195
+ `{{jobs[1]}}`; // Returns "Designer"
188
196
  ```
189
197
 
190
198
  #### Collections
@@ -200,7 +208,7 @@ Collections, or arrays of objects, can be filtered by including a filter express
200
208
  // ]
201
209
  // }
202
210
  `{{users[.name == "John"].age}}` // Returns 30
203
- `{{users[.age > 25].name}}` // Returns ["John"]
211
+ `{{users[.age > 25].name}}`; // Returns ["John"]
204
212
  ```
205
213
 
206
214
  #### Built-in Functions
@@ -219,11 +227,11 @@ Calculates the next anniversary date for a given date.
219
227
 
220
228
  ```js
221
229
  // If today is April 10, 2025, and a birthday is December 25, 2000
222
- "{{nextAnniversary('25/12/2000', 'dd/MM/yyyy')}}"
230
+ "{{nextAnniversary('25/12/2000', 'dd/MM/yyyy')}}";
223
231
  // Returns Date object for December 25, 2025 (this year's anniversary)
224
232
 
225
233
  // If today is April 10, 2025, and a birthday is February 15, 1990
226
- "{{nextAnniversary('15/02/1990', 'dd/MM/yyyy')}}"
234
+ "{{nextAnniversary('15/02/1990', 'dd/MM/yyyy')}}";
227
235
  // Returns Date object for February 15, 2026 (next year's anniversary)
228
236
  ```
229
237
 
@@ -238,10 +246,10 @@ Calculates the number of complete years elapsed between two dates.
238
246
 
239
247
  ```js
240
248
  // Calculate years between two specific dates
241
- "{{yearsElapsed('01/01/2015', 'dd/MM/yyyy', '01/01/2025')}}" // Returns 10
249
+ "{{yearsElapsed('01/01/2015', 'dd/MM/yyyy', '01/01/2025')}}"; // Returns 10
242
250
 
243
251
  // Calculate years from a date to today (assuming today is April 10, 2025)
244
- "{{yearsElapsed('01/01/2015', 'dd/MM/yyyy')}}" // Returns 10
252
+ "{{yearsElapsed('01/01/2015', 'dd/MM/yyyy')}}"; // Returns 10
245
253
  ```
246
254
 
247
255
  ###### hasPassed(date, format, yearsToAdd?)
@@ -255,13 +263,13 @@ Determines if a given date (optionally with added years) has passed.
255
263
 
256
264
  ```js
257
265
  // Check if a date has passed (assuming today is April 10, 2025)
258
- "{{hasPassed('01/01/2020', 'dd/MM/yyyy')}}" // Returns true
266
+ "{{hasPassed('01/01/2020', 'dd/MM/yyyy')}}"; // Returns true
259
267
 
260
268
  // Check if a date has passed (assuming today is April 10, 2025)
261
- "{{hasPassed('01/01/2026', 'dd/MM/yyyy')}}" // Returns false
269
+ "{{hasPassed('01/01/2026', 'dd/MM/yyyy')}}"; // Returns false
262
270
 
263
271
  // Check if a date + 5 years has passed (2020 + 5 = 2025)
264
- "{{hasPassed('01/01/2020', 'dd/MM/yyyy', 5)}}"
272
+ "{{hasPassed('01/01/2020', 'dd/MM/yyyy', 5)}}";
265
273
  // Returns true if April 10, 2025 is after January 1, 2025
266
274
  ```
267
275
 
@@ -273,7 +281,7 @@ Returns the current date and time.
273
281
 
274
282
  ```js
275
283
  // Get the current date and time
276
- "{{now()}}" // Returns "2025-04-10T12:00:00.000Z" (example)
284
+ "{{now()}}"; // Returns "2025-04-10T12:00:00.000Z" (example)
277
285
  ```
278
286
 
279
287
  ##### Array Functions
@@ -288,16 +296,16 @@ Checks if an array includes a specific value or all values from another array.
288
296
 
289
297
  ```js
290
298
  // Check if an array includes a specific value
291
- "{{includes([1, 2, 3], 2)}}" // Returns true
299
+ "{{includes([1, 2, 3], 2)}}"; // Returns true
292
300
 
293
301
  // Check if an array includes a specific value
294
- "{{includes([1, 2, 3], 5)}}" // Returns false
302
+ "{{includes([1, 2, 3], 5)}}"; // Returns false
295
303
 
296
304
  // Can be used with context variables
297
- "{{includes($.allowedRoles, $.currentUser.role)}}"
305
+ "{{includes($.allowedRoles, $.currentUser.role)}}";
298
306
 
299
307
  // Check if an array includes all of values of the second array
300
- "{{includes([1, 2, 3, 4], [2, 4])}}" // Returns true
308
+ "{{includes([1, 2, 3, 4], [2, 4])}}"; // Returns true
301
309
  ```
302
310
 
303
311
  ###### includesSome(array, value)
@@ -310,16 +318,16 @@ Checks if an array includes at least one value from another array or a single va
310
318
 
311
319
  ```js
312
320
  // Check if an array includes at least one value
313
- "{{includesSome([1, 2, 3], 2)}}" // Returns true
321
+ "{{includesSome([1, 2, 3], 2)}}"; // Returns true
314
322
 
315
323
  // Check if an array includes at least one value from another array
316
- "{{includesSome([1, 2, 3], [2, 5])}}" // Returns true
324
+ "{{includesSome([1, 2, 3], [2, 5])}}"; // Returns true
317
325
 
318
326
  // Check if an array includes at least one value from another array (none match)
319
- "{{includesSome([1, 2, 3], [4, 5])}}" // Returns false
327
+ "{{includesSome([1, 2, 3], [4, 5])}}"; // Returns false
320
328
 
321
329
  // Can be used with context variables
322
- "{{includesSome($.allowedRoles, $.currentUser.roles)}}"
330
+ "{{includesSome($.allowedRoles, $.currentUser.roles)}}";
323
331
  ```
324
332
 
325
333
  ##### Object Functions
@@ -333,12 +341,12 @@ Checks if an object is present (not null or undefined).
333
341
 
334
342
  ```js
335
343
  // Check if an object is present
336
- "{{present({})}}" // Returns true
337
- "{{present(null)}}" // Returns false
338
- "{{present(undefined)}}" // Returns false
339
- "{{present('string')}}" // Returns true
340
- "{{present(0)}}" // Returns true
341
- "{{present([])}}" // Returns true
344
+ "{{present({})}}"; // Returns true
345
+ "{{present(null)}}"; // Returns false
346
+ "{{present(undefined)}}"; // Returns false
347
+ "{{present('string')}}"; // Returns true
348
+ "{{present(0)}}"; // Returns true
349
+ "{{present([])}}"; // Returns true
342
350
  ```
343
351
 
344
352
  ###### missing(object)
@@ -350,12 +358,12 @@ Checks if an object is missing (null or undefined).
350
358
 
351
359
  ```js
352
360
  // Check if an object is not present
353
- "{{missing({})}}" // Returns false
354
- "{{missing(null)}}" // Returns true
355
- "{{missing(undefined)}}" // Returns true
356
- "{{missing('string')}}" // Returns false
357
- "{{missing(0)}}" // Returns false
358
- "{{missing([])}}" // Returns false
361
+ "{{missing({})}}"; // Returns false
362
+ "{{missing(null)}}"; // Returns true
363
+ "{{missing(undefined)}}"; // Returns true
364
+ "{{missing('string')}}"; // Returns false
365
+ "{{missing(0)}}"; // Returns false
366
+ "{{missing([])}}"; // Returns false
359
367
  ```
360
368
 
361
369
  ###### keys(object)
@@ -367,10 +375,10 @@ Returns the keys of an object as an array. If the input is not an object, null,
367
375
 
368
376
  ```js
369
377
  // Get keys from an object
370
- "{{keys({ a: 1, b: 2 })}}" // Returns ["a", "b"]
378
+ "{{keys({ a: 1, b: 2 })}}"; // Returns ["a", "b"]
371
379
 
372
380
  // Get keys from a context variable
373
- "{{keys($.user)}}"
381
+ "{{keys($.user)}}";
374
382
  ```
375
383
 
376
384
  ###### values(object)
@@ -382,14 +390,36 @@ Returns the values of an object as an array. If the input is not an object, null
382
390
 
383
391
  ```js
384
392
  // Get values from an object
385
- "{{values({ a: 1, b: 2 })}}" // Returns [1, 2]
393
+ "{{values({ a: 1, b: 2 })}}"; // Returns [1, 2]
386
394
 
387
395
  // Get values from a context variable
388
- "{{values($.user)}}"
396
+ "{{values($.user)}}";
389
397
  ```
390
398
 
391
399
  ##### String Functions
392
400
 
401
+ ###### capitalize(value, mode?)
402
+
403
+ Capitalizes characters in a string.
404
+
405
+ - `value` (string): The string to capitalize
406
+ - `mode` (string, optional): 'first' to capitalize first character only, 'each' to capitalize each word (default: 'first')
407
+ - Returns: capitalized string, or empty string for invalid input
408
+
409
+ ```js
410
+ // Capitalize first character (default)
411
+ "{{capitalize('hello')}}"; // Returns "Hello"
412
+ "{{capitalize('hello world')}}"; // Returns "Hello world"
413
+
414
+ // Capitalize each word
415
+ "{{capitalize('hello world', 'each')}}"; // Returns "Hello World"
416
+ "{{capitalize('the great gatsby', 'each')}}"; // Returns "The Great Gatsby"
417
+
418
+ // Capitalize from context variable
419
+ "{{capitalize($.name)}}";
420
+ "{{capitalize($.title, 'each')}}";
421
+ ```
422
+
393
423
  ###### decodeBase64(encodedValue)
394
424
 
395
425
  Decodes a Base64 encoded string and returns the decoded result.
@@ -430,6 +460,59 @@ Encodes a string to Base64 and returns the encoded result.
430
460
  "{{encodeBase64("")}}" // Returns ""
431
461
  ```
432
462
 
463
+ ###### truncate(value, maxLength, suffix?)
464
+
465
+ Truncates a string to a specified maximum length, optionally appending a suffix.
466
+
467
+ - `value` (string): The string to truncate
468
+ - `maxLength` (number): Maximum length of the result (including suffix)
469
+ - `suffix` (string, optional): Suffix to append when truncating, defaults to "..."
470
+ - Returns: truncated string, or original string if shorter than maxLength
471
+
472
+ ```js
473
+ // Truncate with default suffix
474
+ "{{truncate('Hello World', 8)}}"; // Returns "Hello..."
475
+
476
+ // Truncate with custom suffix
477
+ "{{truncate('Hello World', 8, '…')}}"; // Returns "Hello W…"
478
+
479
+ // Truncate with no suffix
480
+ "{{truncate('Hello World', 5, '')}}"; // Returns "Hello"
481
+
482
+ // No truncation needed
483
+ "{{truncate('Hi', 10)}}"; // Returns "Hi"
484
+
485
+ // Truncate from context variable
486
+ "{{truncate($.description, 100)}}";
487
+ ```
488
+
489
+ ###### padStart(value, targetLength, padString?)
490
+
491
+ Pads the start of a string with another string until it reaches the target length.
492
+
493
+ - `value` (string | number): The value to pad (numbers are converted to strings)
494
+ - `targetLength` (number): The target length of the resulting string
495
+ - `padString` (string, optional): The string to pad with, defaults to space " "
496
+ - Returns: padded string, or original if already at or beyond target length
497
+
498
+ ```js
499
+ // Pad with zeros (common for formatting numbers)
500
+ "{{padStart('5', 3, '0')}}"; // Returns "005"
501
+ "{{padStart(5, 3, '0')}}"; // Returns "005" (numbers work too)
502
+
503
+ // Pad with default space
504
+ "{{padStart('hello', 10)}}"; // Returns " hello"
505
+
506
+ // Pad with custom character
507
+ "{{padStart('abc', 6, '*')}}"; // Returns "***abc"
508
+
509
+ // No padding needed if already long enough
510
+ "{{padStart('hello', 3)}}"; // Returns "hello"
511
+
512
+ // Pad from context variable
513
+ "{{padStart($.id, 8, '0')}}";
514
+ ```
515
+
433
516
  For more information on the JEXL syntax, refer to the [JEXL Syntax documentation](https://commons.apache.org/proper/commons-jexl/reference/syntax.html).
434
517
 
435
518
  ### String Interpolation
@@ -440,16 +523,16 @@ Examples:
440
523
 
441
524
  ```js
442
525
  // Given the context: { name: "John", age: 30 }
443
- "Hello ${name}" // Returns "Hello John"
444
- "User is ${age}" // Returns "User is 30"
526
+ "Hello ${name}"; // Returns "Hello John"
527
+ "User is ${age}"; // Returns "User is 30"
445
528
  // You can also use JEXL inside string syntax
446
- "Status: ${age > 18 ? 'Adult' : 'Minor'}" // Returns "Status: Adult"
447
- "Age in 5 years: ${age + 5}" // Returns "Age in 5 years: 35"
529
+ "Status: ${age > 18 ? 'Adult' : 'Minor'}"; // Returns "Status: Adult"
530
+ "Age in 5 years: ${age + 5}"; // Returns "Age in 5 years: 35"
448
531
  ```
449
532
 
450
533
  Note: If the expression is a string without any of the patterns described above, it will be returned as is.
451
534
 
452
535
  ```js
453
536
  // Given the context: { name: "John", age: 30 }
454
- "Hello world" // Returns "Hello world"
537
+ "Hello world"; // Returns "Hello world"
455
538
  ```
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`@stackone/utils`),l=require(`jexl`);l=s(l);let u=require(`jsonpath-plus`);const d=`capitalize`,f=(e,t=`first`)=>(0,c.isMissing)(e)||typeof e!=`string`?``:(t===`each`?`each`:`first`)==`each`?e.split(/(\s+)/).map(e=>e.trim()?e.charAt(0).toUpperCase()+e.slice(1):e).join(``):e.charAt(0).toUpperCase()+e.slice(1),p=`padStart`,m=(e,t,n=` `)=>{if(e==null)return``;let r=String(e);if((0,c.isMissing)(t)||typeof t!=`number`||t<0)return r;let i=typeof n==`string`?n:` `;return r.padStart(t,i)},h=`truncate`,g=(e,t,n=`...`)=>{if((0,c.isMissing)(e)||typeof e!=`string`)return``;if((0,c.isMissing)(t)||typeof t!=`number`||t<0)return e;let r=typeof n==`string`?n:`...`;if(e.length<=t)return e;let i=Math.max(0,t-r.length);return i<=0?e.slice(0,t):e.slice(0,i)+r},_=(e=()=>new l.Jexl)=>{let t=e();return t.addFunction(`nextAnniversary`,(e,t)=>(0,c.calculateNextAnniversary)({initialDate:e,format:t})),t.addFunction(`yearsElapsed`,(e,t,n)=>(0,c.calculateYearsElapsed)({startDate:e,endDate:n,format:t})),t.addFunction(`hasPassed`,(e,t,n)=>(0,c.dateHasPassed)({date:e,yearsToAdd:n,format:t})),t.addFunction(`now`,()=>new Date().toISOString()),t.addFunction(`includes`,(e,t)=>(0,c.isMissing)(e)||!Array.isArray(e)||e.length===0||(0,c.isMissing)(t)?!1:Array.isArray(t)?t.every(t=>e.includes(t)):e.includes(t)),t.addFunction(`includesSome`,(e,t)=>(0,c.isMissing)(e)||!Array.isArray(e)||e.length===0||(0,c.isMissing)(t)?!1:Array.isArray(t)?t.some(t=>e.includes(t)):e.includes(t)),t.addFunction(`present`,e=>(0,c.notMissing)(e)),t.addFunction(`missing`,e=>(0,c.isMissing)(e)),t.addFunction(`keys`,e=>(0,c.isMissing)(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.keys(e):[]),t.addFunction(`values`,e=>(0,c.isMissing)(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.values(e):[]),t.addFunction(`decodeBase64`,e=>{if((0,c.isMissing)(e)||typeof e!=`string`)return``;try{return(0,c.decodeFromBase64)(e)}catch{return``}}),t.addFunction(`encodeBase64`,e=>{if((0,c.isMissing)(e)||typeof e!=`string`)return``;try{return(0,c.encodeToBase64)(e)}catch{return``}}),t.addFunction(`deltaFromNowMs`,(e,t)=>{let n=Date.now(),r;if(typeof e==`number`)r=t===`seconds`?e*1e3:e;else if(typeof e==`string`)r=t===`timestamp`?parseInt(e,10):t===`seconds`?parseFloat(e)*1e3:new Date(e).getTime();else throw Error(`Unsupported date input type`);return r-n}),t.addBinaryOp(`??`,0,(e,t)=>(0,c.isMissing)(e)?t:(0,c.isMissing)(t)?e:e??t),t.addFunction(`capitalize`,f),t.addFunction(`padStart`,m),t.addFunction(`truncate`,g),t},v=/\${([^}]+)}/g,y=e=>e.replace(/\$\./g,``).trim(),b=(e,t)=>{try{return e.compile(t)}catch{return null}},x=e=>{if(e.startsWith(`{{`)&&e.endsWith(`}}`))return e.slice(2,-2)},S=(e,t)=>{try{if(!e.startsWith(`$`))throw Error(`JSONPath expression must start with '$': ${e}`);if(e.includes(`$_`)||e.match(/\$[^.[]/g)||e.includes(`[`)&&!e.includes(`]`)||e.includes(` `)&&!e.includes(`[`))throw Error(`Invalid JSONPath expression: ${e}`);let n=(0,u.JSONPath)({path:e,json:t});return n.length===0?void 0:n.length===1?n[0]:n}catch{throw Error(`Invalid JSONPath expression: ${e}`)}},C=(e,t,n)=>e.replace(t,String(n)),w=(e,t,n,r)=>{let i=e.path.trim();if(!i)return r;try{let a=b(t,i);if(a){let t=a.evalSync(n);if(t!==void 0)return C(r,e.toReplace,t)}let o=O(`$.${i}`,n).value;return(0,c.notMissing)(o)?C(r,e.toReplace,o):r}catch{return r}},T=(e,t,n)=>{let r=e.match(v);if(!r)return;let i=r.length,a=Array(i);for(let e=0;e<i;e++)a[e]={toReplace:r[e],path:r[e].slice(2,-1)};return a.reduce((e,r)=>w(r,n,t,e),String(e))},E=(e,t,n,r)=>{if(Array.isArray(t)){let e=parseInt(n,10);if(!isNaN(e)&&(e<0||e>=t.length))return{value:void 0,error:`Invalid array index '${n}' at '${r}'`,availableKeys:t.map((e,t)=>t.toString())}}return(0,c.isObject)(t)?{value:void 0,error:`Key '${n}' not found at '${r}'`,availableKeys:Object.keys(t)}:{value:void 0,error:`${e} at '${r}'`,availableKeys:[]}},D=(e,t)=>{if(e[0]!==`$`)return{value:void 0,error:`JSON path must start with $`};let n=t,r=`$`;for(let t=1;t<e.length;t++){let i=e[t],a=i.startsWith(`[`)?`${r}${i}`:`${r}.${i}`;if(Array.isArray(n)){let e=parseInt(i,10);if(isNaN(e)||e<0||e>=n.length)return E(`Invalid array index`,n,i,r);n=n[e],r=a}else if((0,c.isObject)(n)){if(!Object.prototype.hasOwnProperty.call(n,i))return E(`Key not found`,n,i,r);n=n[i],r=a}else return{value:void 0,error:`Cannot access '${i}' at '${r}' - parent is not an object`,availableKeys:[]}}return{value:n}},O=(e,t)=>{let n=/(\.\.)|(\[\*\])|(\[\?\()|(\[\d+:\d+\])/;try{if(n.test(e)){let n=S(e,t);return n===void 0?{value:void 0,error:`Invalid or empty JSONPath: '${e}'`}:{value:n}}return D((e.match(/\$|(?:\['([^']+)'\])|(?:\["([^"]+)"\])|\[\d+\]|[^[\].]+/g)||[]).map(e=>e.replace(/^\['([^']+)'\]$/,`$1`).replace(/^\["([^"]+)"\]$/,`$1`).replace(/^\[(\d+)\]$/,`$1`)),t)}catch(e){return{value:void 0,error:`Something went wrong with evaluation of JSON path: ${String(e)}`}}},k=(e,t)=>{let n=O(e,t);if(n.error)throw Error(`${n.error}${n.availableKeys?.length?`. Available keys: ${n.availableKeys.join(`, `)}`:``}`);return n.value},A=(e,t)=>{try{return S(e,t)}catch{throw Error(`Invalid JSON path: "${e}"`)}},j=(e,t,n)=>{let r=e?.trim();if(r==null||r===``)throw Error(`Empty expression`);let i=(0,c.isObject)(t)?t:{},a=_(),o=x(r),s=y(o??r),l=T(s,i,a);if(l)return l;if(!o&&r.startsWith(`$`))return n?.incrementalJsonPath?k(r,i):A(r,i);if(!l&&!o)return e;let u=b(a,s);if(!u||s===`.`)throw Error(`Invalid expression: "${r}"`);try{return u.evalSync(i)}catch{return}},M=(e,t)=>{try{return j(e,t)}catch{return null}},N=(e,t)=>{let n=e=>Array.isArray(e)?e.map(n):typeof e==`object`&&e?N(e,t):typeof e==`string`?M(e,t):e;return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,n(t)]))},P=e=>{try{return j(e),!0}catch{return!1}};exports.evaluate=j,exports.isValidExpression=P,exports.safeEvaluate=M,exports.safeEvaluateRecord=N;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{calculateNextAnniversary as e,calculateYearsElapsed as t,dateHasPassed as n,decodeFromBase64 as r,encodeToBase64 as i,isMissing as a,isObject as o,notMissing as s}from"@stackone/utils";import*as c from"jexl";import{JSONPath as l}from"jsonpath-plus";const u=(o=()=>new c.Jexl)=>{let l=o();return l.addFunction(`nextAnniversary`,(t,n)=>e({initialDate:t,format:n})),l.addFunction(`yearsElapsed`,(e,n,r)=>t({startDate:e,endDate:r,format:n})),l.addFunction(`hasPassed`,(e,t,r)=>n({date:e,yearsToAdd:r,format:t})),l.addFunction(`now`,()=>new Date().toISOString()),l.addFunction(`includes`,(e,t)=>a(e)||!Array.isArray(e)||e.length===0||a(t)?!1:Array.isArray(t)?t.every(t=>e.includes(t)):e.includes(t)),l.addFunction(`includesSome`,(e,t)=>a(e)||!Array.isArray(e)||e.length===0||a(t)?!1:Array.isArray(t)?t.some(t=>e.includes(t)):e.includes(t)),l.addFunction(`present`,e=>s(e)),l.addFunction(`missing`,e=>a(e)),l.addFunction(`keys`,e=>a(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.keys(e):[]),l.addFunction(`values`,e=>a(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.values(e):[]),l.addFunction(`decodeBase64`,e=>{if(a(e)||typeof e!=`string`)return``;try{return r(e)}catch{return``}}),l.addFunction(`encodeBase64`,e=>{if(a(e)||typeof e!=`string`)return``;try{return i(e)}catch{return``}}),l.addFunction(`deltaFromNowMs`,(e,t)=>{let n=Date.now(),r;if(typeof e==`number`)r=t===`seconds`?e*1e3:e;else if(typeof e==`string`)r=t===`timestamp`?parseInt(e,10):t===`seconds`?parseFloat(e)*1e3:new Date(e).getTime();else throw Error(`Unsupported date input type`);return r-n}),l.addBinaryOp(`??`,0,(e,t)=>a(e)?t:a(t)?e:e??t),l},d=/\${([^}]+)}/g,f=e=>e.replace(/\$\./g,``).trim(),p=(e,t)=>{try{let n=e.compile(t);return n}catch{return null}},m=e=>{if(e.startsWith(`{{`)&&e.endsWith(`}}`))return e.slice(2,-2)},h=(e,t)=>{try{if(!e.startsWith(`$`))throw Error(`JSONPath expression must start with '$': ${e}`);if(e.includes(`$_`)||e.match(/\$[^.[]/g)||e.includes(`[`)&&!e.includes(`]`)||e.includes(` `)&&!e.includes(`[`))throw Error(`Invalid JSONPath expression: ${e}`);let n=l({path:e,json:t});return n.length===0?void 0:n.length===1?n[0]:n}catch{throw Error(`Invalid JSONPath expression: ${e}`)}},g=(e,t,n)=>e.replace(t,String(n)),_=(e,t,n,r)=>{let i=e.path.trim();if(!i)return r;try{let a=p(t,i);if(a){let t=a.evalSync(n);if(t!==void 0)return g(r,e.toReplace,t)}let o=x(`$.${i}`,n),c=o.value;return s(c)?g(r,e.toReplace,c):r}catch{return r}},v=(e,t,n)=>{let r=e.match(d);if(!r)return;let i=r.length,a=Array(i);for(let e=0;e<i;e++)a[e]={toReplace:r[e],path:r[e].slice(2,-1)};return a.reduce((e,r)=>_(r,n,t,e),String(e))},y=(e,t,n,r)=>{if(Array.isArray(t)){let e=parseInt(n,10);if(!isNaN(e)&&(e<0||e>=t.length))return{value:void 0,error:`Invalid array index '${n}' at '${r}'`,availableKeys:t.map((e,t)=>t.toString())}}return o(t)?{value:void 0,error:`Key '${n}' not found at '${r}'`,availableKeys:Object.keys(t)}:{value:void 0,error:`${e} at '${r}'`,availableKeys:[]}},b=(e,t)=>{if(e[0]!==`$`)return{value:void 0,error:`JSON path must start with $`};let n=t,r=`$`;for(let t=1;t<e.length;t++){let i=e[t],a=i.startsWith(`[`)?`${r}${i}`:`${r}.${i}`;if(Array.isArray(n)){let e=parseInt(i,10);if(isNaN(e)||e<0||e>=n.length)return y(`Invalid array index`,n,i,r);n=n[e],r=a}else if(o(n)){if(!Object.prototype.hasOwnProperty.call(n,i))return y(`Key not found`,n,i,r);n=n[i],r=a}else return{value:void 0,error:`Cannot access '${i}' at '${r}' - parent is not an object`,availableKeys:[]}}return{value:n}},x=(e,t)=>{let n=/(\.\.)|(\[\*\])|(\[\?\()|(\[\d+:\d+\])/;try{if(n.test(e)){let n=h(e,t);return n===void 0?{value:void 0,error:`Invalid or empty JSONPath: '${e}'`}:{value:n}}let r=e.match(/\$|(?:\['([^']+)'\])|(?:\["([^"]+)"\])|\[\d+\]|[^[\].]+/g)||[],i=r.map(e=>e.replace(/^\['([^']+)'\]$/,`$1`).replace(/^\["([^"]+)"\]$/,`$1`).replace(/^\[(\d+)\]$/,`$1`));return b(i,t)}catch(e){return{value:void 0,error:`Something went wrong with evaluation of JSON path: ${String(e)}`}}},S=(e,t)=>{let n=x(e,t);if(n.error)throw Error(`${n.error}${n.availableKeys?.length?`. Available keys: ${n.availableKeys.join(`, `)}`:``}`);return n.value},C=(e,t)=>{try{return h(e,t)}catch{throw Error(`Invalid JSON path: "${e}"`)}},w=(e,t,n)=>{let r=e?.trim();if(r==null||r===``)throw Error(`Empty expression`);let i=o(t)?t:{},a=u(),s=m(r),c=s??r,l=f(c),d=v(l,i,a);if(d)return d;if(!s&&r.startsWith(`$`))return n?.incrementalJsonPath?S(r,i):C(r,i);if(!d&&!s)return e;let h=p(a,l);if(!h||l===`.`)throw Error(`Invalid expression: "${r}"`);try{return h.evalSync(i)}catch{return}},T=(e,t)=>{try{return w(e,t)}catch{return null}},E=(e,t)=>{let n=e=>Array.isArray(e)?e.map(n):typeof e==`object`&&e?E(e,t):typeof e==`string`?T(e,t):e;return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,n(t)]))},D=e=>{try{return w(e),!0}catch{return!1}};export{w as evaluate,D as isValidExpression,T as safeEvaluate,E as safeEvaluateRecord};
1
+ import{calculateNextAnniversary as e,calculateYearsElapsed as t,dateHasPassed as n,decodeFromBase64 as r,encodeToBase64 as i,isMissing as a,isObject as o,notMissing as s}from"@stackone/utils";import*as c from"jexl";import{JSONPath as l}from"jsonpath-plus";const u=(e,t=`first`)=>a(e)||typeof e!=`string`?``:(t===`each`?`each`:`first`)==`each`?e.split(/(\s+)/).map(e=>e.trim()?e.charAt(0).toUpperCase()+e.slice(1):e).join(``):e.charAt(0).toUpperCase()+e.slice(1),d=(e,t,n=` `)=>{if(e==null)return``;let r=String(e);if(a(t)||typeof t!=`number`||t<0)return r;let i=typeof n==`string`?n:` `;return r.padStart(t,i)},f=(e,t,n=`...`)=>{if(a(e)||typeof e!=`string`)return``;if(a(t)||typeof t!=`number`||t<0)return e;let r=typeof n==`string`?n:`...`;if(e.length<=t)return e;let i=Math.max(0,t-r.length);return i<=0?e.slice(0,t):e.slice(0,i)+r},p=(o=()=>new c.Jexl)=>{let l=o();return l.addFunction(`nextAnniversary`,(t,n)=>e({initialDate:t,format:n})),l.addFunction(`yearsElapsed`,(e,n,r)=>t({startDate:e,endDate:r,format:n})),l.addFunction(`hasPassed`,(e,t,r)=>n({date:e,yearsToAdd:r,format:t})),l.addFunction(`now`,()=>new Date().toISOString()),l.addFunction(`includes`,(e,t)=>a(e)||!Array.isArray(e)||e.length===0||a(t)?!1:Array.isArray(t)?t.every(t=>e.includes(t)):e.includes(t)),l.addFunction(`includesSome`,(e,t)=>a(e)||!Array.isArray(e)||e.length===0||a(t)?!1:Array.isArray(t)?t.some(t=>e.includes(t)):e.includes(t)),l.addFunction(`present`,e=>s(e)),l.addFunction(`missing`,e=>a(e)),l.addFunction(`keys`,e=>a(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.keys(e):[]),l.addFunction(`values`,e=>a(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.values(e):[]),l.addFunction(`decodeBase64`,e=>{if(a(e)||typeof e!=`string`)return``;try{return r(e)}catch{return``}}),l.addFunction(`encodeBase64`,e=>{if(a(e)||typeof e!=`string`)return``;try{return i(e)}catch{return``}}),l.addFunction(`deltaFromNowMs`,(e,t)=>{let n=Date.now(),r;if(typeof e==`number`)r=t===`seconds`?e*1e3:e;else if(typeof e==`string`)r=t===`timestamp`?parseInt(e,10):t===`seconds`?parseFloat(e)*1e3:new Date(e).getTime();else throw Error(`Unsupported date input type`);return r-n}),l.addBinaryOp(`??`,0,(e,t)=>a(e)?t:a(t)?e:e??t),l.addFunction(`capitalize`,u),l.addFunction(`padStart`,d),l.addFunction(`truncate`,f),l},m=/\${([^}]+)}/g,h=e=>e.replace(/\$\./g,``).trim(),g=(e,t)=>{try{return e.compile(t)}catch{return null}},_=e=>{if(e.startsWith(`{{`)&&e.endsWith(`}}`))return e.slice(2,-2)},v=(e,t)=>{try{if(!e.startsWith(`$`))throw Error(`JSONPath expression must start with '$': ${e}`);if(e.includes(`$_`)||e.match(/\$[^.[]/g)||e.includes(`[`)&&!e.includes(`]`)||e.includes(` `)&&!e.includes(`[`))throw Error(`Invalid JSONPath expression: ${e}`);let n=l({path:e,json:t});return n.length===0?void 0:n.length===1?n[0]:n}catch{throw Error(`Invalid JSONPath expression: ${e}`)}},y=(e,t,n)=>e.replace(t,String(n)),b=(e,t,n,r)=>{let i=e.path.trim();if(!i)return r;try{let a=g(t,i);if(a){let t=a.evalSync(n);if(t!==void 0)return y(r,e.toReplace,t)}let o=w(`$.${i}`,n).value;return s(o)?y(r,e.toReplace,o):r}catch{return r}},x=(e,t,n)=>{let r=e.match(m);if(!r)return;let i=r.length,a=Array(i);for(let e=0;e<i;e++)a[e]={toReplace:r[e],path:r[e].slice(2,-1)};return a.reduce((e,r)=>b(r,n,t,e),String(e))},S=(e,t,n,r)=>{if(Array.isArray(t)){let e=parseInt(n,10);if(!isNaN(e)&&(e<0||e>=t.length))return{value:void 0,error:`Invalid array index '${n}' at '${r}'`,availableKeys:t.map((e,t)=>t.toString())}}return o(t)?{value:void 0,error:`Key '${n}' not found at '${r}'`,availableKeys:Object.keys(t)}:{value:void 0,error:`${e} at '${r}'`,availableKeys:[]}},C=(e,t)=>{if(e[0]!==`$`)return{value:void 0,error:`JSON path must start with $`};let n=t,r=`$`;for(let t=1;t<e.length;t++){let i=e[t],a=i.startsWith(`[`)?`${r}${i}`:`${r}.${i}`;if(Array.isArray(n)){let e=parseInt(i,10);if(isNaN(e)||e<0||e>=n.length)return S(`Invalid array index`,n,i,r);n=n[e],r=a}else if(o(n)){if(!Object.prototype.hasOwnProperty.call(n,i))return S(`Key not found`,n,i,r);n=n[i],r=a}else return{value:void 0,error:`Cannot access '${i}' at '${r}' - parent is not an object`,availableKeys:[]}}return{value:n}},w=(e,t)=>{let n=/(\.\.)|(\[\*\])|(\[\?\()|(\[\d+:\d+\])/;try{if(n.test(e)){let n=v(e,t);return n===void 0?{value:void 0,error:`Invalid or empty JSONPath: '${e}'`}:{value:n}}return C((e.match(/\$|(?:\['([^']+)'\])|(?:\["([^"]+)"\])|\[\d+\]|[^[\].]+/g)||[]).map(e=>e.replace(/^\['([^']+)'\]$/,`$1`).replace(/^\["([^"]+)"\]$/,`$1`).replace(/^\[(\d+)\]$/,`$1`)),t)}catch(e){return{value:void 0,error:`Something went wrong with evaluation of JSON path: ${String(e)}`}}},T=(e,t)=>{let n=w(e,t);if(n.error)throw Error(`${n.error}${n.availableKeys?.length?`. Available keys: ${n.availableKeys.join(`, `)}`:``}`);return n.value},E=(e,t)=>{try{return v(e,t)}catch{throw Error(`Invalid JSON path: "${e}"`)}},D=(e,t,n)=>{let r=e?.trim();if(r==null||r===``)throw Error(`Empty expression`);let i=o(t)?t:{},a=p(),s=_(r),c=h(s??r),l=x(c,i,a);if(l)return l;if(!s&&r.startsWith(`$`))return n?.incrementalJsonPath?T(r,i):E(r,i);if(!l&&!s)return e;let u=g(a,c);if(!u||c===`.`)throw Error(`Invalid expression: "${r}"`);try{return u.evalSync(i)}catch{return}},O=(e,t)=>{try{return D(e,t)}catch{return null}},k=(e,t)=>{let n=e=>Array.isArray(e)?e.map(n):typeof e==`object`&&e?k(e,t):typeof e==`string`?O(e,t):e;return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,n(t)]))},A=e=>{try{return D(e),!0}catch{return!1}};export{D as evaluate,A as isValidExpression,O as safeEvaluate,k as safeEvaluateRecord};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@stackone/expressions",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "",
5
- "main": "dist/index.js",
5
+ "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
7
- "types": "dist/index.d.ts",
7
+ "types": "dist/index.d.cts",
8
8
  "files": [
9
9
  "dist",
10
10
  "package.json",
@@ -12,9 +12,9 @@
12
12
  ],
13
13
  "exports": {
14
14
  ".": {
15
- "types": "./dist/index.d.ts",
15
+ "types": "./dist/index.d.cts",
16
16
  "import": "./dist/index.mjs",
17
- "require": "./dist/index.js"
17
+ "require": "./dist/index.cjs"
18
18
  },
19
19
  "./package.json": "./package.json"
20
20
  },
@@ -56,4 +56,4 @@
56
56
  "cjs"
57
57
  ]
58
58
  }
59
- }
59
+ }
package/dist/index.js DELETED
@@ -1 +0,0 @@
1
- var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=s(require(`@stackone/utils`)),l=s(require(`jexl`)),u=s(require(`jsonpath-plus`)),d=(e=()=>new l.Jexl)=>{let t=e();return t.addFunction(`nextAnniversary`,(e,t)=>(0,c.calculateNextAnniversary)({initialDate:e,format:t})),t.addFunction(`yearsElapsed`,(e,t,n)=>(0,c.calculateYearsElapsed)({startDate:e,endDate:n,format:t})),t.addFunction(`hasPassed`,(e,t,n)=>(0,c.dateHasPassed)({date:e,yearsToAdd:n,format:t})),t.addFunction(`now`,()=>new Date().toISOString()),t.addFunction(`includes`,(e,t)=>(0,c.isMissing)(e)||!Array.isArray(e)||e.length===0||(0,c.isMissing)(t)?!1:Array.isArray(t)?t.every(t=>e.includes(t)):e.includes(t)),t.addFunction(`includesSome`,(e,t)=>(0,c.isMissing)(e)||!Array.isArray(e)||e.length===0||(0,c.isMissing)(t)?!1:Array.isArray(t)?t.some(t=>e.includes(t)):e.includes(t)),t.addFunction(`present`,e=>(0,c.notMissing)(e)),t.addFunction(`missing`,e=>(0,c.isMissing)(e)),t.addFunction(`keys`,e=>(0,c.isMissing)(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.keys(e):[]),t.addFunction(`values`,e=>(0,c.isMissing)(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.values(e):[]),t.addFunction(`decodeBase64`,e=>{if((0,c.isMissing)(e)||typeof e!=`string`)return``;try{return(0,c.decodeFromBase64)(e)}catch{return``}}),t.addFunction(`encodeBase64`,e=>{if((0,c.isMissing)(e)||typeof e!=`string`)return``;try{return(0,c.encodeToBase64)(e)}catch{return``}}),t.addFunction(`deltaFromNowMs`,(e,t)=>{let n=Date.now(),r;if(typeof e==`number`)r=t===`seconds`?e*1e3:e;else if(typeof e==`string`)r=t===`timestamp`?parseInt(e,10):t===`seconds`?parseFloat(e)*1e3:new Date(e).getTime();else throw Error(`Unsupported date input type`);return r-n}),t.addBinaryOp(`??`,0,(e,t)=>(0,c.isMissing)(e)?t:(0,c.isMissing)(t)?e:e??t),t},f=/\${([^}]+)}/g,p=e=>e.replace(/\$\./g,``).trim(),m=(e,t)=>{try{let n=e.compile(t);return n}catch{return null}},h=e=>{if(e.startsWith(`{{`)&&e.endsWith(`}}`))return e.slice(2,-2)},g=(e,t)=>{try{if(!e.startsWith(`$`))throw Error(`JSONPath expression must start with '$': ${e}`);if(e.includes(`$_`)||e.match(/\$[^.[]/g)||e.includes(`[`)&&!e.includes(`]`)||e.includes(` `)&&!e.includes(`[`))throw Error(`Invalid JSONPath expression: ${e}`);let n=(0,u.JSONPath)({path:e,json:t});return n.length===0?void 0:n.length===1?n[0]:n}catch{throw Error(`Invalid JSONPath expression: ${e}`)}},_=(e,t,n)=>e.replace(t,String(n)),v=(e,t,n,r)=>{let i=e.path.trim();if(!i)return r;try{let a=m(t,i);if(a){let t=a.evalSync(n);if(t!==void 0)return _(r,e.toReplace,t)}let o=S(`$.${i}`,n),s=o.value;return(0,c.notMissing)(s)?_(r,e.toReplace,s):r}catch{return r}},y=(e,t,n)=>{let r=e.match(f);if(!r)return;let i=r.length,a=Array(i);for(let e=0;e<i;e++)a[e]={toReplace:r[e],path:r[e].slice(2,-1)};return a.reduce((e,r)=>v(r,n,t,e),String(e))},b=(e,t,n,r)=>{if(Array.isArray(t)){let e=parseInt(n,10);if(!isNaN(e)&&(e<0||e>=t.length))return{value:void 0,error:`Invalid array index '${n}' at '${r}'`,availableKeys:t.map((e,t)=>t.toString())}}return(0,c.isObject)(t)?{value:void 0,error:`Key '${n}' not found at '${r}'`,availableKeys:Object.keys(t)}:{value:void 0,error:`${e} at '${r}'`,availableKeys:[]}},x=(e,t)=>{if(e[0]!==`$`)return{value:void 0,error:`JSON path must start with $`};let n=t,r=`$`;for(let t=1;t<e.length;t++){let i=e[t],a=i.startsWith(`[`)?`${r}${i}`:`${r}.${i}`;if(Array.isArray(n)){let e=parseInt(i,10);if(isNaN(e)||e<0||e>=n.length)return b(`Invalid array index`,n,i,r);n=n[e],r=a}else if((0,c.isObject)(n)){if(!Object.prototype.hasOwnProperty.call(n,i))return b(`Key not found`,n,i,r);n=n[i],r=a}else return{value:void 0,error:`Cannot access '${i}' at '${r}' - parent is not an object`,availableKeys:[]}}return{value:n}},S=(e,t)=>{let n=/(\.\.)|(\[\*\])|(\[\?\()|(\[\d+:\d+\])/;try{if(n.test(e)){let n=g(e,t);return n===void 0?{value:void 0,error:`Invalid or empty JSONPath: '${e}'`}:{value:n}}let r=e.match(/\$|(?:\['([^']+)'\])|(?:\["([^"]+)"\])|\[\d+\]|[^[\].]+/g)||[],i=r.map(e=>e.replace(/^\['([^']+)'\]$/,`$1`).replace(/^\["([^"]+)"\]$/,`$1`).replace(/^\[(\d+)\]$/,`$1`));return x(i,t)}catch(e){return{value:void 0,error:`Something went wrong with evaluation of JSON path: ${String(e)}`}}},C=(e,t)=>{let n=S(e,t);if(n.error)throw Error(`${n.error}${n.availableKeys?.length?`. Available keys: ${n.availableKeys.join(`, `)}`:``}`);return n.value},w=(e,t)=>{try{return g(e,t)}catch{throw Error(`Invalid JSON path: "${e}"`)}},T=(e,t,n)=>{let r=e?.trim();if(r==null||r===``)throw Error(`Empty expression`);let i=(0,c.isObject)(t)?t:{},a=d(),o=h(r),s=o??r,l=p(s),u=y(l,i,a);if(u)return u;if(!o&&r.startsWith(`$`))return n?.incrementalJsonPath?C(r,i):w(r,i);if(!u&&!o)return e;let f=m(a,l);if(!f||l===`.`)throw Error(`Invalid expression: "${r}"`);try{return f.evalSync(i)}catch{return}},E=(e,t)=>{try{return T(e,t)}catch{return null}},D=(e,t)=>{let n=e=>Array.isArray(e)?e.map(n):typeof e==`object`&&e?D(e,t):typeof e==`string`?E(e,t):e;return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,n(t)]))},O=e=>{try{return T(e),!0}catch{return!1}};exports.evaluate=T,exports.isValidExpression=O,exports.safeEvaluate=E,exports.safeEvaluateRecord=D;
File without changes