@statedelta-libs/expressions 1.1.0 → 1.2.1

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
@@ -15,6 +15,7 @@
15
15
  - **Path syntax** - Suporte a wildcards (`items[*].price`)
16
16
  - **Dependency extraction** - Para dirty tracking/reatividade
17
17
  - **Conditions nativo** - Condicionais integradas com expressions nos lados
18
+ - **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
@@ -455,6 +456,120 @@ Ambas as abordagens são **seguras contra injeção de código**:
455
456
 
456
457
  Funções só são acessíveis se existirem no `scope` fornecido pelo desenvolvedor.
457
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
+ Transforms retornam `Expression` ou `TransformResult`. Use `TransformResult` quando os args contêm tipos domain-specific (não `FnArg`):
466
+
467
+ ```typescript
468
+ import type { TransformFn, TransformResult } from '@statedelta-libs/expressions';
469
+
470
+ const transforms: Record<string, TransformFn> = {
471
+ // TransformResult.args aceita unknown[] — sem casts necessários
472
+ $query: (node) => ({
473
+ $fn: "__query",
474
+ args: [node.$query, node.params ?? {}]
475
+ }),
476
+ $test: (node) => ({
477
+ $fn: "__test",
478
+ args: [node.$test] // TestSpec, QueryParams, etc. — qualquer tipo
479
+ }),
480
+ };
481
+ ```
482
+
483
+ ### Uso com compile() e compileAST()
484
+
485
+ ```typescript
486
+ import { compile, compileAST } from '@statedelta-libs/expressions';
487
+
488
+ const scope = {
489
+ __query: (name, params) => queryEngine.run(name, params),
490
+ };
491
+
492
+ // Closures
493
+ const { fn } = compile(
494
+ { $query: "isKingAttacked", params: { row: 0, col: 4 } },
495
+ { scope, transforms }
496
+ );
497
+
498
+ // AST (mesmo contrato)
499
+ const { fn } = compileAST(
500
+ { $query: "isKingAttacked", params: { row: 0, col: 4 } },
501
+ { scope, transforms }
502
+ );
503
+ ```
504
+
505
+ ### Expressions dentro de params
506
+
507
+ Os params do transform são compilados recursivamente — referências e expressões dentro deles são resolvidas normalmente:
508
+
509
+ ```typescript
510
+ const { fn } = compile(
511
+ { $query: "check", params: { row: { $: "myRow" }, col: { $: "myCol" } } },
512
+ { scope, transforms }
513
+ );
514
+
515
+ fn({ myRow: 5, myCol: 3 });
516
+ // → __query("check", { row: 5, col: 3 })
517
+ ```
518
+
519
+ ### Aninhamento
520
+
521
+ Transforms funcionam em qualquer posição — dentro de `$if`, `$pipe`, `$fn`, conditions, plain objects:
522
+
523
+ ```typescript
524
+ // Dentro de condition
525
+ {
526
+ $if: {
527
+ left: { $query: "isAttacked", params: { row: 0 } },
528
+ op: "eq",
529
+ right: true
530
+ },
531
+ then: "check",
532
+ else: "safe"
533
+ }
534
+
535
+ // Dentro de plain object (walk automático)
536
+ {
537
+ damage: { $query: "getDamage", params: { base: 10 } },
538
+ name: "attack"
539
+ }
540
+ ```
541
+
542
+ ### Extração de deps
543
+
544
+ `extractDeps` também resolve transforms para capturar dependências internas:
545
+
546
+ ```typescript
547
+ import { extractDeps } from '@statedelta-libs/expressions';
548
+
549
+ const deps = extractDeps(
550
+ { $query: "check", params: { row: { $: "myRow" } } },
551
+ transforms
552
+ );
553
+ // ["myRow"]
554
+ ```
555
+
556
+ ### Proteção contra loops infinitos
557
+
558
+ Se um transform retornar um objeto com a mesma chave de entrada, um erro é lançado:
559
+
560
+ ```typescript
561
+ const badTransforms = {
562
+ $loop: (node) => ({ $loop: node.$loop }), // mesma chave!
563
+ };
564
+
565
+ compile({ $loop: "test" }, { transforms: badTransforms });
566
+ // Error: Transform "$loop" returned object with same key — infinite loop
567
+ ```
568
+
569
+ ### Performance
570
+
571
+ 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.
572
+
458
573
  ## Type Detection
459
574
 
460
575
  O compilador detecta automaticamente o tipo de expressão baseado na estrutura do objeto:
@@ -466,6 +581,7 @@ O compilador detecta automaticamente o tipo de expressão baseado na estrutura d
466
581
  | Function | `{ $fn }` presente | `{ $fn: "add", args: [...] }` |
467
582
  | Pipe | `{ $pipe }` presente | `{ $pipe: [...] }` |
468
583
  | Condition | `{ left, op }` com operador válido | `{ left: { $: "age" }, op: "gte", right: 18 }` |
584
+ | Custom Transform | Chave registrada em `transforms` | `{ $query: "check", params: {...} }` |
469
585
  | Literal | Nenhum dos acima | `{ foo: "bar" }`, `42`, `"hello"` |
470
586
 
471
587
  ### Distinção entre Conditions e Effect Objects
@@ -616,6 +732,8 @@ import type {
616
732
  Scope,
617
733
  CompileOptions,
618
734
  AccessorFn,
735
+ TransformFn,
736
+ TransformResult,
619
737
  } from '@statedelta-libs/expressions';
620
738
 
621
739
  // Type guards
@@ -626,6 +744,7 @@ import {
626
744
  isPipe,
627
745
  isCondition,
628
746
  isLiteral,
747
+ isTransformResult,
629
748
  } from '@statedelta-libs/expressions';
