@statedelta-libs/expressions 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,7 +14,8 @@
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
- - **Integração** - Usa `@statedelta-libs/conditions` para condicionais
17
+ - **Conditions nativo** - Condicionais integradas com expressions nos lados
18
+ - **Custom Transforms** - Extensão do walker via transforms registrados (`$query`, `$mapper`, etc.)
18
19
  - **Type-safe** - TypeScript nativo com inferência
19
20
 
20
21
  ## Instalação
@@ -93,6 +94,75 @@ fn(data); // Executa (mais rápido que compile())
93
94
  | Hot path crítico | `compileAST()` | V8 JIT otimiza melhor |
94
95
  | Expressões complexas | `compileAST()` | Ganho maior em nested calls |
95
96
 
97
+ #### useAccessor (compileAST)
98
+
99
+ Para contextos inteligentes (ex: `TickContext`), use `useAccessor: true` para gerar `accessor(path, data)` ao invés de acesso direto:
100
+
101
+ ```typescript
102
+ const ctx = new TickContext();
103
+
104
+ const { fn } = compileAST(
105
+ { $fn: "add", args: [{ $: "hp" }, { $: "mp" }] },
106
+ {
107
+ scope: {
108
+ add,
109
+ accessor: (path) => ctx.get(path) // closure que captura ctx
110
+ },
111
+ useAccessor: true
112
+ }
113
+ );
114
+
115
+ fn(); // usa ctx.get("hp") + ctx.get("mp")
116
+ ```
117
+
118
+ Código gerado:
119
+ ```js
120
+ (function(scope){
121
+ const{add,accessor}=scope;
122
+ return function(data){
123
+ return add(accessor("hp",data),accessor("mp",data))
124
+ }
125
+ })
126
+ ```
127
+
128
+ #### lexicalPrefix (compileAST)
129
+
130
+ Para máxima performance em paths específicos, use `lexicalPrefix` para acesso direto via destructuring:
131
+
132
+ ```typescript
133
+ const ctx = new TickContext();
134
+
135
+ const { fn } = compileAST(
136
+ { $fn: "add", args: [{ $: "hp" }, { $: "params.damage" }] },
137
+ {
138
+ scope: {
139
+ add,
140
+ accessor: (path) => ctx.get(path)
141
+ },
142
+ useAccessor: true,
143
+ lexicalPrefix: "params" // params.* vai direto, resto via accessor
144
+ }
145
+ );
146
+
147
+ fn({ params: { damage: 25 } }); // ctx.get("hp") + params.damage
148
+ ```
149
+
150
+ Código gerado:
151
+ ```js
152
+ (function(scope){
153
+ const{add,accessor}=scope;
154
+ return function(data){
155
+ const{params}=data??{}; // destructuring direto (rápido!)
156
+ return add(accessor("hp",data),params?.damage)
157
+ }
158
+ })
159
+ ```
160
+
161
+ | Path | Com lexicalPrefix | Sem lexicalPrefix |
162
+ |------|-------------------|-------------------|
163
+ | `params.damage` | `params?.damage` (direto) | `accessor("params.damage", data)` |
164
+ | `hp` | `accessor("hp", data)` | `accessor("hp", data)` |
165
+
96
166
  ### evaluate() / evaluateAST()
97
167
 
98
168
  Compila e executa em um passo.
