@statedelta-libs/expressions 0.2.1 → 1.1.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 +168 -12
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +72 -20
- package/dist/index.d.ts +72 -20
- package/dist/index.js +1 -1
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
- **$pipe** - Composição com valor inicial (sintaxe DSL)
|
|
15
15
|
- **Path syntax** - Suporte a wildcards (`items[*].price`)
|
|
16
16
|
- **Dependency extraction** - Para dirty tracking/reatividade
|
|
17
|
-
- **
|
|
17
|
+
- **Conditions nativo** - Condicionais integradas com expressions nos lados
|
|
18
18
|
- **Type-safe** - TypeScript nativo com inferência
|
|
19
19
|
|
|
20
20
|
## Instalação
|
|
@@ -93,6 +93,75 @@ fn(data); // Executa (mais rápido que compile())
|
|
|
93
93
|
| Hot path crítico | `compileAST()` | V8 JIT otimiza melhor |
|
|
94
94
|
| Expressões complexas | `compileAST()` | Ganho maior em nested calls |
|
|
95
95
|
|
|
96
|
+
#### useAccessor (compileAST)
|
|
97
|
+
|
|
98
|
+
Para contextos inteligentes (ex: `TickContext`), use `useAccessor: true` para gerar `accessor(path, data)` ao invés de acesso direto:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const ctx = new TickContext();
|
|
102
|
+
|
|
103
|
+
const { fn } = compileAST(
|
|
104
|
+
{ $fn: "add", args: [{ $: "hp" }, { $: "mp" }] },
|
|
105
|
+
{
|
|
106
|
+
scope: {
|
|
107
|
+
add,
|
|
108
|
+
accessor: (path) => ctx.get(path) // closure que captura ctx
|
|
109
|
+
},
|
|
110
|
+
useAccessor: true
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
fn(); // usa ctx.get("hp") + ctx.get("mp")
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Código gerado:
|
|
118
|
+
```js
|
|
119
|
+
(function(scope){
|
|
120
|
+
const{add,accessor}=scope;
|
|
121
|
+
return function(data){
|
|
122
|
+
return add(accessor("hp",data),accessor("mp",data))
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### lexicalPrefix (compileAST)
|
|
128
|
+
|
|
129
|
+
Para máxima performance em paths específicos, use `lexicalPrefix` para acesso direto via destructuring:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
const ctx = new TickContext();
|
|
133
|
+
|
|
134
|
+
const { fn } = compileAST(
|
|
135
|
+
{ $fn: "add", args: [{ $: "hp" }, { $: "params.damage" }] },
|
|
136
|
+
{
|
|
137
|
+
scope: {
|
|
138
|
+
add,
|
|
139
|
+
accessor: (path) => ctx.get(path)
|
|
140
|
+
},
|
|
141
|
+
useAccessor: true,
|
|
142
|
+
lexicalPrefix: "params" // params.* vai direto, resto via accessor
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
fn({ params: { damage: 25 } }); // ctx.get("hp") + params.damage
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Código gerado:
|
|
150
|
+
```js
|
|
151
|
+
(function(scope){
|
|
152
|
+
const{add,accessor}=scope;
|
|
153
|
+
return function(data){
|
|
154
|
+
const{params}=data??{}; // destructuring direto (rápido!)
|
|
155
|
+
return add(accessor("hp",data),params?.damage)
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
| Path | Com lexicalPrefix | Sem lexicalPrefix |
|
|
161
|
+
|------|-------------------|-------------------|
|
|
162
|
+
| `params.damage` | `params?.damage` (direto) | `accessor("params.damage", data)` |
|
|
163
|
+
| `hp` | `accessor("hp", data)` | `accessor("hp", data)` |
|
|
164
|
+
|
|
96
165
|
### evaluate() / evaluateAST()
|
|
97
166
|
|
|
98
167
|
Compila e executa em um passo.
|
|
@@ -122,6 +191,33 @@ const deps = extractDeps({
|
|
|
122
191
|
// ["$isVip", "price.vip", "price.regular"]
|
|
123
192
|
```
|
|
124
193
|
|
|
194
|
+
## JSON Aninhado (Walk Automático)
|
|
195
|
+
|
|
196
|
+
O compilador **percorre automaticamente** todo o JSON e resolve expressões onde quer que estejam:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
const { fn } = compile({
|
|
200
|
+
name: "John",
|
|
201
|
+
damage: { $: "params.damage" },
|
|
202
|
+
active: { $if: "hp.current", then: true, else: false },
|
|
203
|
+
nested: {
|
|
204
|
+
deep: {
|
|
205
|
+
value: { $fn: "add", args: [{ $: "a" }, { $: "b" }] }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}, { scope });
|
|
209
|
+
|
|
210
|
+
fn({ params: { damage: 25 }, hp: { current: 100 }, a: 1, b: 2 });
|
|
211
|
+
// {
|
|
212
|
+
// name: "John",
|
|
213
|
+
// damage: 25,
|
|
214
|
+
// active: true,
|
|
215
|
+
// nested: { deep: { value: 3 } }
|
|
216
|
+
// }
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Não precisa de walker manual - o `compile()` e `compileAST()` já fazem isso internamente.
|
|
220
|
+
|
|
125
221
|
## Tipos de Expressão
|
|
126
222
|
|
|
127
223
|
### Literal
|
|
@@ -146,7 +242,7 @@ true
|
|
|
146
242
|
|
|
147
243
|
```typescript
|
|
148
244
|
{
|
|
149
|
-
$if: {
|
|
245
|
+
$if: { left: { $: "age" }, op: "gte", right: 18 },
|
|
150
246
|
then: "adult",
|
|
151
247
|
else: "minor"
|
|
152
248
|
}
|
|
@@ -189,14 +285,36 @@ Chama função do scope com argumentos compilados.
|
|
|
189
285
|
// → scope.getTimestamp()
|
|
190
286
|
```
|
|
191
287
|
|
|
192
|
-
### Condition
|
|
288
|
+
### Condition
|
|
289
|
+
|
|
290
|
+
Condicionais compiladas internamente. Ambos os lados aceitam qualquer expressão:
|
|
193
291
|
|
|
194
292
|
```typescript
|
|
195
|
-
//
|
|
196
|
-
{
|
|
293
|
+
// Ref vs literal (básico)
|
|
294
|
+
{ left: { $: "user.age" }, op: "gte", right: 18 }
|
|
295
|
+
|
|
296
|
+
// Ref vs Ref
|
|
297
|
+
{ left: { $: "price" }, op: "lte", right: { $: "budget" } }
|
|
298
|
+
|
|
299
|
+
// $fn nos lados
|
|
300
|
+
{ left: { $fn: "add", args: [{ $: "a" }, { $: "b" }] }, op: "gt", right: 100 }
|
|
301
|
+
|
|
302
|
+
// $pipe no lado
|
|
303
|
+
{ left: { $pipe: [{ $: "name" }, { $fn: "upper" }] }, op: "eq", right: "ADMIN" }
|
|
304
|
+
|
|
305
|
+
// Condition group
|
|
306
|
+
{
|
|
307
|
+
logic: "AND",
|
|
308
|
+
conditions: [
|
|
309
|
+
{ left: { $: "active" }, op: "eq", right: true },
|
|
310
|
+
{ left: { $fn: "len", args: [{ $: "items" }] }, op: "gte", right: 3 }
|
|
311
|
+
]
|
|
312
|
+
}
|
|
197
313
|
```
|
|
198
314
|
|
|
199
|
-
|
|
315
|
+
**Operadores:** `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`, `contains`, `notContains`, `exists`, `notExists`, `matches`, `notMatches`, `startsWith`, `endsWith`
|
|
316
|
+
|
|
317
|
+
> **Nota:** Objetos com `op: "set"` ou outros operadores não-condition são tratados como literals.
|
|
200
318
|
|
|
201
319
|
## Scope
|
|
202
320
|
|
|
@@ -254,7 +372,7 @@ O accessor é propagado para:
|
|
|
254
372
|
- Shorthand de `$if` (`{ $if: "path", ... }`)
|
|
255
373
|
- Argumentos de `$fn`
|
|
256
374
|
- Steps de `$pipe`
|
|
257
|
-
- Conditions (
|
|
375
|
+
- Conditions (compiladas internamente)
|
|
258
376
|
|
|
259
377
|
**Performance:** Igual ao acesso direto (~25-30M ops/s).
|
|
260
378
|
|
|
@@ -347,16 +465,16 @@ O compilador detecta automaticamente o tipo de expressão baseado na estrutura d
|
|
|
347
465
|
| Conditional | `{ $if, then }` presentes | `{ $if: cond, then: x, else: y }` |
|
|
348
466
|
| Function | `{ $fn }` presente | `{ $fn: "add", args: [...] }` |
|
|
349
467
|
| Pipe | `{ $pipe }` presente | `{ $pipe: [...] }` |
|
|
350
|
-
| Condition | `{
|
|
468
|
+
| Condition | `{ left, op }` com operador válido | `{ left: { $: "age" }, op: "gte", right: 18 }` |
|
|
351
469
|
| Literal | Nenhum dos acima | `{ foo: "bar" }`, `42`, `"hello"` |
|
|
352
470
|
|
|
353
471
|
### Distinção entre Conditions e Effect Objects
|
|
354
472
|
|
|
355
|
-
Objetos com `
|
|
473
|
+
Objetos com `left` e `op` só são tratados como conditions se `op` for um operador válido:
|
|
356
474
|
|
|
357
475
|
```typescript
|
|
358
476
|
// ✓ Condition (op: "eq" é operador válido)
|
|
359
|
-
{
|
|
477
|
+
{ left: { $: "user.age" }, op: "eq", right: 18 }
|
|
360
478
|
|
|
361
479
|
// ✓ Literal object (op: "set" NÃO é operador de condition)
|
|
362
480
|
{ resource: "state", op: "set", path: "currentPlayer", value: "X" }
|
|
@@ -371,7 +489,7 @@ Funções declarativas para construir expressões. Disponíveis via namespace `b
|
|
|
371
489
|
```typescript
|
|
372
490
|
import { builders, compile } from '@statedelta-libs/expressions';
|
|
373
491
|
|
|
374
|
-
const { $, $fn, $if, $pipe } = builders;
|
|
492
|
+
const { $, $fn, $if, $pipe, $cond } = builders;
|
|
375
493
|
```
|
|
376
494
|
|
|
377
495
|
### `$` / `ref` - Path Reference
|
|
@@ -423,13 +541,33 @@ $pipe(
|
|
|
423
541
|
)
|
|
424
542
|
```
|
|
425
543
|
|
|
544
|
+
### `$cond` / `cond` - Condition
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
// Básico
|
|
548
|
+
$cond($("age"), "gte", 18)
|
|
549
|
+
// { left: { $: "age" }, op: "gte", right: 18 }
|
|
550
|
+
|
|
551
|
+
// Exists (sem right)
|
|
552
|
+
$cond($("email"), "exists")
|
|
553
|
+
|
|
554
|
+
// Ref vs Ref
|
|
555
|
+
$cond($("price"), "lte", $("budget"))
|
|
556
|
+
|
|
557
|
+
// Com $fn nos lados
|
|
558
|
+
$cond($fn("add", [$("a"), $("b")]), "gt", 100)
|
|
559
|
+
|
|
560
|
+
// Com $pipe
|
|
561
|
+
$cond($pipe($("name"), $fn("upper")), "eq", "ADMIN")
|
|
562
|
+
```
|
|
563
|
+
|
|
426
564
|
### Exemplo Completo
|
|
427
565
|
|
|
428
566
|
```typescript
|
|
429
567
|
import { builders, compile } from '@statedelta-libs/expressions';
|
|
430
568
|
import { filter, map, sum } from '@statedelta-libs/operators';
|
|
431
569
|
|
|
432
|
-
const { $, $fn, $if, $pipe } = builders;
|
|
570
|
+
const { $, $fn, $if, $pipe, $cond } = builders;
|
|
433
571
|
|
|
434
572
|
const scope = { filter, map, sum };
|
|
435
573
|
|
|
@@ -459,6 +597,7 @@ fn({
|
|
|
459
597
|
| `$` | `ref` |
|
|
460
598
|
| `$fn` | `fn` |
|
|
461
599
|
| `$pipe` | `pipe` |
|
|
600
|
+
| `$cond` | `cond` |
|
|
462
601
|
|
|
463
602
|
## TypeScript
|
|
464
603
|
|
|
@@ -470,6 +609,10 @@ import type {
|
|
|
470
609
|
ConditionalExpr,
|
|
471
610
|
FnExpr,
|
|
472
611
|
PipeExpr,
|
|
612
|
+
Condition,
|
|
613
|
+
ConditionGroup,
|
|
614
|
+
ConditionExpr,
|
|
615
|
+
ConditionOp,
|
|
473
616
|
Scope,
|
|
474
617
|
CompileOptions,
|
|
475
618
|
AccessorFn,
|
|
@@ -512,6 +655,19 @@ import {
|
|
|
512
655
|
|
|
513
656
|
4. **Novo**: `$pipe` como sintaxe DSL para composição
|
|
514
657
|
|
|
658
|
+
### v1.0 → v1.1
|
|
659
|
+
|
|
660
|
+
1. **Conditions internas**: `@statedelta-libs/conditions` não é mais dependência. Conditions são compiladas internamente.
|
|
661
|
+
|
|
662
|
+
2. **Expressions nos lados**: `left`/`right` de conditions agora aceitam qualquer `Expression` (`$fn`, `$pipe`, `$if`, etc), não apenas `Ref | literal`.
|
|
663
|
+
|
|
664
|
+
3. **Novo builder**: `$cond(left, op, right?)` para construir conditions com expressions:
|
|
665
|
+
```typescript
|
|
666
|
+
$cond($fn("add", [$("a"), $("b")]), "gt", 100)
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
4. **Novos tipos**: `ConditionOp`, `Condition`, `ConditionGroup`, `ConditionExpr` exportados diretamente do expressions.
|
|
670
|
+
|
|
515
671
|
## Licença
|
|
516
672
|
|
|
517
673
|
MIT © Anderson D. Rosa
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var conditions=require('@statedelta-libs/conditions'),omniAst=require('omni-ast');var on=Object.defineProperty;var rn=(n,e)=>{for(var i in e)on(n,i,{get:e[i],enumerable:true});};var g=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,h=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,T=n=>n!==null&&typeof n=="object"&&"$fn"in n&&typeof n.$fn=="string",b=n=>n!==null&&typeof n=="object"&&"$pipe"in n&&Array.isArray(n.$pipe),_=new Set(["eq","neq","gt","gte","lt","lte","in","notIn","contains","notContains","exists","notExists","matches","notMatches","startsWith","endsWith"]),y=n=>n!==null&&typeof n=="object"&&"path"in n&&"op"in n&&_.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),E=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,sn=n=>y(n)||E(n),D=n=>{if(n===null)return true;let e=typeof n;if(e==="string"||e==="number"||e==="boolean"||Array.isArray(n))return true;if(e==="object"&&n!==null){let i=n,t="path"in i&&"op"in i&&_.has(i.op);return !("$"in i)&&!("$if"in i)&&!("$fn"in i)&&!("$pipe"in i)&&!t&&!("logic"in i)}return false};var x=new Map;function q(n){let e=[],i=n.length,t=0,r="";for(;t<i;){let f=n[t];if(f===".")r&&(e.push({type:"key",value:r}),r=""),t++;else if(f==="["){r&&(e.push({type:"key",value:r}),r=""),t++;let o=t;for(;t<i&&n[t]!=="]";)t++;let s=n.slice(o,t);if(t++,s==="*")e.push({type:"wildcard",value:"*"});else {let u=parseInt(s,10);e.push({type:"index",value:isNaN(u)?s:u});}}else r+=f,t++;}return r&&e.push({type:"key",value:r}),e}function J(n){return n.includes("[*]")}function O(n){let e=x.get(n);return e||(e=J(n)?fn(n):ln(n),x.set(n,e),e)}function ln(n){if(!n.includes(".")&&!n.includes("["))return r=>r?.[n];let e=q(n),i=e.length;if(i===2){let[r,f]=e,o=r.value,s=f.value;return u=>u?.[o]?.[s]}if(i===3){let[r,f,o]=e,s=r.value,u=f.value,a=o.value;return c=>c?.[s]?.[u]?.[a]}let t=e.map(r=>r.value);return r=>{let f=r;for(let o=0;o<i&&f!=null;o++)f=f[t[o]];return f}}function fn(n){let e=q(n),i=[];for(let t=0;t<e.length;t++)e[t].type==="wildcard"&&i.push(t);return i.length===1?un(e,i[0]):an(e,i)}function un(n,e){let i=n.slice(0,e).map(o=>o.value),t=n.slice(e+1).map(o=>o.value),r=i.length,f=t.length;if(f===0){if(r===1){let o=i[0];return s=>s?.[o]}return o=>{let s=o;for(let u=0;u<r&&s!=null;u++)s=s[i[u]];return s}}if(f===1){let o=t[0];if(r===1){let s=i[0];return u=>{let a=u?.[s];if(Array.isArray(a))return a.map(c=>c?.[o])}}return s=>{let u=s;for(let a=0;a<r&&u!=null;a++)u=u[i[a]];if(Array.isArray(u))return u.map(a=>a?.[o])}}return o=>{let s=o;for(let u=0;u<r&&s!=null;u++)s=s[i[u]];if(Array.isArray(s))return s.map(u=>{let a=u;for(let c=0;c<f&&a!=null;c++)a=a[t[c]];return a})}}function an(n,e){let i=[],t=0;for(let f=0;f<e.length;f++){let o=e[f],s=f===e.length-1,u=n.slice(t,o).map(a=>a.value);u.length>0&&i.push({type:"access",keys:u}),i.push({type:s?"map":"flatMap",keys:[]}),t=o+1;}let r=n.slice(t).map(f=>f.value);return f=>{let o=f;for(let s of i){if(o==null)return;if(s.type==="access")for(let u of s.keys){if(o==null)return;o=o[u];}else if(s.type==="flatMap"){if(!Array.isArray(o))return;o=o.flatMap(u=>{let a=u;return Array.isArray(a)?a:[a]});}else if(s.type==="map"){if(!Array.isArray(o))return;r.length>0&&(o=o.map(u=>{let a=u;for(let c of r){if(a==null)return;a=a[c];}return a}));}}return o}}function cn(n,e){return O(e)(n)}function R(n){let e=n.indexOf("[*]");return e===-1?n:n.slice(0,e)}function pn(){x.clear();}function dn(){return x.size}function w(n){let e=new Set;return S(n,e),Array.from(e)}function S(n,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r=0;r<n.length;r++)S(n[r],e);return}if(g(n)){e.add(R(n.$));return}if(h(n)){if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if;e.add(R(r));}else S(n.$if,e);S(n.then,e),n.else!==void 0&&S(n.else,e);return}if(b(n)){for(let r=0;r<n.$pipe.length;r++)S(n.$pipe[r],e);return}if(T(n)){if(n.args)for(let r=0;r<n.args.length;r++)S(n.args[r],e);return}if(y(n)){e.add(R(n.path)),n.value!==void 0&&conditions.isRef(n.value)&&e.add(R(n.value.$));return}if(E(n)){for(let r=0;r<n.conditions.length;r++)S(n.conditions[r],e);return}let i=n,t=Object.keys(i);for(let r=0;r<t.length;r++)S(i[t[r]],e);}function gn(n){return w(n).length>0}function yn(n){return w(n).length===0}function En(n){return JSON.stringify(n)}function F(n,e={}){let i=e.scope??{},t=e.accessor,r=C(n,i,t),f=w(n),o=En(n);return {fn:r,deps:f,hash:o}}function C(n,e,i){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let t=n.map(r=>C(r,e,i));return r=>t.map(f=>f(r))}if(g(n))return hn(n,i);if(h(n))return Tn(n,e,i);if(b(n))return bn(n,e,i);if(T(n))return Cn(n,e,i);if(y(n))return conditions.compile(n,i?{accessor:i}:void 0);if(E(n))return conditions.compile(n,i?{accessor:i}:void 0);if(D(n)){let t=n,r=Object.keys(t),f=r.map(o=>C(t[o],e,i));return o=>{let s={};for(let u=0;u<r.length;u++)s[r[u]]=f[u](o);return s}}return ()=>n}function K(n,e){return e?i=>e(n,i):O(n)}function hn(n,e){return K(n.$,e)}function Tn(n,e,i){let t;if(typeof n.$if=="string"){let o=n.$if.startsWith("!")?n.$if.slice(1):n.$if,s=K(o,i);t=n.$if.startsWith("!")?a=>!s(a):a=>!!s(a);}else {let o=C(n.$if,e,i);t=s=>!!o(s);}let r=C(n.then,e,i),f=n.else!==void 0?C(n.else,e,i):()=>{};return o=>t(o)?r(o):f(o)}function bn(n,e,i){let t=n.$pipe;if(t.length===0)return ()=>{};if(t.length===1)return C(t[0],e,i);let r=C(t[0],e,i),f=t.slice(1).map(s=>C(s,e,i)),o=f.length;if(o===1){let[s]=f;return u=>{let a=r(u),c=s(u);return typeof c=="function"?c(a):c}}if(o===2){let[s,u]=f;return a=>{let c=r(a),p=s(a);return c=typeof p=="function"?p(c):p,p=u(a),typeof p=="function"?p(c):p}}if(o===3){let[s,u,a]=f;return c=>{let p=r(c),d=s(c);return p=typeof d=="function"?d(p):d,d=u(c),p=typeof d=="function"?d(p):d,d=a(c),typeof d=="function"?d(p):d}}return s=>{let u=r(s);for(let a=0;a<o;a++){let c=f[a](s);u=typeof c=="function"?c(u):c;}return u}}function Cn(n,e,i){let t=n.$fn,r=n.args;if(r===void 0)return ()=>{let s=e[t];if(!s)throw new Error(`Function not found in scope: ${t}`);return s};let f=r.map(s=>C(s,e,i)),o=f.length;if(o===0)return s=>{let u=e[t];if(!u)throw new Error(`Function not found in scope: ${t}`);return u()};if(o===1){let[s]=f;return u=>{let a=e[t];if(!a)throw new Error(`Function not found in scope: ${t}`);return a(s(u))}}if(o===2){let[s,u]=f;return a=>{let c=e[t];if(!c)throw new Error(`Function not found in scope: ${t}`);return c(s(a),u(a))}}if(o===3){let[s,u,a]=f;return c=>{let p=e[t];if(!p)throw new Error(`Function not found in scope: ${t}`);return p(s(c),u(c),a(c))}}return s=>{let u=e[t];if(!u)throw new Error(`Function not found in scope: ${t}`);return u(...f.map(a=>a(s)))}}function $n(n,e,i={}){return F(n,i).fn(e)}var v=class{constructor(e=1e3){this.cache=new Map,this._maxSize=e;}get(e,i={}){let t=JSON.stringify(e),r=this.cache.get(t);if(r)return this.cache.delete(t),this.cache.set(t,r),r;let f=F(e,i);if(this.cache.size>=this._maxSize){let o=this.cache.keys().next().value;o&&this.cache.delete(o);}return this.cache.set(t,f),f}has(e){return this.cache.has(JSON.stringify(e))}delete(e){return this.cache.delete(JSON.stringify(e))}clear(){this.cache.clear();}get size(){return this.cache.size}get maxSize(){return this._maxSize}set maxSize(e){for(this._maxSize=e;this.cache.size>this._maxSize;){let i=this.cache.keys().next().value;i&&this.cache.delete(i);}}},Y=new v;function Sn(n,e={}){return Y.get(n,e)}function I(n,e="root",i={}){let t=[];return k(n,e,t,i),{valid:t.length===0,errors:t}}function k(n,e,i,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let o=0;o<n.length;o++)k(n[o],`${e}[${o}]`,i,t);return}if(g(n)){(!n.$||typeof n.$!="string")&&i.push(`${e}: invalid reference, $ must be non-empty string`);return}if(h(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||i.push(`${e}.$if: empty path in string shorthand`):k(n.$if,`${e}.$if`,i,t),k(n.then,`${e}.then`,i,t),n.else!==void 0&&k(n.else,`${e}.else`,i,t);return}if(b(n)){if(!Array.isArray(n.$pipe)){i.push(`${e}.$pipe: must be an array`);return}if(n.$pipe.length===0){i.push(`${e}.$pipe: must have at least one element`);return}for(let o=0;o<n.$pipe.length;o++)k(n.$pipe[o],`${e}.$pipe[${o}]`,i,t);return}if(T(n)){if(!n.$fn||typeof n.$fn!="string"){i.push(`${e}: invalid function, $fn must be non-empty string`);return}if(t.scope&&!(n.$fn in t.scope)&&i.push(`${e}: function "${n.$fn}" not found in scope`),n.args!==void 0)if(!Array.isArray(n.args))i.push(`${e}.args: must be an array`);else for(let o=0;o<n.args.length;o++)k(n.args[o],`${e}.args[${o}]`,i,t);return}if(y(n)){let o=conditions.validate(n,e);o.valid||i.push(...o.errors);return}if(E(n)){let o=conditions.validate(n,e);o.valid||i.push(...o.errors);return}let r=n,f=Object.keys(r);for(let o=0;o<f.length;o++){let s=f[o];k(r[s],`${e}.${s}`,i,t);}}function An(n,e={}){let i=I(n,"root",e);if(!i.valid)throw new Error(`Invalid expression: ${i.errors.join("; ")}`)}function kn(n,e={}){return I(n,"root",e).valid}var Z={};rn(Z,{$:()=>Q,$fn:()=>U,$if:()=>xn,$pipe:()=>X,fn:()=>Rn,pipe:()=>On,ref:()=>wn});function Q(n){return {$:n}}var wn=Q;function U(n,e){return e===void 0||e.length===0?{$fn:n}:{$fn:n,args:e}}var Rn=U;function xn(n,e,i){return i===void 0?{$if:n,then:e}:{$if:n,then:e,else:i}}function X(...n){return {$pipe:n}}var On=X;var L="data",P="scope",Fn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function W(n,e={}){let{dataParam:i=L,scopeParam:t=P,noPrefixes:r=false,useAccessor:f=false,lexicalPrefix:o}=e;return m(n,i,t,r,f,o)}function m(n,e,i,t,r,f){if(n===null)return omniAst.builders.literal(null);if(typeof n=="string")return omniAst.builders.literal(n);if(typeof n=="number")return omniAst.builders.literal(n);if(typeof n=="boolean")return omniAst.builders.literal(n);if(Array.isArray(n))return omniAst.builders.arrayExpression(n.map(o=>m(o,e,i,t,r,f)));if(g(n))return vn(n.$,e,t,r,f);if(h(n))return jn(n,e,i,t,r,f);if(b(n))return Wn(n.$pipe,e,i,t,r,f);if(T(n))return Gn(n,e,i,t,r,f);if(y(n))return zn(n,e,i,t,r,f);if(E(n))return Mn(n,e,i,t,r,f);if(typeof n=="object"){let s=Object.entries(n).map(([u,a])=>omniAst.builders.property(omniAst.builders.identifier(u),m(a,e,i,t,r,f)));return omniAst.builders.objectExpression(s)}return omniAst.builders.literal(null)}var N="accessor";function j(n,e){return e?n===e||n.startsWith(e+"."):false}function vn(n,e,i,t,r){return t?j(n,r)?A(n,e,true):omniAst.builders.callExpression(omniAst.builders.identifier(N),[omniAst.builders.literal(n),omniAst.builders.identifier(e)]):n.includes("[*]")?Nn(n,e,i):A(n,e,i)}function A(n,e,i){let t=G(n);if(t.length===0)return i?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(e);let r;if(i){let f=t[0];r=omniAst.builders.identifier(f.value);for(let o=1;o<t.length;o++){let s=t[o];s.type==="key"?r=omniAst.builders.memberExpression(r,omniAst.builders.identifier(s.value),false,true):r=omniAst.builders.memberExpression(r,omniAst.builders.literal(s.value),true,true);}}else {r=omniAst.builders.identifier(e);for(let f of t)f.type==="key"?r=omniAst.builders.memberExpression(r,omniAst.builders.identifier(f.value),false,true):r=omniAst.builders.memberExpression(r,omniAst.builders.literal(f.value),true,true);}return r}function Nn(n,e,i){let t=n.indexOf("[*]"),r=n.slice(0,t),f=n.slice(t+3),o;if(r?o=A(r,e,i):o=i?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(e),!f||f==="")return o;if(f.includes("[*]"))return nn(o,f);let s="_i",u=f.startsWith(".")?f.slice(1):f,a=omniAst.builders.identifier(s);if(u){let c=G(u);for(let p of c)p.type==="key"?a=omniAst.builders.memberExpression(a,omniAst.builders.identifier(p.value),false,true):a=omniAst.builders.memberExpression(a,omniAst.builders.literal(p.value),true,true);}return omniAst.builders.callExpression(omniAst.builders.memberExpression(o,omniAst.builders.identifier("map"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(s)],a)])}function nn(n,e){let i=e.indexOf("[*]"),t=e.slice(0,i),r=e.slice(i+3),f="_i",o=t.startsWith(".")?t.slice(1):t,s=omniAst.builders.identifier(f);if(o){let a=G(o);for(let c of a)c.type==="key"&&(s=omniAst.builders.memberExpression(s,omniAst.builders.identifier(c.value),false,true));}if(r.includes("[*]")){let a=nn(s,r);return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(f)],a)])}let u=r.startsWith(".")?r.slice(1):r;if(u){let a=G(u);for(let c of a)c.type==="key"&&(s=omniAst.builders.memberExpression(s,omniAst.builders.identifier(c.value),false,true));}return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(f)],s)])}function jn(n,e,i,t,r,f){let o;if(typeof n.$if=="string"){let a=n.$if.startsWith("!"),c=a?n.$if.slice(1):n.$if,p;r?j(c,f)?p=A(c,e,true):p=omniAst.builders.callExpression(omniAst.builders.identifier(N),[omniAst.builders.literal(c),omniAst.builders.identifier(e)]):p=A(c,e,t),o=a?omniAst.builders.unaryExpression("!",p):p;}else o=m(n.$if,e,i,t,r,f);let s=m(n.then,e,i,t,r,f),u=n.else!==void 0?m(n.else,e,i,t,r,f):omniAst.builders.identifier("undefined");return omniAst.builders.conditionalExpression(o,s,u)}function Gn(n,e,i,t,r,f){let o=t?omniAst.builders.identifier(n.$fn):omniAst.builders.memberExpression(omniAst.builders.identifier(i),omniAst.builders.identifier(n.$fn),false,false);if(n.args===void 0)return o;let s=n.args.map(u=>m(u,e,i,t,r,f));return omniAst.builders.callExpression(o,s)}function Wn(n,e,i,t,r,f){if(n.length===0)return omniAst.builders.identifier("undefined");if(n.length===1)return m(n[0],e,i,t,r,f);let o=m(n[0],e,i,t,r,f);for(let s=1;s<n.length;s++){let u=m(n[s],e,i,t,r,f);o=omniAst.builders.callExpression(u,[o]);}return o}function zn(n,e,i,t,r,f){let o;r?j(n.path,f)?o=A(n.path,e,true):o=omniAst.builders.callExpression(omniAst.builders.identifier(N),[omniAst.builders.literal(n.path),omniAst.builders.identifier(e)]):o=A(n.path,e,t);let s=n.value!==void 0?g(n.value)?r?j(n.value.$,f)?A(n.value.$,e,true):omniAst.builders.callExpression(omniAst.builders.identifier(N),[omniAst.builders.literal(n.value.$),omniAst.builders.identifier(e)]):A(n.value.$,e,t):m(n.value,e,i,t,r,f):omniAst.builders.literal(null),u=Fn[n.op];if(u)return omniAst.builders.binaryExpression(u,o,s);switch(n.op){case "in":return omniAst.builders.callExpression(omniAst.builders.memberExpression(s,omniAst.builders.identifier("includes")),[o]);case "notIn":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(s,omniAst.builders.identifier("includes")),[o]));case "contains":return omniAst.builders.callExpression(omniAst.builders.memberExpression(o,omniAst.builders.identifier("includes"),false,true),[s]);case "notContains":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(o,omniAst.builders.identifier("includes"),false,true),[s]));case "exists":return omniAst.builders.binaryExpression("!=",o,omniAst.builders.literal(null));case "notExists":return omniAst.builders.binaryExpression("==",o,omniAst.builders.literal(null));case "matches":return omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[s]),omniAst.builders.identifier("test")),[o]);case "notMatches":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[s]),omniAst.builders.identifier("test")),[o]));case "startsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(o,omniAst.builders.identifier("startsWith"),false,true),[s]);case "endsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(o,omniAst.builders.identifier("endsWith"),false,true),[s]);default:return omniAst.builders.binaryExpression("===",o,s)}}function Mn(n,e,i,t,r,f){let{logic:o,conditions:s}=n,u=o==="AND"?"&&":"||";if(s.length===0)return omniAst.builders.literal(o==="AND");if(s.length===1)return m(s[0],e,i,t,r,f);let a=m(s[0],e,i,t,r,f);for(let c=1;c<s.length;c++){let p=m(s[c],e,i,t,r,f);a=omniAst.builders.logicalExpression(u,a,p);}return a}function G(n){let e=[],i=n.length,t=0,r="";for(;t<i;){let f=n[t];if(f===".")r&&(e.push({type:"key",value:r}),r=""),t++;else if(f==="["){r&&(e.push({type:"key",value:r}),r=""),t++;let o=t;for(;t<i&&n[t]!=="]";)t++;let s=n.slice(o,t);if(t++,s!=="*"){let u=parseInt(s,10);e.push({type:"index",value:isNaN(u)?s:u});}}else r+=f,t++;}return r&&e.push({type:"key",value:r}),e}function en(n,e=[L]){return omniAst.builders.arrowFunctionExpression(e.map(i=>omniAst.builders.identifier(i)),n)}function z(n){let e=new Set;return $(n,e),e}function $(n,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let t of n)$(t,e);return}if(g(n))return;if(h(n)){$(n.$if,e),$(n.then,e),n.else!==void 0&&$(n.else,e);return}if(b(n)){for(let t of n.$pipe)$(t,e);return}if(T(n)){if(e.add(n.$fn),n.args)for(let t of n.args)$(t,e);return}if(y(n)){n.value!==void 0&&typeof n.value=="object"&&$(n.value,e);return}if(E(n)){for(let t of n.conditions)$(t,e);return}let i=n;for(let t of Object.keys(i))$(i[t],e);}function M(n){let e=new Set;for(let i of n){let t=i.indexOf("."),r=i.indexOf("["),f=i.length;t!==-1&&(f=Math.min(f,t)),r!==-1&&(f=Math.min(f,r));let o=i.slice(0,f);o&&e.add(o);}return e}function In(n){return JSON.stringify(n)}function Ln(n,e,i,t,r){let f=W(n,{noPrefixes:true,useAccessor:t,lexicalPrefix:r}),o=omniAst.generate(f),s="";t?r&&(s=`const{${r}}=data??{};`):e.size>0&&(s=`const{${[...e].join(",")}}=data??{};`);let u=t?new Set([...i,"accessor"]):i,a=u.size>0?`const{${[...u].join(",")}}=scope;`:"";return a?`(function(scope){${a}return function(data){${s}return ${o}}})`:`(function(){return function(data){${s}return ${o}}})`}function V(n,e={}){let{scope:i={},returnCode:t=false,useAccessor:r=false,lexicalPrefix:f}=e,o=w(n),s=M(o),u=z(n),a=In(n),c=Ln(n,s,u,r,f);if(t)return {code:c,deps:o,hash:a,dataRoots:[...s],scopeFns:[...u]};let p;try{p=new Function(`return ${c}`)()(i);}catch(d){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${d instanceof Error?d.message:String(d)}`)}return {fn:p,deps:o,hash:a}}function tn(n,e,i={}){let{fn:t}=V(n,i);return t(e)}var he="0.1.1";exports.ExpressionCache=v;exports.VERSION=he;exports.assertValid=An;exports.builders=Z;exports.cache=Y;exports.cached=Sn;exports.clearPathCache=pn;exports.compile=F;exports.compileAST=V;exports.compilePath=O;exports.dslToAST=W;exports.evaluate=$n;exports.evaluateAST=tn;exports.extractDataRoots=M;exports.extractDeps=w;exports.extractScopeFns=z;exports.get=cn;exports.getPathCacheSize=dn;exports.hasDeps=gn;exports.hasWildcard=J;exports.isCondition=y;exports.isConditionExpr=sn;exports.isConditionGroup=E;exports.isConditional=h;exports.isFn=T;exports.isLiteral=D;exports.isPipe=b;exports.isPure=yn;exports.isRef=g;exports.isValid=kn;exports.normalizePath=R;exports.validate=I;exports.wrapInFunction=en;
|
|
1
|
+
'use strict';var omniAst=require('omni-ast');var on=Object.defineProperty;var rn=(n,t)=>{for(var s in t)on(n,s,{get:t[s],enumerable:true});};var y=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,T=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,b=n=>n!==null&&typeof n=="object"&&"$fn"in n&&typeof n.$fn=="string",C=n=>n!==null&&typeof n=="object"&&"$pipe"in n&&Array.isArray(n.$pipe),x=new Set(["eq","neq","gt","gte","lt","lte","in","notIn","contains","notContains","exists","notExists","matches","notMatches","startsWith","endsWith"]),h=n=>n!==null&&typeof n=="object"&&"left"in n&&"op"in n&&x.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),E=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,sn=n=>h(n)||E(n),I=n=>{if(n===null)return true;let t=typeof n;if(t==="string"||t==="number"||t==="boolean"||Array.isArray(n))return true;if(t==="object"&&n!==null){let s=n,e="left"in s&&"op"in s&&x.has(s.op);return !("$"in s)&&!("$if"in s)&&!("$fn"in s)&&!("$pipe"in s)&&!e&&!("logic"in s)}return false};var R=new Map;function q(n){let t=[],s=n.length,e=0,r="";for(;e<s;){let o=n[e];if(o===".")r&&(t.push({type:"key",value:r}),r=""),e++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),e++;let i=e;for(;e<s&&n[e]!=="]";)e++;let f=n.slice(i,e);if(e++,f==="*")t.push({type:"wildcard",value:"*"});else {let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,e++;}return r&&t.push({type:"key",value:r}),t}function J(n){return n.includes("[*]")}function O(n){let t=R.get(n);return t||(t=J(n)?un(n):fn(n),R.set(n,t),t)}function fn(n){if(!n.includes(".")&&!n.includes("["))return r=>r?.[n];let t=q(n),s=t.length;if(s===2){let[r,o]=t,i=r.value,f=o.value;return l=>l?.[i]?.[f]}if(s===3){let[r,o,i]=t,f=r.value,l=o.value,c=i.value;return a=>a?.[f]?.[l]?.[c]}let e=t.map(r=>r.value);return r=>{let o=r;for(let i=0;i<s&&o!=null;i++)o=o[e[i]];return o}}function un(n){let t=q(n),s=[];for(let e=0;e<t.length;e++)t[e].type==="wildcard"&&s.push(e);return s.length===1?ln(t,s[0]):cn(t,s)}function ln(n,t){let s=n.slice(0,t).map(i=>i.value),e=n.slice(t+1).map(i=>i.value),r=s.length,o=e.length;if(o===0){if(r===1){let i=s[0];return f=>f?.[i]}return i=>{let f=i;for(let l=0;l<r&&f!=null;l++)f=f[s[l]];return f}}if(o===1){let i=e[0];if(r===1){let f=s[0];return l=>{let c=l?.[f];if(Array.isArray(c))return c.map(a=>a?.[i])}}return f=>{let l=f;for(let c=0;c<r&&l!=null;c++)l=l[s[c]];if(Array.isArray(l))return l.map(c=>c?.[i])}}return i=>{let f=i;for(let l=0;l<r&&f!=null;l++)f=f[s[l]];if(Array.isArray(f))return f.map(l=>{let c=l;for(let a=0;a<o&&c!=null;a++)c=c[e[a]];return c})}}function cn(n,t){let s=[],e=0;for(let o=0;o<t.length;o++){let i=t[o],f=o===t.length-1,l=n.slice(e,i).map(c=>c.value);l.length>0&&s.push({type:"access",keys:l}),s.push({type:f?"map":"flatMap",keys:[]}),e=i+1;}let r=n.slice(e).map(o=>o.value);return o=>{let i=o;for(let f of s){if(i==null)return;if(f.type==="access")for(let l of f.keys){if(i==null)return;i=i[l];}else if(f.type==="flatMap"){if(!Array.isArray(i))return;i=i.flatMap(l=>{let c=l;return Array.isArray(c)?c:[c]});}else if(f.type==="map"){if(!Array.isArray(i))return;r.length>0&&(i=i.map(l=>{let c=l;for(let a of r){if(c==null)return;c=c[a];}return c}));}}return i}}function an(n,t){return O(t)(n)}function F(n){let t=n.indexOf("[*]");return t===-1?n:n.slice(0,t)}function pn(){R.clear();}function dn(){return R.size}function k(n){let t=new Set;return A(n,t),Array.from(t)}function A(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r=0;r<n.length;r++)A(n[r],t);return}if(y(n)){t.add(F(n.$));return}if(T(n)){if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if;t.add(F(r));}else A(n.$if,t);A(n.then,t),n.else!==void 0&&A(n.else,t);return}if(C(n)){for(let r=0;r<n.$pipe.length;r++)A(n.$pipe[r],t);return}if(b(n)){if(n.args)for(let r=0;r<n.args.length;r++){let o=n.args[r];typeof o!="function"&&A(o,t);}return}if(h(n)){A(n.left,t),n.right!==void 0&&A(n.right,t);return}if(E(n)){for(let r=0;r<n.conditions.length;r++)A(n.conditions[r],t);return}let s=n,e=Object.keys(s);for(let r=0;r<e.length;r++)A(s[e[r]],t);}function gn(n){return k(n).length>0}function mn(n){return k(n).length===0}function yn(n){return JSON.stringify(n)}function N(n,t={}){let s=t.scope??{},e=t.accessor,r=m(n,s,e),o=k(n),i=yn(n);return {fn:r,deps:o,hash:i}}function m(n,t,s){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let e=n.map(r=>m(r,t,s));return r=>e.map(o=>o(r))}if(y(n))return hn(n,s);if(T(n))return En(n,t,s);if(C(n))return Tn(n,t,s);if(b(n))return bn(n,t,s);if(h(n))return Cn(n,t,s);if(E(n))return An(n,t,s);if(I(n)){let e=n,r=Object.keys(e),o=r.map(i=>m(e[i],t,s));return i=>{let f={};for(let l=0;l<r.length;l++)f[r[l]]=o[l](i);return f}}return ()=>n}function B(n,t){return t?s=>t(n,s):O(n)}function hn(n,t){return B(n.$,t)}function En(n,t,s){let e;if(typeof n.$if=="string"){let i=n.$if.startsWith("!")?n.$if.slice(1):n.$if,f=B(i,s);e=n.$if.startsWith("!")?c=>!f(c):c=>!!f(c);}else {let i=m(n.$if,t,s);e=f=>!!i(f);}let r=m(n.then,t,s),o=n.else!==void 0?m(n.else,t,s):()=>{};return i=>e(i)?r(i):o(i)}function Tn(n,t,s){let e=n.$pipe;if(e.length===0)return ()=>{};if(e.length===1)return m(e[0],t,s);let r=m(e[0],t,s),o=e.slice(1).map(f=>m(f,t,s)),i=o.length;if(i===1){let[f]=o;return l=>{let c=r(l),a=f(l);return typeof a=="function"?a(c):a}}if(i===2){let[f,l]=o;return c=>{let a=r(c),p=f(c);return a=typeof p=="function"?p(a):p,p=l(c),typeof p=="function"?p(a):p}}if(i===3){let[f,l,c]=o;return a=>{let p=r(a),d=f(a);return p=typeof d=="function"?d(p):d,d=l(a),p=typeof d=="function"?d(p):d,d=c(a),typeof d=="function"?d(p):d}}return f=>{let l=r(f);for(let c=0;c<i;c++){let a=o[c](f);l=typeof a=="function"?a(l):a;}return l}}function bn(n,t,s){let e=n.$fn,r=n.args;if(r===void 0)return ()=>{let f=t[e];if(!f)throw new Error(`Function not found in scope: ${e}`);return f};let o=r.map(f=>typeof f=="function"?()=>f:m(f,t,s)),i=o.length;if(i===0)return f=>{let l=t[e];if(!l)throw new Error(`Function not found in scope: ${e}`);return l()};if(i===1){let[f]=o;return l=>{let c=t[e];if(!c)throw new Error(`Function not found in scope: ${e}`);return c(f(l))}}if(i===2){let[f,l]=o;return c=>{let a=t[e];if(!a)throw new Error(`Function not found in scope: ${e}`);return a(f(c),l(c))}}if(i===3){let[f,l,c]=o;return a=>{let p=t[e];if(!p)throw new Error(`Function not found in scope: ${e}`);return p(f(a),l(a),c(a))}}return f=>{let l=t[e];if(!l)throw new Error(`Function not found in scope: ${e}`);return l(...o.map(c=>c(f)))}}function Cn(n,t,s){let e=m(n.left,t,s),r=n.right!==void 0?m(n.right,t,s):()=>{};switch(n.op){case "eq":return o=>e(o)===r(o);case "neq":return o=>e(o)!==r(o);case "gt":return o=>e(o)>r(o);case "gte":return o=>e(o)>=r(o);case "lt":return o=>e(o)<r(o);case "lte":return o=>e(o)<=r(o);case "in":return o=>{let i=r(o);return Array.isArray(i)&&i.includes(e(o))};case "notIn":return o=>{let i=r(o);return !Array.isArray(i)||!i.includes(e(o))};case "contains":return o=>{let i=e(o);return Array.isArray(i)&&i.includes(r(o))};case "notContains":return o=>{let i=e(o);return !Array.isArray(i)||!i.includes(r(o))};case "exists":return o=>e(o)!==void 0;case "notExists":return o=>e(o)===void 0;case "matches":return o=>{let i=e(o),f=r(o);return typeof i!="string"||typeof f!="string"?false:new RegExp(f).test(i)};case "notMatches":return o=>{let i=e(o),f=r(o);return typeof i!="string"||typeof f!="string"?true:!new RegExp(f).test(i)};case "startsWith":return o=>{let i=e(o),f=r(o);return typeof i=="string"&&typeof f=="string"&&i.startsWith(f)};case "endsWith":return o=>{let i=e(o),f=r(o);return typeof i=="string"&&typeof f=="string"&&i.endsWith(f)}}}function An(n,t,s){let e=n.conditions.map(o=>m(o,t,s)),r=e.length;if(r===1)return o=>!!e[0](o);if(r===2){let[o,i]=e;return n.logic==="AND"?f=>!!o(f)&&!!i(f):f=>!!o(f)||!!i(f)}if(r===3){let[o,i,f]=e;return n.logic==="AND"?l=>!!o(l)&&!!i(l)&&!!f(l):l=>!!o(l)||!!i(l)||!!f(l)}return n.logic==="AND"?o=>{for(let i=0;i<r;i++)if(!e[i](o))return false;return true}:o=>{for(let i=0;i<r;i++)if(e[i](o))return true;return false}}function $n(n,t,s={}){return N(n,s).fn(t)}var v=class{constructor(t=1e3){this.cache=new Map,this._maxSize=t;}get(t,s={}){let e=JSON.stringify(t),r=this.cache.get(e);if(r)return this.cache.delete(e),this.cache.set(e,r),r;let o=N(t,s);if(this.cache.size>=this._maxSize){let i=this.cache.keys().next().value;i&&this.cache.delete(i);}return this.cache.set(e,o),o}has(t){return this.cache.has(JSON.stringify(t))}delete(t){return this.cache.delete(JSON.stringify(t))}clear(){this.cache.clear();}get size(){return this.cache.size}get maxSize(){return this._maxSize}set maxSize(t){for(this._maxSize=t;this.cache.size>this._maxSize;){let s=this.cache.keys().next().value;s&&this.cache.delete(s);}}},K=new v;function Sn(n,t={}){return K.get(n,t)}function M(n,t="root",s={}){let e=[];return $(n,t,e,s),{valid:e.length===0,errors:e}}function $(n,t,s,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let i=0;i<n.length;i++)$(n[i],`${t}[${i}]`,s,e);return}if(y(n)){(!n.$||typeof n.$!="string")&&s.push(`${t}: invalid reference, $ must be non-empty string`);return}if(T(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||s.push(`${t}.$if: empty path in string shorthand`):$(n.$if,`${t}.$if`,s,e),$(n.then,`${t}.then`,s,e),n.else!==void 0&&$(n.else,`${t}.else`,s,e);return}if(C(n)){if(!Array.isArray(n.$pipe)){s.push(`${t}.$pipe: must be an array`);return}if(n.$pipe.length===0){s.push(`${t}.$pipe: must have at least one element`);return}for(let i=0;i<n.$pipe.length;i++)$(n.$pipe[i],`${t}.$pipe[${i}]`,s,e);return}if(b(n)){if(!n.$fn||typeof n.$fn!="string"){s.push(`${t}: invalid function, $fn must be non-empty string`);return}if(e.scope&&!(n.$fn in e.scope)&&s.push(`${t}: function "${n.$fn}" not found in scope`),n.args!==void 0)if(!Array.isArray(n.args))s.push(`${t}.args: must be an array`);else for(let i=0;i<n.args.length;i++){let f=n.args[i];typeof f!="function"&&$(f,`${t}.args[${i}]`,s,e);}return}if(h(n)){x.has(n.op)||s.push(`${t}: invalid operator "${n.op}"`),$(n.left,`${t}.left`,s,e),n.right!==void 0&&$(n.right,`${t}.right`,s,e);return}if(E(n)){if(n.logic!=="AND"&&n.logic!=="OR"&&s.push(`${t}: invalid logic "${n.logic}", must be "AND" or "OR"`),!Array.isArray(n.conditions)){s.push(`${t}.conditions: must be an array`);return}for(let i=0;i<n.conditions.length;i++)$(n.conditions[i],`${t}.conditions[${i}]`,s,e);return}let r=n,o=Object.keys(r);for(let i=0;i<o.length;i++){let f=o[i];$(r[f],`${t}.${f}`,s,e);}}function kn(n,t={}){let s=M(n,"root",t);if(!s.valid)throw new Error(`Invalid expression: ${s.errors.join("; ")}`)}function wn(n,t={}){return M(n,"root",t).valid}var U={};rn(U,{$:()=>P,$cond:()=>Q,$fn:()=>Y,$if:()=>On,$pipe:()=>H,cond:()=>Nn,fn:()=>Rn,pipe:()=>Fn,ref:()=>xn});function P(n){return {$:n}}var xn=P;function Y(n,t){return t===void 0||t.length===0?{$fn:n}:{$fn:n,args:t}}var Rn=Y;function On(n,t,s){return s===void 0?{$if:n,then:t}:{$if:n,then:t,else:s}}function H(...n){return {$pipe:n}}var Fn=H;function Q(n,t,s){return s===void 0?{left:n,op:t}:{left:n,op:t,right:s}}var Nn=Q;var z="data",Z="scope",vn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function G(n,t={}){let{dataParam:s=z,scopeParam:e=Z,noPrefixes:r=false,useAccessor:o=false,lexicalPrefix:i}=t;return g(n,s,e,r,o,i)}function g(n,t,s,e,r,o){if(n===null)return omniAst.builders.literal(null);if(typeof n=="string")return omniAst.builders.literal(n);if(typeof n=="number")return omniAst.builders.literal(n);if(typeof n=="boolean")return omniAst.builders.literal(n);if(Array.isArray(n))return omniAst.builders.arrayExpression(n.map(i=>g(i,t,s,e,r,o)));if(y(n))return jn(n.$,t,e,r,o);if(T(n))return Wn(n,t,s,e,r,o);if(C(n))return In(n.$pipe,t,s,e,r,o);if(b(n))return Dn(n,t,s,e,r,o);if(h(n))return Mn(n,t,s,e,r,o);if(E(n))return zn(n,t,s,e,r,o);if(typeof n=="object"){let f=Object.entries(n).map(([l,c])=>omniAst.builders.property(omniAst.builders.identifier(l),g(c,t,s,e,r,o)));return omniAst.builders.objectExpression(f)}return omniAst.builders.literal(null)}var L="accessor";function V(n,t){return t?n===t||n.startsWith(t+"."):false}function jn(n,t,s,e,r){return e?V(n,r)?w(n,t,true):omniAst.builders.callExpression(omniAst.builders.identifier(L),[omniAst.builders.literal(n),omniAst.builders.identifier(t)]):n.includes("[*]")?Gn(n,t,s):w(n,t,s)}function w(n,t,s){let e=j(n);if(e.length===0)return s?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(t);let r;if(s){let o=e[0];r=omniAst.builders.identifier(o.value);for(let i=1;i<e.length;i++){let f=e[i];f.type==="key"?r=omniAst.builders.memberExpression(r,omniAst.builders.identifier(f.value),false,true):r=omniAst.builders.memberExpression(r,omniAst.builders.literal(f.value),true,true);}}else {r=omniAst.builders.identifier(t);for(let o of e)o.type==="key"?r=omniAst.builders.memberExpression(r,omniAst.builders.identifier(o.value),false,true):r=omniAst.builders.memberExpression(r,omniAst.builders.literal(o.value),true,true);}return r}function Gn(n,t,s){let e=n.indexOf("[*]"),r=n.slice(0,e),o=n.slice(e+3),i;if(r?i=w(r,t,s):i=s?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(t),!o||o==="")return i;if(o.includes("[*]"))return nn(i,o);let f="_i",l=o.startsWith(".")?o.slice(1):o,c=omniAst.builders.identifier(f);if(l){let a=j(l);for(let p of a)p.type==="key"?c=omniAst.builders.memberExpression(c,omniAst.builders.identifier(p.value),false,true):c=omniAst.builders.memberExpression(c,omniAst.builders.literal(p.value),true,true);}return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("map"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(f)],c)])}function nn(n,t){let s=t.indexOf("[*]"),e=t.slice(0,s),r=t.slice(s+3),o="_i",i=e.startsWith(".")?e.slice(1):e,f=omniAst.builders.identifier(o);if(i){let c=j(i);for(let a of c)a.type==="key"&&(f=omniAst.builders.memberExpression(f,omniAst.builders.identifier(a.value),false,true));}if(r.includes("[*]")){let c=nn(f,r);return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(o)],c)])}let l=r.startsWith(".")?r.slice(1):r;if(l){let c=j(l);for(let a of c)a.type==="key"&&(f=omniAst.builders.memberExpression(f,omniAst.builders.identifier(a.value),false,true));}return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(o)],f)])}function Wn(n,t,s,e,r,o){let i;if(typeof n.$if=="string"){let c=n.$if.startsWith("!"),a=c?n.$if.slice(1):n.$if,p;r?V(a,o)?p=w(a,t,true):p=omniAst.builders.callExpression(omniAst.builders.identifier(L),[omniAst.builders.literal(a),omniAst.builders.identifier(t)]):p=w(a,t,e),i=c?omniAst.builders.unaryExpression("!",p):p;}else i=g(n.$if,t,s,e,r,o);let f=g(n.then,t,s,e,r,o),l=n.else!==void 0?g(n.else,t,s,e,r,o):omniAst.builders.identifier("undefined");return omniAst.builders.conditionalExpression(i,f,l)}function Dn(n,t,s,e,r,o){let i=e?omniAst.builders.identifier(n.$fn):omniAst.builders.memberExpression(omniAst.builders.identifier(s),omniAst.builders.identifier(n.$fn),false,false);if(n.args===void 0)return i;let f=n.args.map(l=>typeof l=="function"?omniAst.builders.literal(null):g(l,t,s,e,r,o));return omniAst.builders.callExpression(i,f)}function In(n,t,s,e,r,o){if(n.length===0)return omniAst.builders.identifier("undefined");if(n.length===1)return g(n[0],t,s,e,r,o);let i=g(n[0],t,s,e,r,o);for(let f=1;f<n.length;f++){let l=g(n[f],t,s,e,r,o);i=omniAst.builders.callExpression(l,[i]);}return i}function X(n,t,s,e,r,o){if(y(n)){let i=n.$;return r?V(i,o)?w(i,t,true):omniAst.builders.callExpression(omniAst.builders.identifier(L),[omniAst.builders.literal(i),omniAst.builders.identifier(t)]):w(i,t,e)}return g(n,t,s,e,r,o)}function Mn(n,t,s,e,r,o){let i=X(n.left,t,s,e,r,o),f=n.right!==void 0?X(n.right,t,s,e,r,o):omniAst.builders.literal(null),l=vn[n.op];if(l)return omniAst.builders.binaryExpression(l,i,f);switch(n.op){case "in":return omniAst.builders.callExpression(omniAst.builders.memberExpression(f,omniAst.builders.identifier("includes")),[i]);case "notIn":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(f,omniAst.builders.identifier("includes")),[i]));case "contains":return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("includes"),false,true),[f]);case "notContains":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("includes"),false,true),[f]));case "exists":return omniAst.builders.binaryExpression("!=",i,omniAst.builders.literal(null));case "notExists":return omniAst.builders.binaryExpression("==",i,omniAst.builders.literal(null));case "matches":return omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[f]),omniAst.builders.identifier("test")),[i]);case "notMatches":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[f]),omniAst.builders.identifier("test")),[i]));case "startsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("startsWith"),false,true),[f]);case "endsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("endsWith"),false,true),[f]);default:return omniAst.builders.binaryExpression("===",i,f)}}function zn(n,t,s,e,r,o){let{logic:i,conditions:f}=n,l=i==="AND"?"&&":"||";if(f.length===0)return omniAst.builders.literal(i==="AND");if(f.length===1)return g(f[0],t,s,e,r,o);let c=g(f[0],t,s,e,r,o);for(let a=1;a<f.length;a++){let p=g(f[a],t,s,e,r,o);c=omniAst.builders.logicalExpression(l,c,p);}return c}function j(n){let t=[],s=n.length,e=0,r="";for(;e<s;){let o=n[e];if(o===".")r&&(t.push({type:"key",value:r}),r=""),e++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),e++;let i=e;for(;e<s&&n[e]!=="]";)e++;let f=n.slice(i,e);if(e++,f!=="*"){let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,e++;}return r&&t.push({type:"key",value:r}),t}function tn(n,t=[z]){return omniAst.builders.arrowFunctionExpression(t.map(s=>omniAst.builders.identifier(s)),n)}function W(n){let t=new Set;return S(n,t),t}function S(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let e of n)S(e,t);return}if(y(n))return;if(T(n)){S(n.$if,t),S(n.then,t),n.else!==void 0&&S(n.else,t);return}if(C(n)){for(let e of n.$pipe)S(e,t);return}if(b(n)){if(t.add(n.$fn),n.args)for(let e of n.args)typeof e!="function"&&S(e,t);return}if(h(n)){n.left!==void 0&&typeof n.left=="object"&&S(n.left,t),n.right!==void 0&&typeof n.right=="object"&&S(n.right,t);return}if(E(n)){for(let e of n.conditions)S(e,t);return}let s=n;for(let e of Object.keys(s))S(s[e],t);}function D(n){let t=new Set;for(let s of n){let e=s.indexOf("."),r=s.indexOf("["),o=s.length;e!==-1&&(o=Math.min(o,e)),r!==-1&&(o=Math.min(o,r));let i=s.slice(0,o);i&&t.add(i);}return t}function Vn(n){return JSON.stringify(n)}function _n(n,t,s,e,r){let o=G(n,{noPrefixes:true,useAccessor:e,lexicalPrefix:r}),i=omniAst.generate(o),f="";e?r&&(f=`const{${r}}=data??{};`):t.size>0&&(f=`const{${[...t].join(",")}}=data??{};`);let l=e?new Set([...s,"accessor"]):s,c=l.size>0?`const{${[...l].join(",")}}=scope;`:"";return c?`(function(scope){${c}return function(data){${f}return ${i}}})`:`(function(){return function(data){${f}return ${i}}})`}function _(n,t={}){let{scope:s={},returnCode:e=false,useAccessor:r=false,lexicalPrefix:o}=t,i=k(n),f=D(i),l=W(n),c=Vn(n),a=_n(n,f,l,r,o);if(e)return {code:a,deps:i,hash:c,dataRoots:[...f],scopeFns:[...l]};let p;try{p=new Function(`return ${a}`)()(s);}catch(d){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${d instanceof Error?d.message:String(d)}`)}return {fn:p,deps:i,hash:c}}function en(n,t,s={}){let{fn:e}=_(n,s);return e(t)}var ht="0.1.1";exports.ExpressionCache=v;exports.VERSION=ht;exports.assertValid=kn;exports.builders=U;exports.cache=K;exports.cached=Sn;exports.clearPathCache=pn;exports.compile=N;exports.compileAST=_;exports.compilePath=O;exports.dslToAST=G;exports.evaluate=$n;exports.evaluateAST=en;exports.extractDataRoots=D;exports.extractDeps=k;exports.extractScopeFns=W;exports.get=an;exports.getPathCacheSize=dn;exports.hasDeps=gn;exports.hasWildcard=J;exports.isCondition=h;exports.isConditionExpr=sn;exports.isConditionGroup=E;exports.isConditional=T;exports.isFn=b;exports.isLiteral=I;exports.isPipe=C;exports.isPure=mn;exports.isRef=y;exports.isValid=wn;exports.normalizePath=F;exports.validate=M;exports.wrapInFunction=tn;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { ConditionExpr, Condition, ConditionGroup } from '@statedelta-libs/conditions';
|
|
2
|
-
export { Condition, ConditionExpr, ConditionGroup, Ref } from '@statedelta-libs/conditions';
|
|
3
1
|
import { types } from 'omni-ast';
|
|
4
2
|
|
|
5
3
|
/**
|
|
@@ -7,7 +5,10 @@ import { types } from 'omni-ast';
|
|
|
7
5
|
*
|
|
8
6
|
* Core types for expression compilation.
|
|
9
7
|
*/
|
|
10
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Condition operators
|
|
10
|
+
*/
|
|
11
|
+
type ConditionOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "contains" | "notContains" | "exists" | "notExists" | "matches" | "notMatches" | "startsWith" | "endsWith";
|
|
11
12
|
/**
|
|
12
13
|
* Reference to a path in data object
|
|
13
14
|
* @example { "$": "user.name" }
|
|
@@ -25,14 +26,26 @@ interface ConditionalExpr {
|
|
|
25
26
|
then: Expression;
|
|
26
27
|
else?: Expression;
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Callback function passed as argument to $fn (predicates, mappers, etc.)
|
|
31
|
+
* These are native JS functions, not DSL expressions.
|
|
32
|
+
* @example (item) => item.active
|
|
33
|
+
* @example (n) => n * 2
|
|
34
|
+
*/
|
|
35
|
+
type CallbackFn = (...args: any[]) => any;
|
|
36
|
+
/**
|
|
37
|
+
* Argument to a $fn expression: can be a DSL expression or a native callback
|
|
38
|
+
*/
|
|
39
|
+
type FnArg = Expression | CallbackFn;
|
|
28
40
|
/**
|
|
29
41
|
* Function call expression
|
|
30
42
|
* Calls a function from the provided scope with compiled arguments
|
|
31
43
|
* @example { "$fn": "add", "args": [{ "$": "a" }, { "$": "b" }] }
|
|
44
|
+
* @example { "$fn": "filter", "args": [(item) => item.active] }
|
|
32
45
|
*/
|
|
33
46
|
interface FnExpr {
|
|
34
47
|
$fn: string;
|
|
35
|
-
args?:
|
|
48
|
+
args?: FnArg[];
|
|
36
49
|
}
|
|
37
50
|
/**
|
|
38
51
|
* Pipe expression (DSL syntax for composition with initial value)
|
|
@@ -49,16 +62,31 @@ type Literal = string | number | boolean | null | Literal[] | {
|
|
|
49
62
|
[key: string]: Literal;
|
|
50
63
|
};
|
|
51
64
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
|
|
65
|
+
* Condition expression - both sides accept any Expression
|
|
66
|
+
* @example { left: { $: "age" }, op: "gte", right: 18 }
|
|
67
|
+
* @example { left: { $fn: "getAge", args: [{ $: "user" }] }, op: "gte", right: 18 }
|
|
68
|
+
*/
|
|
69
|
+
interface Condition {
|
|
70
|
+
left: Expression;
|
|
71
|
+
op: ConditionOp;
|
|
72
|
+
right?: Expression;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Condition group with AND/OR logic
|
|
76
|
+
* @example { logic: "AND", conditions: [...] }
|
|
56
77
|
*/
|
|
57
|
-
|
|
78
|
+
interface ConditionGroup {
|
|
79
|
+
logic: "AND" | "OR";
|
|
80
|
+
conditions: Expression[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Union of condition types
|
|
84
|
+
*/
|
|
85
|
+
type ConditionExpr = Condition | ConditionGroup;
|
|
58
86
|
/**
|
|
59
87
|
* Union of all expression types
|
|
60
88
|
*/
|
|
61
|
-
type Expression = Literal | RefExpr | ConditionalExpr | FnExpr | PipeExpr | ConditionExpr
|
|
89
|
+
type Expression = Literal | RefExpr | ConditionalExpr | FnExpr | PipeExpr | ConditionExpr;
|
|
62
90
|
/**
|
|
63
91
|
* Compiled expression function
|
|
64
92
|
*/
|
|
@@ -95,7 +123,13 @@ interface ValidationResult {
|
|
|
95
123
|
errors: string[];
|
|
96
124
|
}
|
|
97
125
|
/**
|
|
98
|
-
* Function scope - functions available to $fn expressions
|
|
126
|
+
* Function scope - functions available to $fn expressions.
|
|
127
|
+
*
|
|
128
|
+
* Uses `any` for function parameters because TypeScript's contravariance
|
|
129
|
+
* makes it impossible to assign typed functions like `(a: number, b: number) => number`
|
|
130
|
+
* to `(...args: unknown[]) => unknown`. This is the standard pattern for
|
|
131
|
+
* heterogeneous function registries (similar to Lodash, Ramda, etc.).
|
|
132
|
+
*
|
|
99
133
|
* @example { add, subtract, multiply, filter, map, sum }
|
|
100
134
|
*/
|
|
101
135
|
type Scope = Record<string, (...args: any[]) => any>;
|
|
@@ -132,16 +166,14 @@ declare const isFn: (v: unknown) => v is FnExpr;
|
|
|
132
166
|
*/
|
|
133
167
|
declare const isPipe: (v: unknown) => v is PipeExpr;
|
|
134
168
|
/**
|
|
135
|
-
* Check if value is a condition
|
|
169
|
+
* Check if value is a condition expression
|
|
136
170
|
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* properties (e.g., { resource: "x", op: "set", path: "y", value: z })
|
|
140
|
-
* but "set" is NOT a condition operator.
|
|
171
|
+
* Verifies `op` is a valid condition operator to distinguish from
|
|
172
|
+
* effect objects that also have `left` and `op` (e.g. op: "set").
|
|
141
173
|
*/
|
|
142
174
|
declare const isCondition: (v: unknown) => v is Condition;
|
|
143
175
|
/**
|
|
144
|
-
* Check if value is a condition group
|
|
176
|
+
* Check if value is a condition group
|
|
145
177
|
*/
|
|
146
178
|
declare const isConditionGroup: (v: unknown) => v is ConditionGroup;
|
|
147
179
|
/**
|
|
@@ -408,7 +440,7 @@ declare const ref: typeof $;
|
|
|
408
440
|
* $fn("sum") // no args - returns function reference
|
|
409
441
|
* $fn("now", []) // empty args - calls function
|
|
410
442
|
*/
|
|
411
|
-
declare function $fn(name: string, args?:
|
|
443
|
+
declare function $fn(name: string, args?: FnArg[]): FnExpr;
|
|
412
444
|
/**
|
|
413
445
|
* Alias for $fn (function builder)
|
|
414
446
|
*/
|
|
@@ -442,16 +474,36 @@ declare function $pipe(...steps: Expression[]): PipeExpr;
|
|
|
442
474
|
* Alias for $pipe (pipe builder)
|
|
443
475
|
*/
|
|
444
476
|
declare const pipe: typeof $pipe;
|
|
477
|
+
/**
|
|
478
|
+
* Create a condition expression.
|
|
479
|
+
*
|
|
480
|
+
* @param left - Left side (any expression)
|
|
481
|
+
* @param op - Condition operator
|
|
482
|
+
* @param right - Right side (any expression, optional for exists/notExists)
|
|
483
|
+
* @returns Condition
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* $cond($("age"), "gte", 18)
|
|
487
|
+
* $cond($fn("getScore", [$("user")]), "gt", 100)
|
|
488
|
+
* $cond($("email"), "exists")
|
|
489
|
+
*/
|
|
490
|
+
declare function $cond(left: Expression, op: ConditionOp, right?: Expression): Condition;
|
|
491
|
+
/**
|
|
492
|
+
* Alias for $cond (condition builder)
|
|
493
|
+
*/
|
|
494
|
+
declare const cond: typeof $cond;
|
|
445
495
|
|
|
446
496
|
declare const builders_$: typeof $;
|
|
497
|
+
declare const builders_$cond: typeof $cond;
|
|
447
498
|
declare const builders_$fn: typeof $fn;
|
|
448
499
|
declare const builders_$if: typeof $if;
|
|
449
500
|
declare const builders_$pipe: typeof $pipe;
|
|
501
|
+
declare const builders_cond: typeof cond;
|
|
450
502
|
declare const builders_fn: typeof fn;
|
|
451
503
|
declare const builders_pipe: typeof pipe;
|
|
452
504
|
declare const builders_ref: typeof ref;
|
|
453
505
|
declare namespace builders {
|
|
454
|
-
export { builders_$ as $, builders_$fn as $fn, builders_$if as $if, builders_$pipe as $pipe, builders_fn as fn, builders_pipe as pipe, builders_ref as ref };
|
|
506
|
+
export { builders_$ as $, builders_$cond as $cond, builders_$fn as $fn, builders_$if as $if, builders_$pipe as $pipe, builders_cond as cond, builders_fn as fn, builders_pipe as pipe, builders_ref as ref };
|
|
455
507
|
}
|
|
456
508
|
|
|
457
509
|
/**
|
|
@@ -674,4 +726,4 @@ declare function evaluateAST<T = unknown, R = unknown>(expr: Expression, data: T
|
|
|
674
726
|
*/
|
|
675
727
|
declare const VERSION = "0.1.1";
|
|
676
728
|
|
|
677
|
-
export { type AccessorFn, type CallbackFn, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, type ConditionalExpr, type Expression, ExpressionCache, type FnExpr, type Literal, type PathGetter, type PipeExpr, type RefExpr, type Scope, type TransformOptions, VERSION, type ValidateOptions, type ValidationResult, assertValid, builders, cache, cached, clearPathCache, compile, compileAST, compilePath, dslToAST, evaluate, evaluateAST, extractDataRoots, extractDeps, extractScopeFns, get, getPathCacheSize, hasDeps, hasWildcard, isCondition, isConditionExpr, isConditionGroup, isConditional, isFn, isLiteral, isPipe, isPure, isRef, isValid, normalizePath, validate, wrapInFunction };
|
|
729
|
+
export { type AccessorFn, type CallbackFn, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, type Condition, type ConditionExpr, type ConditionGroup, type ConditionOp, type ConditionalExpr, type Expression, ExpressionCache, type FnArg, type FnExpr, type Literal, type PathGetter, type PipeExpr, type RefExpr, type Scope, type TransformOptions, VERSION, type ValidateOptions, type ValidationResult, assertValid, builders, cache, cached, clearPathCache, compile, compileAST, compilePath, dslToAST, evaluate, evaluateAST, extractDataRoots, extractDeps, extractScopeFns, get, getPathCacheSize, hasDeps, hasWildcard, isCondition, isConditionExpr, isConditionGroup, isConditional, isFn, isLiteral, isPipe, isPure, isRef, isValid, normalizePath, validate, wrapInFunction };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { ConditionExpr, Condition, ConditionGroup } from '@statedelta-libs/conditions';
|
|
2
|
-
export { Condition, ConditionExpr, ConditionGroup, Ref } from '@statedelta-libs/conditions';
|
|
3
1
|
import { types } from 'omni-ast';
|
|
4
2
|
|
|
5
3
|
/**
|
|
@@ -7,7 +5,10 @@ import { types } from 'omni-ast';
|
|
|
7
5
|
*
|
|
8
6
|
* Core types for expression compilation.
|
|
9
7
|
*/
|
|
10
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Condition operators
|
|
10
|
+
*/
|
|
11
|
+
type ConditionOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "contains" | "notContains" | "exists" | "notExists" | "matches" | "notMatches" | "startsWith" | "endsWith";
|
|
11
12
|
/**
|
|
12
13
|
* Reference to a path in data object
|
|
13
14
|
* @example { "$": "user.name" }
|
|
@@ -25,14 +26,26 @@ interface ConditionalExpr {
|
|
|
25
26
|
then: Expression;
|
|
26
27
|
else?: Expression;
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Callback function passed as argument to $fn (predicates, mappers, etc.)
|
|
31
|
+
* These are native JS functions, not DSL expressions.
|
|
32
|
+
* @example (item) => item.active
|
|
33
|
+
* @example (n) => n * 2
|
|
34
|
+
*/
|
|
35
|
+
type CallbackFn = (...args: any[]) => any;
|
|
36
|
+
/**
|
|
37
|
+
* Argument to a $fn expression: can be a DSL expression or a native callback
|
|
38
|
+
*/
|
|
39
|
+
type FnArg = Expression | CallbackFn;
|
|
28
40
|
/**
|
|
29
41
|
* Function call expression
|
|
30
42
|
* Calls a function from the provided scope with compiled arguments
|
|
31
43
|
* @example { "$fn": "add", "args": [{ "$": "a" }, { "$": "b" }] }
|
|
44
|
+
* @example { "$fn": "filter", "args": [(item) => item.active] }
|
|
32
45
|
*/
|
|
33
46
|
interface FnExpr {
|
|
34
47
|
$fn: string;
|
|
35
|
-
args?:
|
|
48
|
+
args?: FnArg[];
|
|
36
49
|
}
|
|
37
50
|
/**
|
|
38
51
|
* Pipe expression (DSL syntax for composition with initial value)
|
|
@@ -49,16 +62,31 @@ type Literal = string | number | boolean | null | Literal[] | {
|
|
|
49
62
|
[key: string]: Literal;
|
|
50
63
|
};
|
|
51
64
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
|
|
65
|
+
* Condition expression - both sides accept any Expression
|
|
66
|
+
* @example { left: { $: "age" }, op: "gte", right: 18 }
|
|
67
|
+
* @example { left: { $fn: "getAge", args: [{ $: "user" }] }, op: "gte", right: 18 }
|
|
68
|
+
*/
|
|
69
|
+
interface Condition {
|
|
70
|
+
left: Expression;
|
|
71
|
+
op: ConditionOp;
|
|
72
|
+
right?: Expression;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Condition group with AND/OR logic
|
|
76
|
+
* @example { logic: "AND", conditions: [...] }
|
|
56
77
|
*/
|
|
57
|
-
|
|
78
|
+
interface ConditionGroup {
|
|
79
|
+
logic: "AND" | "OR";
|
|
80
|
+
conditions: Expression[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Union of condition types
|
|
84
|
+
*/
|
|
85
|
+
type ConditionExpr = Condition | ConditionGroup;
|
|
58
86
|
/**
|
|
59
87
|
* Union of all expression types
|
|
60
88
|
*/
|
|
61
|
-
type Expression = Literal | RefExpr | ConditionalExpr | FnExpr | PipeExpr | ConditionExpr
|
|
89
|
+
type Expression = Literal | RefExpr | ConditionalExpr | FnExpr | PipeExpr | ConditionExpr;
|
|
62
90
|
/**
|
|
63
91
|
* Compiled expression function
|
|
64
92
|
*/
|
|
@@ -95,7 +123,13 @@ interface ValidationResult {
|
|
|
95
123
|
errors: string[];
|
|
96
124
|
}
|
|
97
125
|
/**
|
|
98
|
-
* Function scope - functions available to $fn expressions
|
|
126
|
+
* Function scope - functions available to $fn expressions.
|
|
127
|
+
*
|
|
128
|
+
* Uses `any` for function parameters because TypeScript's contravariance
|
|
129
|
+
* makes it impossible to assign typed functions like `(a: number, b: number) => number`
|
|
130
|
+
* to `(...args: unknown[]) => unknown`. This is the standard pattern for
|
|
131
|
+
* heterogeneous function registries (similar to Lodash, Ramda, etc.).
|
|
132
|
+
*
|
|
99
133
|
* @example { add, subtract, multiply, filter, map, sum }
|
|
100
134
|
*/
|
|
101
135
|
type Scope = Record<string, (...args: any[]) => any>;
|
|
@@ -132,16 +166,14 @@ declare const isFn: (v: unknown) => v is FnExpr;
|
|
|
132
166
|
*/
|
|
133
167
|
declare const isPipe: (v: unknown) => v is PipeExpr;
|
|
134
168
|
/**
|
|
135
|
-
* Check if value is a condition
|
|
169
|
+
* Check if value is a condition expression
|
|
136
170
|
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* properties (e.g., { resource: "x", op: "set", path: "y", value: z })
|
|
140
|
-
* but "set" is NOT a condition operator.
|
|
171
|
+
* Verifies `op` is a valid condition operator to distinguish from
|
|
172
|
+
* effect objects that also have `left` and `op` (e.g. op: "set").
|
|
141
173
|
*/
|
|
142
174
|
declare const isCondition: (v: unknown) => v is Condition;
|
|
143
175
|
/**
|
|
144
|
-
* Check if value is a condition group
|
|
176
|
+
* Check if value is a condition group
|
|
145
177
|
*/
|
|
146
178
|
declare const isConditionGroup: (v: unknown) => v is ConditionGroup;
|
|
147
179
|
/**
|
|
@@ -408,7 +440,7 @@ declare const ref: typeof $;
|
|
|
408
440
|
* $fn("sum") // no args - returns function reference
|
|
409
441
|
* $fn("now", []) // empty args - calls function
|
|
410
442
|
*/
|
|
411
|
-
declare function $fn(name: string, args?:
|
|
443
|
+
declare function $fn(name: string, args?: FnArg[]): FnExpr;
|
|
412
444
|
/**
|
|
413
445
|
* Alias for $fn (function builder)
|
|
414
446
|
*/
|
|
@@ -442,16 +474,36 @@ declare function $pipe(...steps: Expression[]): PipeExpr;
|
|
|
442
474
|
* Alias for $pipe (pipe builder)
|
|
443
475
|
*/
|
|
444
476
|
declare const pipe: typeof $pipe;
|
|
477
|
+
/**
|
|
478
|
+
* Create a condition expression.
|
|
479
|
+
*
|
|
480
|
+
* @param left - Left side (any expression)
|
|
481
|
+
* @param op - Condition operator
|
|
482
|
+
* @param right - Right side (any expression, optional for exists/notExists)
|
|
483
|
+
* @returns Condition
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* $cond($("age"), "gte", 18)
|
|
487
|
+
* $cond($fn("getScore", [$("user")]), "gt", 100)
|
|
488
|
+
* $cond($("email"), "exists")
|
|
489
|
+
*/
|
|
490
|
+
declare function $cond(left: Expression, op: ConditionOp, right?: Expression): Condition;
|
|
491
|
+
/**
|
|
492
|
+
* Alias for $cond (condition builder)
|
|
493
|
+
*/
|
|
494
|
+
declare const cond: typeof $cond;
|
|
445
495
|
|
|
446
496
|
declare const builders_$: typeof $;
|
|
497
|
+
declare const builders_$cond: typeof $cond;
|
|
447
498
|
declare const builders_$fn: typeof $fn;
|
|
448
499
|
declare const builders_$if: typeof $if;
|
|
449
500
|
declare const builders_$pipe: typeof $pipe;
|
|
501
|
+
declare const builders_cond: typeof cond;
|
|
450
502
|
declare const builders_fn: typeof fn;
|
|
451
503
|
declare const builders_pipe: typeof pipe;
|
|
452
504
|
declare const builders_ref: typeof ref;
|
|
453
505
|
declare namespace builders {
|
|
454
|
-
export { builders_$ as $, builders_$fn as $fn, builders_$if as $if, builders_$pipe as $pipe, builders_fn as fn, builders_pipe as pipe, builders_ref as ref };
|
|
506
|
+
export { builders_$ as $, builders_$cond as $cond, builders_$fn as $fn, builders_$if as $if, builders_$pipe as $pipe, builders_cond as cond, builders_fn as fn, builders_pipe as pipe, builders_ref as ref };
|
|
455
507
|
}
|
|
456
508
|
|
|
457
509
|
/**
|
|
@@ -674,4 +726,4 @@ declare function evaluateAST<T = unknown, R = unknown>(expr: Expression, data: T
|
|
|
674
726
|
*/
|
|
675
727
|
declare const VERSION = "0.1.1";
|
|
676
728
|
|
|
677
|
-
export { type AccessorFn, type CallbackFn, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, type ConditionalExpr, type Expression, ExpressionCache, type FnExpr, type Literal, type PathGetter, type PipeExpr, type RefExpr, type Scope, type TransformOptions, VERSION, type ValidateOptions, type ValidationResult, assertValid, builders, cache, cached, clearPathCache, compile, compileAST, compilePath, dslToAST, evaluate, evaluateAST, extractDataRoots, extractDeps, extractScopeFns, get, getPathCacheSize, hasDeps, hasWildcard, isCondition, isConditionExpr, isConditionGroup, isConditional, isFn, isLiteral, isPipe, isPure, isRef, isValid, normalizePath, validate, wrapInFunction };
|
|
729
|
+
export { type AccessorFn, type CallbackFn, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, type Condition, type ConditionExpr, type ConditionGroup, type ConditionOp, type ConditionalExpr, type Expression, ExpressionCache, type FnArg, type FnExpr, type Literal, type PathGetter, type PipeExpr, type RefExpr, type Scope, type TransformOptions, VERSION, type ValidateOptions, type ValidationResult, assertValid, builders, cache, cached, clearPathCache, compile, compileAST, compilePath, dslToAST, evaluate, evaluateAST, extractDataRoots, extractDeps, extractScopeFns, get, getPathCacheSize, hasDeps, hasWildcard, isCondition, isConditionExpr, isConditionGroup, isConditional, isFn, isLiteral, isPipe, isPure, isRef, isValid, normalizePath, validate, wrapInFunction };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {isRef,compile,validate}from'@statedelta-libs/conditions';import {builders,generate}from'omni-ast';var on=Object.defineProperty;var rn=(n,e)=>{for(var i in e)on(n,i,{get:e[i],enumerable:true});};var g=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,h=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,T=n=>n!==null&&typeof n=="object"&&"$fn"in n&&typeof n.$fn=="string",b=n=>n!==null&&typeof n=="object"&&"$pipe"in n&&Array.isArray(n.$pipe),_=new Set(["eq","neq","gt","gte","lt","lte","in","notIn","contains","notContains","exists","notExists","matches","notMatches","startsWith","endsWith"]),y=n=>n!==null&&typeof n=="object"&&"path"in n&&"op"in n&&_.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),E=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,sn=n=>y(n)||E(n),D=n=>{if(n===null)return true;let e=typeof n;if(e==="string"||e==="number"||e==="boolean"||Array.isArray(n))return true;if(e==="object"&&n!==null){let i=n,t="path"in i&&"op"in i&&_.has(i.op);return !("$"in i)&&!("$if"in i)&&!("$fn"in i)&&!("$pipe"in i)&&!t&&!("logic"in i)}return false};var x=new Map;function q(n){let e=[],i=n.length,t=0,r="";for(;t<i;){let f=n[t];if(f===".")r&&(e.push({type:"key",value:r}),r=""),t++;else if(f==="["){r&&(e.push({type:"key",value:r}),r=""),t++;let o=t;for(;t<i&&n[t]!=="]";)t++;let s=n.slice(o,t);if(t++,s==="*")e.push({type:"wildcard",value:"*"});else {let u=parseInt(s,10);e.push({type:"index",value:isNaN(u)?s:u});}}else r+=f,t++;}return r&&e.push({type:"key",value:r}),e}function J(n){return n.includes("[*]")}function O(n){let e=x.get(n);return e||(e=J(n)?fn(n):ln(n),x.set(n,e),e)}function ln(n){if(!n.includes(".")&&!n.includes("["))return r=>r?.[n];let e=q(n),i=e.length;if(i===2){let[r,f]=e,o=r.value,s=f.value;return u=>u?.[o]?.[s]}if(i===3){let[r,f,o]=e,s=r.value,u=f.value,a=o.value;return c=>c?.[s]?.[u]?.[a]}let t=e.map(r=>r.value);return r=>{let f=r;for(let o=0;o<i&&f!=null;o++)f=f[t[o]];return f}}function fn(n){let e=q(n),i=[];for(let t=0;t<e.length;t++)e[t].type==="wildcard"&&i.push(t);return i.length===1?un(e,i[0]):an(e,i)}function un(n,e){let i=n.slice(0,e).map(o=>o.value),t=n.slice(e+1).map(o=>o.value),r=i.length,f=t.length;if(f===0){if(r===1){let o=i[0];return s=>s?.[o]}return o=>{let s=o;for(let u=0;u<r&&s!=null;u++)s=s[i[u]];return s}}if(f===1){let o=t[0];if(r===1){let s=i[0];return u=>{let a=u?.[s];if(Array.isArray(a))return a.map(c=>c?.[o])}}return s=>{let u=s;for(let a=0;a<r&&u!=null;a++)u=u[i[a]];if(Array.isArray(u))return u.map(a=>a?.[o])}}return o=>{let s=o;for(let u=0;u<r&&s!=null;u++)s=s[i[u]];if(Array.isArray(s))return s.map(u=>{let a=u;for(let c=0;c<f&&a!=null;c++)a=a[t[c]];return a})}}function an(n,e){let i=[],t=0;for(let f=0;f<e.length;f++){let o=e[f],s=f===e.length-1,u=n.slice(t,o).map(a=>a.value);u.length>0&&i.push({type:"access",keys:u}),i.push({type:s?"map":"flatMap",keys:[]}),t=o+1;}let r=n.slice(t).map(f=>f.value);return f=>{let o=f;for(let s of i){if(o==null)return;if(s.type==="access")for(let u of s.keys){if(o==null)return;o=o[u];}else if(s.type==="flatMap"){if(!Array.isArray(o))return;o=o.flatMap(u=>{let a=u;return Array.isArray(a)?a:[a]});}else if(s.type==="map"){if(!Array.isArray(o))return;r.length>0&&(o=o.map(u=>{let a=u;for(let c of r){if(a==null)return;a=a[c];}return a}));}}return o}}function cn(n,e){return O(e)(n)}function R(n){let e=n.indexOf("[*]");return e===-1?n:n.slice(0,e)}function pn(){x.clear();}function dn(){return x.size}function w(n){let e=new Set;return S(n,e),Array.from(e)}function S(n,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r=0;r<n.length;r++)S(n[r],e);return}if(g(n)){e.add(R(n.$));return}if(h(n)){if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if;e.add(R(r));}else S(n.$if,e);S(n.then,e),n.else!==void 0&&S(n.else,e);return}if(b(n)){for(let r=0;r<n.$pipe.length;r++)S(n.$pipe[r],e);return}if(T(n)){if(n.args)for(let r=0;r<n.args.length;r++)S(n.args[r],e);return}if(y(n)){e.add(R(n.path)),n.value!==void 0&&isRef(n.value)&&e.add(R(n.value.$));return}if(E(n)){for(let r=0;r<n.conditions.length;r++)S(n.conditions[r],e);return}let i=n,t=Object.keys(i);for(let r=0;r<t.length;r++)S(i[t[r]],e);}function gn(n){return w(n).length>0}function yn(n){return w(n).length===0}function En(n){return JSON.stringify(n)}function F(n,e={}){let i=e.scope??{},t=e.accessor,r=C(n,i,t),f=w(n),o=En(n);return {fn:r,deps:f,hash:o}}function C(n,e,i){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let t=n.map(r=>C(r,e,i));return r=>t.map(f=>f(r))}if(g(n))return hn(n,i);if(h(n))return Tn(n,e,i);if(b(n))return bn(n,e,i);if(T(n))return Cn(n,e,i);if(y(n))return compile(n,i?{accessor:i}:void 0);if(E(n))return compile(n,i?{accessor:i}:void 0);if(D(n)){let t=n,r=Object.keys(t),f=r.map(o=>C(t[o],e,i));return o=>{let s={};for(let u=0;u<r.length;u++)s[r[u]]=f[u](o);return s}}return ()=>n}function K(n,e){return e?i=>e(n,i):O(n)}function hn(n,e){return K(n.$,e)}function Tn(n,e,i){let t;if(typeof n.$if=="string"){let o=n.$if.startsWith("!")?n.$if.slice(1):n.$if,s=K(o,i);t=n.$if.startsWith("!")?a=>!s(a):a=>!!s(a);}else {let o=C(n.$if,e,i);t=s=>!!o(s);}let r=C(n.then,e,i),f=n.else!==void 0?C(n.else,e,i):()=>{};return o=>t(o)?r(o):f(o)}function bn(n,e,i){let t=n.$pipe;if(t.length===0)return ()=>{};if(t.length===1)return C(t[0],e,i);let r=C(t[0],e,i),f=t.slice(1).map(s=>C(s,e,i)),o=f.length;if(o===1){let[s]=f;return u=>{let a=r(u),c=s(u);return typeof c=="function"?c(a):c}}if(o===2){let[s,u]=f;return a=>{let c=r(a),p=s(a);return c=typeof p=="function"?p(c):p,p=u(a),typeof p=="function"?p(c):p}}if(o===3){let[s,u,a]=f;return c=>{let p=r(c),d=s(c);return p=typeof d=="function"?d(p):d,d=u(c),p=typeof d=="function"?d(p):d,d=a(c),typeof d=="function"?d(p):d}}return s=>{let u=r(s);for(let a=0;a<o;a++){let c=f[a](s);u=typeof c=="function"?c(u):c;}return u}}function Cn(n,e,i){let t=n.$fn,r=n.args;if(r===void 0)return ()=>{let s=e[t];if(!s)throw new Error(`Function not found in scope: ${t}`);return s};let f=r.map(s=>C(s,e,i)),o=f.length;if(o===0)return s=>{let u=e[t];if(!u)throw new Error(`Function not found in scope: ${t}`);return u()};if(o===1){let[s]=f;return u=>{let a=e[t];if(!a)throw new Error(`Function not found in scope: ${t}`);return a(s(u))}}if(o===2){let[s,u]=f;return a=>{let c=e[t];if(!c)throw new Error(`Function not found in scope: ${t}`);return c(s(a),u(a))}}if(o===3){let[s,u,a]=f;return c=>{let p=e[t];if(!p)throw new Error(`Function not found in scope: ${t}`);return p(s(c),u(c),a(c))}}return s=>{let u=e[t];if(!u)throw new Error(`Function not found in scope: ${t}`);return u(...f.map(a=>a(s)))}}function $n(n,e,i={}){return F(n,i).fn(e)}var v=class{constructor(e=1e3){this.cache=new Map,this._maxSize=e;}get(e,i={}){let t=JSON.stringify(e),r=this.cache.get(t);if(r)return this.cache.delete(t),this.cache.set(t,r),r;let f=F(e,i);if(this.cache.size>=this._maxSize){let o=this.cache.keys().next().value;o&&this.cache.delete(o);}return this.cache.set(t,f),f}has(e){return this.cache.has(JSON.stringify(e))}delete(e){return this.cache.delete(JSON.stringify(e))}clear(){this.cache.clear();}get size(){return this.cache.size}get maxSize(){return this._maxSize}set maxSize(e){for(this._maxSize=e;this.cache.size>this._maxSize;){let i=this.cache.keys().next().value;i&&this.cache.delete(i);}}},Y=new v;function Sn(n,e={}){return Y.get(n,e)}function I(n,e="root",i={}){let t=[];return k(n,e,t,i),{valid:t.length===0,errors:t}}function k(n,e,i,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let o=0;o<n.length;o++)k(n[o],`${e}[${o}]`,i,t);return}if(g(n)){(!n.$||typeof n.$!="string")&&i.push(`${e}: invalid reference, $ must be non-empty string`);return}if(h(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||i.push(`${e}.$if: empty path in string shorthand`):k(n.$if,`${e}.$if`,i,t),k(n.then,`${e}.then`,i,t),n.else!==void 0&&k(n.else,`${e}.else`,i,t);return}if(b(n)){if(!Array.isArray(n.$pipe)){i.push(`${e}.$pipe: must be an array`);return}if(n.$pipe.length===0){i.push(`${e}.$pipe: must have at least one element`);return}for(let o=0;o<n.$pipe.length;o++)k(n.$pipe[o],`${e}.$pipe[${o}]`,i,t);return}if(T(n)){if(!n.$fn||typeof n.$fn!="string"){i.push(`${e}: invalid function, $fn must be non-empty string`);return}if(t.scope&&!(n.$fn in t.scope)&&i.push(`${e}: function "${n.$fn}" not found in scope`),n.args!==void 0)if(!Array.isArray(n.args))i.push(`${e}.args: must be an array`);else for(let o=0;o<n.args.length;o++)k(n.args[o],`${e}.args[${o}]`,i,t);return}if(y(n)){let o=validate(n,e);o.valid||i.push(...o.errors);return}if(E(n)){let o=validate(n,e);o.valid||i.push(...o.errors);return}let r=n,f=Object.keys(r);for(let o=0;o<f.length;o++){let s=f[o];k(r[s],`${e}.${s}`,i,t);}}function An(n,e={}){let i=I(n,"root",e);if(!i.valid)throw new Error(`Invalid expression: ${i.errors.join("; ")}`)}function kn(n,e={}){return I(n,"root",e).valid}var Z={};rn(Z,{$:()=>Q,$fn:()=>U,$if:()=>xn,$pipe:()=>X,fn:()=>Rn,pipe:()=>On,ref:()=>wn});function Q(n){return {$:n}}var wn=Q;function U(n,e){return e===void 0||e.length===0?{$fn:n}:{$fn:n,args:e}}var Rn=U;function xn(n,e,i){return i===void 0?{$if:n,then:e}:{$if:n,then:e,else:i}}function X(...n){return {$pipe:n}}var On=X;var L="data",P="scope",Fn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function W(n,e={}){let{dataParam:i=L,scopeParam:t=P,noPrefixes:r=false,useAccessor:f=false,lexicalPrefix:o}=e;return m(n,i,t,r,f,o)}function m(n,e,i,t,r,f){if(n===null)return builders.literal(null);if(typeof n=="string")return builders.literal(n);if(typeof n=="number")return builders.literal(n);if(typeof n=="boolean")return builders.literal(n);if(Array.isArray(n))return builders.arrayExpression(n.map(o=>m(o,e,i,t,r,f)));if(g(n))return vn(n.$,e,t,r,f);if(h(n))return jn(n,e,i,t,r,f);if(b(n))return Wn(n.$pipe,e,i,t,r,f);if(T(n))return Gn(n,e,i,t,r,f);if(y(n))return zn(n,e,i,t,r,f);if(E(n))return Mn(n,e,i,t,r,f);if(typeof n=="object"){let s=Object.entries(n).map(([u,a])=>builders.property(builders.identifier(u),m(a,e,i,t,r,f)));return builders.objectExpression(s)}return builders.literal(null)}var N="accessor";function j(n,e){return e?n===e||n.startsWith(e+"."):false}function vn(n,e,i,t,r){return t?j(n,r)?A(n,e,true):builders.callExpression(builders.identifier(N),[builders.literal(n),builders.identifier(e)]):n.includes("[*]")?Nn(n,e,i):A(n,e,i)}function A(n,e,i){let t=G(n);if(t.length===0)return i?builders.identifier("undefined"):builders.identifier(e);let r;if(i){let f=t[0];r=builders.identifier(f.value);for(let o=1;o<t.length;o++){let s=t[o];s.type==="key"?r=builders.memberExpression(r,builders.identifier(s.value),false,true):r=builders.memberExpression(r,builders.literal(s.value),true,true);}}else {r=builders.identifier(e);for(let f of t)f.type==="key"?r=builders.memberExpression(r,builders.identifier(f.value),false,true):r=builders.memberExpression(r,builders.literal(f.value),true,true);}return r}function Nn(n,e,i){let t=n.indexOf("[*]"),r=n.slice(0,t),f=n.slice(t+3),o;if(r?o=A(r,e,i):o=i?builders.identifier("undefined"):builders.identifier(e),!f||f==="")return o;if(f.includes("[*]"))return nn(o,f);let s="_i",u=f.startsWith(".")?f.slice(1):f,a=builders.identifier(s);if(u){let c=G(u);for(let p of c)p.type==="key"?a=builders.memberExpression(a,builders.identifier(p.value),false,true):a=builders.memberExpression(a,builders.literal(p.value),true,true);}return builders.callExpression(builders.memberExpression(o,builders.identifier("map"),false,true),[builders.arrowFunctionExpression([builders.identifier(s)],a)])}function nn(n,e){let i=e.indexOf("[*]"),t=e.slice(0,i),r=e.slice(i+3),f="_i",o=t.startsWith(".")?t.slice(1):t,s=builders.identifier(f);if(o){let a=G(o);for(let c of a)c.type==="key"&&(s=builders.memberExpression(s,builders.identifier(c.value),false,true));}if(r.includes("[*]")){let a=nn(s,r);return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(f)],a)])}let u=r.startsWith(".")?r.slice(1):r;if(u){let a=G(u);for(let c of a)c.type==="key"&&(s=builders.memberExpression(s,builders.identifier(c.value),false,true));}return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(f)],s)])}function jn(n,e,i,t,r,f){let o;if(typeof n.$if=="string"){let a=n.$if.startsWith("!"),c=a?n.$if.slice(1):n.$if,p;r?j(c,f)?p=A(c,e,true):p=builders.callExpression(builders.identifier(N),[builders.literal(c),builders.identifier(e)]):p=A(c,e,t),o=a?builders.unaryExpression("!",p):p;}else o=m(n.$if,e,i,t,r,f);let s=m(n.then,e,i,t,r,f),u=n.else!==void 0?m(n.else,e,i,t,r,f):builders.identifier("undefined");return builders.conditionalExpression(o,s,u)}function Gn(n,e,i,t,r,f){let o=t?builders.identifier(n.$fn):builders.memberExpression(builders.identifier(i),builders.identifier(n.$fn),false,false);if(n.args===void 0)return o;let s=n.args.map(u=>m(u,e,i,t,r,f));return builders.callExpression(o,s)}function Wn(n,e,i,t,r,f){if(n.length===0)return builders.identifier("undefined");if(n.length===1)return m(n[0],e,i,t,r,f);let o=m(n[0],e,i,t,r,f);for(let s=1;s<n.length;s++){let u=m(n[s],e,i,t,r,f);o=builders.callExpression(u,[o]);}return o}function zn(n,e,i,t,r,f){let o;r?j(n.path,f)?o=A(n.path,e,true):o=builders.callExpression(builders.identifier(N),[builders.literal(n.path),builders.identifier(e)]):o=A(n.path,e,t);let s=n.value!==void 0?g(n.value)?r?j(n.value.$,f)?A(n.value.$,e,true):builders.callExpression(builders.identifier(N),[builders.literal(n.value.$),builders.identifier(e)]):A(n.value.$,e,t):m(n.value,e,i,t,r,f):builders.literal(null),u=Fn[n.op];if(u)return builders.binaryExpression(u,o,s);switch(n.op){case "in":return builders.callExpression(builders.memberExpression(s,builders.identifier("includes")),[o]);case "notIn":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(s,builders.identifier("includes")),[o]));case "contains":return builders.callExpression(builders.memberExpression(o,builders.identifier("includes"),false,true),[s]);case "notContains":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(o,builders.identifier("includes"),false,true),[s]));case "exists":return builders.binaryExpression("!=",o,builders.literal(null));case "notExists":return builders.binaryExpression("==",o,builders.literal(null));case "matches":return builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[s]),builders.identifier("test")),[o]);case "notMatches":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[s]),builders.identifier("test")),[o]));case "startsWith":return builders.callExpression(builders.memberExpression(o,builders.identifier("startsWith"),false,true),[s]);case "endsWith":return builders.callExpression(builders.memberExpression(o,builders.identifier("endsWith"),false,true),[s]);default:return builders.binaryExpression("===",o,s)}}function Mn(n,e,i,t,r,f){let{logic:o,conditions:s}=n,u=o==="AND"?"&&":"||";if(s.length===0)return builders.literal(o==="AND");if(s.length===1)return m(s[0],e,i,t,r,f);let a=m(s[0],e,i,t,r,f);for(let c=1;c<s.length;c++){let p=m(s[c],e,i,t,r,f);a=builders.logicalExpression(u,a,p);}return a}function G(n){let e=[],i=n.length,t=0,r="";for(;t<i;){let f=n[t];if(f===".")r&&(e.push({type:"key",value:r}),r=""),t++;else if(f==="["){r&&(e.push({type:"key",value:r}),r=""),t++;let o=t;for(;t<i&&n[t]!=="]";)t++;let s=n.slice(o,t);if(t++,s!=="*"){let u=parseInt(s,10);e.push({type:"index",value:isNaN(u)?s:u});}}else r+=f,t++;}return r&&e.push({type:"key",value:r}),e}function en(n,e=[L]){return builders.arrowFunctionExpression(e.map(i=>builders.identifier(i)),n)}function z(n){let e=new Set;return $(n,e),e}function $(n,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let t of n)$(t,e);return}if(g(n))return;if(h(n)){$(n.$if,e),$(n.then,e),n.else!==void 0&&$(n.else,e);return}if(b(n)){for(let t of n.$pipe)$(t,e);return}if(T(n)){if(e.add(n.$fn),n.args)for(let t of n.args)$(t,e);return}if(y(n)){n.value!==void 0&&typeof n.value=="object"&&$(n.value,e);return}if(E(n)){for(let t of n.conditions)$(t,e);return}let i=n;for(let t of Object.keys(i))$(i[t],e);}function M(n){let e=new Set;for(let i of n){let t=i.indexOf("."),r=i.indexOf("["),f=i.length;t!==-1&&(f=Math.min(f,t)),r!==-1&&(f=Math.min(f,r));let o=i.slice(0,f);o&&e.add(o);}return e}function In(n){return JSON.stringify(n)}function Ln(n,e,i,t,r){let f=W(n,{noPrefixes:true,useAccessor:t,lexicalPrefix:r}),o=generate(f),s="";t?r&&(s=`const{${r}}=data??{};`):e.size>0&&(s=`const{${[...e].join(",")}}=data??{};`);let u=t?new Set([...i,"accessor"]):i,a=u.size>0?`const{${[...u].join(",")}}=scope;`:"";return a?`(function(scope){${a}return function(data){${s}return ${o}}})`:`(function(){return function(data){${s}return ${o}}})`}function V(n,e={}){let{scope:i={},returnCode:t=false,useAccessor:r=false,lexicalPrefix:f}=e,o=w(n),s=M(o),u=z(n),a=In(n),c=Ln(n,s,u,r,f);if(t)return {code:c,deps:o,hash:a,dataRoots:[...s],scopeFns:[...u]};let p;try{p=new Function(`return ${c}`)()(i);}catch(d){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${d instanceof Error?d.message:String(d)}`)}return {fn:p,deps:o,hash:a}}function tn(n,e,i={}){let{fn:t}=V(n,i);return t(e)}var he="0.1.1";export{v as ExpressionCache,he as VERSION,An as assertValid,Z as builders,Y as cache,Sn as cached,pn as clearPathCache,F as compile,V as compileAST,O as compilePath,W as dslToAST,$n as evaluate,tn as evaluateAST,M as extractDataRoots,w as extractDeps,z as extractScopeFns,cn as get,dn as getPathCacheSize,gn as hasDeps,J as hasWildcard,y as isCondition,sn as isConditionExpr,E as isConditionGroup,h as isConditional,T as isFn,D as isLiteral,b as isPipe,yn as isPure,g as isRef,kn as isValid,R as normalizePath,I as validate,en as wrapInFunction};
|
|
1
|
+
import {builders,generate}from'omni-ast';var on=Object.defineProperty;var rn=(n,t)=>{for(var s in t)on(n,s,{get:t[s],enumerable:true});};var y=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,T=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,b=n=>n!==null&&typeof n=="object"&&"$fn"in n&&typeof n.$fn=="string",C=n=>n!==null&&typeof n=="object"&&"$pipe"in n&&Array.isArray(n.$pipe),x=new Set(["eq","neq","gt","gte","lt","lte","in","notIn","contains","notContains","exists","notExists","matches","notMatches","startsWith","endsWith"]),h=n=>n!==null&&typeof n=="object"&&"left"in n&&"op"in n&&x.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),E=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,sn=n=>h(n)||E(n),I=n=>{if(n===null)return true;let t=typeof n;if(t==="string"||t==="number"||t==="boolean"||Array.isArray(n))return true;if(t==="object"&&n!==null){let s=n,e="left"in s&&"op"in s&&x.has(s.op);return !("$"in s)&&!("$if"in s)&&!("$fn"in s)&&!("$pipe"in s)&&!e&&!("logic"in s)}return false};var R=new Map;function q(n){let t=[],s=n.length,e=0,r="";for(;e<s;){let o=n[e];if(o===".")r&&(t.push({type:"key",value:r}),r=""),e++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),e++;let i=e;for(;e<s&&n[e]!=="]";)e++;let f=n.slice(i,e);if(e++,f==="*")t.push({type:"wildcard",value:"*"});else {let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,e++;}return r&&t.push({type:"key",value:r}),t}function J(n){return n.includes("[*]")}function O(n){let t=R.get(n);return t||(t=J(n)?un(n):fn(n),R.set(n,t),t)}function fn(n){if(!n.includes(".")&&!n.includes("["))return r=>r?.[n];let t=q(n),s=t.length;if(s===2){let[r,o]=t,i=r.value,f=o.value;return l=>l?.[i]?.[f]}if(s===3){let[r,o,i]=t,f=r.value,l=o.value,c=i.value;return a=>a?.[f]?.[l]?.[c]}let e=t.map(r=>r.value);return r=>{let o=r;for(let i=0;i<s&&o!=null;i++)o=o[e[i]];return o}}function un(n){let t=q(n),s=[];for(let e=0;e<t.length;e++)t[e].type==="wildcard"&&s.push(e);return s.length===1?ln(t,s[0]):cn(t,s)}function ln(n,t){let s=n.slice(0,t).map(i=>i.value),e=n.slice(t+1).map(i=>i.value),r=s.length,o=e.length;if(o===0){if(r===1){let i=s[0];return f=>f?.[i]}return i=>{let f=i;for(let l=0;l<r&&f!=null;l++)f=f[s[l]];return f}}if(o===1){let i=e[0];if(r===1){let f=s[0];return l=>{let c=l?.[f];if(Array.isArray(c))return c.map(a=>a?.[i])}}return f=>{let l=f;for(let c=0;c<r&&l!=null;c++)l=l[s[c]];if(Array.isArray(l))return l.map(c=>c?.[i])}}return i=>{let f=i;for(let l=0;l<r&&f!=null;l++)f=f[s[l]];if(Array.isArray(f))return f.map(l=>{let c=l;for(let a=0;a<o&&c!=null;a++)c=c[e[a]];return c})}}function cn(n,t){let s=[],e=0;for(let o=0;o<t.length;o++){let i=t[o],f=o===t.length-1,l=n.slice(e,i).map(c=>c.value);l.length>0&&s.push({type:"access",keys:l}),s.push({type:f?"map":"flatMap",keys:[]}),e=i+1;}let r=n.slice(e).map(o=>o.value);return o=>{let i=o;for(let f of s){if(i==null)return;if(f.type==="access")for(let l of f.keys){if(i==null)return;i=i[l];}else if(f.type==="flatMap"){if(!Array.isArray(i))return;i=i.flatMap(l=>{let c=l;return Array.isArray(c)?c:[c]});}else if(f.type==="map"){if(!Array.isArray(i))return;r.length>0&&(i=i.map(l=>{let c=l;for(let a of r){if(c==null)return;c=c[a];}return c}));}}return i}}function an(n,t){return O(t)(n)}function F(n){let t=n.indexOf("[*]");return t===-1?n:n.slice(0,t)}function pn(){R.clear();}function dn(){return R.size}function k(n){let t=new Set;return A(n,t),Array.from(t)}function A(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r=0;r<n.length;r++)A(n[r],t);return}if(y(n)){t.add(F(n.$));return}if(T(n)){if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if;t.add(F(r));}else A(n.$if,t);A(n.then,t),n.else!==void 0&&A(n.else,t);return}if(C(n)){for(let r=0;r<n.$pipe.length;r++)A(n.$pipe[r],t);return}if(b(n)){if(n.args)for(let r=0;r<n.args.length;r++){let o=n.args[r];typeof o!="function"&&A(o,t);}return}if(h(n)){A(n.left,t),n.right!==void 0&&A(n.right,t);return}if(E(n)){for(let r=0;r<n.conditions.length;r++)A(n.conditions[r],t);return}let s=n,e=Object.keys(s);for(let r=0;r<e.length;r++)A(s[e[r]],t);}function gn(n){return k(n).length>0}function mn(n){return k(n).length===0}function yn(n){return JSON.stringify(n)}function N(n,t={}){let s=t.scope??{},e=t.accessor,r=m(n,s,e),o=k(n),i=yn(n);return {fn:r,deps:o,hash:i}}function m(n,t,s){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let e=n.map(r=>m(r,t,s));return r=>e.map(o=>o(r))}if(y(n))return hn(n,s);if(T(n))return En(n,t,s);if(C(n))return Tn(n,t,s);if(b(n))return bn(n,t,s);if(h(n))return Cn(n,t,s);if(E(n))return An(n,t,s);if(I(n)){let e=n,r=Object.keys(e),o=r.map(i=>m(e[i],t,s));return i=>{let f={};for(let l=0;l<r.length;l++)f[r[l]]=o[l](i);return f}}return ()=>n}function B(n,t){return t?s=>t(n,s):O(n)}function hn(n,t){return B(n.$,t)}function En(n,t,s){let e;if(typeof n.$if=="string"){let i=n.$if.startsWith("!")?n.$if.slice(1):n.$if,f=B(i,s);e=n.$if.startsWith("!")?c=>!f(c):c=>!!f(c);}else {let i=m(n.$if,t,s);e=f=>!!i(f);}let r=m(n.then,t,s),o=n.else!==void 0?m(n.else,t,s):()=>{};return i=>e(i)?r(i):o(i)}function Tn(n,t,s){let e=n.$pipe;if(e.length===0)return ()=>{};if(e.length===1)return m(e[0],t,s);let r=m(e[0],t,s),o=e.slice(1).map(f=>m(f,t,s)),i=o.length;if(i===1){let[f]=o;return l=>{let c=r(l),a=f(l);return typeof a=="function"?a(c):a}}if(i===2){let[f,l]=o;return c=>{let a=r(c),p=f(c);return a=typeof p=="function"?p(a):p,p=l(c),typeof p=="function"?p(a):p}}if(i===3){let[f,l,c]=o;return a=>{let p=r(a),d=f(a);return p=typeof d=="function"?d(p):d,d=l(a),p=typeof d=="function"?d(p):d,d=c(a),typeof d=="function"?d(p):d}}return f=>{let l=r(f);for(let c=0;c<i;c++){let a=o[c](f);l=typeof a=="function"?a(l):a;}return l}}function bn(n,t,s){let e=n.$fn,r=n.args;if(r===void 0)return ()=>{let f=t[e];if(!f)throw new Error(`Function not found in scope: ${e}`);return f};let o=r.map(f=>typeof f=="function"?()=>f:m(f,t,s)),i=o.length;if(i===0)return f=>{let l=t[e];if(!l)throw new Error(`Function not found in scope: ${e}`);return l()};if(i===1){let[f]=o;return l=>{let c=t[e];if(!c)throw new Error(`Function not found in scope: ${e}`);return c(f(l))}}if(i===2){let[f,l]=o;return c=>{let a=t[e];if(!a)throw new Error(`Function not found in scope: ${e}`);return a(f(c),l(c))}}if(i===3){let[f,l,c]=o;return a=>{let p=t[e];if(!p)throw new Error(`Function not found in scope: ${e}`);return p(f(a),l(a),c(a))}}return f=>{let l=t[e];if(!l)throw new Error(`Function not found in scope: ${e}`);return l(...o.map(c=>c(f)))}}function Cn(n,t,s){let e=m(n.left,t,s),r=n.right!==void 0?m(n.right,t,s):()=>{};switch(n.op){case "eq":return o=>e(o)===r(o);case "neq":return o=>e(o)!==r(o);case "gt":return o=>e(o)>r(o);case "gte":return o=>e(o)>=r(o);case "lt":return o=>e(o)<r(o);case "lte":return o=>e(o)<=r(o);case "in":return o=>{let i=r(o);return Array.isArray(i)&&i.includes(e(o))};case "notIn":return o=>{let i=r(o);return !Array.isArray(i)||!i.includes(e(o))};case "contains":return o=>{let i=e(o);return Array.isArray(i)&&i.includes(r(o))};case "notContains":return o=>{let i=e(o);return !Array.isArray(i)||!i.includes(r(o))};case "exists":return o=>e(o)!==void 0;case "notExists":return o=>e(o)===void 0;case "matches":return o=>{let i=e(o),f=r(o);return typeof i!="string"||typeof f!="string"?false:new RegExp(f).test(i)};case "notMatches":return o=>{let i=e(o),f=r(o);return typeof i!="string"||typeof f!="string"?true:!new RegExp(f).test(i)};case "startsWith":return o=>{let i=e(o),f=r(o);return typeof i=="string"&&typeof f=="string"&&i.startsWith(f)};case "endsWith":return o=>{let i=e(o),f=r(o);return typeof i=="string"&&typeof f=="string"&&i.endsWith(f)}}}function An(n,t,s){let e=n.conditions.map(o=>m(o,t,s)),r=e.length;if(r===1)return o=>!!e[0](o);if(r===2){let[o,i]=e;return n.logic==="AND"?f=>!!o(f)&&!!i(f):f=>!!o(f)||!!i(f)}if(r===3){let[o,i,f]=e;return n.logic==="AND"?l=>!!o(l)&&!!i(l)&&!!f(l):l=>!!o(l)||!!i(l)||!!f(l)}return n.logic==="AND"?o=>{for(let i=0;i<r;i++)if(!e[i](o))return false;return true}:o=>{for(let i=0;i<r;i++)if(e[i](o))return true;return false}}function $n(n,t,s={}){return N(n,s).fn(t)}var v=class{constructor(t=1e3){this.cache=new Map,this._maxSize=t;}get(t,s={}){let e=JSON.stringify(t),r=this.cache.get(e);if(r)return this.cache.delete(e),this.cache.set(e,r),r;let o=N(t,s);if(this.cache.size>=this._maxSize){let i=this.cache.keys().next().value;i&&this.cache.delete(i);}return this.cache.set(e,o),o}has(t){return this.cache.has(JSON.stringify(t))}delete(t){return this.cache.delete(JSON.stringify(t))}clear(){this.cache.clear();}get size(){return this.cache.size}get maxSize(){return this._maxSize}set maxSize(t){for(this._maxSize=t;this.cache.size>this._maxSize;){let s=this.cache.keys().next().value;s&&this.cache.delete(s);}}},K=new v;function Sn(n,t={}){return K.get(n,t)}function M(n,t="root",s={}){let e=[];return $(n,t,e,s),{valid:e.length===0,errors:e}}function $(n,t,s,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let i=0;i<n.length;i++)$(n[i],`${t}[${i}]`,s,e);return}if(y(n)){(!n.$||typeof n.$!="string")&&s.push(`${t}: invalid reference, $ must be non-empty string`);return}if(T(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||s.push(`${t}.$if: empty path in string shorthand`):$(n.$if,`${t}.$if`,s,e),$(n.then,`${t}.then`,s,e),n.else!==void 0&&$(n.else,`${t}.else`,s,e);return}if(C(n)){if(!Array.isArray(n.$pipe)){s.push(`${t}.$pipe: must be an array`);return}if(n.$pipe.length===0){s.push(`${t}.$pipe: must have at least one element`);return}for(let i=0;i<n.$pipe.length;i++)$(n.$pipe[i],`${t}.$pipe[${i}]`,s,e);return}if(b(n)){if(!n.$fn||typeof n.$fn!="string"){s.push(`${t}: invalid function, $fn must be non-empty string`);return}if(e.scope&&!(n.$fn in e.scope)&&s.push(`${t}: function "${n.$fn}" not found in scope`),n.args!==void 0)if(!Array.isArray(n.args))s.push(`${t}.args: must be an array`);else for(let i=0;i<n.args.length;i++){let f=n.args[i];typeof f!="function"&&$(f,`${t}.args[${i}]`,s,e);}return}if(h(n)){x.has(n.op)||s.push(`${t}: invalid operator "${n.op}"`),$(n.left,`${t}.left`,s,e),n.right!==void 0&&$(n.right,`${t}.right`,s,e);return}if(E(n)){if(n.logic!=="AND"&&n.logic!=="OR"&&s.push(`${t}: invalid logic "${n.logic}", must be "AND" or "OR"`),!Array.isArray(n.conditions)){s.push(`${t}.conditions: must be an array`);return}for(let i=0;i<n.conditions.length;i++)$(n.conditions[i],`${t}.conditions[${i}]`,s,e);return}let r=n,o=Object.keys(r);for(let i=0;i<o.length;i++){let f=o[i];$(r[f],`${t}.${f}`,s,e);}}function kn(n,t={}){let s=M(n,"root",t);if(!s.valid)throw new Error(`Invalid expression: ${s.errors.join("; ")}`)}function wn(n,t={}){return M(n,"root",t).valid}var U={};rn(U,{$:()=>P,$cond:()=>Q,$fn:()=>Y,$if:()=>On,$pipe:()=>H,cond:()=>Nn,fn:()=>Rn,pipe:()=>Fn,ref:()=>xn});function P(n){return {$:n}}var xn=P;function Y(n,t){return t===void 0||t.length===0?{$fn:n}:{$fn:n,args:t}}var Rn=Y;function On(n,t,s){return s===void 0?{$if:n,then:t}:{$if:n,then:t,else:s}}function H(...n){return {$pipe:n}}var Fn=H;function Q(n,t,s){return s===void 0?{left:n,op:t}:{left:n,op:t,right:s}}var Nn=Q;var z="data",Z="scope",vn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function G(n,t={}){let{dataParam:s=z,scopeParam:e=Z,noPrefixes:r=false,useAccessor:o=false,lexicalPrefix:i}=t;return g(n,s,e,r,o,i)}function g(n,t,s,e,r,o){if(n===null)return builders.literal(null);if(typeof n=="string")return builders.literal(n);if(typeof n=="number")return builders.literal(n);if(typeof n=="boolean")return builders.literal(n);if(Array.isArray(n))return builders.arrayExpression(n.map(i=>g(i,t,s,e,r,o)));if(y(n))return jn(n.$,t,e,r,o);if(T(n))return Wn(n,t,s,e,r,o);if(C(n))return In(n.$pipe,t,s,e,r,o);if(b(n))return Dn(n,t,s,e,r,o);if(h(n))return Mn(n,t,s,e,r,o);if(E(n))return zn(n,t,s,e,r,o);if(typeof n=="object"){let f=Object.entries(n).map(([l,c])=>builders.property(builders.identifier(l),g(c,t,s,e,r,o)));return builders.objectExpression(f)}return builders.literal(null)}var L="accessor";function V(n,t){return t?n===t||n.startsWith(t+"."):false}function jn(n,t,s,e,r){return e?V(n,r)?w(n,t,true):builders.callExpression(builders.identifier(L),[builders.literal(n),builders.identifier(t)]):n.includes("[*]")?Gn(n,t,s):w(n,t,s)}function w(n,t,s){let e=j(n);if(e.length===0)return s?builders.identifier("undefined"):builders.identifier(t);let r;if(s){let o=e[0];r=builders.identifier(o.value);for(let i=1;i<e.length;i++){let f=e[i];f.type==="key"?r=builders.memberExpression(r,builders.identifier(f.value),false,true):r=builders.memberExpression(r,builders.literal(f.value),true,true);}}else {r=builders.identifier(t);for(let o of e)o.type==="key"?r=builders.memberExpression(r,builders.identifier(o.value),false,true):r=builders.memberExpression(r,builders.literal(o.value),true,true);}return r}function Gn(n,t,s){let e=n.indexOf("[*]"),r=n.slice(0,e),o=n.slice(e+3),i;if(r?i=w(r,t,s):i=s?builders.identifier("undefined"):builders.identifier(t),!o||o==="")return i;if(o.includes("[*]"))return nn(i,o);let f="_i",l=o.startsWith(".")?o.slice(1):o,c=builders.identifier(f);if(l){let a=j(l);for(let p of a)p.type==="key"?c=builders.memberExpression(c,builders.identifier(p.value),false,true):c=builders.memberExpression(c,builders.literal(p.value),true,true);}return builders.callExpression(builders.memberExpression(i,builders.identifier("map"),false,true),[builders.arrowFunctionExpression([builders.identifier(f)],c)])}function nn(n,t){let s=t.indexOf("[*]"),e=t.slice(0,s),r=t.slice(s+3),o="_i",i=e.startsWith(".")?e.slice(1):e,f=builders.identifier(o);if(i){let c=j(i);for(let a of c)a.type==="key"&&(f=builders.memberExpression(f,builders.identifier(a.value),false,true));}if(r.includes("[*]")){let c=nn(f,r);return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(o)],c)])}let l=r.startsWith(".")?r.slice(1):r;if(l){let c=j(l);for(let a of c)a.type==="key"&&(f=builders.memberExpression(f,builders.identifier(a.value),false,true));}return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(o)],f)])}function Wn(n,t,s,e,r,o){let i;if(typeof n.$if=="string"){let c=n.$if.startsWith("!"),a=c?n.$if.slice(1):n.$if,p;r?V(a,o)?p=w(a,t,true):p=builders.callExpression(builders.identifier(L),[builders.literal(a),builders.identifier(t)]):p=w(a,t,e),i=c?builders.unaryExpression("!",p):p;}else i=g(n.$if,t,s,e,r,o);let f=g(n.then,t,s,e,r,o),l=n.else!==void 0?g(n.else,t,s,e,r,o):builders.identifier("undefined");return builders.conditionalExpression(i,f,l)}function Dn(n,t,s,e,r,o){let i=e?builders.identifier(n.$fn):builders.memberExpression(builders.identifier(s),builders.identifier(n.$fn),false,false);if(n.args===void 0)return i;let f=n.args.map(l=>typeof l=="function"?builders.literal(null):g(l,t,s,e,r,o));return builders.callExpression(i,f)}function In(n,t,s,e,r,o){if(n.length===0)return builders.identifier("undefined");if(n.length===1)return g(n[0],t,s,e,r,o);let i=g(n[0],t,s,e,r,o);for(let f=1;f<n.length;f++){let l=g(n[f],t,s,e,r,o);i=builders.callExpression(l,[i]);}return i}function X(n,t,s,e,r,o){if(y(n)){let i=n.$;return r?V(i,o)?w(i,t,true):builders.callExpression(builders.identifier(L),[builders.literal(i),builders.identifier(t)]):w(i,t,e)}return g(n,t,s,e,r,o)}function Mn(n,t,s,e,r,o){let i=X(n.left,t,s,e,r,o),f=n.right!==void 0?X(n.right,t,s,e,r,o):builders.literal(null),l=vn[n.op];if(l)return builders.binaryExpression(l,i,f);switch(n.op){case "in":return builders.callExpression(builders.memberExpression(f,builders.identifier("includes")),[i]);case "notIn":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(f,builders.identifier("includes")),[i]));case "contains":return builders.callExpression(builders.memberExpression(i,builders.identifier("includes"),false,true),[f]);case "notContains":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(i,builders.identifier("includes"),false,true),[f]));case "exists":return builders.binaryExpression("!=",i,builders.literal(null));case "notExists":return builders.binaryExpression("==",i,builders.literal(null));case "matches":return builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[f]),builders.identifier("test")),[i]);case "notMatches":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[f]),builders.identifier("test")),[i]));case "startsWith":return builders.callExpression(builders.memberExpression(i,builders.identifier("startsWith"),false,true),[f]);case "endsWith":return builders.callExpression(builders.memberExpression(i,builders.identifier("endsWith"),false,true),[f]);default:return builders.binaryExpression("===",i,f)}}function zn(n,t,s,e,r,o){let{logic:i,conditions:f}=n,l=i==="AND"?"&&":"||";if(f.length===0)return builders.literal(i==="AND");if(f.length===1)return g(f[0],t,s,e,r,o);let c=g(f[0],t,s,e,r,o);for(let a=1;a<f.length;a++){let p=g(f[a],t,s,e,r,o);c=builders.logicalExpression(l,c,p);}return c}function j(n){let t=[],s=n.length,e=0,r="";for(;e<s;){let o=n[e];if(o===".")r&&(t.push({type:"key",value:r}),r=""),e++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),e++;let i=e;for(;e<s&&n[e]!=="]";)e++;let f=n.slice(i,e);if(e++,f!=="*"){let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,e++;}return r&&t.push({type:"key",value:r}),t}function tn(n,t=[z]){return builders.arrowFunctionExpression(t.map(s=>builders.identifier(s)),n)}function W(n){let t=new Set;return S(n,t),t}function S(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let e of n)S(e,t);return}if(y(n))return;if(T(n)){S(n.$if,t),S(n.then,t),n.else!==void 0&&S(n.else,t);return}if(C(n)){for(let e of n.$pipe)S(e,t);return}if(b(n)){if(t.add(n.$fn),n.args)for(let e of n.args)typeof e!="function"&&S(e,t);return}if(h(n)){n.left!==void 0&&typeof n.left=="object"&&S(n.left,t),n.right!==void 0&&typeof n.right=="object"&&S(n.right,t);return}if(E(n)){for(let e of n.conditions)S(e,t);return}let s=n;for(let e of Object.keys(s))S(s[e],t);}function D(n){let t=new Set;for(let s of n){let e=s.indexOf("."),r=s.indexOf("["),o=s.length;e!==-1&&(o=Math.min(o,e)),r!==-1&&(o=Math.min(o,r));let i=s.slice(0,o);i&&t.add(i);}return t}function Vn(n){return JSON.stringify(n)}function _n(n,t,s,e,r){let o=G(n,{noPrefixes:true,useAccessor:e,lexicalPrefix:r}),i=generate(o),f="";e?r&&(f=`const{${r}}=data??{};`):t.size>0&&(f=`const{${[...t].join(",")}}=data??{};`);let l=e?new Set([...s,"accessor"]):s,c=l.size>0?`const{${[...l].join(",")}}=scope;`:"";return c?`(function(scope){${c}return function(data){${f}return ${i}}})`:`(function(){return function(data){${f}return ${i}}})`}function _(n,t={}){let{scope:s={},returnCode:e=false,useAccessor:r=false,lexicalPrefix:o}=t,i=k(n),f=D(i),l=W(n),c=Vn(n),a=_n(n,f,l,r,o);if(e)return {code:a,deps:i,hash:c,dataRoots:[...f],scopeFns:[...l]};let p;try{p=new Function(`return ${a}`)()(s);}catch(d){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${d instanceof Error?d.message:String(d)}`)}return {fn:p,deps:i,hash:c}}function en(n,t,s={}){let{fn:e}=_(n,s);return e(t)}var ht="0.1.1";export{v as ExpressionCache,ht as VERSION,kn as assertValid,U as builders,K as cache,Sn as cached,pn as clearPathCache,N as compile,_ as compileAST,O as compilePath,G as dslToAST,$n as evaluate,en as evaluateAST,D as extractDataRoots,k as extractDeps,W as extractScopeFns,an as get,dn as getPathCacheSize,gn as hasDeps,J as hasWildcard,h as isCondition,sn as isConditionExpr,E as isConditionGroup,T as isConditional,b as isFn,I as isLiteral,C as isPipe,mn as isPure,y as isRef,wn as isValid,F as normalizePath,M as validate,tn as wrapInFunction};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statedelta-libs/expressions",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "JSON DSL compiler for optimized functions - StateDelta expression engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"
|
|
18
|
-
"omni-ast": "^2.0.0"
|
|
17
|
+
"omni-ast": "^2.0.2"
|
|
19
18
|
},
|
|
20
19
|
"files": [
|
|
21
20
|
"dist",
|