630
749
  ```
631
750
 
@@ -668,6 +787,37 @@ import {
668
787
 
669
788
  4. **Novos tipos**: `ConditionOp`, `Condition`, `ConditionGroup`, `ConditionExpr` exportados diretamente do expressions.
670
789
 
790
+ ### v1.1 → v1.2
791
+
792
+ 1. **Custom Transforms**: Nova option `transforms` em `CompileOptions` e `CompileASTOptions`. Permite estender o walker com tipos de expressão customizados (`$query`, `$mapper`, etc.):
793
+ ```typescript
794
+ const transforms = {
795
+ $query: (node) => ({ $fn: "__query", args: [node.$query, node.params ?? {}] }),
796
+ };
797
+ compile(expr, { scope, transforms });
798
+ compileAST(expr, { scope, transforms });
799
+ ```
800
+
801
+ 2. **extractDeps com transforms**: `extractDeps` agora aceita `transforms` como segundo argumento para capturar deps dentro de expressões customizadas:
802
+ ```typescript
803
+ extractDeps(expr, transforms);
804
+ ```
805
+
806
+ 3. **Novos tipos**: `TransformFn` e `TransformResult` exportados diretamente do expressions.
807
+
808
+ 4. **TransformResult**: Transforms podem retornar `TransformResult` com `args: unknown[]` para tipos domain-specific:
809
+ ```typescript
810
+ // TransformResult.args aceita unknown[] — sem casts necessários
811
+ const transforms: Record<string, TransformFn> = {
812
+ $test: (node) => ({
813
+ $fn: "__test",
814
+ args: [node.$test] // TestSpec, QueryParams, etc.
815
+ }),
816
+ };
817
+ ```
818
+
819
+ 5. **Zero breaking change**: O campo `transforms` é opcional. Sem ele, o comportamento é idêntico ao anterior.
820
+
671
821
  ## Licença
672
822
 
673
823
  MIT © Anderson D. Rosa
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var omniAst=require('omni-ast');var on=Object.defineProperty;var rn=(n,t)=>{for(var s in t)on(n,s,{get:t[s],enumerable:true});};var y=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,T=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,b=n=>n!==null&&typeof n=="object"&&"$fn"in n&&typeof n.$fn=="string",C=n=>n!==null&&typeof n=="object"&&"$pipe"in n&&Array.isArray(n.$pipe),x=new Set(["eq","neq","gt","gte","lt","lte","in","notIn","contains","notContains","exists","notExists","matches","notMatches","startsWith","endsWith"]),h=n=>n!==null&&typeof n=="object"&&"left"in n&&"op"in n&&x.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),E=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,sn=n=>h(n)||E(n),I=n=>{if(n===null)return true;let t=typeof n;if(t==="string"||t==="number"||t==="boolean"||Array.isArray(n))return true;if(t==="object"&&n!==null){let s=n,e="left"in s&&"op"in s&&x.has(s.op);return !("$"in s)&&!("$if"in s)&&!("$fn"in s)&&!("$pipe"in s)&&!e&&!("logic"in s)}return false};var R=new Map;function q(n){let t=[],s=n.length,e=0,r="";for(;e<s;){let o=n[e];if(o===".")r&&(t.push({type:"key",value:r}),r=""),e++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),e++;let i=e;for(;e<s&&n[e]!=="]";)e++;let f=n.slice(i,e);if(e++,f==="*")t.push({type:"wildcard",value:"*"});else {let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,e++;}return r&&t.push({type:"key",value:r}),t}function J(n){return n.includes("[*]")}function O(n){let t=R.get(n);return t||(t=J(n)?un(n):fn(n),R.set(n,t),t)}function fn(n){if(!n.includes(".")&&!n.includes("["))return r=>r?.[n];let t=q(n),s=t.length;if(s===2){let[r,o]=t,i=r.value,f=o.value;return l=>l?.[i]?.[f]}if(s===3){let[r,o,i]=t,f=r.value,l=o.value,c=i.value;return a=>a?.[f]?.[l]?.[c]}let e=t.map(r=>r.value);return r=>{let o=r;for(let i=0;i<s&&o!=null;i++)o=o[e[i]];return o}}function un(n){let t=q(n),s=[];for(let e=0;e<t.length;e++)t[e].type==="wildcard"&&s.push(e);return s.length===1?ln(t,s[0]):cn(t,s)}function ln(n,t){let s=n.slice(0,t).map(i=>i.value),e=n.slice(t+1).map(i=>i.value),r=s.length,o=e.length;if(o===0){if(r===1){let i=s[0];return f=>f?.[i]}return i=>{let f=i;for(let l=0;l<r&&f!=null;l++)f=f[s[l]];return f}}if(o===1){let i=e[0];if(r===1){let f=s[0];return l=>{let c=l?.[f];if(Array.isArray(c))return c.map(a=>a?.[i])}}return f=>{let l=f;for(let c=0;c<r&&l!=null;c++)l=l[s[c]];if(Array.isArray(l))return l.map(c=>c?.[i])}}return i=>{let f=i;for(let l=0;l<r&&f!=null;l++)f=f[s[l]];if(Array.isArray(f))return f.map(l=>{let c=l;for(let a=0;a<o&&c!=null;a++)c=c[e[a]];return c})}}function cn(n,t){let s=[],e=0;for(let o=0;o<t.length;o++){let i=t[o],f=o===t.length-1,l=n.slice(e,i).map(c=>c.value);l.length>0&&s.push({type:"access",keys:l}),s.push({type:f?"map":"flatMap",keys:[]}),e=i+1;}let r=n.slice(e).map(o=>o.value);return o=>{let i=o;for(let f of s){if(i==null)return;if(f.type==="access")for(let l of f.keys){if(i==null)return;i=i[l];}else if(f.type==="flatMap"){if(!Array.isArray(i))return;i=i.flatMap(l=>{let c=l;return Array.isArray(c)?c:[c]});}else if(f.type==="map"){if(!Array.isArray(i))return;r.length>0&&(i=i.map(l=>{let c=l;for(let a of r){if(c==null)return;c=c[a];}return c}));}}return i}}function an(n,t){return O(t)(n)}function F(n){let t=n.indexOf("[*]");return t===-1?n:n.slice(0,t)}function pn(){R.clear();}function dn(){return R.size}function k(n){let t=new Set;return A(n,t),Array.from(t)}function A(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r=0;r<n.length;r++)A(n[r],t);return}if(y(n)){t.add(F(n.$));return}if(T(n)){if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if;t.add(F(r));}else A(n.$if,t);A(n.then,t),n.else!==void 0&&A(n.else,t);return}if(C(n)){for(let r=0;r<n.$pipe.length;r++)A(n.$pipe[r],t);return}if(b(n)){if(n.args)for(let r=0;r<n.args.length;r++){let o=n.args[r];typeof o!="function"&&A(o,t);}return}if(h(n)){A(n.left,t),n.right!==void 0&&A(n.right,t);return}if(E(n)){for(let r=0;r<n.conditions.length;r++)A(n.conditions[r],t);return}let s=n,e=Object.keys(s);for(let r=0;r<e.length;r++)A(s[e[r]],t);}function gn(n){return k(n).length>0}function mn(n){return k(n).length===0}function yn(n){return JSON.stringify(n)}function N(n,t={}){let s=t.scope??{},e=t.accessor,r=m(n,s,e),o=k(n),i=yn(n);return {fn:r,deps:o,hash:i}}function m(n,t,s){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let e=n.map(r=>m(r,t,s));return r=>e.map(o=>o(r))}if(y(n))return hn(n,s);if(T(n))return En(n,t,s);if(C(n))return Tn(n,t,s);if(b(n))return bn(n,t,s);if(h(n))return Cn(n,t,s);if(E(n))return An(n,t,s);if(I(n)){let e=n,r=Object.keys(e),o=r.map(i=>m(e[i],t,s));return i=>{let f={};for(let l=0;l<r.length;l++)f[r[l]]=o[l](i);return f}}return ()=>n}function B(n,t){return t?s=>t(n,s):O(n)}function hn(n,t){return B(n.$,t)}function En(n,t,s){let e;if(typeof n.$if=="string"){let i=n.$if.startsWith("!")?n.$if.slice(1):n.$if,f=B(i,s);e=n.$if.startsWith("!")?c=>!f(c):c=>!!f(c);}else {let i=m(n.$if,t,s);e=f=>!!i(f);}let r=m(n.then,t,s),o=n.else!==void 0?m(n.else,t,s):()=>{};return i=>e(i)?r(i):o(i)}function Tn(n,t,s){let e=n.$pipe;if(e.length===0)return ()=>{};if(e.length===1)return m(e[0],t,s);let r=m(e[0],t,s),o=e.slice(1).map(f=>m(f,t,s)),i=o.length;if(i===1){let[f]=o;return l=>{let c=r(l),a=f(l);return typeof a=="function"?a(c):a}}if(i===2){let[f,l]=o;return c=>{let a=r(c),p=f(c);return a=typeof p=="function"?p(a):p,p=l(c),typeof p=="function"?p(a):p}}if(i===3){let[f,l,c]=o;return a=>{let p=r(a),d=f(a);return p=typeof d=="function"?d(p):d,d=l(a),p=typeof d=="function"?d(p):d,d=c(a),typeof d=="function"?d(p):d}}return f=>{let l=r(f);for(let c=0;c<i;c++){let a=o[c](f);l=typeof a=="function"?a(l):a;}return l}}function bn(n,t,s){let e=n.$fn,r=n.args;if(r===void 0)return ()=>{let f=t[e];if(!f)throw new Error(`Function not found in scope: ${e}`);return f};let o=r.map(f=>typeof f=="function"?()=>f:m(f,t,s)),i=o.length;if(i===0)return f=>{let l=t[e];if(!l)throw new Error(`Function not found in scope: ${e}`);return l()};if(i===1){let[f]=o;return l=>{let c=t[e];if(!c)throw new Error(`Function not found in scope: ${e}`);return c(f(l))}}if(i===2){let[f,l]=o;return c=>{let a=t[e];if(!a)throw new Error(`Function not found in scope: ${e}`);return a(f(c),l(c))}}if(i===3){let[f,l,c]=o;return a=>{let p=t[e];if(!p)throw new Error(`Function not found in scope: ${e}`);return p(f(a),l(a),c(a))}}return f=>{let l=t[e];if(!l)throw new Error(`Function not found in scope: ${e}`);return l(...o.map(c=>c(f)))}}function Cn(n,t,s){let e=m(n.left,t,s),r=n.right!==void 0?m(n.right,t,s):()=>{};switch(n.op){case "eq":return o=>e(o)===r(o);case "neq":return o=>e(o)!==r(o);case "gt":return o=>e(o)>r(o);case "gte":return o=>e(o)>=r(o);case "lt":return o=>e(o)<r(o);case "lte":return o=>e(o)<=r(o);case "in":return o=>{let i=r(o);return Array.isArray(i)&&i.includes(e(o))};case "notIn":return o=>{let i=r(o);return !Array.isArray(i)||!i.includes(e(o))};case "contains":return o=>{let i=e(o);return Array.isArray(i)&&i.includes(r(o))};case "notContains":return o=>{let i=e(o);return !Array.isArray(i)||!i.includes(r(o))};case "exists":return o=>e(o)!==void 0;case "notExists":return o=>e(o)===void 0;case "matches":return o=>{let i=e(o),f=r(o);return typeof i!="string"||typeof f!="string"?false:new RegExp(f).test(i)};case "notMatches":return o=>{let i=e(o),f=r(o);return typeof i!="string"||typeof f!="string"?true:!new RegExp(f).test(i)};case "startsWith":return o=>{let i=e(o),f=r(o);return typeof i=="string"&&typeof f=="string"&&i.startsWith(f)};case "endsWith":return o=>{let i=e(o),f=r(o);return typeof i=="string"&&typeof f=="string"&&i.endsWith(f)}}}function An(n,t,s){let e=n.conditions.map(o=>m(o,t,s)),r=e.length;if(r===1)return o=>!!e[0](o);if(r===2){let[o,i]=e;return n.logic==="AND"?f=>!!o(f)&&!!i(f):f=>!!o(f)||!!i(f)}if(r===3){let[o,i,f]=e;return n.logic==="AND"?l=>!!o(l)&&!!i(l)&&!!f(l):l=>!!o(l)||!!i(l)||!!f(l)}return n.logic==="AND"?o=>{for(let i=0;i<r;i++)if(!e[i](o))return false;return true}:o=>{for(let i=0;i<r;i++)if(e[i](o))return true;return false}}function $n(n,t,s={}){return N(n,s).fn(t)}var v=class{constructor(t=1e3){this.cache=new Map,this._maxSize=t;}get(t,s={}){let e=JSON.stringify(t),r=this.cache.get(e);if(r)return this.cache.delete(e),this.cache.set(e,r),r;let o=N(t,s);if(this.cache.size>=this._maxSize){let i=this.cache.keys().next().value;i&&this.cache.delete(i);}return this.cache.set(e,o),o}has(t){return this.cache.has(JSON.stringify(t))}delete(t){return this.cache.delete(JSON.stringify(t))}clear(){this.cache.clear();}get size(){return this.cache.size}get maxSize(){return this._maxSize}set maxSize(t){for(this._maxSize=t;this.cache.size>this._maxSize;){let s=this.cache.keys().next().value;s&&this.cache.delete(s);}}},K=new v;function Sn(n,t={}){return K.get(n,t)}function M(n,t="root",s={}){let e=[];return $(n,t,e,s),{valid:e.length===0,errors:e}}function $(n,t,s,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let i=0;i<n.length;i++)$(n[i],`${t}[${i}]`,s,e);return}if(y(n)){(!n.$||typeof n.$!="string")&&s.push(`${t}: invalid reference, $ must be non-empty string`);return}if(T(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||s.push(`${t}.$if: empty path in string shorthand`):$(n.$if,`${t}.$if`,s,e),$(n.then,`${t}.then`,s,e),n.else!==void 0&&$(n.else,`${t}.else`,s,e);return}if(C(n)){if(!Array.isArray(n.$pipe)){s.push(`${t}.$pipe: must be an array`);return}if(n.$pipe.length===0){s.push(`${t}.$pipe: must have at least one element`);return}for(let i=0;i<n.$pipe.length;i++)$(n.$pipe[i],`${t}.$pipe[${i}]`,s,e);return}if(b(n)){if(!n.$fn||typeof n.$fn!="string"){s.push(`${t}: invalid function, $fn must be non-empty string`);return}if(e.scope&&!(n.$fn in e.scope)&&s.push(`${t}: function "${n.$fn}" not found in scope`),n.args!==void 0)if(!Array.isArray(n.args))s.push(`${t}.args: must be an array`);else for(let i=0;i<n.args.length;i++){let f=n.args[i];typeof f!="function"&&$(f,`${t}.args[${i}]`,s,e);}return}if(h(n)){x.has(n.op)||s.push(`${t}: invalid operator "${n.op}"`),$(n.left,`${t}.left`,s,e),n.right!==void 0&&$(n.right,`${t}.right`,s,e);return}if(E(n)){if(n.logic!=="AND"&&n.logic!=="OR"&&s.push(`${t}: invalid logic "${n.logic}", must be "AND" or "OR"`),!Array.isArray(n.conditions)){s.push(`${t}.conditions: must be an array`);return}for(let i=0;i<n.conditions.length;i++)$(n.conditions[i],`${t}.conditions[${i}]`,s,e);return}let r=n,o=Object.keys(r);for(let i=0;i<o.length;i++){let f=o[i];$(r[f],`${t}.${f}`,s,e);}}function kn(n,t={}){let s=M(n,"root",t);if(!s.valid)throw new Error(`Invalid expression: ${s.errors.join("; ")}`)}function wn(n,t={}){return M(n,"root",t).valid}var U={};rn(U,{$:()=>P,$cond:()=>Q,$fn:()=>Y,$if:()=>On,$pipe:()=>H,cond:()=>Nn,fn:()=>Rn,pipe:()=>Fn,ref:()=>xn});function P(n){return {$:n}}var xn=P;function Y(n,t){return t===void 0||t.length===0?{$fn:n}:{$fn:n,args:t}}var Rn=Y;function On(n,t,s){return s===void 0?{$if:n,then:t}:{$if:n,then:t,else:s}}function H(...n){return {$pipe:n}}var Fn=H;function Q(n,t,s){return s===void 0?{left:n,op:t}:{left:n,op:t,right:s}}var Nn=Q;var z="data",Z="scope",vn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function G(n,t={}){let{dataParam:s=z,scopeParam:e=Z,noPrefixes:r=false,useAccessor:o=false,lexicalPrefix:i}=t;return g(n,s,e,r,o,i)}function g(n,t,s,e,r,o){if(n===null)return omniAst.builders.literal(null);if(typeof n=="string")return omniAst.builders.literal(n);if(typeof n=="number")return omniAst.builders.literal(n);if(typeof n=="boolean")return omniAst.builders.literal(n);if(Array.isArray(n))return omniAst.builders.arrayExpression(n.map(i=>g(i,t,s,e,r,o)));if(y(n))return jn(n.$,t,e,r,o);if(T(n))return Wn(n,t,s,e,r,o);if(C(n))return In(n.$pipe,t,s,e,r,o);if(b(n))return Dn(n,t,s,e,r,o);if(h(n))return Mn(n,t,s,e,r,o);if(E(n))return zn(n,t,s,e,r,o);if(typeof n=="object"){let f=Object.entries(n).map(([l,c])=>omniAst.builders.property(omniAst.builders.identifier(l),g(c,t,s,e,r,o)));return omniAst.builders.objectExpression(f)}return omniAst.builders.literal(null)}var L="accessor";function V(n,t){return t?n===t||n.startsWith(t+"."):false}function jn(n,t,s,e,r){return e?V(n,r)?w(n,t,true):omniAst.builders.callExpression(omniAst.builders.identifier(L),[omniAst.builders.literal(n),omniAst.builders.identifier(t)]):n.includes("[*]")?Gn(n,t,s):w(n,t,s)}function w(n,t,s){let e=j(n);if(e.length===0)return s?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(t);let r;if(s){let o=e[0];r=omniAst.builders.identifier(o.value);for(let i=1;i<e.length;i++){let f=e[i];f.type==="key"?r=omniAst.builders.memberExpression(r,omniAst.builders.identifier(f.value),false,true):r=omniAst.builders.memberExpression(r,omniAst.builders.literal(f.value),true,true);}}else {r=omniAst.builders.identifier(t);for(let o of e)o.type==="key"?r=omniAst.builders.memberExpression(r,omniAst.builders.identifier(o.value),false,true):r=omniAst.builders.memberExpression(r,omniAst.builders.literal(o.value),true,true);}return r}function Gn(n,t,s){let e=n.indexOf("[*]"),r=n.slice(0,e),o=n.slice(e+3),i;if(r?i=w(r,t,s):i=s?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(t),!o||o==="")return i;if(o.includes("[*]"))return nn(i,o);let f="_i",l=o.startsWith(".")?o.slice(1):o,c=omniAst.builders.identifier(f);if(l){let a=j(l);for(let p of a)p.type==="key"?c=omniAst.builders.memberExpression(c,omniAst.builders.identifier(p.value),false,true):c=omniAst.builders.memberExpression(c,omniAst.builders.literal(p.value),true,true);}return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("map"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(f)],c)])}function nn(n,t){let s=t.indexOf("[*]"),e=t.slice(0,s),r=t.slice(s+3),o="_i",i=e.startsWith(".")?e.slice(1):e,f=omniAst.builders.identifier(o);if(i){let c=j(i);for(let a of c)a.type==="key"&&(f=omniAst.builders.memberExpression(f,omniAst.builders.identifier(a.value),false,true));}if(r.includes("[*]")){let c=nn(f,r);return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(o)],c)])}let l=r.startsWith(".")?r.slice(1):r;if(l){let c=j(l);for(let a of c)a.type==="key"&&(f=omniAst.builders.memberExpression(f,omniAst.builders.identifier(a.value),false,true));}return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(o)],f)])}function Wn(n,t,s,e,r,o){let i;if(typeof n.$if=="string"){let c=n.$if.startsWith("!"),a=c?n.$if.slice(1):n.$if,p;r?V(a,o)?p=w(a,t,true):p=omniAst.builders.callExpression(omniAst.builders.identifier(L),[omniAst.builders.literal(a),omniAst.builders.identifier(t)]):p=w(a,t,e),i=c?omniAst.builders.unaryExpression("!",p):p;}else i=g(n.$if,t,s,e,r,o);let f=g(n.then,t,s,e,r,o),l=n.else!==void 0?g(n.else,t,s,e,r,o):omniAst.builders.identifier("undefined");return omniAst.builders.conditionalExpression(i,f,l)}function Dn(n,t,s,e,r,o){let i=e?omniAst.builders.identifier(n.$fn):omniAst.builders.memberExpression(omniAst.builders.identifier(s),omniAst.builders.identifier(n.$fn),false,false);if(n.args===void 0)return i;let f=n.args.map(l=>typeof l=="function"?omniAst.builders.literal(null):g(l,t,s,e,r,o));return omniAst.builders.callExpression(i,f)}function In(n,t,s,e,r,o){if(n.length===0)return omniAst.builders.identifier("undefined");if(n.length===1)return g(n[0],t,s,e,r,o);let i=g(n[0],t,s,e,r,o);for(let f=1;f<n.length;f++){let l=g(n[f],t,s,e,r,o);i=omniAst.builders.callExpression(l,[i]);}return i}function X(n,t,s,e,r,o){if(y(n)){let i=n.$;return r?V(i,o)?w(i,t,true):omniAst.builders.callExpression(omniAst.builders.identifier(L),[omniAst.builders.literal(i),omniAst.builders.identifier(t)]):w(i,t,e)}return g(n,t,s,e,r,o)}function Mn(n,t,s,e,r,o){let i=X(n.left,t,s,e,r,o),f=n.right!==void 0?X(n.right,t,s,e,r,o):omniAst.builders.literal(null),l=vn[n.op];if(l)return omniAst.builders.binaryExpression(l,i,f);switch(n.op){case "in":return omniAst.builders.callExpression(omniAst.builders.memberExpression(f,omniAst.builders.identifier("includes")),[i]);case "notIn":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(f,omniAst.builders.identifier("includes")),[i]));case "contains":return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("includes"),false,true),[f]);case "notContains":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("includes"),false,true),[f]));case "exists":return omniAst.builders.binaryExpression("!=",i,omniAst.builders.literal(null));case "notExists":return omniAst.builders.binaryExpression("==",i,omniAst.builders.literal(null));case "matches":return omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[f]),omniAst.builders.identifier("test")),[i]);case "notMatches":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[f]),omniAst.builders.identifier("test")),[i]));case "startsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("startsWith"),false,true),[f]);case "endsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("endsWith"),false,true),[f]);default:return omniAst.builders.binaryExpression("===",i,f)}}function zn(n,t,s,e,r,o){let{logic:i,conditions:f}=n,l=i==="AND"?"&&":"||";if(f.length===0)return omniAst.builders.literal(i==="AND");if(f.length===1)return g(f[0],t,s,e,r,o);let c=g(f[0],t,s,e,r,o);for(let a=1;a<f.length;a++){let p=g(f[a],t,s,e,r,o);c=omniAst.builders.logicalExpression(l,c,p);}return c}function j(n){let t=[],s=n.length,e=0,r="";for(;e<s;){let o=n[e];if(o===".")r&&(t.push({type:"key",value:r}),r=""),e++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),e++;let i=e;for(;e<s&&n[e]!=="]";)e++;let f=n.slice(i,e);if(e++,f!=="*"){let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,e++;}return r&&t.push({type:"key",value:r}),t}function tn(n,t=[z]){return omniAst.builders.arrowFunctionExpression(t.map(s=>omniAst.builders.identifier(s)),n)}function W(n){let t=new Set;return S(n,t),t}function S(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let e of n)S(e,t);return}if(y(n))return;if(T(n)){S(n.$if,t),S(n.then,t),n.else!==void 0&&S(n.else,t);return}if(C(n)){for(let e of n.$pipe)S(e,t);return}if(b(n)){if(t.add(n.$fn),n.args)for(let e of n.args)typeof e!="function"&&S(e,t);return}if(h(n)){n.left!==void 0&&typeof n.left=="object"&&S(n.left,t),n.right!==void 0&&typeof n.right=="object"&&S(n.right,t);return}if(E(n)){for(let e of n.conditions)S(e,t);return}let s=n;for(let e of Object.keys(s))S(s[e],t);}function D(n){let t=new Set;for(let s of n){let e=s.indexOf("."),r=s.indexOf("["),o=s.length;e!==-1&&(o=Math.min(o,e)),r!==-1&&(o=Math.min(o,r));let i=s.slice(0,o);i&&t.add(i);}return t}function Vn(n){return JSON.stringify(n)}function _n(n,t,s,e,r){let o=G(n,{noPrefixes:true,useAccessor:e,lexicalPrefix:r}),i=omniAst.generate(o),f="";e?r&&(f=`const{${r}}=data??{};`):t.size>0&&(f=`const{${[...t].join(",")}}=data??{};`);let l=e?new Set([...s,"accessor"]):s,c=l.size>0?`const{${[...l].join(",")}}=scope;`:"";return c?`(function(scope){${c}return function(data){${f}return ${i}}})`:`(function(){return function(data){${f}return ${i}}})`}function _(n,t={}){let{scope:s={},returnCode:e=false,useAccessor:r=false,lexicalPrefix:o}=t,i=k(n),f=D(i),l=W(n),c=Vn(n),a=_n(n,f,l,r,o);if(e)return {code:a,deps:i,hash:c,dataRoots:[...f],scopeFns:[...l]};let p;try{p=new Function(`return ${a}`)()(s);}catch(d){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${d instanceof Error?d.message:String(d)}`)}return {fn:p,deps:i,hash:c}}function en(n,t,s={}){let{fn:e}=_(n,s);return e(t)}var ht="0.1.1";exports.ExpressionCache=v;exports.VERSION=ht;exports.assertValid=kn;exports.builders=U;exports.cache=K;exports.cached=Sn;exports.clearPathCache=pn;exports.compile=N;exports.compileAST=_;exports.compilePath=O;exports.dslToAST=G;exports.evaluate=$n;exports.evaluateAST=en;exports.extractDataRoots=D;exports.extractDeps=k;exports.extractScopeFns=W;exports.get=an;exports.getPathCacheSize=dn;exports.hasDeps=gn;exports.hasWildcard=J;exports.isCondition=h;exports.isConditionExpr=sn;exports.isConditionGroup=E;exports.isConditional=T;exports.isFn=b;exports.isLiteral=I;exports.isPipe=C;exports.isPure=mn;exports.isRef=y;exports.isValid=wn;exports.normalizePath=F;exports.validate=M;exports.wrapInFunction=tn;
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",fn=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,un=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 u=parseInt(r,10);e.push({type:"index",value:isNaN(u)?r:u});}}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)?ln(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 u=>u?.[t]?.[r]}if(i===3){let[o,s,t]=e,r=o.value,u=s.value,l=t.value;return a=>a?.[r]?.[u]?.[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 ln(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?an(e,i[0]):pn(e,i)}function an(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 u=0;u<o&&r!=null;u++)r=r[i[u]];return r}}if(s===1){let t=f[0];if(o===1){let r=i[0];return u=>{let l=u?.[r];if(Array.isArray(l))return l.map(a=>a?.[t])}}return r=>{let u=r;for(let l=0;l<o&&u!=null;l++)u=u[i[l]];if(Array.isArray(u))return u.map(l=>l?.[t])}}return t=>{let r=t;for(let u=0;u<o&&r!=null;u++)r=r[i[u]];if(Array.isArray(r))return r.map(u=>{let l=u;for(let a=0;a<s&&l!=null;a++)l=l[f[a]];return l})}}function pn(n,e){let i=[],f=0;for(let s=0;s<e.length;s++){let t=e[s],r=s===e.length-1,u=n.slice(f,t).map(l=>l.value);u.length>0&&i.push({type:"access",keys:u}),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 u of r.keys){if(t==null)return;t=t[u];}else if(r.type==="flatMap"){if(!Array.isArray(t))return;t=t.flatMap(u=>{let l=u;return Array.isArray(l)?l:[l]});}else if(r.type==="map"){if(!Array.isArray(t))return;o.length>0&&(t=t.map(u=>{let l=u;for(let a of o){if(l==null)return;l=l[a];}return l}));}}return t}}function dn(n,e){return O(e)(n)}function j(n){let e=n.indexOf("[*]");return e===-1?n:n.slice(0,e)}function gn(){x.clear();}function yn(){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 u=t[r];if(u in i){let l=i[u](s);if(typeof l=="object"&&l!==null&&u in l)throw new Error(`Transform "${u}" 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 mn(n){return w(n).length>0}function hn(n){return w(n).length===0}function En(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=En(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 Tn(n,i);if(A(n))return bn(n,e,i,f);if(k(n))return Cn(n,e,i,f);if($(n))return An(n,e,i,f);if(E(n))return $n(n,e,i,f);if(T(n))return kn(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 u=f[r](o);if(typeof u=="object"&&u!==null&&r in u)throw new Error(`Transform "${r}" returned object with same key \u2014 infinite loop`);return m(u,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 u={};for(let l=0;l<s.length;l++)u[s[l]]=t[l](r);return u}}return ()=>n}function K(n,e){return e?i=>e(n,i):O(n)}function Tn(n,e){return K(n.$,e)}function bn(n,e,i,f){let o;if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if,u=K(r,i);o=n.$if.startsWith("!")?a=>!u(a):a=>!!u(a);}else {let r=m(n.$if,e,i,f);o=u=>!!r(u);}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 Cn(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(u=>m(u,e,i,f)),r=t.length;if(r===1){let[u]=t;return l=>{let a=s(l),p=u(l);return typeof p=="function"?p(a):p}}if(r===2){let[u,l]=t;return a=>{let p=s(a),d=u(a);return p=typeof d=="function"?d(p):d,d=l(a),typeof d=="function"?d(p):d}}if(r===3){let[u,l,a]=t;return p=>{let d=s(p),g=u(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 u=>{let l=s(u);for(let a=0;a<r;a++){let p=t[a](u);l=typeof p=="function"?p(l):p;}return l}}function An(n,e,i,f){let o=n.$fn,s=n.args;if(s===void 0)return ()=>{let u=e[o];if(!u)throw new Error(`Function not found in scope: ${o}`);return u};let t=s.map(u=>typeof u=="function"?()=>u:m(u,e,i,f)),r=t.length;if(r===0)return u=>{let l=e[o];if(!l)throw new Error(`Function not found in scope: ${o}`);return l()};if(r===1){let[u]=t;return l=>{let a=e[o];if(!a)throw new Error(`Function not found in scope: ${o}`);return a(u(l))}}if(r===2){let[u,l]=t;return a=>{let p=e[o];if(!p)throw new Error(`Function not found in scope: ${o}`);return p(u(a),l(a))}}if(r===3){let[u,l,a]=t;return p=>{let d=e[o];if(!d)throw new Error(`Function not found in scope: ${o}`);return d(u(p),l(p),a(p))}}return u=>{let l=e[o];if(!l)throw new Error(`Function not found in scope: ${o}`);return l(...t.map(a=>a(u)))}}function $n(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),u=s(t);return typeof r!="string"||typeof u!="string"?false:new RegExp(u).test(r)};case "notMatches":return t=>{let r=o(t),u=s(t);return typeof r!="string"||typeof u!="string"?true:!new RegExp(u).test(r)};case "startsWith":return t=>{let r=o(t),u=s(t);return typeof r=="string"&&typeof u=="string"&&r.startsWith(u)};case "endsWith":return t=>{let r=o(t),u=s(t);return typeof r=="string"&&typeof u=="string"&&r.endsWith(u)}}}function kn(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"?u=>!!t(u)&&!!r(u):u=>!!t(u)||!!r(u)}if(s===3){let[t,r,u]=o;return n.logic==="AND"?l=>!!t(l)&&!!r(l)&&!!u(l):l=>!!t(l)||!!r(l)||!!u(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 Sn(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 wn(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 Rn(n,e={}){let i=z(n,"root",e);if(!i.valid)throw new Error(`Invalid expression: ${i.errors.join("; ")}`)}function Fn(n,e={}){return z(n,"root",e).valid}var Z={};sn(Z,{$:()=>H,$cond:()=>X,$fn:()=>Q,$if:()=>jn,$pipe:()=>U,cond:()=>vn,fn:()=>On,pipe:()=>Nn,ref:()=>xn});function H(n){return {$:n}}var xn=H;function Q(n,e){return e===void 0||e.length===0?{$fn:n}:{$fn:n,args:e}}var On=Q;function jn(n,e,i){return i===void 0?{$if:n,then:e}:{$if:n,then:e,else:i}}function U(...n){return {$pipe:n}}var Nn=U;function X(n,e,i){return i===void 0?{left:n,op:e}:{left:n,op:e,right:i}}var vn=X;var L="data",nn="scope",Gn={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 Wn(n.$,e,f,o,s);if(A(n))return In(n,e,i,f,o,s,t);if(k(n))return zn(n.$pipe,e,i,f,o,s,t);if($(n))return Mn(n,e,i,f,o,s,t);if(E(n))return Ln(n,e,i,f,o,s,t);if(T(n))return Vn(n,e,i,f,o,s,t);if(t&&typeof n=="object"){let r=n,u=Object.keys(r);for(let l=0;l<u.length;l++){let a=u[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 u=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(u)}return omniAst.builders.literal(null)}var V="accessor";function _(n,e){return e?n===e||n.startsWith(e+"."):false}function Wn(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("[*]")?Dn(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 Dn(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",u=s.startsWith(".")?s.slice(1):s,l=omniAst.builders.identifier(r);if(u){let a=G(u);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 u=o.startsWith(".")?o.slice(1):o;if(u){let l=G(u);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 In(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 u=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,u,l)}function Mn(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 u=n.args.map(l=>typeof l=="function"?omniAst.builders.literal(null):y(l,e,i,f,o,s,t));return omniAst.builders.callExpression(r,u)}function zn(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 u=1;u<n.length;u++){let l=y(n[u],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 Ln(n,e,i,f,o,s,t){let r=P(n.left,e,i,f,o,s,t),u=n.right!==void 0?P(n.right,e,i,f,o,s,t):omniAst.builders.literal(null),l=Gn[n.op];if(l)return omniAst.builders.binaryExpression(l,r,u);switch(n.op){case "in":return omniAst.builders.callExpression(omniAst.builders.memberExpression(u,omniAst.builders.identifier("includes")),[r]);case "notIn":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(u,omniAst.builders.identifier("includes")),[r]));case "contains":return omniAst.builders.callExpression(omniAst.builders.memberExpression(r,omniAst.builders.identifier("includes"),false,true),[u]);case "notContains":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(r,omniAst.builders.identifier("includes"),false,true),[u]));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"),[u]),omniAst.builders.identifier("test")),[r]);case "notMatches":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[u]),omniAst.builders.identifier("test")),[r]));case "startsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(r,omniAst.builders.identifier("startsWith"),false,true),[u]);case "endsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(r,omniAst.builders.identifier("endsWith"),false,true),[u]);default:return omniAst.builders.binaryExpression("===",r,u)}}function Vn(n,e,i,f,o,s,t){let{logic:r,conditions:u}=n,l=r==="AND"?"&&":"||";if(u.length===0)return omniAst.builders.literal(r==="AND");if(u.length===1)return y(u[0],e,i,f,o,s,t);let a=y(u[0],e,i,f,o,s,t);for(let p=1;p<u.length;p++){let d=y(u[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 u=parseInt(r,10);e.push({type:"index",value:isNaN(u)?r:u});}}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 u=i[r](o);if(typeof u=="object"&&u!==null&&r in u)throw new Error(`Transform "${r}" returned object with same key \u2014 infinite loop`);C(u,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 qn(n){return JSON.stringify(n)}function Jn(n,e,i,f,o,s){let t=W(n,{noPrefixes:true,useAccessor:f,lexicalPrefix:o,transforms:s}),r=omniAst.generate(t),u="";f?o&&(u=`const{${o}}=data??{};`):e.size>0&&(u=`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){${u}return ${r}}})`:`(function(){return function(data){${u}return ${r}}})`}function q(n,e={}){let{scope:i={},returnCode:f=false,useAccessor:o=false,lexicalPrefix:s,transforms:t}=e,r=w(n,t),u=I(r),l=D(n,t),a=qn(n),p=Jn(n,u,l,o,s,t);if(f)return {code:p,deps:r,hash:a,dataRoots:[...u],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 Te="1.2.1";exports.ExpressionCache=v;exports.VERSION=Te;exports.assertValid=Rn;exports.builders=Z;exports.cache=Y;exports.cached=wn;exports.clearPathCache=gn;exports.compile=N;exports.compileAST=q;exports.compilePath=O;exports.dslToAST=W;exports.evaluate=Sn;exports.evaluateAST=on;exports.extractDataRoots=I;exports.extractDeps=w;exports.extractScopeFns=D;exports.get=dn;exports.getPathCacheSize=yn;exports.hasDeps=mn;exports.hasWildcard=B;exports.isCondition=E;exports.isConditionExpr=un;exports.isConditionGroup=T;exports.isConditional=A;exports.isFn=$;exports.isLiteral=M;exports.isPipe=k;exports.isPure=hn;exports.isRef=h;exports.isTransformResult=fn;exports.isValid=Fn;exports.normalizePath=j;exports.validate=z;exports.wrapInFunction=tn;
package/dist/index.d.cts CHANGED
@@ -47,6 +47,29 @@ interface FnExpr {
47
47
  $fn: string;
48
48
  args?: FnArg[];
49
49
  }
50
+ /**
51
+ * Result of a transform function.
52
+ *
53
+ * Structurally similar to FnExpr but with relaxed args typing.
54
+ * Transforms can return domain-specific types in args (e.g., TestSpec, QueryParams)
55
+ * that will be passed to the scope function at runtime.
56
+ *
57
+ * Type safety for these args comes from the scope function implementation,
58
+ * not from the expression type system.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * // Transform for $test
63
+ * const transform: TransformFn = (node) => ({
64
+ * $fn: "__test",
65
+ * args: [node.$test] // TestSpec, not FnArg
66
+ * });
67
+ * ```
68
+ */
69
+ interface TransformResult {
70
+ readonly $fn: string;
71
+ readonly args?: unknown[];
72
+ }
50
73
  /**
51
74
  * Pipe expression (DSL syntax for composition with initial value)
52
75
  * First element is the initial value, rest are transformers
@@ -133,6 +156,31 @@ interface ValidationResult {
133
156
  * @example { add, subtract, multiply, filter, map, sum }
134
157
  */
135
158
  type Scope = Record<string, (...args: any[]) => any>;
159
+ /**
160
+ * Transform function for custom expression types.
161
+ *
162
+ * Receives the raw node (e.g., { $query: "name", params: {...} }) and returns:
163
+ * - Expression: for complex rewrites to standard expressions
164
+ * - TransformResult: for $fn calls with domain-specific args
165
+ *
166
+ * The returned value is compiled recursively. TransformResult args are
167
+ * compiled as literals and passed to the scope function at runtime.
168
+ *
169
+ * @example
170
+ * ```ts
171
+ * const transforms = {
172
+ * $query: (node) => ({
173
+ * $fn: "__query",
174
+ * args: [node.$query, node.params ?? {}]
175
+ * }),
176
+ * $test: (node) => ({
177
+ * $fn: "__test",
178
+ * args: [node.$test] // TestSpec passed as-is
179
+ * }),
180
+ * };
181
+ * ```
182
+ */
183
+ type TransformFn = (node: Record<string, unknown>) => Expression | TransformResult;
136
184
  /**
137
185
  * Options for compilation
138
186
  */
@@ -148,6 +196,13 @@ interface CompileOptions<T = unknown> {
148
196
  * compile(expr, { accessor: (path, ctx) => ctx.get(path) })
149
197
  */
150
198
  accessor?: AccessorFn<T>;
199
+ /**
200
+ * Custom expression transforms.
201
+ * Key = marker (e.g. "$query"), value = transform function.
202
+ * The walker calls the transform before treating as literal.
203
+ * The returned Expression is compiled recursively.
204
+ */
205
+ transforms?: Record<string, TransformFn>;
151
206
  }
152
207
  /**
153
208
  * Check if value is a reference expression
@@ -161,6 +216,12 @@ declare const isConditional: (v: unknown) => v is ConditionalExpr;
161
216
  * Check if value is a function call expression
162
217
  */
163
218
  declare const isFn: (v: unknown) => v is FnExpr;
219
+ /**
220
+ * Check if value is a transform result.
221
+ * Note: TransformResult is structurally similar to FnExpr,
222
+ * so this guard is mainly for documentation/intent.
223
+ */
224
+ declare const isTransformResult: (v: unknown) => v is TransformResult;
164
225
  /**
165
226
  * Check if value is a pipe expression
166
227
  */
@@ -292,7 +353,7 @@ declare function getPathCacheSize(): number;
292
353
  * @example { "$": "user.age" } → ["user.age"]
293
354
  * @example { "$if": "$isVip", "then": { "$": "price.vip" } } → ["$isVip", "price.vip"]
294
355
  */
295
- declare function extractDeps(expr: Expression): string[];
356
+ declare function extractDeps(expr: Expression, transforms?: Record<string, TransformFn>): string[];
296
357
  /**
297
358
  * Check if expression has dependencies
298
359
  */
@@ -547,6 +608,11 @@ interface TransformOptions {
547
608
  * - `lexicalPrefix: "params"` → `params?.foo` instead of `accessor("params.foo", data)`
548
609
  */
549
610
  lexicalPrefix?: string;
611
+ /**
612
+ * Custom expression transforms.
613
+ * Key = marker (e.g. "$query"), value = transform function.
614
+ */
615
+ transforms?: Record<string, TransformFn>;
550
616
  }
551
617
  /**
552
618
  * Transform DSL expression to AST node
@@ -583,6 +649,7 @@ declare function wrapInFunction(bodyAst: ASTNode, params?: string[]): ASTNode;
583
649
  * Extract all function names used from scope in an expression
584
650
  *
585
651
  * @param expr - DSL expression to analyze
652
+ * @param transforms - Optional custom transforms (to resolve custom nodes before collecting)
586
653
  * @returns Set of function names used
587
654
  *
588
655
  * @example
@@ -600,7 +667,7 @@ declare function wrapInFunction(bodyAst: ASTNode, params?: string[]): ASTNode;
600
667
  * // Set { "filter", "sum" }
601
668
  * ```
602
669
  */
603
- declare function extractScopeFns(expr: Expression): Set<string>;
670
+ declare function extractScopeFns(expr: Expression, transforms?: Record<string, TransformFn>): Set<string>;
604
671
  /**
605
672
  * Extract root-level data dependencies from paths
606
673
  *
@@ -642,6 +709,11 @@ interface CompileASTOptions {
642
709
  * - `lexicalPrefix: "params"` → `params?.foo` instead of `accessor("params.foo", data)`
643
710
  */
644
711
  lexicalPrefix?: string;
712
+ /**
713
+ * Custom expression transforms.
714
+ * Key = marker (e.g. "$query"), value = transform function.
715
+ */
716
+ transforms?: Record<string, TransformFn>;
645
717
  }
646
718
  /** Result when returnCode is true */
647
719
  interface CompileASTCodeResult {
@@ -724,6 +796,6 @@ declare function evaluateAST<T = unknown, R = unknown>(expr: Expression, data: T
724
796
  * ); // 3
725
797
  * ```
726
798
  */
727
- declare const VERSION = "0.1.1";
799
+ declare const VERSION = "1.2.1";
728
800
 
729
- export { type AccessorFn, type CallbackFn, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, type Condition, type ConditionExpr, type ConditionGroup, type ConditionOp, type ConditionalExpr, type Expression, ExpressionCache, type FnArg, type FnExpr, type Literal, type PathGetter, type PipeExpr, type RefExpr, type Scope, type TransformOptions, VERSION, type ValidateOptions, type ValidationResult, assertValid, builders, cache, cached, clearPathCache, compile, compileAST, compilePath, dslToAST, evaluate, evaluateAST, extractDataRoots, extractDeps, extractScopeFns, get, getPathCacheSize, hasDeps, hasWildcard, isCondition, isConditionExpr, isConditionGroup, isConditional, isFn, isLiteral, isPipe, isPure, isRef, isValid, normalizePath, validate, wrapInFunction };
801
+ 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, type TransformResult, 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, isTransformResult, isValid, normalizePath, validate, wrapInFunction };
package/dist/index.d.ts CHANGED
@@ -47,6 +47,29 @@ interface FnExpr {
47
47
  $fn: string;
48
48
  args?: FnArg[];
49
49
  }
50
+ /**
51
+ * Result of a transform function.
52
+ *
53
+ * Structurally similar to FnExpr but with relaxed args typing.
54
+ * Transforms can return domain-specific types in args (e.g., TestSpec, QueryParams)
55
+ * that will be passed to the scope function at runtime.
56
+ *
57
+ * Type safety for these args comes from the scope function implementation,
58
+ * not from the expression type system.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * // Transform for $test
63
+ * const transform: TransformFn = (node) => ({
64
+ * $fn: "__test",
65
+ * args: [node.$test] // TestSpec, not FnArg
66
+ * });
67
+ * ```
68
+ */
69
+ interface TransformResult {
70
+ readonly $fn: string;
71
+ readonly args?: unknown[];
72
+ }
50
73
  /**
51
74
  * Pipe expression (DSL syntax for composition with initial value)
52
75
  * First element is the initial value, rest are transformers
@@ -133,6 +156,31 @@ interface ValidationResult {
133
156
  * @example { add, subtract, multiply, filter, map, sum }
134
157
  */
135
158
  type Scope = Record<string, (...args: any[]) => any>;
159
+ /**
160
+ * Transform function for custom expression types.
161
+ *
162
+ * Receives the raw node (e.g., { $query: "name", params: {...} }) and returns:
163
+ * - Expression: for complex rewrites to standard expressions
164
+ * - TransformResult: for $fn calls with domain-specific args
165
+ *
166
+ * The returned value is compiled recursively. TransformResult args are
167
+ * compiled as literals and passed to the scope function at runtime.
168
+ *
169
+ * @example
170
+ * ```ts
171
+ * const transforms = {
172
+ * $query: (node) => ({
173
+ * $fn: "__query",
174
+ * args: [node.$query, node.params ?? {}]
175
+ * }),
176
+ * $test: (node) => ({
177
+ * $fn: "__test",
178
+ * args: [node.$test] // TestSpec passed as-is
179
+ * }),
180
+ * };
181
+ * ```
182
+ */
183
+ type TransformFn = (node: Record<string, unknown>) => Expression | TransformResult;
136
184
  /**
137
185
  * Options for compilation
138
186
  */
@@ -148,6 +196,13 @@ interface CompileOptions<T = unknown> {
148
196
  * compile(expr, { accessor: (path, ctx) => ctx.get(path) })
149
197
  */
150
198
  accessor?: AccessorFn<T>;
199
+ /**
200
+ * Custom expression transforms.
201
+ * Key = marker (e.g. "$query"), value = transform function.
202
+ * The walker calls the transform before treating as literal.
203
+ * The returned Expression is compiled recursively.
204
+ */
205
+ transforms?: Record<string, TransformFn>;
151
206
  }
152
207
  /**
153
208
  * Check if value is a reference expression
@@ -161,6 +216,12 @@ declare const isConditional: (v: unknown) => v is ConditionalExpr;
161
216
  * Check if value is a function call expression
162
217
  */
163
218
  declare const isFn: (v: unknown) => v is FnExpr;
219
+ /**
220
+ * Check if value is a transform result.
221
+ * Note: TransformResult is structurally similar to FnExpr,
222
+ * so this guard is mainly for documentation/intent.
223
+ */
224
+ declare const isTransformResult: (v: unknown) => v is TransformResult;
164
225
  /**
165
226
  * Check if value is a pipe expression
166
227
  */
@@ -292,7 +353,7 @@ declare function getPathCacheSize(): number;
292
353
  * @example { "$": "user.age" } → ["user.age"]
293
354
  * @example { "$if": "$isVip", "then": { "$": "price.vip" } } → ["$isVip", "price.vip"]
294
355
  */
295
- declare function extractDeps(expr: Expression): string[];
356
+ declare function extractDeps(expr: Expression, transforms?: Record<string, TransformFn>): string[];
296
357
  /**
297
358
  * Check if expression has dependencies
298
359
  */
@@ -547,6 +608,11 @@ interface TransformOptions {
547
608
  * - `lexicalPrefix: "params"` → `params?.foo` instead of `accessor("params.foo", data)`
548
609
  */
549
610
  lexicalPrefix?: string;
611
+ /**
612
+ * Custom expression transforms.
613
+ * Key = marker (e.g. "$query"), value = transform function.
614
+ */
615
+ transforms?: Record<string, TransformFn>;
550
616
  }
551
617
  /**
552
618
  * Transform DSL expression to AST node
@@ -583,6 +649,7 @@ declare function wrapInFunction(bodyAst: ASTNode, params?: string[]): ASTNode;
583
649
  * Extract all function names used from scope in an expression
584
650
  *
585
651
  * @param expr - DSL expression to analyze
652
+ * @param transforms - Optional custom transforms (to resolve custom nodes before collecting)
586
653
  * @returns Set of function names used
587
654
  *
588
655
  * @example
@@ -600,7 +667,7 @@ declare function wrapInFunction(bodyAst: ASTNode, params?: string[]): ASTNode;
600
667
  * // Set { "filter", "sum" }
601
668
  * ```
602
669
  */
603
- declare function extractScopeFns(expr: Expression): Set<string>;
670
+ declare function extractScopeFns(expr: Expression, transforms?: Record<string, TransformFn>): Set<string>;
604
671
  /**
605
672
  * Extract root-level data dependencies from paths
606
673
  *
@@ -642,6 +709,11 @@ interface CompileASTOptions {
642
709
  * - `lexicalPrefix: "params"` → `params?.foo` instead of `accessor("params.foo", data)`
643
710
  */
644
711
  lexicalPrefix?: string;
712
+ /**
713
+ * Custom expression transforms.
714
+ * Key = marker (e.g. "$query"), value = transform function.
715
+ */
716
+ transforms?: Record<string, TransformFn>;
645
717
  }
646
718
  /** Result when returnCode is true */
647
719
  interface CompileASTCodeResult {
@@ -724,6 +796,6 @@ declare function evaluateAST<T = unknown, R = unknown>(expr: Expression, data: T
724
796
  * ); // 3
725
797
  * ```
726
798
  */
727
- declare const VERSION = "0.1.1";
799
+ declare const VERSION = "1.2.1";
728
800
 
729
- export { type AccessorFn, type CallbackFn, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, type Condition, type ConditionExpr, type ConditionGroup, type ConditionOp, type ConditionalExpr, type Expression, ExpressionCache, type FnArg, type FnExpr, type Literal, type PathGetter, type PipeExpr, type RefExpr, type Scope, type TransformOptions, VERSION, type ValidateOptions, type ValidationResult, assertValid, builders, cache, cached, clearPathCache, compile, compileAST, compilePath, dslToAST, evaluate, evaluateAST, extractDataRoots, extractDeps, extractScopeFns, get, getPathCacheSize, hasDeps, hasWildcard, isCondition, isConditionExpr, isConditionGroup, isConditional, isFn, isLiteral, isPipe, isPure, isRef, isValid, normalizePath, validate, wrapInFunction };
801
+ 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, type TransformResult, 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, isTransformResult, isValid, normalizePath, validate, wrapInFunction };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import {builders,generate}from'omni-ast';var on=Object.defineProperty;var rn=(n,t)=>{for(var s in t)on(n,s,{get:t[s],enumerable:true});};var y=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,T=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,b=n=>n!==null&&typeof n=="object"&&"$fn"in n&&typeof n.$fn=="string",C=n=>n!==null&&typeof n=="object"&&"$pipe"in n&&Array.isArray(n.$pipe),x=new Set(["eq","neq","gt","gte","lt","lte","in","notIn","contains","notContains","exists","notExists","matches","notMatches","startsWith","endsWith"]),h=n=>n!==null&&typeof n=="object"&&"left"in n&&"op"in n&&x.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),E=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,sn=n=>h(n)||E(n),I=n=>{if(n===null)return true;let t=typeof n;if(t==="string"||t==="number"||t==="boolean"||Array.isArray(n))return true;if(t==="object"&&n!==null){let s=n,e="left"in s&&"op"in s&&x.has(s.op);return !("$"in s)&&!("$if"in s)&&!("$fn"in s)&&!("$pipe"in s)&&!e&&!("logic"in s)}return false};var R=new Map;function q(n){let t=[],s=n.length,e=0,r="";for(;e<s;){let o=n[e];if(o===".")r&&(t.push({type:"key",value:r}),r=""),e++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),e++;let i=e;for(;e<s&&n[e]!=="]";)e++;let f=n.slice(i,e);if(e++,f==="*")t.push({type:"wildcard",value:"*"});else {let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,e++;}return r&&t.push({type:"key",value:r}),t}function J(n){return n.includes("[*]")}function O(n){let t=R.get(n);return t||(t=J(n)?un(n):fn(n),R.set(n,t),t)}function fn(n){if(!n.includes(".")&&!n.includes("["))return r=>r?.[n];let t=q(n),s=t.length;if(s===2){let[r,o]=t,i=r.value,f=o.value;return l=>l?.[i]?.[f]}if(s===3){let[r,o,i]=t,f=r.value,l=o.value,c=i.value;return a=>a?.[f]?.[l]?.[c]}let e=t.map(r=>r.value);return r=>{let o=r;for(let i=0;i<s&&o!=null;i++)o=o[e[i]];return o}}function un(n){let t=q(n),s=[];for(let e=0;e<t.length;e++)t[e].type==="wildcard"&&s.push(e);return s.length===1?ln(t,s[0]):cn(t,s)}function ln(n,t){let s=n.slice(0,t).map(i=>i.value),e=n.slice(t+1).map(i=>i.value),r=s.length,o=e.length;if(o===0){if(r===1){let i=s[0];return f=>f?.[i]}return i=>{let f=i;for(let l=0;l<r&&f!=null;l++)f=f[s[l]];return f}}if(o===1){let i=e[0];if(r===1){let f=s[0];return l=>{let c=l?.[f];if(Array.isArray(c))return c.map(a=>a?.[i])}}return f=>{let l=f;for(let c=0;c<r&&l!=null;c++)l=l[s[c]];if(Array.isArray(l))return l.map(c=>c?.[i])}}return i=>{let f=i;for(let l=0;l<r&&f!=null;l++)f=f[s[l]];if(Array.isArray(f))return f.map(l=>{let c=l;for(let a=0;a<o&&c!=null;a++)c=c[e[a]];return c})}}function cn(n,t){let s=[],e=0;for(let o=0;o<t.length;o++){let i=t[o],f=o===t.length-1,l=n.slice(e,i).map(c=>c.value);l.length>0&&s.push({type:"access",keys:l}),s.push({type:f?"map":"flatMap",keys:[]}),e=i+1;}let r=n.slice(e).map(o=>o.value);return o=>{let i=o;for(let f of s){if(i==null)return;if(f.type==="access")for(let l of f.keys){if(i==null)return;i=i[l];}else if(f.type==="flatMap"){if(!Array.isArray(i))return;i=i.flatMap(l=>{let c=l;return Array.isArray(c)?c:[c]});}else if(f.type==="map"){if(!Array.isArray(i))return;r.length>0&&(i=i.map(l=>{let c=l;for(let a of r){if(c==null)return;c=c[a];}return c}));}}return i}}function an(n,t){return O(t)(n)}function F(n){let t=n.indexOf("[*]");return t===-1?n:n.slice(0,t)}function pn(){R.clear();}function dn(){return R.size}function k(n){let t=new Set;return A(n,t),Array.from(t)}function A(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r=0;r<n.length;r++)A(n[r],t);return}if(y(n)){t.add(F(n.$));return}if(T(n)){if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if;t.add(F(r));}else A(n.$if,t);A(n.then,t),n.else!==void 0&&A(n.else,t);return}if(C(n)){for(let r=0;r<n.$pipe.length;r++)A(n.$pipe[r],t);return}if(b(n)){if(n.args)for(let r=0;r<n.args.length;r++){let o=n.args[r];typeof o!="function"&&A(o,t);}return}if(h(n)){A(n.left,t),n.right!==void 0&&A(n.right,t);return}if(E(n)){for(let r=0;r<n.conditions.length;r++)A(n.conditions[r],t);return}let s=n,e=Object.keys(s);for(let r=0;r<e.length;r++)A(s[e[r]],t);}function gn(n){return k(n).length>0}function mn(n){return k(n).length===0}function yn(n){return JSON.stringify(n)}function N(n,t={}){let s=t.scope??{},e=t.accessor,r=m(n,s,e),o=k(n),i=yn(n);return {fn:r,deps:o,hash:i}}function m(n,t,s){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let e=n.map(r=>m(r,t,s));return r=>e.map(o=>o(r))}if(y(n))return hn(n,s);if(T(n))return En(n,t,s);if(C(n))return Tn(n,t,s);if(b(n))return bn(n,t,s);if(h(n))return Cn(n,t,s);if(E(n))return An(n,t,s);if(I(n)){let e=n,r=Object.keys(e),o=r.map(i=>m(e[i],t,s));return i=>{let f={};for(let l=0;l<r.length;l++)f[r[l]]=o[l](i);return f}}return ()=>n}function B(n,t){return t?s=>t(n,s):O(n)}function hn(n,t){return B(n.$,t)}function En(n,t,s){let e;if(typeof n.$if=="string"){let i=n.$if.startsWith("!")?n.$if.slice(1):n.$if,f=B(i,s);e=n.$if.startsWith("!")?c=>!f(c):c=>!!f(c);}else {let i=m(n.$if,t,s);e=f=>!!i(f);}let r=m(n.then,t,s),o=n.else!==void 0?m(n.else,t,s):()=>{};return i=>e(i)?r(i):o(i)}function Tn(n,t,s){let e=n.$pipe;if(e.length===0)return ()=>{};if(e.length===1)return m(e[0],t,s);let r=m(e[0],t,s),o=e.slice(1).map(f=>m(f,t,s)),i=o.length;if(i===1){let[f]=o;return l=>{let c=r(l),a=f(l);return typeof a=="function"?a(c):a}}if(i===2){let[f,l]=o;return c=>{let a=r(c),p=f(c);return a=typeof p=="function"?p(a):p,p=l(c),typeof p=="function"?p(a):p}}if(i===3){let[f,l,c]=o;return a=>{let p=r(a),d=f(a);return p=typeof d=="function"?d(p):d,d=l(a),p=typeof d=="function"?d(p):d,d=c(a),typeof d=="function"?d(p):d}}return f=>{let l=r(f);for(let c=0;c<i;c++){let a=o[c](f);l=typeof a=="function"?a(l):a;}return l}}function bn(n,t,s){let e=n.$fn,r=n.args;if(r===void 0)return ()=>{let f=t[e];if(!f)throw new Error(`Function not found in scope: ${e}`);return f};let o=r.map(f=>typeof f=="function"?()=>f:m(f,t,s)),i=o.length;if(i===0)return f=>{let l=t[e];if(!l)throw new Error(`Function not found in scope: ${e}`);return l()};if(i===1){let[f]=o;return l=>{let c=t[e];if(!c)throw new Error(`Function not found in scope: ${e}`);return c(f(l))}}if(i===2){let[f,l]=o;return c=>{let a=t[e];if(!a)throw new Error(`Function not found in scope: ${e}`);return a(f(c),l(c))}}if(i===3){let[f,l,c]=o;return a=>{let p=t[e];if(!p)throw new Error(`Function not found in scope: ${e}`);return p(f(a),l(a),c(a))}}return f=>{let l=t[e];if(!l)throw new Error(`Function not found in scope: ${e}`);return l(...o.map(c=>c(f)))}}function Cn(n,t,s){let e=m(n.left,t,s),r=n.right!==void 0?m(n.right,t,s):()=>{};switch(n.op){case "eq":return o=>e(o)===r(o);case "neq":return o=>e(o)!==r(o);case "gt":return o=>e(o)>r(o);case "gte":return o=>e(o)>=r(o);case "lt":return o=>e(o)<r(o);case "lte":return o=>e(o)<=r(o);case "in":return o=>{let i=r(o);return Array.isArray(i)&&i.includes(e(o))};case "notIn":return o=>{let i=r(o);return !Array.isArray(i)||!i.includes(e(o))};case "contains":return o=>{let i=e(o);return Array.isArray(i)&&i.includes(r(o))};case "notContains":return o=>{let i=e(o);return !Array.isArray(i)||!i.includes(r(o))};case "exists":return o=>e(o)!==void 0;case "notExists":return o=>e(o)===void 0;case "matches":return o=>{let i=e(o),f=r(o);return typeof i!="string"||typeof f!="string"?false:new RegExp(f).test(i)};case "notMatches":return o=>{let i=e(o),f=r(o);return typeof i!="string"||typeof f!="string"?true:!new RegExp(f).test(i)};case "startsWith":return o=>{let i=e(o),f=r(o);return typeof i=="string"&&typeof f=="string"&&i.startsWith(f)};case "endsWith":return o=>{let i=e(o),f=r(o);return typeof i=="string"&&typeof f=="string"&&i.endsWith(f)}}}function An(n,t,s){let e=n.conditions.map(o=>m(o,t,s)),r=e.length;if(r===1)return o=>!!e[0](o);if(r===2){let[o,i]=e;return n.logic==="AND"?f=>!!o(f)&&!!i(f):f=>!!o(f)||!!i(f)}if(r===3){let[o,i,f]=e;return n.logic==="AND"?l=>!!o(l)&&!!i(l)&&!!f(l):l=>!!o(l)||!!i(l)||!!f(l)}return n.logic==="AND"?o=>{for(let i=0;i<r;i++)if(!e[i](o))return false;return true}:o=>{for(let i=0;i<r;i++)if(e[i](o))return true;return false}}function $n(n,t,s={}){return N(n,s).fn(t)}var v=class{constructor(t=1e3){this.cache=new Map,this._maxSize=t;}get(t,s={}){let e=JSON.stringify(t),r=this.cache.get(e);if(r)return this.cache.delete(e),this.cache.set(e,r),r;let o=N(t,s);if(this.cache.size>=this._maxSize){let i=this.cache.keys().next().value;i&&this.cache.delete(i);}return this.cache.set(e,o),o}has(t){return this.cache.has(JSON.stringify(t))}delete(t){return this.cache.delete(JSON.stringify(t))}clear(){this.cache.clear();}get size(){return this.cache.size}get maxSize(){return this._maxSize}set maxSize(t){for(this._maxSize=t;this.cache.size>this._maxSize;){let s=this.cache.keys().next().value;s&&this.cache.delete(s);}}},K=new v;function Sn(n,t={}){return K.get(n,t)}function M(n,t="root",s={}){let e=[];return $(n,t,e,s),{valid:e.length===0,errors:e}}function $(n,t,s,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let i=0;i<n.length;i++)$(n[i],`${t}[${i}]`,s,e);return}if(y(n)){(!n.$||typeof n.$!="string")&&s.push(`${t}: invalid reference, $ must be non-empty string`);return}if(T(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||s.push(`${t}.$if: empty path in string shorthand`):$(n.$if,`${t}.$if`,s,e),$(n.then,`${t}.then`,s,e),n.else!==void 0&&$(n.else,`${t}.else`,s,e);return}if(C(n)){if(!Array.isArray(n.$pipe)){s.push(`${t}.$pipe: must be an array`);return}if(n.$pipe.length===0){s.push(`${t}.$pipe: must have at least one element`);return}for(let i=0;i<n.$pipe.length;i++)$(n.$pipe[i],`${t}.$pipe[${i}]`,s,e);return}if(b(n)){if(!n.$fn||typeof n.$fn!="string"){s.push(`${t}: invalid function, $fn must be non-empty string`);return}if(e.scope&&!(n.$fn in e.scope)&&s.push(`${t}: function "${n.$fn}" not found in scope`),n.args!==void 0)if(!Array.isArray(n.args))s.push(`${t}.args: must be an array`);else for(let i=0;i<n.args.length;i++){let f=n.args[i];typeof f!="function"&&$(f,`${t}.args[${i}]`,s,e);}return}if(h(n)){x.has(n.op)||s.push(`${t}: invalid operator "${n.op}"`),$(n.left,`${t}.left`,s,e),n.right!==void 0&&$(n.right,`${t}.right`,s,e);return}if(E(n)){if(n.logic!=="AND"&&n.logic!=="OR"&&s.push(`${t}: invalid logic "${n.logic}", must be "AND" or "OR"`),!Array.isArray(n.conditions)){s.push(`${t}.conditions: must be an array`);return}for(let i=0;i<n.conditions.length;i++)$(n.conditions[i],`${t}.conditions[${i}]`,s,e);return}let r=n,o=Object.keys(r);for(let i=0;i<o.length;i++){let f=o[i];$(r[f],`${t}.${f}`,s,e);}}function kn(n,t={}){let s=M(n,"root",t);if(!s.valid)throw new Error(`Invalid expression: ${s.errors.join("; ")}`)}function wn(n,t={}){return M(n,"root",t).valid}var U={};rn(U,{$:()=>P,$cond:()=>Q,$fn:()=>Y,$if:()=>On,$pipe:()=>H,cond:()=>Nn,fn:()=>Rn,pipe:()=>Fn,ref:()=>xn});function P(n){return {$:n}}var xn=P;function Y(n,t){return t===void 0||t.length===0?{$fn:n}:{$fn:n,args:t}}var Rn=Y;function On(n,t,s){return s===void 0?{$if:n,then:t}:{$if:n,then:t,else:s}}function H(...n){return {$pipe:n}}var Fn=H;function Q(n,t,s){return s===void 0?{left:n,op:t}:{left:n,op:t,right:s}}var Nn=Q;var z="data",Z="scope",vn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function G(n,t={}){let{dataParam:s=z,scopeParam:e=Z,noPrefixes:r=false,useAccessor:o=false,lexicalPrefix:i}=t;return g(n,s,e,r,o,i)}function g(n,t,s,e,r,o){if(n===null)return builders.literal(null);if(typeof n=="string")return builders.literal(n);if(typeof n=="number")return builders.literal(n);if(typeof n=="boolean")return builders.literal(n);if(Array.isArray(n))return builders.arrayExpression(n.map(i=>g(i,t,s,e,r,o)));if(y(n))return jn(n.$,t,e,r,o);if(T(n))return Wn(n,t,s,e,r,o);if(C(n))return In(n.$pipe,t,s,e,r,o);if(b(n))return Dn(n,t,s,e,r,o);if(h(n))return Mn(n,t,s,e,r,o);if(E(n))return zn(n,t,s,e,r,o);if(typeof n=="object"){let f=Object.entries(n).map(([l,c])=>builders.property(builders.identifier(l),g(c,t,s,e,r,o)));return builders.objectExpression(f)}return builders.literal(null)}var L="accessor";function V(n,t){return t?n===t||n.startsWith(t+"."):false}function jn(n,t,s,e,r){return e?V(n,r)?w(n,t,true):builders.callExpression(builders.identifier(L),[builders.literal(n),builders.identifier(t)]):n.includes("[*]")?Gn(n,t,s):w(n,t,s)}function w(n,t,s){let e=j(n);if(e.length===0)return s?builders.identifier("undefined"):builders.identifier(t);let r;if(s){let o=e[0];r=builders.identifier(o.value);for(let i=1;i<e.length;i++){let f=e[i];f.type==="key"?r=builders.memberExpression(r,builders.identifier(f.value),false,true):r=builders.memberExpression(r,builders.literal(f.value),true,true);}}else {r=builders.identifier(t);for(let o of e)o.type==="key"?r=builders.memberExpression(r,builders.identifier(o.value),false,true):r=builders.memberExpression(r,builders.literal(o.value),true,true);}return r}function Gn(n,t,s){let e=n.indexOf("[*]"),r=n.slice(0,e),o=n.slice(e+3),i;if(r?i=w(r,t,s):i=s?builders.identifier("undefined"):builders.identifier(t),!o||o==="")return i;if(o.includes("[*]"))return nn(i,o);let f="_i",l=o.startsWith(".")?o.slice(1):o,c=builders.identifier(f);if(l){let a=j(l);for(let p of a)p.type==="key"?c=builders.memberExpression(c,builders.identifier(p.value),false,true):c=builders.memberExpression(c,builders.literal(p.value),true,true);}return builders.callExpression(builders.memberExpression(i,builders.identifier("map"),false,true),[builders.arrowFunctionExpression([builders.identifier(f)],c)])}function nn(n,t){let s=t.indexOf("[*]"),e=t.slice(0,s),r=t.slice(s+3),o="_i",i=e.startsWith(".")?e.slice(1):e,f=builders.identifier(o);if(i){let c=j(i);for(let a of c)a.type==="key"&&(f=builders.memberExpression(f,builders.identifier(a.value),false,true));}if(r.includes("[*]")){let c=nn(f,r);return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(o)],c)])}let l=r.startsWith(".")?r.slice(1):r;if(l){let c=j(l);for(let a of c)a.type==="key"&&(f=builders.memberExpression(f,builders.identifier(a.value),false,true));}return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(o)],f)])}function Wn(n,t,s,e,r,o){let i;if(typeof n.$if=="string"){let c=n.$if.startsWith("!"),a=c?n.$if.slice(1):n.$if,p;r?V(a,o)?p=w(a,t,true):p=builders.callExpression(builders.identifier(L),[builders.literal(a),builders.identifier(t)]):p=w(a,t,e),i=c?builders.unaryExpression("!",p):p;}else i=g(n.$if,t,s,e,r,o);let f=g(n.then,t,s,e,r,o),l=n.else!==void 0?g(n.else,t,s,e,r,o):builders.identifier("undefined");return builders.conditionalExpression(i,f,l)}function Dn(n,t,s,e,r,o){let i=e?builders.identifier(n.$fn):builders.memberExpression(builders.identifier(s),builders.identifier(n.$fn),false,false);if(n.args===void 0)return i;let f=n.args.map(l=>typeof l=="function"?builders.literal(null):g(l,t,s,e,r,o));return builders.callExpression(i,f)}function In(n,t,s,e,r,o){if(n.length===0)return builders.identifier("undefined");if(n.length===1)return g(n[0],t,s,e,r,o);let i=g(n[0],t,s,e,r,o);for(let f=1;f<n.length;f++){let l=g(n[f],t,s,e,r,o);i=builders.callExpression(l,[i]);}return i}function X(n,t,s,e,r,o){if(y(n)){let i=n.$;return r?V(i,o)?w(i,t,true):builders.callExpression(builders.identifier(L),[builders.literal(i),builders.identifier(t)]):w(i,t,e)}return g(n,t,s,e,r,o)}function Mn(n,t,s,e,r,o){let i=X(n.left,t,s,e,r,o),f=n.right!==void 0?X(n.right,t,s,e,r,o):builders.literal(null),l=vn[n.op];if(l)return builders.binaryExpression(l,i,f);switch(n.op){case "in":return builders.callExpression(builders.memberExpression(f,builders.identifier("includes")),[i]);case "notIn":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(f,builders.identifier("includes")),[i]));case "contains":return builders.callExpression(builders.memberExpression(i,builders.identifier("includes"),false,true),[f]);case "notContains":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(i,builders.identifier("includes"),false,true),[f]));case "exists":return builders.binaryExpression("!=",i,builders.literal(null));case "notExists":return builders.binaryExpression("==",i,builders.literal(null));case "matches":return builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[f]),builders.identifier("test")),[i]);case "notMatches":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[f]),builders.identifier("test")),[i]));case "startsWith":return builders.callExpression(builders.memberExpression(i,builders.identifier("startsWith"),false,true),[f]);case "endsWith":return builders.callExpression(builders.memberExpression(i,builders.identifier("endsWith"),false,true),[f]);default:return builders.binaryExpression("===",i,f)}}function zn(n,t,s,e,r,o){let{logic:i,conditions:f}=n,l=i==="AND"?"&&":"||";if(f.length===0)return builders.literal(i==="AND");if(f.length===1)return g(f[0],t,s,e,r,o);let c=g(f[0],t,s,e,r,o);for(let a=1;a<f.length;a++){let p=g(f[a],t,s,e,r,o);c=builders.logicalExpression(l,c,p);}return c}function j(n){let t=[],s=n.length,e=0,r="";for(;e<s;){let o=n[e];if(o===".")r&&(t.push({type:"key",value:r}),r=""),e++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),e++;let i=e;for(;e<s&&n[e]!=="]";)e++;let f=n.slice(i,e);if(e++,f!=="*"){let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,e++;}return r&&t.push({type:"key",value:r}),t}function tn(n,t=[z]){return builders.arrowFunctionExpression(t.map(s=>builders.identifier(s)),n)}function W(n){let t=new Set;return S(n,t),t}function S(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let e of n)S(e,t);return}if(y(n))return;if(T(n)){S(n.$if,t),S(n.then,t),n.else!==void 0&&S(n.else,t);return}if(C(n)){for(let e of n.$pipe)S(e,t);return}if(b(n)){if(t.add(n.$fn),n.args)for(let e of n.args)typeof e!="function"&&S(e,t);return}if(h(n)){n.left!==void 0&&typeof n.left=="object"&&S(n.left,t),n.right!==void 0&&typeof n.right=="object"&&S(n.right,t);return}if(E(n)){for(let e of n.conditions)S(e,t);return}let s=n;for(let e of Object.keys(s))S(s[e],t);}function D(n){let t=new Set;for(let s of n){let e=s.indexOf("."),r=s.indexOf("["),o=s.length;e!==-1&&(o=Math.min(o,e)),r!==-1&&(o=Math.min(o,r));let i=s.slice(0,o);i&&t.add(i);}return t}function Vn(n){return JSON.stringify(n)}function _n(n,t,s,e,r){let o=G(n,{noPrefixes:true,useAccessor:e,lexicalPrefix:r}),i=generate(o),f="";e?r&&(f=`const{${r}}=data??{};`):t.size>0&&(f=`const{${[...t].join(",")}}=data??{};`);let l=e?new Set([...s,"accessor"]):s,c=l.size>0?`const{${[...l].join(",")}}=scope;`:"";return c?`(function(scope){${c}return function(data){${f}return ${i}}})`:`(function(){return function(data){${f}return ${i}}})`}function _(n,t={}){let{scope:s={},returnCode:e=false,useAccessor:r=false,lexicalPrefix:o}=t,i=k(n),f=D(i),l=W(n),c=Vn(n),a=_n(n,f,l,r,o);if(e)return {code:a,deps:i,hash:c,dataRoots:[...f],scopeFns:[...l]};let p;try{p=new Function(`return ${a}`)()(s);}catch(d){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${d instanceof Error?d.message:String(d)}`)}return {fn:p,deps:i,hash:c}}function en(n,t,s={}){let{fn:e}=_(n,s);return e(t)}var ht="0.1.1";export{v as ExpressionCache,ht as VERSION,kn as assertValid,U as builders,K as cache,Sn as cached,pn as clearPathCache,N as compile,_ as compileAST,O as compilePath,G as dslToAST,$n as evaluate,en as evaluateAST,D as extractDataRoots,k as extractDeps,W as extractScopeFns,an as get,dn as getPathCacheSize,gn as hasDeps,J as hasWildcard,h as isCondition,sn as isConditionExpr,E as isConditionGroup,T as isConditional,b as isFn,I as isLiteral,C as isPipe,mn as isPure,y as isRef,wn as isValid,F as normalizePath,M as validate,tn as wrapInFunction};
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",fn=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,un=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 u=parseInt(r,10);e.push({type:"index",value:isNaN(u)?r:u});}}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)?ln(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 u=>u?.[t]?.[r]}if(i===3){let[o,s,t]=e,r=o.value,u=s.value,l=t.value;return a=>a?.[r]?.[u]?.[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 ln(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?an(e,i[0]):pn(e,i)}function an(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 u=0;u<o&&r!=null;u++)r=r[i[u]];return r}}if(s===1){let t=f[0];if(o===1){let r=i[0];return u=>{let l=u?.[r];if(Array.isArray(l))return l.map(a=>a?.[t])}}return r=>{let u=r;for(let l=0;l<o&&u!=null;l++)u=u[i[l]];if(Array.isArray(u))return u.map(l=>l?.[t])}}return t=>{let r=t;for(let u=0;u<o&&r!=null;u++)r=r[i[u]];if(Array.isArray(r))return r.map(u=>{let l=u;for(let a=0;a<s&&l!=null;a++)l=l[f[a]];return l})}}function pn(n,e){let i=[],f=0;for(let s=0;s<e.length;s++){let t=e[s],r=s===e.length-1,u=n.slice(f,t).map(l=>l.value);u.length>0&&i.push({type:"access",keys:u}),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 u of r.keys){if(t==null)return;t=t[u];}else if(r.type==="flatMap"){if(!Array.isArray(t))return;t=t.flatMap(u=>{let l=u;return Array.isArray(l)?l:[l]});}else if(r.type==="map"){if(!Array.isArray(t))return;o.length>0&&(t=t.map(u=>{let l=u;for(let a of o){if(l==null)return;l=l[a];}return l}));}}return t}}function dn(n,e){return O(e)(n)}function j(n){let e=n.indexOf("[*]");return e===-1?n:n.slice(0,e)}function gn(){x.clear();}function yn(){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 u=t[r];if(u in i){let l=i[u](s);if(typeof l=="object"&&l!==null&&u in l)throw new Error(`Transform "${u}" 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 mn(n){return w(n).length>0}function hn(n){return w(n).length===0}function En(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=En(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 Tn(n,i);if(A(n))return bn(n,e,i,f);if(k(n))return Cn(n,e,i,f);if($(n))return An(n,e,i,f);if(E(n))return $n(n,e,i,f);if(T(n))return kn(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 u=f[r](o);if(typeof u=="object"&&u!==null&&r in u)throw new Error(`Transform "${r}" returned object with same key \u2014 infinite loop`);return m(u,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 u={};for(let l=0;l<s.length;l++)u[s[l]]=t[l](r);return u}}return ()=>n}function K(n,e){return e?i=>e(n,i):O(n)}function Tn(n,e){return K(n.$,e)}function bn(n,e,i,f){let o;if(typeof n.$if=="string"){let r=n.$if.startsWith("!")?n.$if.slice(1):n.$if,u=K(r,i);o=n.$if.startsWith("!")?a=>!u(a):a=>!!u(a);}else {let r=m(n.$if,e,i,f);o=u=>!!r(u);}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 Cn(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(u=>m(u,e,i,f)),r=t.length;if(r===1){let[u]=t;return l=>{let a=s(l),p=u(l);return typeof p=="function"?p(a):p}}if(r===2){let[u,l]=t;return a=>{let p=s(a),d=u(a);return p=typeof d=="function"?d(p):d,d=l(a),typeof d=="function"?d(p):d}}if(r===3){let[u,l,a]=t;return p=>{let d=s(p),g=u(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 u=>{let l=s(u);for(let a=0;a<r;a++){let p=t[a](u);l=typeof p=="function"?p(l):p;}return l}}function An(n,e,i,f){let o=n.$fn,s=n.args;if(s===void 0)return ()=>{let u=e[o];if(!u)throw new Error(`Function not found in scope: ${o}`);return u};let t=s.map(u=>typeof u=="function"?()=>u:m(u,e,i,f)),r=t.length;if(r===0)return u=>{let l=e[o];if(!l)throw new Error(`Function not found in scope: ${o}`);return l()};if(r===1){let[u]=t;return l=>{let a=e[o];if(!a)throw new Error(`Function not found in scope: ${o}`);return a(u(l))}}if(r===2){let[u,l]=t;return a=>{let p=e[o];if(!p)throw new Error(`Function not found in scope: ${o}`);return p(u(a),l(a))}}if(r===3){let[u,l,a]=t;return p=>{let d=e[o];if(!d)throw new Error(`Function not found in scope: ${o}`);return d(u(p),l(p),a(p))}}return u=>{let l=e[o];if(!l)throw new Error(`Function not found in scope: ${o}`);return l(...t.map(a=>a(u)))}}function $n(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),u=s(t);return typeof r!="string"||typeof u!="string"?false:new RegExp(u).test(r)};case "notMatches":return t=>{let r=o(t),u=s(t);return typeof r!="string"||typeof u!="string"?true:!new RegExp(u).test(r)};case "startsWith":return t=>{let r=o(t),u=s(t);return typeof r=="string"&&typeof u=="string"&&r.startsWith(u)};case "endsWith":return t=>{let r=o(t),u=s(t);return typeof r=="string"&&typeof u=="string"&&r.endsWith(u)}}}function kn(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"?u=>!!t(u)&&!!r(u):u=>!!t(u)||!!r(u)}if(s===3){let[t,r,u]=o;return n.logic==="AND"?l=>!!t(l)&&!!r(l)&&!!u(l):l=>!!t(l)||!!r(l)||!!u(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 Sn(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 wn(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 Rn(n,e={}){let i=z(n,"root",e);if(!i.valid)throw new Error(`Invalid expression: ${i.errors.join("; ")}`)}function Fn(n,e={}){return z(n,"root",e).valid}var Z={};sn(Z,{$:()=>H,$cond:()=>X,$fn:()=>Q,$if:()=>jn,$pipe:()=>U,cond:()=>vn,fn:()=>On,pipe:()=>Nn,ref:()=>xn});function H(n){return {$:n}}var xn=H;function Q(n,e){return e===void 0||e.length===0?{$fn:n}:{$fn:n,args:e}}var On=Q;function jn(n,e,i){return i===void 0?{$if:n,then:e}:{$if:n,then:e,else:i}}function U(...n){return {$pipe:n}}var Nn=U;function X(n,e,i){return i===void 0?{left:n,op:e}:{left:n,op:e,right:i}}var vn=X;var L="data",nn="scope",Gn={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 Wn(n.$,e,f,o,s);if(A(n))return In(n,e,i,f,o,s,t);if(k(n))return zn(n.$pipe,e,i,f,o,s,t);if($(n))return Mn(n,e,i,f,o,s,t);if(E(n))return Ln(n,e,i,f,o,s,t);if(T(n))return Vn(n,e,i,f,o,s,t);if(t&&typeof n=="object"){let r=n,u=Object.keys(r);for(let l=0;l<u.length;l++){let a=u[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 u=Object.entries(n).map(([l,a])=>builders.property(builders.identifier(l),y(a,e,i,f,o,s,t)));return builders.objectExpression(u)}return builders.literal(null)}var V="accessor";function _(n,e){return e?n===e||n.startsWith(e+"."):false}function Wn(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("[*]")?Dn(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 Dn(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",u=s.startsWith(".")?s.slice(1):s,l=builders.identifier(r);if(u){let a=G(u);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 u=o.startsWith(".")?o.slice(1):o;if(u){let l=G(u);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 In(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 u=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,u,l)}function Mn(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 u=n.args.map(l=>typeof l=="function"?builders.literal(null):y(l,e,i,f,o,s,t));return builders.callExpression(r,u)}function zn(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 u=1;u<n.length;u++){let l=y(n[u],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 Ln(n,e,i,f,o,s,t){let r=P(n.left,e,i,f,o,s,t),u=n.right!==void 0?P(n.right,e,i,f,o,s,t):builders.literal(null),l=Gn[n.op];if(l)return builders.binaryExpression(l,r,u);switch(n.op){case "in":return builders.callExpression(builders.memberExpression(u,builders.identifier("includes")),[r]);case "notIn":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(u,builders.identifier("includes")),[r]));case "contains":return builders.callExpression(builders.memberExpression(r,builders.identifier("includes"),false,true),[u]);case "notContains":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(r,builders.identifier("includes"),false,true),[u]));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"),[u]),builders.identifier("test")),[r]);case "notMatches":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[u]),builders.identifier("test")),[r]));case "startsWith":return builders.callExpression(builders.memberExpression(r,builders.identifier("startsWith"),false,true),[u]);case "endsWith":return builders.callExpression(builders.memberExpression(r,builders.identifier("endsWith"),false,true),[u]);default:return builders.binaryExpression("===",r,u)}}function Vn(n,e,i,f,o,s,t){let{logic:r,conditions:u}=n,l=r==="AND"?"&&":"||";if(u.length===0)return builders.literal(r==="AND");if(u.length===1)return y(u[0],e,i,f,o,s,t);let a=y(u[0],e,i,f,o,s,t);for(let p=1;p<u.length;p++){let d=y(u[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 u=parseInt(r,10);e.push({type:"index",value:isNaN(u)?r:u});}}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 u=i[r](o);if(typeof u=="object"&&u!==null&&r in u)throw new Error(`Transform "${r}" returned object with same key \u2014 infinite loop`);C(u,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 qn(n){return JSON.stringify(n)}function Jn(n,e,i,f,o,s){let t=W(n,{noPrefixes:true,useAccessor:f,lexicalPrefix:o,transforms:s}),r=generate(t),u="";f?o&&(u=`const{${o}}=data??{};`):e.size>0&&(u=`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){${u}return ${r}}})`:`(function(){return function(data){${u}return ${r}}})`}function q(n,e={}){let{scope:i={},returnCode:f=false,useAccessor:o=false,lexicalPrefix:s,transforms:t}=e,r=w(n,t),u=I(r),l=D(n,t),a=qn(n),p=Jn(n,u,l,o,s,t);if(f)return {code:p,deps:r,hash:a,dataRoots:[...u],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 Te="1.2.1";export{v as ExpressionCache,Te as VERSION,Rn as assertValid,Z as builders,Y as cache,wn as cached,gn as clearPathCache,N as compile,q as compileAST,O as compilePath,W as dslToAST,Sn as evaluate,on as evaluateAST,I as extractDataRoots,w as extractDeps,D as extractScopeFns,dn as get,yn as getPathCacheSize,mn as hasDeps,B as hasWildcard,E as isCondition,un as isConditionExpr,T as isConditionGroup,A as isConditional,$ as isFn,M as isLiteral,k as isPipe,hn as isPure,h as isRef,fn as isTransformResult,Fn 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.1.0",
3
+ "version": "1.2.1",
4
4
  "description": "JSON DSL compiler for optimized functions - StateDelta expression engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",