@@ -122,6 +192,33 @@ const deps = extractDeps({
122
192
  // ["$isVip", "price.vip", "price.regular"]
123
193
  ```
124
194
 
195
+ ## JSON Aninhado (Walk Automático)
196
+
197
+ O compilador **percorre automaticamente** todo o JSON e resolve expressões onde quer que estejam:
198
+
199
+ ```typescript
200
+ const { fn } = compile({
201
+ name: "John",
202
+ damage: { $: "params.damage" },
203
+ active: { $if: "hp.current", then: true, else: false },
204
+ nested: {
205
+ deep: {
206
+ value: { $fn: "add", args: [{ $: "a" }, { $: "b" }] }
207
+ }
208
+ }
209
+ }, { scope });
210
+
211
+ fn({ params: { damage: 25 }, hp: { current: 100 }, a: 1, b: 2 });
212
+ // {
213
+ // name: "John",
214
+ // damage: 25,
215
+ // active: true,
216
+ // nested: { deep: { value: 3 } }
217
+ // }
218
+ ```
219
+
220
+ Não precisa de walker manual - o `compile()` e `compileAST()` já fazem isso internamente.
221
+
125
222
  ## Tipos de Expressão
126
223
 
127
224
  ### Literal
@@ -189,14 +286,36 @@ Chama função do scope com argumentos compilados.
189
286
  // → scope.getTimestamp()
190
287
  ```
191
288
 
192
- ### Condition (delegado)
289
+ ### Condition
290
+
291
+ Condicionais compiladas internamente. Ambos os lados aceitam qualquer expressão:
193
292
 
194
293
  ```typescript
195
- // Detectado automaticamente e delegado para @statedelta-libs/conditions
294
+ // Ref vs literal (básico)
196
295
  { left: { $: "user.age" }, op: "gte", right: 18 }
296
+
297
+ // Ref vs Ref
298
+ { left: { $: "price" }, op: "lte", right: { $: "budget" } }
299
+
300
+ // $fn nos lados
301
+ { left: { $fn: "add", args: [{ $: "a" }, { $: "b" }] }, op: "gt", right: 100 }
302
+
303
+ // $pipe no lado
304
+ { left: { $pipe: [{ $: "name" }, { $fn: "upper" }] }, op: "eq", right: "ADMIN" }
305
+
306
+ // Condition group
307
+ {
308
+ logic: "AND",
309
+ conditions: [
310
+ { left: { $: "active" }, op: "eq", right: true },
311
+ { left: { $fn: "len", args: [{ $: "items" }] }, op: "gte", right: 3 }
312
+ ]
313
+ }
197
314
  ```
198
315
 
199
- > **Nota:** Apenas objetos com operadores de condition válidos (`eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`, `contains`, `notContains`, `exists`, `notExists`, `matches`, `notMatches`, `startsWith`, `endsWith`) são detectados como conditions. Objetos com `op: "set"` ou outros operadores não são conditions e são tratados como literals.
316
+ **Operadores:** `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`, `contains`, `notContains`, `exists`, `notExists`, `matches`, `notMatches`, `startsWith`, `endsWith`
317
+
318
+ > **Nota:** Objetos com `op: "set"` ou outros operadores não-condition são tratados como literals.
200
319
 
201
320
  ## Scope
202
321
 
@@ -254,7 +373,7 @@ O accessor é propagado para:
254
373
  - Shorthand de `$if` (`{ $if: "path", ... }`)
255
374
  - Argumentos de `$fn`
256
375
  - Steps de `$pipe`
257
- - Conditions (delegadas para `@statedelta-libs/conditions`)
376
+ - Conditions (compiladas internamente)
258
377
 
259
378
  **Performance:** Igual ao acesso direto (~25-30M ops/s).
260
379
 
@@ -337,6 +456,115 @@ Ambas as abordagens são **seguras contra injeção de código**:
337
456
 
338
457
  Funções só são acessíveis se existirem no `scope` fornecido pelo desenvolvedor.
339
458
 
459
+ ## Custom Transforms
460
+
461
+ Mecanismo de extensão do walker para tipos de expressão customizados. Permite registrar transforms que interceptam objetos com chaves específicas e os convertem em expressões padrão antes da compilação.
462
+
463
+ ### API
464
+
465
+ ```typescript
466
+ const transforms = {
467
+ $query: (node) => ({
468
+ $fn: "__query",
469
+ args: [node.$query, node.params ?? {}]
470
+ }),
471
+ $mapper: (node) => ({
472
+ $fn: "__mapper",
473
+ args: [node.$mapper, node.params ?? {}]
474
+ }),
475
+ };
476
+ ```
477
+
478
+ ### Uso com compile() e compileAST()
479
+
480
+ ```typescript
481
+ import { compile, compileAST } from '@statedelta-libs/expressions';
482
+
483
+ const scope = {
484
+ __query: (name, params) => queryEngine.run(name, params),
485
+ };
486
+
487
+ // Closures
488
+ const { fn } = compile(
489
+ { $query: "isKingAttacked", params: { row: 0, col: 4 } },
490
+ { scope, transforms }
491
+ );
492
+
493
+ // AST (mesmo contrato)
494
+ const { fn } = compileAST(
495
+ { $query: "isKingAttacked", params: { row: 0, col: 4 } },
496
+ { scope, transforms }
497
+ );
498
+ ```
499
+
500
+ ### Expressions dentro de params
501
+
502
+ Os params do transform são compilados recursivamente — referências e expressões dentro deles são resolvidas normalmente:
503
+
504
+ ```typescript
505
+ const { fn } = compile(
506
+ { $query: "check", params: { row: { $: "myRow" }, col: { $: "myCol" } } },
507
+ { scope, transforms }
508
+ );
509
+
510
+ fn({ myRow: 5, myCol: 3 });
511
+ // → __query("check", { row: 5, col: 3 })
512
+ ```
513
+
514
+ ### Aninhamento
515
+
516
+ Transforms funcionam em qualquer posição — dentro de `$if`, `$pipe`, `$fn`, conditions, plain objects:
517
+
518
+ ```typescript
519
+ // Dentro de condition
520
+ {
521
+ $if: {
522
+ left: { $query: "isAttacked", params: { row: 0 } },
523
+ op: "eq",
524
+ right: true
525
+ },
526
+ then: "check",
527
+ else: "safe"
528
+ }
529
+
530
+ // Dentro de plain object (walk automático)
531
+ {
532
+ damage: { $query: "getDamage", params: { base: 10 } },
533
+ name: "attack"
534
+ }
535
+ ```
536
+
537
+ ### Extração de deps
538
+
539
+ `extractDeps` também resolve transforms para capturar dependências internas:
540
+
541
+ ```typescript
542
+ import { extractDeps } from '@statedelta-libs/expressions';
543
+
544
+ const deps = extractDeps(
545
+ { $query: "check", params: { row: { $: "myRow" } } },
546
+ transforms
547
+ );
548
+ // ["myRow"]
549
+ ```
550
+
551
+ ### Proteção contra loops infinitos
552
+
553
+ Se um transform retornar um objeto com a mesma chave de entrada, um erro é lançado:
554
+
555
+ ```typescript
556
+ const badTransforms = {
557
+ $loop: (node) => ({ $loop: node.$loop }), // mesma chave!
558
+ };
559
+
560
+ compile({ $loop: "test" }, { transforms: badTransforms });
561
+ // Error: Transform "$loop" returned object with same key — infinite loop
562
+ ```
563
+
564
+ ### Performance
565
+
566
+ Transforms são resolvidos **em tempo de compilação**. Zero overhead em runtime — a função compilada resultante é idêntica a uma expressão `$fn` normal.
567
+
340
568
  ## Type Detection
341
569
 
342
570
  O compilador detecta automaticamente o tipo de expressão baseado na estrutura do objeto:
@@ -348,6 +576,7 @@ O compilador detecta automaticamente o tipo de expressão baseado na estrutura d
348
576
  | Function | `{ $fn }` presente | `{ $fn: "add", args: [...] }` |
349
577
  | Pipe | `{ $pipe }` presente | `{ $pipe: [...] }` |
350
578
  | Condition | `{ left, op }` com operador válido | `{ left: { $: "age" }, op: "gte", right: 18 }` |
579
+ | Custom Transform | Chave registrada em `transforms` | `{ $query: "check", params: {...} }` |
351
580
  | Literal | Nenhum dos acima | `{ foo: "bar" }`, `42`, `"hello"` |
352
581
 
353
582
  ### Distinção entre Conditions e Effect Objects
@@ -371,7 +600,7 @@ Funções declarativas para construir expressões. Disponíveis via namespace `b
371
600
  ```typescript
372
601
  import { builders, compile } from '@statedelta-libs/expressions';
373
602
 
374
- const { $, $fn, $if, $pipe } = builders;
603
+ const { $, $fn, $if, $pipe, $cond } = builders;
375
604
  ```
376
605
 
377
606
  ### `$` / `ref` - Path Reference
@@ -423,13 +652,33 @@ $pipe(
423
652
  )
424
653
  ```
425
654
 
655
+ ### `$cond` / `cond` - Condition
656
+
657
+ ```typescript
658
+ // Básico
659
+ $cond($("age"), "gte", 18)
660
+ // { left: { $: "age" }, op: "gte", right: 18 }
661
+
662
+ // Exists (sem right)
663
+ $cond($("email"), "exists")
664
+
665
+ // Ref vs Ref
666
+ $cond($("price"), "lte", $("budget"))
667
+
668
+ // Com $fn nos lados
669
+ $cond($fn("add", [$("a"), $("b")]), "gt", 100)
670
+
671
+ // Com $pipe
672
+ $cond($pipe($("name"), $fn("upper")), "eq", "ADMIN")
673
+ ```
674
+
426
675
  ### Exemplo Completo
427
676
 
428
677
  ```typescript
429
678
  import { builders, compile } from '@statedelta-libs/expressions';
430
679
  import { filter, map, sum } from '@statedelta-libs/operators';
431
680
 
432
- const { $, $fn, $if, $pipe } = builders;
681
+ const { $, $fn, $if, $pipe, $cond } = builders;
433
682
 
434
683
  const scope = { filter, map, sum };
435
684
 
@@ -459,6 +708,7 @@ fn({
459
708
  | `$` | `ref` |
460
709
  | `$fn` | `fn` |
461
710
  | `$pipe` | `pipe` |
711
+ | `$cond` | `cond` |
462
712
 
463
713
  ## TypeScript
464
714
 
@@ -470,9 +720,14 @@ import type {
470
720
  ConditionalExpr,
471
721
  FnExpr,
472
722
  PipeExpr,
723
+ Condition,
724
+ ConditionGroup,
725
+ ConditionExpr,
726
+ ConditionOp,
473
727
  Scope,
474
728
  CompileOptions,
475
729
  AccessorFn,
730
+ TransformFn,
476
731
  } from '@statedelta-libs/expressions';
477
732
 
478
733
  // Type guards
@@ -512,6 +767,39 @@ import {
512
767
 
513
768
  4. **Novo**: `$pipe` como sintaxe DSL para composição
514
769
 
770
+ ### v1.0 → v1.1
771
+
772
+ 1. **Conditions internas**: `@statedelta-libs/conditions` não é mais dependência. Conditions são compiladas internamente.
773
+
774
+ 2. **Expressions nos lados**: `left`/`right` de conditions agora aceitam qualquer `Expression` (`$fn`, `$pipe`, `$if`, etc), não apenas `Ref | literal`.
775
+
776
+ 3. **Novo builder**: `$cond(left, op, right?)` para construir conditions com expressions:
777
+ ```typescript
778
+ $cond($fn("add", [$("a"), $("b")]), "gt", 100)
779
+ ```
780
+
781
+ 4. **Novos tipos**: `ConditionOp`, `Condition`, `ConditionGroup`, `ConditionExpr` exportados diretamente do expressions.
782
+
783
+ ### v1.1 → v1.2
784
+
785
+ 1. **Custom Transforms**: Nova option `transforms` em `CompileOptions` e `CompileASTOptions`. Permite estender o walker com tipos de expressão customizados (`$query`, `$mapper`, etc.):
786
+ ```typescript
787
+ const transforms = {
788
+ $query: (node) => ({ $fn: "__query", args: [node.$query, node.params ?? {}] }),
789
+ };
790
+ compile(expr, { scope, transforms });
791
+ compileAST(expr, { scope, transforms });
792
+ ```
793
+
794
+ 2. **extractDeps com transforms**: `extractDeps` agora aceita `transforms` como segundo argumento para capturar deps dentro de expressões customizadas:
795
+ ```typescript
796
+ extractDeps(expr, transforms);
797
+ ```
798
+
799
+ 3. **Novo tipo**: `TransformFn` exportado diretamente do expressions.
800
+
801
+ 4. **Zero breaking change**: O campo `transforms` é opcional. Sem ele, o comportamento é idêntico ao anterior.
802
+
515
803
  ## Licença
516
804
 
517
805
  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 sn=Object.defineProperty;var fn=(n,e)=>{for(var i in e)sn(n,i,{get:e[i],enumerable:true});};var m=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,E=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"&&"left"in n&&"op"in n&&_.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),h=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,ln=n=>y(n)||h(n),z=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="left"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 R=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 F(n){let e=R.get(n);return e||(e=J(n)?cn(n):un(n),R.set(n,e),e)}function un(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,c=o.value;return a=>a?.[s]?.[u]?.[c]}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 cn(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?an(e,i[0]):pn(e,i)}function an(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 c=u?.[s];if(Array.isArray(c))return c.map(a=>a?.[o])}}return s=>{let u=s;for(let c=0;c<r&&u!=null;c++)u=u[i[c]];if(Array.isArray(u))return u.map(c=>c?.[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 c=u;for(let a=0;a<f&&c!=null;a++)c=c[t[a]];return c})}}function pn(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(c=>c.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 c=u;return Array.isArray(c)?c:[c]});}else if(s.type==="map"){if(!Array.isArray(o))return;r.length>0&&(o=o.map(u=>{let c=u;for(let a of r){if(c==null)return;c=c[a];}return c}));}}return o}}function dn(n,e){return F(e)(n)}function x(n){let e=n.indexOf("[*]");return e===-1?n:n.slice(0,e)}function gn(){R.clear();}function mn(){return R.size}function k(n){let e=new Set;return $(n,e),Array.from(e)}function $(n,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r=0;r<n.length;r++)$(n[r],e);return}if(m(n)){e.add(x(n.$));return}if(E(n)){if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if;e.add(x(r));}else $(n.$if,e);$(n.then,e),n.else!==void 0&&$(n.else,e);return}if(b(n)){for(let r=0;r<n.$pipe.length;r++)$(n.$pipe[r],e);return}if(T(n)){if(n.args)for(let r=0;r<n.args.length;r++){let f=n.args[r];typeof f!="function"&&$(f,e);}return}if(y(n)){conditions.isRef(n.left)&&e.add(x(n.left.$)),n.right!==void 0&&conditions.isRef(n.right)&&e.add(x(n.right.$));return}if(h(n)){for(let r=0;r<n.conditions.length;r++)$(n.conditions[r],e);return}let i=n,t=Object.keys(i);for(let r=0;r<t.length;r++)$(i[t[r]],e);}function yn(n){return k(n).length>0}function hn(n){return k(n).length===0}function En(n){return JSON.stringify(n)}function O(n,e={}){let i=e.scope??{},t=e.accessor,r=S(n,i,t),f=k(n),o=En(n);return {fn:r,deps:f,hash:o}}function S(n,e,i){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let t=n.map(r=>S(r,e,i));return r=>t.map(f=>f(r))}if(m(n))return Tn(n,i);if(E(n))return bn(n,e,i);if(b(n))return Cn(n,e,i);if(T(n))return Sn(n,e,i);if(y(n))return conditions.compile(n,i?{accessor:i}:void 0);if(h(n))return conditions.compile(n,i?{accessor:i}:void 0);if(z(n)){let t=n,r=Object.keys(t),f=r.map(o=>S(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 Y(n,e){return e?i=>e(n,i):F(n)}function Tn(n,e){return Y(n.$,e)}function bn(n,e,i){let t;if(typeof n.$if=="string"){let o=n.$if.startsWith("!")?n.$if.slice(1):n.$if,s=Y(o,i);t=n.$if.startsWith("!")?c=>!s(c):c=>!!s(c);}else {let o=S(n.$if,e,i);t=s=>!!o(s);}let r=S(n.then,e,i),f=n.else!==void 0?S(n.else,e,i):()=>{};return o=>t(o)?r(o):f(o)}function Cn(n,e,i){let t=n.$pipe;if(t.length===0)return ()=>{};if(t.length===1)return S(t[0],e,i);let r=S(t[0],e,i),f=t.slice(1).map(s=>S(s,e,i)),o=f.length;if(o===1){let[s]=f;return u=>{let c=r(u),a=s(u);return typeof a=="function"?a(c):a}}if(o===2){let[s,u]=f;return c=>{let a=r(c),p=s(c);return a=typeof p=="function"?p(a):p,p=u(c),typeof p=="function"?p(a):p}}if(o===3){let[s,u,c]=f;return a=>{let p=r(a),d=s(a);return p=typeof d=="function"?d(p):d,d=u(a),p=typeof d=="function"?d(p):d,d=c(a),typeof d=="function"?d(p):d}}return s=>{let u=r(s);for(let c=0;c<o;c++){let a=f[c](s);u=typeof a=="function"?a(u):a;}return u}}function Sn(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=>typeof s=="function"?()=>s:S(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 c=e[t];if(!c)throw new Error(`Function not found in scope: ${t}`);return c(s(u))}}if(o===2){let[s,u]=f;return c=>{let a=e[t];if(!a)throw new Error(`Function not found in scope: ${t}`);return a(s(c),u(c))}}if(o===3){let[s,u,c]=f;return a=>{let p=e[t];if(!p)throw new Error(`Function not found in scope: ${t}`);return p(s(a),u(a),c(a))}}return s=>{let u=e[t];if(!u)throw new Error(`Function not found in scope: ${t}`);return u(...f.map(c=>c(s)))}}function $n(n,e,i={}){return O(n,i).fn(e)}var N=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=O(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);}}},H=new N;function An(n,e={}){return H.get(n,e)}function M(n,e="root",i={}){let t=[];return A(n,e,t,i),{valid:t.length===0,errors:t}}function A(n,e,i,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let o=0;o<n.length;o++)A(n[o],`${e}[${o}]`,i,t);return}if(m(n)){(!n.$||typeof n.$!="string")&&i.push(`${e}: invalid reference, $ must be non-empty string`);return}if(E(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||i.push(`${e}.$if: empty path in string shorthand`):A(n.$if,`${e}.$if`,i,t),A(n.then,`${e}.then`,i,t),n.else!==void 0&&A(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++)A(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++){let s=n.args[o];typeof s!="function"&&A(s,`${e}.args[${o}]`,i,t);}return}if(y(n)){let o=conditions.validate(n,e);o.valid||i.push(...o.errors);return}if(h(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];A(r[s],`${e}.${s}`,i,t);}}function kn(n,e={}){let i=M(n,"root",e);if(!i.valid)throw new Error(`Invalid expression: ${i.errors.join("; ")}`)}function wn(n,e={}){return M(n,"root",e).valid}var Z={};fn(Z,{$:()=>Q,$fn:()=>U,$if:()=>Fn,$pipe:()=>X,fn:()=>Rn,pipe:()=>On,ref:()=>xn});function Q(n){return {$:n}}var xn=Q;function U(n,e){return e===void 0||e.length===0?{$fn:n}:{$fn:n,args:e}}var Rn=U;function Fn(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 D="data",en="scope",Nn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function v(n,e={}){let{dataParam:i=D,scopeParam:t=en,noPrefixes:r=false,useAccessor:f=false,lexicalPrefix:o}=e;return g(n,i,t,r,f,o)}function g(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=>g(o,e,i,t,r,f)));if(m(n))return jn(n.$,e,t,r,f);if(E(n))return Gn(n,e,i,t,r,f);if(b(n))return zn(n.$pipe,e,i,t,r,f);if(T(n))return Wn(n,e,i,t,r,f);if(y(n))return Mn(n,e,i,t,r,f);if(h(n))return Dn(n,e,i,t,r,f);if(typeof n=="object"){let s=Object.entries(n).map(([u,c])=>omniAst.builders.property(omniAst.builders.identifier(u),g(c,e,i,t,r,f)));return omniAst.builders.objectExpression(s)}return omniAst.builders.literal(null)}var I="accessor";function L(n,e){return e?n===e||n.startsWith(e+"."):false}function jn(n,e,i,t,r){return t?L(n,r)?w(n,e,true):omniAst.builders.callExpression(omniAst.builders.identifier(I),[omniAst.builders.literal(n),omniAst.builders.identifier(e)]):n.includes("[*]")?vn(n,e,i):w(n,e,i)}function w(n,e,i){let t=j(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 vn(n,e,i){let t=n.indexOf("[*]"),r=n.slice(0,t),f=n.slice(t+3),o;if(r?o=w(r,e,i):o=i?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(e),!f||f==="")return o;if(f.includes("[*]"))return tn(o,f);let s="_i",u=f.startsWith(".")?f.slice(1):f,c=omniAst.builders.identifier(s);if(u){let a=j(u);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(o,omniAst.builders.identifier("map"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(s)],c)])}function tn(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 c=j(o);for(let a of c)a.type==="key"&&(s=omniAst.builders.memberExpression(s,omniAst.builders.identifier(a.value),false,true));}if(r.includes("[*]")){let c=tn(s,r);return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(f)],c)])}let u=r.startsWith(".")?r.slice(1):r;if(u){let c=j(u);for(let a of c)a.type==="key"&&(s=omniAst.builders.memberExpression(s,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(f)],s)])}function Gn(n,e,i,t,r,f){let o;if(typeof n.$if=="string"){let c=n.$if.startsWith("!"),a=c?n.$if.slice(1):n.$if,p;r?L(a,f)?p=w(a,e,true):p=omniAst.builders.callExpression(omniAst.builders.identifier(I),[omniAst.builders.literal(a),omniAst.builders.identifier(e)]):p=w(a,e,t),o=c?omniAst.builders.unaryExpression("!",p):p;}else o=g(n.$if,e,i,t,r,f);let s=g(n.then,e,i,t,r,f),u=n.else!==void 0?g(n.else,e,i,t,r,f):omniAst.builders.identifier("undefined");return omniAst.builders.conditionalExpression(o,s,u)}function Wn(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=>typeof u=="function"?omniAst.builders.literal(null):g(u,e,i,t,r,f));return omniAst.builders.callExpression(o,s)}function zn(n,e,i,t,r,f){if(n.length===0)return omniAst.builders.identifier("undefined");if(n.length===1)return g(n[0],e,i,t,r,f);let o=g(n[0],e,i,t,r,f);for(let s=1;s<n.length;s++){let u=g(n[s],e,i,t,r,f);o=omniAst.builders.callExpression(u,[o]);}return o}function nn(n,e,i,t,r,f){if(m(n)){let o=n.$;return r?L(o,f)?w(o,e,true):omniAst.builders.callExpression(omniAst.builders.identifier(I),[omniAst.builders.literal(o),omniAst.builders.identifier(e)]):w(o,e,t)}return g(n,e,i,t,r,f)}function Mn(n,e,i,t,r,f){let o=nn(n.left,e,i,t,r,f),s=n.right!==void 0?nn(n.right,e,i,t,r,f):omniAst.builders.literal(null),u=Nn[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 Dn(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 g(s[0],e,i,t,r,f);let c=g(s[0],e,i,t,r,f);for(let a=1;a<s.length;a++){let p=g(s[a],e,i,t,r,f);c=omniAst.builders.logicalExpression(u,c,p);}return c}function j(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 on(n,e=[D]){return omniAst.builders.arrowFunctionExpression(e.map(i=>omniAst.builders.identifier(i)),n)}function G(n){let e=new Set;return C(n,e),e}function C(n,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let t of n)C(t,e);return}if(m(n))return;if(E(n)){C(n.$if,e),C(n.then,e),n.else!==void 0&&C(n.else,e);return}if(b(n)){for(let t of n.$pipe)C(t,e);return}if(T(n)){if(e.add(n.$fn),n.args)for(let t of n.args)typeof t!="function"&&C(t,e);return}if(y(n)){n.left!==void 0&&typeof n.left=="object"&&C(n.left,e),n.right!==void 0&&typeof n.right=="object"&&C(n.right,e);return}if(h(n)){for(let t of n.conditions)C(t,e);return}let i=n;for(let t of Object.keys(i))C(i[t],e);}function W(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 Ln(n){return JSON.stringify(n)}function Vn(n,e,i,t,r){let f=v(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,c=u.size>0?`const{${[...u].join(",")}}=scope;`:"";return c?`(function(scope){${c}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=k(n),s=W(o),u=G(n),c=Ln(n),a=Vn(n,s,u,r,f);if(t)return {code:a,deps:o,hash:c,dataRoots:[...s],scopeFns:[...u]};let p;try{p=new Function(`return ${a}`)()(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:c}}function rn(n,e,i={}){let{fn:t}=V(n,i);return t(e)}var Te="0.1.1";exports.ExpressionCache=N;exports.VERSION=Te;exports.assertValid=kn;exports.builders=Z;exports.cache=H;exports.cached=An;exports.clearPathCache=gn;exports.compile=O;exports.compileAST=V;exports.compilePath=F;exports.dslToAST=v;exports.evaluate=$n;exports.evaluateAST=rn;exports.extractDataRoots=W;exports.extractDeps=k;exports.extractScopeFns=G;exports.get=dn;exports.getPathCacheSize=mn;exports.hasDeps=yn;exports.hasWildcard=J;exports.isCondition=y;exports.isConditionExpr=ln;exports.isConditionGroup=h;exports.isConditional=E;exports.isFn=T;exports.isLiteral=z;exports.isPipe=b;exports.isPure=hn;exports.isRef=m;exports.isValid=wn;exports.normalizePath=x;exports.validate=M;exports.wrapInFunction=on;
1
+ 'use strict';var omniAst=require('omni-ast');var rn=Object.defineProperty;var sn=(n,e)=>{for(var i in e)rn(n,i,{get:e[i],enumerable:true});};var h=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,A=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,$=n=>n!==null&&typeof n=="object"&&"$fn"in n&&typeof n.$fn=="string",k=n=>n!==null&&typeof n=="object"&&"$pipe"in n&&Array.isArray(n.$pipe),F=new Set(["eq","neq","gt","gte","lt","lte","in","notIn","contains","notContains","exists","notExists","matches","notMatches","startsWith","endsWith"]),E=n=>n!==null&&typeof n=="object"&&"left"in n&&"op"in n&&F.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),T=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,fn=n=>E(n)||T(n),M=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,f="left"in i&&"op"in i&&F.has(i.op);return !("$"in i)&&!("$if"in i)&&!("$fn"in i)&&!("$pipe"in i)&&!f&&!("logic"in i)}return false};var x=new Map;function J(n){let e=[],i=n.length,f=0,o="";for(;f<i;){let s=n[f];if(s===".")o&&(e.push({type:"key",value:o}),o=""),f++;else if(s==="["){o&&(e.push({type:"key",value:o}),o=""),f++;let t=f;for(;f<i&&n[f]!=="]";)f++;let r=n.slice(t,f);if(f++,r==="*")e.push({type:"wildcard",value:"*"});else {let c=parseInt(r,10);e.push({type:"index",value:isNaN(c)?r:c});}}else o+=s,f++;}return o&&e.push({type:"key",value:o}),e}function B(n){return n.includes("[*]")}function O(n){let e=x.get(n);return e||(e=B(n)?un(n):cn(n),x.set(n,e),e)}function cn(n){if(!n.includes(".")&&!n.includes("["))return o=>o?.[n];let e=J(n),i=e.length;if(i===2){let[o,s]=e,t=o.value,r=s.value;return c=>c?.[t]?.[r]}if(i===3){let[o,s,t]=e,r=o.value,c=s.value,l=t.value;return a=>a?.[r]?.[c]?.[l]}let f=e.map(o=>o.value);return o=>{let s=o;for(let t=0;t<i&&s!=null;t++)s=s[f[t]];return s}}function un(n){let e=J(n),i=[];for(let f=0;f<e.length;f++)e[f].type==="wildcard"&&i.push(f);return i.length===1?ln(e,i[0]):an(e,i)}function ln(n,e){let i=n.slice(0,e).map(t=>t.value),f=n.slice(e+1).map(t=>t.value),o=i.length,s=f.length;if(s===0){if(o===1){let t=i[0];return r=>r?.[t]}return t=>{let r=t;for(let c=0;c<o&&r!=null;c++)r=r[i[c]];return r}}if(s===1){let t=f[0];if(o===1){let r=i[0];return c=>{let l=c?.[r];if(Array.isArray(l))return l.map(a=>a?.[t])}}return r=>{let c=r;for(let l=0;l<o&&c!=null;l++)c=c[i[l]];if(Array.isArray(c))return c.map(l=>l?.[t])}}return t=>{let r=t;for(let c=0;c<o&&r!=null;c++)r=r[i[c]];if(Array.isArray(r))return r.map(c=>{let l=c;for(let a=0;a<s&&l!=null;a++)l=l[f[a]];return l})}}function an(n,e){let i=[],f=0;for(let s=0;s<e.length;s++){let t=e[s],r=s===e.length-1,c=n.slice(f,t).map(l=>l.value);c.length>0&&i.push({type:"access",keys:c}),i.push({type:r?"map":"flatMap",keys:[]}),f=t+1;}let o=n.slice(f).map(s=>s.value);return s=>{let t=s;for(let r of i){if(t==null)return;if(r.type==="access")for(let c of r.keys){if(t==null)return;t=t[c];}else if(r.type==="flatMap"){if(!Array.isArray(t))return;t=t.flatMap(c=>{let l=c;return Array.isArray(l)?l:[l]});}else if(r.type==="map"){if(!Array.isArray(t))return;o.length>0&&(t=t.map(c=>{let l=c;for(let a of o){if(l==null)return;l=l[a];}return l}));}}return t}}function pn(n,e){return O(e)(n)}function j(n){let e=n.indexOf("[*]");return e===-1?n:n.slice(0,e)}function dn(){x.clear();}function gn(){return x.size}function w(n,e){let i=new Set;return b(n,i,e),Array.from(i)}function b(n,e,i){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let s=0;s<n.length;s++)b(n[s],e,i);return}if(h(n)){e.add(j(n.$));return}if(A(n)){if(typeof n.$if=="string"){let s=n.$if.startsWith("!")?n.$if.slice(1):n.$if;e.add(j(s));}else b(n.$if,e,i);b(n.then,e,i),n.else!==void 0&&b(n.else,e,i);return}if(k(n)){for(let s=0;s<n.$pipe.length;s++)b(n.$pipe[s],e,i);return}if($(n)){if(n.args)for(let s=0;s<n.args.length;s++){let t=n.args[s];typeof t!="function"&&b(t,e,i);}return}if(E(n)){b(n.left,e,i),n.right!==void 0&&b(n.right,e,i);return}if(T(n)){for(let s=0;s<n.conditions.length;s++)b(n.conditions[s],e,i);return}if(i){let s=n,t=Object.keys(s);for(let r=0;r<t.length;r++){let c=t[r];if(c in i){let l=i[c](s);if(typeof l=="object"&&l!==null&&c in l)throw new Error(`Transform "${c}" returned object with same key \u2014 infinite loop`);b(l,e,i);return}}}let f=n,o=Object.keys(f);for(let s=0;s<o.length;s++)b(f[o[s]],e,i);}function yn(n){return w(n).length>0}function mn(n){return w(n).length===0}function hn(n){return JSON.stringify(n)}function N(n,e={}){let i=e.scope??{},f=e.accessor,o=e.transforms,s=m(n,i,f,o),t=w(n,o),r=hn(n);return {fn:s,deps:t,hash:r}}function m(n,e,i,f){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let o=n.map(s=>m(s,e,i,f));return s=>o.map(t=>t(s))}if(h(n))return En(n,i);if(A(n))return Tn(n,e,i,f);if(k(n))return bn(n,e,i,f);if($(n))return Cn(n,e,i,f);if(E(n))return An(n,e,i,f);if(T(n))return $n(n,e,i,f);if(f){let o=n,s=Object.keys(o);for(let t=0;t<s.length;t++){let r=s[t];if(r in f){let c=f[r](o);if(typeof c=="object"&&c!==null&&r in c)throw new Error(`Transform "${r}" returned object with same key \u2014 infinite loop`);return m(c,e,i,f)}}}if(M(n)){let o=n,s=Object.keys(o),t=s.map(r=>m(o[r],e,i,f));return r=>{let c={};for(let l=0;l<s.length;l++)c[s[l]]=t[l](r);return c}}return ()=>n}function K(n,e){return e?i=>e(n,i):O(n)}function En(n,e){return K(n.$,e)}function Tn(n,e,i,f){let o;if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if,c=K(r,i);o=n.$if.startsWith("!")?a=>!c(a):a=>!!c(a);}else {let r=m(n.$if,e,i,f);o=c=>!!r(c);}let s=m(n.then,e,i,f),t=n.else!==void 0?m(n.else,e,i,f):()=>{};return r=>o(r)?s(r):t(r)}function bn(n,e,i,f){let o=n.$pipe;if(o.length===0)return ()=>{};if(o.length===1)return m(o[0],e,i,f);let s=m(o[0],e,i,f),t=o.slice(1).map(c=>m(c,e,i,f)),r=t.length;if(r===1){let[c]=t;return l=>{let a=s(l),p=c(l);return typeof p=="function"?p(a):p}}if(r===2){let[c,l]=t;return a=>{let p=s(a),d=c(a);return p=typeof d=="function"?d(p):d,d=l(a),typeof d=="function"?d(p):d}}if(r===3){let[c,l,a]=t;return p=>{let d=s(p),g=c(p);return d=typeof g=="function"?g(d):g,g=l(p),d=typeof g=="function"?g(d):g,g=a(p),typeof g=="function"?g(d):g}}return c=>{let l=s(c);for(let a=0;a<r;a++){let p=t[a](c);l=typeof p=="function"?p(l):p;}return l}}function Cn(n,e,i,f){let o=n.$fn,s=n.args;if(s===void 0)return ()=>{let c=e[o];if(!c)throw new Error(`Function not found in scope: ${o}`);return c};let t=s.map(c=>typeof c=="function"?()=>c:m(c,e,i,f)),r=t.length;if(r===0)return c=>{let l=e[o];if(!l)throw new Error(`Function not found in scope: ${o}`);return l()};if(r===1){let[c]=t;return l=>{let a=e[o];if(!a)throw new Error(`Function not found in scope: ${o}`);return a(c(l))}}if(r===2){let[c,l]=t;return a=>{let p=e[o];if(!p)throw new Error(`Function not found in scope: ${o}`);return p(c(a),l(a))}}if(r===3){let[c,l,a]=t;return p=>{let d=e[o];if(!d)throw new Error(`Function not found in scope: ${o}`);return d(c(p),l(p),a(p))}}return c=>{let l=e[o];if(!l)throw new Error(`Function not found in scope: ${o}`);return l(...t.map(a=>a(c)))}}function An(n,e,i,f){let o=m(n.left,e,i,f),s=n.right!==void 0?m(n.right,e,i,f):()=>{};switch(n.op){case "eq":return t=>o(t)===s(t);case "neq":return t=>o(t)!==s(t);case "gt":return t=>o(t)>s(t);case "gte":return t=>o(t)>=s(t);case "lt":return t=>o(t)<s(t);case "lte":return t=>o(t)<=s(t);case "in":return t=>{let r=s(t);return Array.isArray(r)&&r.includes(o(t))};case "notIn":return t=>{let r=s(t);return !Array.isArray(r)||!r.includes(o(t))};case "contains":return t=>{let r=o(t);return Array.isArray(r)&&r.includes(s(t))};case "notContains":return t=>{let r=o(t);return !Array.isArray(r)||!r.includes(s(t))};case "exists":return t=>o(t)!==void 0;case "notExists":return t=>o(t)===void 0;case "matches":return t=>{let r=o(t),c=s(t);return typeof r!="string"||typeof c!="string"?false:new RegExp(c).test(r)};case "notMatches":return t=>{let r=o(t),c=s(t);return typeof r!="string"||typeof c!="string"?true:!new RegExp(c).test(r)};case "startsWith":return t=>{let r=o(t),c=s(t);return typeof r=="string"&&typeof c=="string"&&r.startsWith(c)};case "endsWith":return t=>{let r=o(t),c=s(t);return typeof r=="string"&&typeof c=="string"&&r.endsWith(c)}}}function $n(n,e,i,f){let o=n.conditions.map(t=>m(t,e,i,f)),s=o.length;if(s===1)return t=>!!o[0](t);if(s===2){let[t,r]=o;return n.logic==="AND"?c=>!!t(c)&&!!r(c):c=>!!t(c)||!!r(c)}if(s===3){let[t,r,c]=o;return n.logic==="AND"?l=>!!t(l)&&!!r(l)&&!!c(l):l=>!!t(l)||!!r(l)||!!c(l)}return n.logic==="AND"?t=>{for(let r=0;r<s;r++)if(!o[r](t))return false;return true}:t=>{for(let r=0;r<s;r++)if(o[r](t))return true;return false}}function kn(n,e,i={}){return N(n,i).fn(e)}var v=class{constructor(e=1e3){this.cache=new Map,this._maxSize=e;}get(e,i={}){let f=JSON.stringify(e),o=this.cache.get(f);if(o)return this.cache.delete(f),this.cache.set(f,o),o;let s=N(e,i);if(this.cache.size>=this._maxSize){let t=this.cache.keys().next().value;t&&this.cache.delete(t);}return this.cache.set(f,s),s}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 z(n,e="root",i={}){let f=[];return S(n,e,f,i),{valid:f.length===0,errors:f}}function S(n,e,i,f){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let t=0;t<n.length;t++)S(n[t],`${e}[${t}]`,i,f);return}if(h(n)){(!n.$||typeof n.$!="string")&&i.push(`${e}: invalid reference, $ must be non-empty string`);return}if(A(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||i.push(`${e}.$if: empty path in string shorthand`):S(n.$if,`${e}.$if`,i,f),S(n.then,`${e}.then`,i,f),n.else!==void 0&&S(n.else,`${e}.else`,i,f);return}if(k(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 t=0;t<n.$pipe.length;t++)S(n.$pipe[t],`${e}.$pipe[${t}]`,i,f);return}if($(n)){if(!n.$fn||typeof n.$fn!="string"){i.push(`${e}: invalid function, $fn must be non-empty string`);return}if(f.scope&&!(n.$fn in f.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 t=0;t<n.args.length;t++){let r=n.args[t];typeof r!="function"&&S(r,`${e}.args[${t}]`,i,f);}return}if(E(n)){F.has(n.op)||i.push(`${e}: invalid operator "${n.op}"`),S(n.left,`${e}.left`,i,f),n.right!==void 0&&S(n.right,`${e}.right`,i,f);return}if(T(n)){if(n.logic!=="AND"&&n.logic!=="OR"&&i.push(`${e}: invalid logic "${n.logic}", must be "AND" or "OR"`),!Array.isArray(n.conditions)){i.push(`${e}.conditions: must be an array`);return}for(let t=0;t<n.conditions.length;t++)S(n.conditions[t],`${e}.conditions[${t}]`,i,f);return}let o=n,s=Object.keys(o);for(let t=0;t<s.length;t++){let r=s[t];S(o[r],`${e}.${r}`,i,f);}}function wn(n,e={}){let i=z(n,"root",e);if(!i.valid)throw new Error(`Invalid expression: ${i.errors.join("; ")}`)}function Rn(n,e={}){return z(n,"root",e).valid}var Z={};sn(Z,{$:()=>H,$cond:()=>X,$fn:()=>Q,$if:()=>On,$pipe:()=>U,cond:()=>Nn,fn:()=>xn,pipe:()=>jn,ref:()=>Fn});function H(n){return {$:n}}var Fn=H;function Q(n,e){return e===void 0||e.length===0?{$fn:n}:{$fn:n,args:e}}var xn=Q;function On(n,e,i){return i===void 0?{$if:n,then:e}:{$if:n,then:e,else:i}}function U(...n){return {$pipe:n}}var jn=U;function X(n,e,i){return i===void 0?{left:n,op:e}:{left:n,op:e,right:i}}var Nn=X;var L="data",nn="scope",vn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function W(n,e={}){let{dataParam:i=L,scopeParam:f=nn,noPrefixes:o=false,useAccessor:s=false,lexicalPrefix:t,transforms:r}=e;return y(n,i,f,o,s,t,r)}function y(n,e,i,f,o,s,t){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(r=>y(r,e,i,f,o,s,t)));if(h(n))return Gn(n.$,e,f,o,s);if(A(n))return Dn(n,e,i,f,o,s,t);if(k(n))return Mn(n.$pipe,e,i,f,o,s,t);if($(n))return In(n,e,i,f,o,s,t);if(E(n))return zn(n,e,i,f,o,s,t);if(T(n))return Ln(n,e,i,f,o,s,t);if(t&&typeof n=="object"){let r=n,c=Object.keys(r);for(let l=0;l<c.length;l++){let a=c[l];if(a in t){let p=t[a](r);if(typeof p=="object"&&p!==null&&a in p)throw new Error(`Transform "${a}" returned object with same key \u2014 infinite loop`);return y(p,e,i,f,o,s,t)}}}if(typeof n=="object"){let c=Object.entries(n).map(([l,a])=>omniAst.builders.property(omniAst.builders.identifier(l),y(a,e,i,f,o,s,t)));return omniAst.builders.objectExpression(c)}return omniAst.builders.literal(null)}var V="accessor";function _(n,e){return e?n===e||n.startsWith(e+"."):false}function Gn(n,e,i,f,o){return f?_(n,o)?R(n,e,true):omniAst.builders.callExpression(omniAst.builders.identifier(V),[omniAst.builders.literal(n),omniAst.builders.identifier(e)]):n.includes("[*]")?Wn(n,e,i):R(n,e,i)}function R(n,e,i){let f=G(n);if(f.length===0)return i?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(e);let o;if(i){let s=f[0];o=omniAst.builders.identifier(s.value);for(let t=1;t<f.length;t++){let r=f[t];r.type==="key"?o=omniAst.builders.memberExpression(o,omniAst.builders.identifier(r.value),false,true):o=omniAst.builders.memberExpression(o,omniAst.builders.literal(r.value),true,true);}}else {o=omniAst.builders.identifier(e);for(let s of f)s.type==="key"?o=omniAst.builders.memberExpression(o,omniAst.builders.identifier(s.value),false,true):o=omniAst.builders.memberExpression(o,omniAst.builders.literal(s.value),true,true);}return o}function Wn(n,e,i){let f=n.indexOf("[*]"),o=n.slice(0,f),s=n.slice(f+3),t;if(o?t=R(o,e,i):t=i?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(e),!s||s==="")return t;if(s.includes("[*]"))return en(t,s);let r="_i",c=s.startsWith(".")?s.slice(1):s,l=omniAst.builders.identifier(r);if(c){let a=G(c);for(let p of a)p.type==="key"?l=omniAst.builders.memberExpression(l,omniAst.builders.identifier(p.value),false,true):l=omniAst.builders.memberExpression(l,omniAst.builders.literal(p.value),true,true);}return omniAst.builders.callExpression(omniAst.builders.memberExpression(t,omniAst.builders.identifier("map"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(r)],l)])}function en(n,e){let i=e.indexOf("[*]"),f=e.slice(0,i),o=e.slice(i+3),s="_i",t=f.startsWith(".")?f.slice(1):f,r=omniAst.builders.identifier(s);if(t){let l=G(t);for(let a of l)a.type==="key"&&(r=omniAst.builders.memberExpression(r,omniAst.builders.identifier(a.value),false,true));}if(o.includes("[*]")){let l=en(r,o);return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(s)],l)])}let c=o.startsWith(".")?o.slice(1):o;if(c){let l=G(c);for(let a of l)a.type==="key"&&(r=omniAst.builders.memberExpression(r,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(s)],r)])}function Dn(n,e,i,f,o,s,t){let r;if(typeof n.$if=="string"){let a=n.$if.startsWith("!"),p=a?n.$if.slice(1):n.$if,d;o?_(p,s)?d=R(p,e,true):d=omniAst.builders.callExpression(omniAst.builders.identifier(V),[omniAst.builders.literal(p),omniAst.builders.identifier(e)]):d=R(p,e,f),r=a?omniAst.builders.unaryExpression("!",d):d;}else r=y(n.$if,e,i,f,o,s,t);let c=y(n.then,e,i,f,o,s,t),l=n.else!==void 0?y(n.else,e,i,f,o,s,t):omniAst.builders.identifier("undefined");return omniAst.builders.conditionalExpression(r,c,l)}function In(n,e,i,f,o,s,t){let r=f?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 r;let c=n.args.map(l=>typeof l=="function"?omniAst.builders.literal(null):y(l,e,i,f,o,s,t));return omniAst.builders.callExpression(r,c)}function Mn(n,e,i,f,o,s,t){if(n.length===0)return omniAst.builders.identifier("undefined");if(n.length===1)return y(n[0],e,i,f,o,s,t);let r=y(n[0],e,i,f,o,s,t);for(let c=1;c<n.length;c++){let l=y(n[c],e,i,f,o,s,t);r=omniAst.builders.callExpression(l,[r]);}return r}function P(n,e,i,f,o,s,t){if(h(n)){let r=n.$;return o?_(r,s)?R(r,e,true):omniAst.builders.callExpression(omniAst.builders.identifier(V),[omniAst.builders.literal(r),omniAst.builders.identifier(e)]):R(r,e,f)}return y(n,e,i,f,o,s,t)}function zn(n,e,i,f,o,s,t){let r=P(n.left,e,i,f,o,s,t),c=n.right!==void 0?P(n.right,e,i,f,o,s,t):omniAst.builders.literal(null),l=vn[n.op];if(l)return omniAst.builders.binaryExpression(l,r,c);switch(n.op){case "in":return omniAst.builders.callExpression(omniAst.builders.memberExpression(c,omniAst.builders.identifier("includes")),[r]);case "notIn":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(c,omniAst.builders.identifier("includes")),[r]));case "contains":return omniAst.builders.callExpression(omniAst.builders.memberExpression(r,omniAst.builders.identifier("includes"),false,true),[c]);case "notContains":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(r,omniAst.builders.identifier("includes"),false,true),[c]));case "exists":return omniAst.builders.binaryExpression("!=",r,omniAst.builders.literal(null));case "notExists":return omniAst.builders.binaryExpression("==",r,omniAst.builders.literal(null));case "matches":return omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[c]),omniAst.builders.identifier("test")),[r]);case "notMatches":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[c]),omniAst.builders.identifier("test")),[r]));case "startsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(r,omniAst.builders.identifier("startsWith"),false,true),[c]);case "endsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(r,omniAst.builders.identifier("endsWith"),false,true),[c]);default:return omniAst.builders.binaryExpression("===",r,c)}}function Ln(n,e,i,f,o,s,t){let{logic:r,conditions:c}=n,l=r==="AND"?"&&":"||";if(c.length===0)return omniAst.builders.literal(r==="AND");if(c.length===1)return y(c[0],e,i,f,o,s,t);let a=y(c[0],e,i,f,o,s,t);for(let p=1;p<c.length;p++){let d=y(c[p],e,i,f,o,s,t);a=omniAst.builders.logicalExpression(l,a,d);}return a}function G(n){let e=[],i=n.length,f=0,o="";for(;f<i;){let s=n[f];if(s===".")o&&(e.push({type:"key",value:o}),o=""),f++;else if(s==="["){o&&(e.push({type:"key",value:o}),o=""),f++;let t=f;for(;f<i&&n[f]!=="]";)f++;let r=n.slice(t,f);if(f++,r!=="*"){let c=parseInt(r,10);e.push({type:"index",value:isNaN(c)?r:c});}}else o+=s,f++;}return o&&e.push({type:"key",value:o}),e}function tn(n,e=[L]){return omniAst.builders.arrowFunctionExpression(e.map(i=>omniAst.builders.identifier(i)),n)}function D(n,e){let i=new Set;return C(n,i,e),i}function C(n,e,i){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let o of n)C(o,e,i);return}if(h(n))return;if(A(n)){C(n.$if,e,i),C(n.then,e,i),n.else!==void 0&&C(n.else,e,i);return}if(k(n)){for(let o of n.$pipe)C(o,e,i);return}if($(n)){if(e.add(n.$fn),n.args)for(let o of n.args)typeof o!="function"&&C(o,e,i);return}if(E(n)){n.left!==void 0&&typeof n.left=="object"&&C(n.left,e,i),n.right!==void 0&&typeof n.right=="object"&&C(n.right,e,i);return}if(T(n)){for(let o of n.conditions)C(o,e,i);return}if(i){let o=n,s=Object.keys(o);for(let t=0;t<s.length;t++){let r=s[t];if(r in i){let c=i[r](o);if(typeof c=="object"&&c!==null&&r in c)throw new Error(`Transform "${r}" returned object with same key \u2014 infinite loop`);C(c,e,i);return}}}let f=n;for(let o of Object.keys(f))C(f[o],e,i);}function I(n){let e=new Set;for(let i of n){let f=i.indexOf("."),o=i.indexOf("["),s=i.length;f!==-1&&(s=Math.min(s,f)),o!==-1&&(s=Math.min(s,o));let t=i.slice(0,s);t&&e.add(t);}return e}function _n(n){return JSON.stringify(n)}function qn(n,e,i,f,o,s){let t=W(n,{noPrefixes:true,useAccessor:f,lexicalPrefix:o,transforms:s}),r=omniAst.generate(t),c="";f?o&&(c=`const{${o}}=data??{};`):e.size>0&&(c=`const{${[...e].join(",")}}=data??{};`);let l=f?new Set([...i,"accessor"]):i,a=l.size>0?`const{${[...l].join(",")}}=scope;`:"";return a?`(function(scope){${a}return function(data){${c}return ${r}}})`:`(function(){return function(data){${c}return ${r}}})`}function q(n,e={}){let{scope:i={},returnCode:f=false,useAccessor:o=false,lexicalPrefix:s,transforms:t}=e,r=w(n,t),c=I(r),l=D(n,t),a=_n(n),p=qn(n,c,l,o,s,t);if(f)return {code:p,deps:r,hash:a,dataRoots:[...c],scopeFns:[...l]};let d;try{d=new Function(`return ${p}`)()(i);}catch(g){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${g instanceof Error?g.message:String(g)}`)}return {fn:d,deps:r,hash:a}}function on(n,e,i={}){let{fn:f}=q(n,i);return f(e)}var Ee="0.1.1";exports.ExpressionCache=v;exports.VERSION=Ee;exports.assertValid=wn;exports.builders=Z;exports.cache=Y;exports.cached=Sn;exports.clearPathCache=dn;exports.compile=N;exports.compileAST=q;exports.compilePath=O;exports.dslToAST=W;exports.evaluate=kn;exports.evaluateAST=on;exports.extractDataRoots=I;exports.extractDeps=w;exports.extractScopeFns=D;exports.get=pn;exports.getPathCacheSize=gn;exports.hasDeps=yn;exports.hasWildcard=B;exports.isCondition=E;exports.isConditionExpr=fn;exports.isConditionGroup=T;exports.isConditional=A;exports.isFn=$;exports.isLiteral=M;exports.isPipe=k;exports.isPure=mn;exports.isRef=h;exports.isValid=Rn;exports.normalizePath=j;exports.validate=z;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" }
@@ -60,6 +61,28 @@ interface PipeExpr {
60
61
  type Literal = string | number | boolean | null | Literal[] | {
61
62
  [key: string]: Literal;
62
63
  };
64
+ /**
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: [...] }
77
+ */
78
+ interface ConditionGroup {
79
+ logic: "AND" | "OR";
80
+ conditions: Expression[];
81
+ }
82
+ /**
83
+ * Union of condition types
84
+ */
85
+ type ConditionExpr = Condition | ConditionGroup;
63
86
  /**
64
87
  * Union of all expression types
65
88
  */
@@ -110,6 +133,14 @@ interface ValidationResult {
110
133
  * @example { add, subtract, multiply, filter, map, sum }
111
134
  */
112
135
  type Scope = Record<string, (...args: any[]) => any>;
136
+ /**
137
+ * Options for compilation
138
+ */
139
+ /**
140
+ * Transform function for custom expression types.
141
+ * Receives the raw node and must return a valid Expression.
142
+ */
143
+ type TransformFn = (node: Record<string, unknown>) => Expression;
113
144
  /**
114
145
  * Options for compilation
115
146
  */
@@ -125,6 +156,13 @@ interface CompileOptions<T = unknown> {
125
156
  * compile(expr, { accessor: (path, ctx) => ctx.get(path) })
126
157
  */
127
158
  accessor?: AccessorFn<T>;
159
+ /**
160
+ * Custom expression transforms.
161
+ * Key = marker (e.g. "$query"), value = transform function.
162
+ * The walker calls the transform before treating as literal.
163
+ * The returned Expression is compiled recursively.
164
+ */
165
+ transforms?: Record<string, TransformFn>;
128
166
  }
129
167
  /**
130
168
  * Check if value is a reference expression
@@ -143,15 +181,14 @@ declare const isFn: (v: unknown) => v is FnExpr;
143
181
  */
144
182
  declare const isPipe: (v: unknown) => v is PipeExpr;
145
183
  /**
146
- * Check if value is a condition (from @statedelta-libs/conditions)
184
+ * Check if value is a condition expression
147
185
  *
148
- * IMPORTANT: Must verify that `op` is a valid condition operator,
149
- * not just any string. Effect objects also have `left` and `op`
150
- * properties but with non-condition operators like "set".
186
+ * Verifies `op` is a valid condition operator to distinguish from
187
+ * effect objects that also have `left` and `op` (e.g. op: "set").
151
188
  */
152
189
  declare const isCondition: (v: unknown) => v is Condition;
153
190
  /**
154
- * Check if value is a condition group (from @statedelta-libs/conditions)
191
+ * Check if value is a condition group
155
192
  */
156
193
  declare const isConditionGroup: (v: unknown) => v is ConditionGroup;
157
194
  /**
@@ -270,7 +307,7 @@ declare function getPathCacheSize(): number;
270
307
  * @example { "$": "user.age" } → ["user.age"]
271
308
  * @example { "$if": "$isVip", "then": { "$": "price.vip" } } → ["$isVip", "price.vip"]
272
309
  */
273
- declare function extractDeps(expr: Expression): string[];
310
+ declare function extractDeps(expr: Expression, transforms?: Record<string, TransformFn>): string[];
274
311
  /**
275
312
  * Check if expression has dependencies
276
313
  */
@@ -452,16 +489,36 @@ declare function $pipe(...steps: Expression[]): PipeExpr;
452
489
  * Alias for $pipe (pipe builder)
453
490
  */
454
491
  declare const pipe: typeof $pipe;
492
+ /**
493
+ * Create a condition expression.
494
+ *
495
+ * @param left - Left side (any expression)
496
+ * @param op - Condition operator
497
+ * @param right - Right side (any expression, optional for exists/notExists)
498
+ * @returns Condition
499
+ *
500
+ * @example
501
+ * $cond($("age"), "gte", 18)
502
+ * $cond($fn("getScore", [$("user")]), "gt", 100)
503
+ * $cond($("email"), "exists")
504
+ */
505
+ declare function $cond(left: Expression, op: ConditionOp, right?: Expression): Condition;
506
+ /**
507
+ * Alias for $cond (condition builder)
508
+ */
509
+ declare const cond: typeof $cond;
455
510
 
456
511
  declare const builders_$: typeof $;
512
+ declare const builders_$cond: typeof $cond;
457
513
  declare const builders_$fn: typeof $fn;
458
514
  declare const builders_$if: typeof $if;
459
515
  declare const builders_$pipe: typeof $pipe;
516
+ declare const builders_cond: typeof cond;
460
517
  declare const builders_fn: typeof fn;
461
518
  declare const builders_pipe: typeof pipe;
462
519
  declare const builders_ref: typeof ref;
463
520
  declare namespace builders {
464
- 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 };
521
+ 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 };
465
522
  }
466
523
 
467
524
  /**
@@ -505,6 +562,11 @@ interface TransformOptions {
505
562
  * - `lexicalPrefix: "params"` → `params?.foo` instead of `accessor("params.foo", data)`
506
563
  */
507
564
  lexicalPrefix?: string;
565
+ /**
566
+ * Custom expression transforms.
567
+ * Key = marker (e.g. "$query"), value = transform function.
568
+ */
569
+ transforms?: Record<string, TransformFn>;
508
570
  }
509
571
  /**
510
572
  * Transform DSL expression to AST node
@@ -541,6 +603,7 @@ declare function wrapInFunction(bodyAst: ASTNode, params?: string[]): ASTNode;
541
603
  * Extract all function names used from scope in an expression
542
604
  *
543
605
  * @param expr - DSL expression to analyze
606
+ * @param transforms - Optional custom transforms (to resolve custom nodes before collecting)
544
607
  * @returns Set of function names used
545
608
  *
546
609
  * @example
@@ -558,7 +621,7 @@ declare function wrapInFunction(bodyAst: ASTNode, params?: string[]): ASTNode;
558
621
  * // Set { "filter", "sum" }
559
622
  * ```
560
623
  */
561
- declare function extractScopeFns(expr: Expression): Set<string>;
624
+ declare function extractScopeFns(expr: Expression, transforms?: Record<string, TransformFn>): Set<string>;
562
625
  /**
563
626
  * Extract root-level data dependencies from paths
564
627
  *
@@ -600,6 +663,11 @@ interface CompileASTOptions {
600
663
  * - `lexicalPrefix: "params"` → `params?.foo` instead of `accessor("params.foo", data)`
601
664
  */
602
665
  lexicalPrefix?: string;
666
+ /**
667
+ * Custom expression transforms.
668
+ * Key = marker (e.g. "$query"), value = transform function.
669
+ */
670
+ transforms?: Record<string, TransformFn>;
603
671
  }
604
672
  /** Result when returnCode is true */
605
673
  interface CompileASTCodeResult {
@@ -684,4 +752,4 @@ declare function evaluateAST<T = unknown, R = unknown>(expr: Expression, data: T
684
752
  */
685
753
  declare const VERSION = "0.1.1";
686
754
 
687
- export { type AccessorFn, type CallbackFn, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, 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 };
755
+ 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 TransformFn, 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" }
@@ -60,6 +61,28 @@ interface PipeExpr {
60
61
  type Literal = string | number | boolean | null | Literal[] | {
61
62
  [key: string]: Literal;
62
63
  };
64
+ /**
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: [...] }
77
+ */
78
+ interface ConditionGroup {
79
+ logic: "AND" | "OR";
80
+ conditions: Expression[];
81
+ }
82
+ /**
83
+ * Union of condition types
84
+ */
85
+ type ConditionExpr = Condition | ConditionGroup;
63
86
  /**
64
87
  * Union of all expression types
65
88
  */
@@ -110,6 +133,14 @@ interface ValidationResult {
110
133
  * @example { add, subtract, multiply, filter, map, sum }
111
134
  */
112
135
  type Scope = Record<string, (...args: any[]) => any>;
136
+ /**
137
+ * Options for compilation
138
+ */
139
+ /**
140
+ * Transform function for custom expression types.
141
+ * Receives the raw node and must return a valid Expression.
142
+ */
143
+ type TransformFn = (node: Record<string, unknown>) => Expression;
113
144
  /**
114
145
  * Options for compilation
115
146
  */
@@ -125,6 +156,13 @@ interface CompileOptions<T = unknown> {
125
156
  * compile(expr, { accessor: (path, ctx) => ctx.get(path) })
126
157
  */
127
158
  accessor?: AccessorFn<T>;
159
+ /**
160
+ * Custom expression transforms.
161
+ * Key = marker (e.g. "$query"), value = transform function.
162
+ * The walker calls the transform before treating as literal.
163
+ * The returned Expression is compiled recursively.
164
+ */
165
+ transforms?: Record<string, TransformFn>;
128
166
  }
129
167
  /**
130
168
  * Check if value is a reference expression
@@ -143,15 +181,14 @@ declare const isFn: (v: unknown) => v is FnExpr;
143
181
  */
144
182
  declare const isPipe: (v: unknown) => v is PipeExpr;
145
183
  /**
146
- * Check if value is a condition (from @statedelta-libs/conditions)
184
+ * Check if value is a condition expression
147
185
  *
148
- * IMPORTANT: Must verify that `op` is a valid condition operator,
149
- * not just any string. Effect objects also have `left` and `op`
150
- * properties but with non-condition operators like "set".
186
+ * Verifies `op` is a valid condition operator to distinguish from
187
+ * effect objects that also have `left` and `op` (e.g. op: "set").
151
188
  */
152
189
  declare const isCondition: (v: unknown) => v is Condition;
153
190
  /**
154
- * Check if value is a condition group (from @statedelta-libs/conditions)
191
+ * Check if value is a condition group
155
192
  */
156
193
  declare const isConditionGroup: (v: unknown) => v is ConditionGroup;
157
194
  /**
@@ -270,7 +307,7 @@ declare function getPathCacheSize(): number;
270
307
  * @example { "$": "user.age" } → ["user.age"]
271
308
  * @example { "$if": "$isVip", "then": { "$": "price.vip" } } → ["$isVip", "price.vip"]
272
309
  */
273
- declare function extractDeps(expr: Expression): string[];
310
+ declare function extractDeps(expr: Expression, transforms?: Record<string, TransformFn>): string[];
274
311
  /**
275
312
  * Check if expression has dependencies
276
313
  */
@@ -452,16 +489,36 @@ declare function $pipe(...steps: Expression[]): PipeExpr;
452
489
  * Alias for $pipe (pipe builder)
453
490
  */
454
491
  declare const pipe: typeof $pipe;
492
+ /**
493
+ * Create a condition expression.
494
+ *
495
+ * @param left - Left side (any expression)
496
+ * @param op - Condition operator
497
+ * @param right - Right side (any expression, optional for exists/notExists)
498
+ * @returns Condition
499
+ *
500
+ * @example
501
+ * $cond($("age"), "gte", 18)
502
+ * $cond($fn("getScore", [$("user")]), "gt", 100)
503
+ * $cond($("email"), "exists")
504
+ */
505
+ declare function $cond(left: Expression, op: ConditionOp, right?: Expression): Condition;
506
+ /**
507
+ * Alias for $cond (condition builder)
508
+ */
509
+ declare const cond: typeof $cond;
455
510
 
456
511
  declare const builders_$: typeof $;
512
+ declare const builders_$cond: typeof $cond;
457
513
  declare const builders_$fn: typeof $fn;
458
514
  declare const builders_$if: typeof $if;
459
515
  declare const builders_$pipe: typeof $pipe;
516
+ declare const builders_cond: typeof cond;
460
517
  declare const builders_fn: typeof fn;
461
518
  declare const builders_pipe: typeof pipe;
462
519
  declare const builders_ref: typeof ref;
463
520
  declare namespace builders {
464
- 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 };
521
+ 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 };
465
522
  }
466
523
 
467
524
  /**
@@ -505,6 +562,11 @@ interface TransformOptions {
505
562
  * - `lexicalPrefix: "params"` → `params?.foo` instead of `accessor("params.foo", data)`
506
563
  */
507
564
  lexicalPrefix?: string;
565
+ /**
566
+ * Custom expression transforms.
567
+ * Key = marker (e.g. "$query"), value = transform function.
568
+ */
569
+ transforms?: Record<string, TransformFn>;
508
570
  }
509
571
  /**
510
572
  * Transform DSL expression to AST node
@@ -541,6 +603,7 @@ declare function wrapInFunction(bodyAst: ASTNode, params?: string[]): ASTNode;
541
603
  * Extract all function names used from scope in an expression
542
604
  *
543
605
  * @param expr - DSL expression to analyze
606
+ * @param transforms - Optional custom transforms (to resolve custom nodes before collecting)
544
607
  * @returns Set of function names used
545
608
  *
546
609
  * @example
@@ -558,7 +621,7 @@ declare function wrapInFunction(bodyAst: ASTNode, params?: string[]): ASTNode;
558
621
  * // Set { "filter", "sum" }
559
622
  * ```
560
623
  */
561
- declare function extractScopeFns(expr: Expression): Set<string>;
624
+ declare function extractScopeFns(expr: Expression, transforms?: Record<string, TransformFn>): Set<string>;
562
625
  /**
563
626
  * Extract root-level data dependencies from paths
564
627
  *
@@ -600,6 +663,11 @@ interface CompileASTOptions {
600
663
  * - `lexicalPrefix: "params"` → `params?.foo` instead of `accessor("params.foo", data)`
601
664
  */
602
665
  lexicalPrefix?: string;
666
+ /**
667
+ * Custom expression transforms.
668
+ * Key = marker (e.g. "$query"), value = transform function.
669
+ */
670
+ transforms?: Record<string, TransformFn>;
603
671
  }
604
672
  /** Result when returnCode is true */
605
673
  interface CompileASTCodeResult {
@@ -684,4 +752,4 @@ declare function evaluateAST<T = unknown, R = unknown>(expr: Expression, data: T
684
752
  */
685
753
  declare const VERSION = "0.1.1";
686
754
 
687
- export { type AccessorFn, type CallbackFn, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, 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 };
755
+ 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 TransformFn, 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 sn=Object.defineProperty;var fn=(n,e)=>{for(var i in e)sn(n,i,{get:e[i],enumerable:true});};var m=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,E=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"&&"left"in n&&"op"in n&&_.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),h=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,ln=n=>y(n)||h(n),z=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="left"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 R=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 F(n){let e=R.get(n);return e||(e=J(n)?cn(n):un(n),R.set(n,e),e)}function un(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,c=o.value;return a=>a?.[s]?.[u]?.[c]}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 cn(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?an(e,i[0]):pn(e,i)}function an(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 c=u?.[s];if(Array.isArray(c))return c.map(a=>a?.[o])}}return s=>{let u=s;for(let c=0;c<r&&u!=null;c++)u=u[i[c]];if(Array.isArray(u))return u.map(c=>c?.[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 c=u;for(let a=0;a<f&&c!=null;a++)c=c[t[a]];return c})}}function pn(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(c=>c.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 c=u;return Array.isArray(c)?c:[c]});}else if(s.type==="map"){if(!Array.isArray(o))return;r.length>0&&(o=o.map(u=>{let c=u;for(let a of r){if(c==null)return;c=c[a];}return c}));}}return o}}function dn(n,e){return F(e)(n)}function x(n){let e=n.indexOf("[*]");return e===-1?n:n.slice(0,e)}function gn(){R.clear();}function mn(){return R.size}function k(n){let e=new Set;return $(n,e),Array.from(e)}function $(n,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r=0;r<n.length;r++)$(n[r],e);return}if(m(n)){e.add(x(n.$));return}if(E(n)){if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if;e.add(x(r));}else $(n.$if,e);$(n.then,e),n.else!==void 0&&$(n.else,e);return}if(b(n)){for(let r=0;r<n.$pipe.length;r++)$(n.$pipe[r],e);return}if(T(n)){if(n.args)for(let r=0;r<n.args.length;r++){let f=n.args[r];typeof f!="function"&&$(f,e);}return}if(y(n)){isRef(n.left)&&e.add(x(n.left.$)),n.right!==void 0&&isRef(n.right)&&e.add(x(n.right.$));return}if(h(n)){for(let r=0;r<n.conditions.length;r++)$(n.conditions[r],e);return}let i=n,t=Object.keys(i);for(let r=0;r<t.length;r++)$(i[t[r]],e);}function yn(n){return k(n).length>0}function hn(n){return k(n).length===0}function En(n){return JSON.stringify(n)}function O(n,e={}){let i=e.scope??{},t=e.accessor,r=S(n,i,t),f=k(n),o=En(n);return {fn:r,deps:f,hash:o}}function S(n,e,i){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let t=n.map(r=>S(r,e,i));return r=>t.map(f=>f(r))}if(m(n))return Tn(n,i);if(E(n))return bn(n,e,i);if(b(n))return Cn(n,e,i);if(T(n))return Sn(n,e,i);if(y(n))return compile(n,i?{accessor:i}:void 0);if(h(n))return compile(n,i?{accessor:i}:void 0);if(z(n)){let t=n,r=Object.keys(t),f=r.map(o=>S(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 Y(n,e){return e?i=>e(n,i):F(n)}function Tn(n,e){return Y(n.$,e)}function bn(n,e,i){let t;if(typeof n.$if=="string"){let o=n.$if.startsWith("!")?n.$if.slice(1):n.$if,s=Y(o,i);t=n.$if.startsWith("!")?c=>!s(c):c=>!!s(c);}else {let o=S(n.$if,e,i);t=s=>!!o(s);}let r=S(n.then,e,i),f=n.else!==void 0?S(n.else,e,i):()=>{};return o=>t(o)?r(o):f(o)}function Cn(n,e,i){let t=n.$pipe;if(t.length===0)return ()=>{};if(t.length===1)return S(t[0],e,i);let r=S(t[0],e,i),f=t.slice(1).map(s=>S(s,e,i)),o=f.length;if(o===1){let[s]=f;return u=>{let c=r(u),a=s(u);return typeof a=="function"?a(c):a}}if(o===2){let[s,u]=f;return c=>{let a=r(c),p=s(c);return a=typeof p=="function"?p(a):p,p=u(c),typeof p=="function"?p(a):p}}if(o===3){let[s,u,c]=f;return a=>{let p=r(a),d=s(a);return p=typeof d=="function"?d(p):d,d=u(a),p=typeof d=="function"?d(p):d,d=c(a),typeof d=="function"?d(p):d}}return s=>{let u=r(s);for(let c=0;c<o;c++){let a=f[c](s);u=typeof a=="function"?a(u):a;}return u}}function Sn(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=>typeof s=="function"?()=>s:S(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 c=e[t];if(!c)throw new Error(`Function not found in scope: ${t}`);return c(s(u))}}if(o===2){let[s,u]=f;return c=>{let a=e[t];if(!a)throw new Error(`Function not found in scope: ${t}`);return a(s(c),u(c))}}if(o===3){let[s,u,c]=f;return a=>{let p=e[t];if(!p)throw new Error(`Function not found in scope: ${t}`);return p(s(a),u(a),c(a))}}return s=>{let u=e[t];if(!u)throw new Error(`Function not found in scope: ${t}`);return u(...f.map(c=>c(s)))}}function $n(n,e,i={}){return O(n,i).fn(e)}var N=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=O(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);}}},H=new N;function An(n,e={}){return H.get(n,e)}function M(n,e="root",i={}){let t=[];return A(n,e,t,i),{valid:t.length===0,errors:t}}function A(n,e,i,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let o=0;o<n.length;o++)A(n[o],`${e}[${o}]`,i,t);return}if(m(n)){(!n.$||typeof n.$!="string")&&i.push(`${e}: invalid reference, $ must be non-empty string`);return}if(E(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||i.push(`${e}.$if: empty path in string shorthand`):A(n.$if,`${e}.$if`,i,t),A(n.then,`${e}.then`,i,t),n.else!==void 0&&A(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++)A(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++){let s=n.args[o];typeof s!="function"&&A(s,`${e}.args[${o}]`,i,t);}return}if(y(n)){let o=validate(n,e);o.valid||i.push(...o.errors);return}if(h(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];A(r[s],`${e}.${s}`,i,t);}}function kn(n,e={}){let i=M(n,"root",e);if(!i.valid)throw new Error(`Invalid expression: ${i.errors.join("; ")}`)}function wn(n,e={}){return M(n,"root",e).valid}var Z={};fn(Z,{$:()=>Q,$fn:()=>U,$if:()=>Fn,$pipe:()=>X,fn:()=>Rn,pipe:()=>On,ref:()=>xn});function Q(n){return {$:n}}var xn=Q;function U(n,e){return e===void 0||e.length===0?{$fn:n}:{$fn:n,args:e}}var Rn=U;function Fn(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 D="data",en="scope",Nn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function v(n,e={}){let{dataParam:i=D,scopeParam:t=en,noPrefixes:r=false,useAccessor:f=false,lexicalPrefix:o}=e;return g(n,i,t,r,f,o)}function g(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=>g(o,e,i,t,r,f)));if(m(n))return jn(n.$,e,t,r,f);if(E(n))return Gn(n,e,i,t,r,f);if(b(n))return zn(n.$pipe,e,i,t,r,f);if(T(n))return Wn(n,e,i,t,r,f);if(y(n))return Mn(n,e,i,t,r,f);if(h(n))return Dn(n,e,i,t,r,f);if(typeof n=="object"){let s=Object.entries(n).map(([u,c])=>builders.property(builders.identifier(u),g(c,e,i,t,r,f)));return builders.objectExpression(s)}return builders.literal(null)}var I="accessor";function L(n,e){return e?n===e||n.startsWith(e+"."):false}function jn(n,e,i,t,r){return t?L(n,r)?w(n,e,true):builders.callExpression(builders.identifier(I),[builders.literal(n),builders.identifier(e)]):n.includes("[*]")?vn(n,e,i):w(n,e,i)}function w(n,e,i){let t=j(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 vn(n,e,i){let t=n.indexOf("[*]"),r=n.slice(0,t),f=n.slice(t+3),o;if(r?o=w(r,e,i):o=i?builders.identifier("undefined"):builders.identifier(e),!f||f==="")return o;if(f.includes("[*]"))return tn(o,f);let s="_i",u=f.startsWith(".")?f.slice(1):f,c=builders.identifier(s);if(u){let a=j(u);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(o,builders.identifier("map"),false,true),[builders.arrowFunctionExpression([builders.identifier(s)],c)])}function tn(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 c=j(o);for(let a of c)a.type==="key"&&(s=builders.memberExpression(s,builders.identifier(a.value),false,true));}if(r.includes("[*]")){let c=tn(s,r);return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(f)],c)])}let u=r.startsWith(".")?r.slice(1):r;if(u){let c=j(u);for(let a of c)a.type==="key"&&(s=builders.memberExpression(s,builders.identifier(a.value),false,true));}return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(f)],s)])}function Gn(n,e,i,t,r,f){let o;if(typeof n.$if=="string"){let c=n.$if.startsWith("!"),a=c?n.$if.slice(1):n.$if,p;r?L(a,f)?p=w(a,e,true):p=builders.callExpression(builders.identifier(I),[builders.literal(a),builders.identifier(e)]):p=w(a,e,t),o=c?builders.unaryExpression("!",p):p;}else o=g(n.$if,e,i,t,r,f);let s=g(n.then,e,i,t,r,f),u=n.else!==void 0?g(n.else,e,i,t,r,f):builders.identifier("undefined");return builders.conditionalExpression(o,s,u)}function Wn(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=>typeof u=="function"?builders.literal(null):g(u,e,i,t,r,f));return builders.callExpression(o,s)}function zn(n,e,i,t,r,f){if(n.length===0)return builders.identifier("undefined");if(n.length===1)return g(n[0],e,i,t,r,f);let o=g(n[0],e,i,t,r,f);for(let s=1;s<n.length;s++){let u=g(n[s],e,i,t,r,f);o=builders.callExpression(u,[o]);}return o}function nn(n,e,i,t,r,f){if(m(n)){let o=n.$;return r?L(o,f)?w(o,e,true):builders.callExpression(builders.identifier(I),[builders.literal(o),builders.identifier(e)]):w(o,e,t)}return g(n,e,i,t,r,f)}function Mn(n,e,i,t,r,f){let o=nn(n.left,e,i,t,r,f),s=n.right!==void 0?nn(n.right,e,i,t,r,f):builders.literal(null),u=Nn[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 Dn(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 g(s[0],e,i,t,r,f);let c=g(s[0],e,i,t,r,f);for(let a=1;a<s.length;a++){let p=g(s[a],e,i,t,r,f);c=builders.logicalExpression(u,c,p);}return c}function j(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 on(n,e=[D]){return builders.arrowFunctionExpression(e.map(i=>builders.identifier(i)),n)}function G(n){let e=new Set;return C(n,e),e}function C(n,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let t of n)C(t,e);return}if(m(n))return;if(E(n)){C(n.$if,e),C(n.then,e),n.else!==void 0&&C(n.else,e);return}if(b(n)){for(let t of n.$pipe)C(t,e);return}if(T(n)){if(e.add(n.$fn),n.args)for(let t of n.args)typeof t!="function"&&C(t,e);return}if(y(n)){n.left!==void 0&&typeof n.left=="object"&&C(n.left,e),n.right!==void 0&&typeof n.right=="object"&&C(n.right,e);return}if(h(n)){for(let t of n.conditions)C(t,e);return}let i=n;for(let t of Object.keys(i))C(i[t],e);}function W(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 Ln(n){return JSON.stringify(n)}function Vn(n,e,i,t,r){let f=v(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,c=u.size>0?`const{${[...u].join(",")}}=scope;`:"";return c?`(function(scope){${c}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=k(n),s=W(o),u=G(n),c=Ln(n),a=Vn(n,s,u,r,f);if(t)return {code:a,deps:o,hash:c,dataRoots:[...s],scopeFns:[...u]};let p;try{p=new Function(`return ${a}`)()(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:c}}function rn(n,e,i={}){let{fn:t}=V(n,i);return t(e)}var Te="0.1.1";export{N as ExpressionCache,Te as VERSION,kn as assertValid,Z as builders,H as cache,An as cached,gn as clearPathCache,O as compile,V as compileAST,F as compilePath,v as dslToAST,$n as evaluate,rn as evaluateAST,W as extractDataRoots,k as extractDeps,G as extractScopeFns,dn as get,mn as getPathCacheSize,yn as hasDeps,J as hasWildcard,y as isCondition,ln as isConditionExpr,h as isConditionGroup,E as isConditional,T as isFn,z as isLiteral,b as isPipe,hn as isPure,m as isRef,wn as isValid,x as normalizePath,M as validate,on as wrapInFunction};
1
+ import {builders,generate}from'omni-ast';var rn=Object.defineProperty;var sn=(n,e)=>{for(var i in e)rn(n,i,{get:e[i],enumerable:true});};var h=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,A=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,$=n=>n!==null&&typeof n=="object"&&"$fn"in n&&typeof n.$fn=="string",k=n=>n!==null&&typeof n=="object"&&"$pipe"in n&&Array.isArray(n.$pipe),F=new Set(["eq","neq","gt","gte","lt","lte","in","notIn","contains","notContains","exists","notExists","matches","notMatches","startsWith","endsWith"]),E=n=>n!==null&&typeof n=="object"&&"left"in n&&"op"in n&&F.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),T=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,fn=n=>E(n)||T(n),M=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,f="left"in i&&"op"in i&&F.has(i.op);return !("$"in i)&&!("$if"in i)&&!("$fn"in i)&&!("$pipe"in i)&&!f&&!("logic"in i)}return false};var x=new Map;function J(n){let e=[],i=n.length,f=0,o="";for(;f<i;){let s=n[f];if(s===".")o&&(e.push({type:"key",value:o}),o=""),f++;else if(s==="["){o&&(e.push({type:"key",value:o}),o=""),f++;let t=f;for(;f<i&&n[f]!=="]";)f++;let r=n.slice(t,f);if(f++,r==="*")e.push({type:"wildcard",value:"*"});else {let c=parseInt(r,10);e.push({type:"index",value:isNaN(c)?r:c});}}else o+=s,f++;}return o&&e.push({type:"key",value:o}),e}function B(n){return n.includes("[*]")}function O(n){let e=x.get(n);return e||(e=B(n)?un(n):cn(n),x.set(n,e),e)}function cn(n){if(!n.includes(".")&&!n.includes("["))return o=>o?.[n];let e=J(n),i=e.length;if(i===2){let[o,s]=e,t=o.value,r=s.value;return c=>c?.[t]?.[r]}if(i===3){let[o,s,t]=e,r=o.value,c=s.value,l=t.value;return a=>a?.[r]?.[c]?.[l]}let f=e.map(o=>o.value);return o=>{let s=o;for(let t=0;t<i&&s!=null;t++)s=s[f[t]];return s}}function un(n){let e=J(n),i=[];for(let f=0;f<e.length;f++)e[f].type==="wildcard"&&i.push(f);return i.length===1?ln(e,i[0]):an(e,i)}function ln(n,e){let i=n.slice(0,e).map(t=>t.value),f=n.slice(e+1).map(t=>t.value),o=i.length,s=f.length;if(s===0){if(o===1){let t=i[0];return r=>r?.[t]}return t=>{let r=t;for(let c=0;c<o&&r!=null;c++)r=r[i[c]];return r}}if(s===1){let t=f[0];if(o===1){let r=i[0];return c=>{let l=c?.[r];if(Array.isArray(l))return l.map(a=>a?.[t])}}return r=>{let c=r;for(let l=0;l<o&&c!=null;l++)c=c[i[l]];if(Array.isArray(c))return c.map(l=>l?.[t])}}return t=>{let r=t;for(let c=0;c<o&&r!=null;c++)r=r[i[c]];if(Array.isArray(r))return r.map(c=>{let l=c;for(let a=0;a<s&&l!=null;a++)l=l[f[a]];return l})}}function an(n,e){let i=[],f=0;for(let s=0;s<e.length;s++){let t=e[s],r=s===e.length-1,c=n.slice(f,t).map(l=>l.value);c.length>0&&i.push({type:"access",keys:c}),i.push({type:r?"map":"flatMap",keys:[]}),f=t+1;}let o=n.slice(f).map(s=>s.value);return s=>{let t=s;for(let r of i){if(t==null)return;if(r.type==="access")for(let c of r.keys){if(t==null)return;t=t[c];}else if(r.type==="flatMap"){if(!Array.isArray(t))return;t=t.flatMap(c=>{let l=c;return Array.isArray(l)?l:[l]});}else if(r.type==="map"){if(!Array.isArray(t))return;o.length>0&&(t=t.map(c=>{let l=c;for(let a of o){if(l==null)return;l=l[a];}return l}));}}return t}}function pn(n,e){return O(e)(n)}function j(n){let e=n.indexOf("[*]");return e===-1?n:n.slice(0,e)}function dn(){x.clear();}function gn(){return x.size}function w(n,e){let i=new Set;return b(n,i,e),Array.from(i)}function b(n,e,i){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let s=0;s<n.length;s++)b(n[s],e,i);return}if(h(n)){e.add(j(n.$));return}if(A(n)){if(typeof n.$if=="string"){let s=n.$if.startsWith("!")?n.$if.slice(1):n.$if;e.add(j(s));}else b(n.$if,e,i);b(n.then,e,i),n.else!==void 0&&b(n.else,e,i);return}if(k(n)){for(let s=0;s<n.$pipe.length;s++)b(n.$pipe[s],e,i);return}if($(n)){if(n.args)for(let s=0;s<n.args.length;s++){let t=n.args[s];typeof t!="function"&&b(t,e,i);}return}if(E(n)){b(n.left,e,i),n.right!==void 0&&b(n.right,e,i);return}if(T(n)){for(let s=0;s<n.conditions.length;s++)b(n.conditions[s],e,i);return}if(i){let s=n,t=Object.keys(s);for(let r=0;r<t.length;r++){let c=t[r];if(c in i){let l=i[c](s);if(typeof l=="object"&&l!==null&&c in l)throw new Error(`Transform "${c}" returned object with same key \u2014 infinite loop`);b(l,e,i);return}}}let f=n,o=Object.keys(f);for(let s=0;s<o.length;s++)b(f[o[s]],e,i);}function yn(n){return w(n).length>0}function mn(n){return w(n).length===0}function hn(n){return JSON.stringify(n)}function N(n,e={}){let i=e.scope??{},f=e.accessor,o=e.transforms,s=m(n,i,f,o),t=w(n,o),r=hn(n);return {fn:s,deps:t,hash:r}}function m(n,e,i,f){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let o=n.map(s=>m(s,e,i,f));return s=>o.map(t=>t(s))}if(h(n))return En(n,i);if(A(n))return Tn(n,e,i,f);if(k(n))return bn(n,e,i,f);if($(n))return Cn(n,e,i,f);if(E(n))return An(n,e,i,f);if(T(n))return $n(n,e,i,f);if(f){let o=n,s=Object.keys(o);for(let t=0;t<s.length;t++){let r=s[t];if(r in f){let c=f[r](o);if(typeof c=="object"&&c!==null&&r in c)throw new Error(`Transform "${r}" returned object with same key \u2014 infinite loop`);return m(c,e,i,f)}}}if(M(n)){let o=n,s=Object.keys(o),t=s.map(r=>m(o[r],e,i,f));return r=>{let c={};for(let l=0;l<s.length;l++)c[s[l]]=t[l](r);return c}}return ()=>n}function K(n,e){return e?i=>e(n,i):O(n)}function En(n,e){return K(n.$,e)}function Tn(n,e,i,f){let o;if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if,c=K(r,i);o=n.$if.startsWith("!")?a=>!c(a):a=>!!c(a);}else {let r=m(n.$if,e,i,f);o=c=>!!r(c);}let s=m(n.then,e,i,f),t=n.else!==void 0?m(n.else,e,i,f):()=>{};return r=>o(r)?s(r):t(r)}function bn(n,e,i,f){let o=n.$pipe;if(o.length===0)return ()=>{};if(o.length===1)return m(o[0],e,i,f);let s=m(o[0],e,i,f),t=o.slice(1).map(c=>m(c,e,i,f)),r=t.length;if(r===1){let[c]=t;return l=>{let a=s(l),p=c(l);return typeof p=="function"?p(a):p}}if(r===2){let[c,l]=t;return a=>{let p=s(a),d=c(a);return p=typeof d=="function"?d(p):d,d=l(a),typeof d=="function"?d(p):d}}if(r===3){let[c,l,a]=t;return p=>{let d=s(p),g=c(p);return d=typeof g=="function"?g(d):g,g=l(p),d=typeof g=="function"?g(d):g,g=a(p),typeof g=="function"?g(d):g}}return c=>{let l=s(c);for(let a=0;a<r;a++){let p=t[a](c);l=typeof p=="function"?p(l):p;}return l}}function Cn(n,e,i,f){let o=n.$fn,s=n.args;if(s===void 0)return ()=>{let c=e[o];if(!c)throw new Error(`Function not found in scope: ${o}`);return c};let t=s.map(c=>typeof c=="function"?()=>c:m(c,e,i,f)),r=t.length;if(r===0)return c=>{let l=e[o];if(!l)throw new Error(`Function not found in scope: ${o}`);return l()};if(r===1){let[c]=t;return l=>{let a=e[o];if(!a)throw new Error(`Function not found in scope: ${o}`);return a(c(l))}}if(r===2){let[c,l]=t;return a=>{let p=e[o];if(!p)throw new Error(`Function not found in scope: ${o}`);return p(c(a),l(a))}}if(r===3){let[c,l,a]=t;return p=>{let d=e[o];if(!d)throw new Error(`Function not found in scope: ${o}`);return d(c(p),l(p),a(p))}}return c=>{let l=e[o];if(!l)throw new Error(`Function not found in scope: ${o}`);return l(...t.map(a=>a(c)))}}function An(n,e,i,f){let o=m(n.left,e,i,f),s=n.right!==void 0?m(n.right,e,i,f):()=>{};switch(n.op){case "eq":return t=>o(t)===s(t);case "neq":return t=>o(t)!==s(t);case "gt":return t=>o(t)>s(t);case "gte":return t=>o(t)>=s(t);case "lt":return t=>o(t)<s(t);case "lte":return t=>o(t)<=s(t);case "in":return t=>{let r=s(t);return Array.isArray(r)&&r.includes(o(t))};case "notIn":return t=>{let r=s(t);return !Array.isArray(r)||!r.includes(o(t))};case "contains":return t=>{let r=o(t);return Array.isArray(r)&&r.includes(s(t))};case "notContains":return t=>{let r=o(t);return !Array.isArray(r)||!r.includes(s(t))};case "exists":return t=>o(t)!==void 0;case "notExists":return t=>o(t)===void 0;case "matches":return t=>{let r=o(t),c=s(t);return typeof r!="string"||typeof c!="string"?false:new RegExp(c).test(r)};case "notMatches":return t=>{let r=o(t),c=s(t);return typeof r!="string"||typeof c!="string"?true:!new RegExp(c).test(r)};case "startsWith":return t=>{let r=o(t),c=s(t);return typeof r=="string"&&typeof c=="string"&&r.startsWith(c)};case "endsWith":return t=>{let r=o(t),c=s(t);return typeof r=="string"&&typeof c=="string"&&r.endsWith(c)}}}function $n(n,e,i,f){let o=n.conditions.map(t=>m(t,e,i,f)),s=o.length;if(s===1)return t=>!!o[0](t);if(s===2){let[t,r]=o;return n.logic==="AND"?c=>!!t(c)&&!!r(c):c=>!!t(c)||!!r(c)}if(s===3){let[t,r,c]=o;return n.logic==="AND"?l=>!!t(l)&&!!r(l)&&!!c(l):l=>!!t(l)||!!r(l)||!!c(l)}return n.logic==="AND"?t=>{for(let r=0;r<s;r++)if(!o[r](t))return false;return true}:t=>{for(let r=0;r<s;r++)if(o[r](t))return true;return false}}function kn(n,e,i={}){return N(n,i).fn(e)}var v=class{constructor(e=1e3){this.cache=new Map,this._maxSize=e;}get(e,i={}){let f=JSON.stringify(e),o=this.cache.get(f);if(o)return this.cache.delete(f),this.cache.set(f,o),o;let s=N(e,i);if(this.cache.size>=this._maxSize){let t=this.cache.keys().next().value;t&&this.cache.delete(t);}return this.cache.set(f,s),s}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 z(n,e="root",i={}){let f=[];return S(n,e,f,i),{valid:f.length===0,errors:f}}function S(n,e,i,f){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let t=0;t<n.length;t++)S(n[t],`${e}[${t}]`,i,f);return}if(h(n)){(!n.$||typeof n.$!="string")&&i.push(`${e}: invalid reference, $ must be non-empty string`);return}if(A(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||i.push(`${e}.$if: empty path in string shorthand`):S(n.$if,`${e}.$if`,i,f),S(n.then,`${e}.then`,i,f),n.else!==void 0&&S(n.else,`${e}.else`,i,f);return}if(k(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 t=0;t<n.$pipe.length;t++)S(n.$pipe[t],`${e}.$pipe[${t}]`,i,f);return}if($(n)){if(!n.$fn||typeof n.$fn!="string"){i.push(`${e}: invalid function, $fn must be non-empty string`);return}if(f.scope&&!(n.$fn in f.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 t=0;t<n.args.length;t++){let r=n.args[t];typeof r!="function"&&S(r,`${e}.args[${t}]`,i,f);}return}if(E(n)){F.has(n.op)||i.push(`${e}: invalid operator "${n.op}"`),S(n.left,`${e}.left`,i,f),n.right!==void 0&&S(n.right,`${e}.right`,i,f);return}if(T(n)){if(n.logic!=="AND"&&n.logic!=="OR"&&i.push(`${e}: invalid logic "${n.logic}", must be "AND" or "OR"`),!Array.isArray(n.conditions)){i.push(`${e}.conditions: must be an array`);return}for(let t=0;t<n.conditions.length;t++)S(n.conditions[t],`${e}.conditions[${t}]`,i,f);return}let o=n,s=Object.keys(o);for(let t=0;t<s.length;t++){let r=s[t];S(o[r],`${e}.${r}`,i,f);}}function wn(n,e={}){let i=z(n,"root",e);if(!i.valid)throw new Error(`Invalid expression: ${i.errors.join("; ")}`)}function Rn(n,e={}){return z(n,"root",e).valid}var Z={};sn(Z,{$:()=>H,$cond:()=>X,$fn:()=>Q,$if:()=>On,$pipe:()=>U,cond:()=>Nn,fn:()=>xn,pipe:()=>jn,ref:()=>Fn});function H(n){return {$:n}}var Fn=H;function Q(n,e){return e===void 0||e.length===0?{$fn:n}:{$fn:n,args:e}}var xn=Q;function On(n,e,i){return i===void 0?{$if:n,then:e}:{$if:n,then:e,else:i}}function U(...n){return {$pipe:n}}var jn=U;function X(n,e,i){return i===void 0?{left:n,op:e}:{left:n,op:e,right:i}}var Nn=X;var L="data",nn="scope",vn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function W(n,e={}){let{dataParam:i=L,scopeParam:f=nn,noPrefixes:o=false,useAccessor:s=false,lexicalPrefix:t,transforms:r}=e;return y(n,i,f,o,s,t,r)}function y(n,e,i,f,o,s,t){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(r=>y(r,e,i,f,o,s,t)));if(h(n))return Gn(n.$,e,f,o,s);if(A(n))return Dn(n,e,i,f,o,s,t);if(k(n))return Mn(n.$pipe,e,i,f,o,s,t);if($(n))return In(n,e,i,f,o,s,t);if(E(n))return zn(n,e,i,f,o,s,t);if(T(n))return Ln(n,e,i,f,o,s,t);if(t&&typeof n=="object"){let r=n,c=Object.keys(r);for(let l=0;l<c.length;l++){let a=c[l];if(a in t){let p=t[a](r);if(typeof p=="object"&&p!==null&&a in p)throw new Error(`Transform "${a}" returned object with same key \u2014 infinite loop`);return y(p,e,i,f,o,s,t)}}}if(typeof n=="object"){let c=Object.entries(n).map(([l,a])=>builders.property(builders.identifier(l),y(a,e,i,f,o,s,t)));return builders.objectExpression(c)}return builders.literal(null)}var V="accessor";function _(n,e){return e?n===e||n.startsWith(e+"."):false}function Gn(n,e,i,f,o){return f?_(n,o)?R(n,e,true):builders.callExpression(builders.identifier(V),[builders.literal(n),builders.identifier(e)]):n.includes("[*]")?Wn(n,e,i):R(n,e,i)}function R(n,e,i){let f=G(n);if(f.length===0)return i?builders.identifier("undefined"):builders.identifier(e);let o;if(i){let s=f[0];o=builders.identifier(s.value);for(let t=1;t<f.length;t++){let r=f[t];r.type==="key"?o=builders.memberExpression(o,builders.identifier(r.value),false,true):o=builders.memberExpression(o,builders.literal(r.value),true,true);}}else {o=builders.identifier(e);for(let s of f)s.type==="key"?o=builders.memberExpression(o,builders.identifier(s.value),false,true):o=builders.memberExpression(o,builders.literal(s.value),true,true);}return o}function Wn(n,e,i){let f=n.indexOf("[*]"),o=n.slice(0,f),s=n.slice(f+3),t;if(o?t=R(o,e,i):t=i?builders.identifier("undefined"):builders.identifier(e),!s||s==="")return t;if(s.includes("[*]"))return en(t,s);let r="_i",c=s.startsWith(".")?s.slice(1):s,l=builders.identifier(r);if(c){let a=G(c);for(let p of a)p.type==="key"?l=builders.memberExpression(l,builders.identifier(p.value),false,true):l=builders.memberExpression(l,builders.literal(p.value),true,true);}return builders.callExpression(builders.memberExpression(t,builders.identifier("map"),false,true),[builders.arrowFunctionExpression([builders.identifier(r)],l)])}function en(n,e){let i=e.indexOf("[*]"),f=e.slice(0,i),o=e.slice(i+3),s="_i",t=f.startsWith(".")?f.slice(1):f,r=builders.identifier(s);if(t){let l=G(t);for(let a of l)a.type==="key"&&(r=builders.memberExpression(r,builders.identifier(a.value),false,true));}if(o.includes("[*]")){let l=en(r,o);return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(s)],l)])}let c=o.startsWith(".")?o.slice(1):o;if(c){let l=G(c);for(let a of l)a.type==="key"&&(r=builders.memberExpression(r,builders.identifier(a.value),false,true));}return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(s)],r)])}function Dn(n,e,i,f,o,s,t){let r;if(typeof n.$if=="string"){let a=n.$if.startsWith("!"),p=a?n.$if.slice(1):n.$if,d;o?_(p,s)?d=R(p,e,true):d=builders.callExpression(builders.identifier(V),[builders.literal(p),builders.identifier(e)]):d=R(p,e,f),r=a?builders.unaryExpression("!",d):d;}else r=y(n.$if,e,i,f,o,s,t);let c=y(n.then,e,i,f,o,s,t),l=n.else!==void 0?y(n.else,e,i,f,o,s,t):builders.identifier("undefined");return builders.conditionalExpression(r,c,l)}function In(n,e,i,f,o,s,t){let r=f?builders.identifier(n.$fn):builders.memberExpression(builders.identifier(i),builders.identifier(n.$fn),false,false);if(n.args===void 0)return r;let c=n.args.map(l=>typeof l=="function"?builders.literal(null):y(l,e,i,f,o,s,t));return builders.callExpression(r,c)}function Mn(n,e,i,f,o,s,t){if(n.length===0)return builders.identifier("undefined");if(n.length===1)return y(n[0],e,i,f,o,s,t);let r=y(n[0],e,i,f,o,s,t);for(let c=1;c<n.length;c++){let l=y(n[c],e,i,f,o,s,t);r=builders.callExpression(l,[r]);}return r}function P(n,e,i,f,o,s,t){if(h(n)){let r=n.$;return o?_(r,s)?R(r,e,true):builders.callExpression(builders.identifier(V),[builders.literal(r),builders.identifier(e)]):R(r,e,f)}return y(n,e,i,f,o,s,t)}function zn(n,e,i,f,o,s,t){let r=P(n.left,e,i,f,o,s,t),c=n.right!==void 0?P(n.right,e,i,f,o,s,t):builders.literal(null),l=vn[n.op];if(l)return builders.binaryExpression(l,r,c);switch(n.op){case "in":return builders.callExpression(builders.memberExpression(c,builders.identifier("includes")),[r]);case "notIn":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(c,builders.identifier("includes")),[r]));case "contains":return builders.callExpression(builders.memberExpression(r,builders.identifier("includes"),false,true),[c]);case "notContains":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(r,builders.identifier("includes"),false,true),[c]));case "exists":return builders.binaryExpression("!=",r,builders.literal(null));case "notExists":return builders.binaryExpression("==",r,builders.literal(null));case "matches":return builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[c]),builders.identifier("test")),[r]);case "notMatches":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[c]),builders.identifier("test")),[r]));case "startsWith":return builders.callExpression(builders.memberExpression(r,builders.identifier("startsWith"),false,true),[c]);case "endsWith":return builders.callExpression(builders.memberExpression(r,builders.identifier("endsWith"),false,true),[c]);default:return builders.binaryExpression("===",r,c)}}function Ln(n,e,i,f,o,s,t){let{logic:r,conditions:c}=n,l=r==="AND"?"&&":"||";if(c.length===0)return builders.literal(r==="AND");if(c.length===1)return y(c[0],e,i,f,o,s,t);let a=y(c[0],e,i,f,o,s,t);for(let p=1;p<c.length;p++){let d=y(c[p],e,i,f,o,s,t);a=builders.logicalExpression(l,a,d);}return a}function G(n){let e=[],i=n.length,f=0,o="";for(;f<i;){let s=n[f];if(s===".")o&&(e.push({type:"key",value:o}),o=""),f++;else if(s==="["){o&&(e.push({type:"key",value:o}),o=""),f++;let t=f;for(;f<i&&n[f]!=="]";)f++;let r=n.slice(t,f);if(f++,r!=="*"){let c=parseInt(r,10);e.push({type:"index",value:isNaN(c)?r:c});}}else o+=s,f++;}return o&&e.push({type:"key",value:o}),e}function tn(n,e=[L]){return builders.arrowFunctionExpression(e.map(i=>builders.identifier(i)),n)}function D(n,e){let i=new Set;return C(n,i,e),i}function C(n,e,i){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let o of n)C(o,e,i);return}if(h(n))return;if(A(n)){C(n.$if,e,i),C(n.then,e,i),n.else!==void 0&&C(n.else,e,i);return}if(k(n)){for(let o of n.$pipe)C(o,e,i);return}if($(n)){if(e.add(n.$fn),n.args)for(let o of n.args)typeof o!="function"&&C(o,e,i);return}if(E(n)){n.left!==void 0&&typeof n.left=="object"&&C(n.left,e,i),n.right!==void 0&&typeof n.right=="object"&&C(n.right,e,i);return}if(T(n)){for(let o of n.conditions)C(o,e,i);return}if(i){let o=n,s=Object.keys(o);for(let t=0;t<s.length;t++){let r=s[t];if(r in i){let c=i[r](o);if(typeof c=="object"&&c!==null&&r in c)throw new Error(`Transform "${r}" returned object with same key \u2014 infinite loop`);C(c,e,i);return}}}let f=n;for(let o of Object.keys(f))C(f[o],e,i);}function I(n){let e=new Set;for(let i of n){let f=i.indexOf("."),o=i.indexOf("["),s=i.length;f!==-1&&(s=Math.min(s,f)),o!==-1&&(s=Math.min(s,o));let t=i.slice(0,s);t&&e.add(t);}return e}function _n(n){return JSON.stringify(n)}function qn(n,e,i,f,o,s){let t=W(n,{noPrefixes:true,useAccessor:f,lexicalPrefix:o,transforms:s}),r=generate(t),c="";f?o&&(c=`const{${o}}=data??{};`):e.size>0&&(c=`const{${[...e].join(",")}}=data??{};`);let l=f?new Set([...i,"accessor"]):i,a=l.size>0?`const{${[...l].join(",")}}=scope;`:"";return a?`(function(scope){${a}return function(data){${c}return ${r}}})`:`(function(){return function(data){${c}return ${r}}})`}function q(n,e={}){let{scope:i={},returnCode:f=false,useAccessor:o=false,lexicalPrefix:s,transforms:t}=e,r=w(n,t),c=I(r),l=D(n,t),a=_n(n),p=qn(n,c,l,o,s,t);if(f)return {code:p,deps:r,hash:a,dataRoots:[...c],scopeFns:[...l]};let d;try{d=new Function(`return ${p}`)()(i);}catch(g){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${g instanceof Error?g.message:String(g)}`)}return {fn:d,deps:r,hash:a}}function on(n,e,i={}){let{fn:f}=q(n,i);return f(e)}var Ee="0.1.1";export{v as ExpressionCache,Ee as VERSION,wn as assertValid,Z as builders,Y as cache,Sn as cached,dn as clearPathCache,N as compile,q as compileAST,O as compilePath,W as dslToAST,kn as evaluate,on as evaluateAST,I as extractDataRoots,w as extractDeps,D as extractScopeFns,pn as get,gn as getPathCacheSize,yn as hasDeps,B as hasWildcard,E as isCondition,fn as isConditionExpr,T as isConditionGroup,A as isConditional,$ as isFn,M as isLiteral,k as isPipe,mn as isPure,h as isRef,Rn as isValid,j as normalizePath,z as validate,tn as wrapInFunction};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statedelta-libs/expressions",
3
- "version": "1.0.0",
3
+ "version": "1.2.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
- "@statedelta-libs/conditions": "^1.0.0",
18
- "omni-ast": "^2.0.0"
17
+ "omni-ast": "^2.0.2"
19
18
  },
20
19
  "files": [
21
20
  "dist",