@statedelta-libs/expressions 0.0.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 ADDED
@@ -0,0 +1,382 @@
1
+ # @statedelta-libs/expressions
2
+
3
+ > Compilador de JSON DSL para funções otimizadas.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@statedelta-libs/expressions.svg)](https://www.npmjs.com/package/@statedelta-libs/expressions)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Características
9
+
10
+ - **Compilação** - Compila uma vez, executa milhões de vezes
11
+ - **Alta performance** - ~3M ops/sec após compilação
12
+ - **Scope externo** - Funções vêm via scope, não hardcoded
13
+ - **$pipe** - Composição com valor inicial (sintaxe DSL)
14
+ - **Path syntax** - Suporte a wildcards (`items[*].price`)
15
+ - **Dependency extraction** - Para dirty tracking/reatividade
16
+ - **Integração** - Usa `@statedelta-libs/conditions` para condicionais
17
+ - **Type-safe** - TypeScript nativo com inferência
18
+
19
+ ## Instalação
20
+
21
+ ```bash
22
+ npm install @statedelta-libs/expressions
23
+ # ou
24
+ pnpm add @statedelta-libs/expressions
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```typescript
30
+ import { compile, evaluate } from '@statedelta-libs/expressions';
31
+ import { filter, map, sum } from '@statedelta-libs/operators';
32
+
33
+ // Define o scope com funções disponíveis
34
+ const scope = { filter, map, sum };
35
+
36
+ // Compilar expressão com $pipe
37
+ const expr = compile({
38
+ $pipe: [
39
+ { $: "items" },
40
+ { $fn: "filter", args: [(item) => item.active] },
41
+ { $fn: "map", args: [(item) => item.price] },
42
+ { $fn: "sum" }
43
+ ]
44
+ }, { scope });
45
+
46
+ // Executar (muito rápido!)
47
+ const data = {
48
+ items: [
49
+ { name: "A", price: 10, active: true },
50
+ { name: "B", price: 20, active: false },
51
+ { name: "C", price: 30, active: true }
52
+ ]
53
+ };
54
+
55
+ expr.fn(data); // 40
56
+ expr.deps; // ["items"]
57
+ ```
58
+
59
+ ## API
60
+
61
+ ### compile()
62
+
63
+ Compila expressão JSON DSL para função otimizada usando closures.
64
+
65
+ ```typescript
66
+ const { fn, deps, hash } = compile(expression, { scope });
67
+
68
+ fn(data); // Executa
69
+ deps; // Paths que a expressão depende
70
+ hash; // Hash único (para cache)
71
+ ```
72
+
73
+ ### compileAST()
74
+
75
+ Compila usando AST + `new Function()`. **Mais rápido na execução**, ideal para expressões executadas muitas vezes.
76
+
77
+ ```typescript
78
+ import { compileAST } from '@statedelta-libs/expressions';
79
+
80
+ const { fn, deps, hash } = compileAST(expression, { scope });
81
+
82
+ fn(data); // Executa (mais rápido que compile())
83
+ ```
84
+
85
+ **Quando usar cada um:**
86
+
87
+ | Cenário | Recomendação | Por quê |
88
+ |---------|--------------|---------|
89
+ | Execução única | `compile()` | Compilação mais rápida |
90
+ | Poucas execuções (<8x) | `compile()` | Overhead de AST não compensa |
91
+ | Muitas execuções (>8x) | `compileAST()` | Execução ~25-170% mais rápida |
92
+ | Hot path crítico | `compileAST()` | V8 JIT otimiza melhor |
93
+ | Expressões complexas | `compileAST()` | Ganho maior em nested calls |
94
+
95
+ ### evaluate() / evaluateAST()
96
+
97
+ Compila e executa em um passo.
98
+
99
+ ```typescript
100
+ const result = evaluate(
101
+ { $fn: "add", args: [{ $: "a" }, { $: "b" }] },
102
+ { a: 1, b: 2 },
103
+ { scope: { add: (a, b) => a + b } }
104
+ );
105
+ // 3
106
+
107
+ // Versão AST
108
+ const result = evaluateAST(expression, data, { scope });
109
+ ```
110
+
111
+ ### extractDeps()
112
+
113
+ Extrai dependências sem compilar.
114
+
115
+ ```typescript
116
+ const deps = extractDeps({
117
+ $if: "$isVip",
118
+ then: { $: "price.vip" },
119
+ else: { $: "price.regular" }
120
+ });
121
+ // ["$isVip", "price.vip", "price.regular"]
122
+ ```
123
+
124
+ ## Tipos de Expressão
125
+
126
+ ### Literal
127
+
128
+ ```typescript
129
+ 42
130
+ "hello"
131
+ true
132
+ [1, 2, 3]
133
+ { a: 1 }
134
+ ```
135
+
136
+ ### Reference ($)
137
+
138
+ ```typescript
139
+ { $: "user.name" } // Acessa user.name
140
+ { $: "items[0].price" } // Acessa índice
141
+ { $: "items[*].price" } // Wildcard → [10, 20, 30]
142
+ ```
143
+
144
+ ### Conditional ($if)
145
+
146
+ ```typescript
147
+ {
148
+ $if: { path: "age", op: "gte", value: 18 },
149
+ then: "adult",
150
+ else: "minor"
151
+ }
152
+
153
+ // Shorthand
154
+ { $if: "$isVip", then: 0.2, else: 0 }
155
+ { $if: "!$isBlocked", then: "allowed" }
156
+ ```
157
+
158
+ ### Pipe ($pipe)
159
+
160
+ Composição com valor inicial - o valor passa por cada função em sequência.
161
+
162
+ ```typescript
163
+ {
164
+ $pipe: [
165
+ { $: "items" }, // Valor inicial
166
+ { $fn: "filter", args: [predicateFn] }, // Retorna função curried
167
+ { $fn: "map", args: [mapperFn] }, // Retorna função curried
168
+ { $fn: "sum" } // Referência à função
169
+ ]
170
+ }
171
+ ```
172
+
173
+ ### Function Call ($fn)
174
+
175
+ Chama função do scope com argumentos compilados.
176
+
177
+ ```typescript
178
+ // Com args: chama a função
179
+ { $fn: "add", args: [{ $: "a" }, { $: "b" }] }
180
+ // → scope.add(data.a, data.b)
181
+
182
+ // Sem args: retorna referência à função (útil em $pipe)
183
+ { $fn: "sum" }
184
+ // → scope.sum
185
+
186
+ // Com args vazio: chama função sem argumentos
187
+ { $fn: "getTimestamp", args: [] }
188
+ // → scope.getTimestamp()
189
+ ```
190
+
191
+ ### Condition (delegado)
192
+
193
+ ```typescript
194
+ // Detectado automaticamente e delegado para @statedelta-libs/conditions
195
+ { path: "user.age", op: "gte", value: 18 }
196
+ ```
197
+
198
+ > **Nota:** Apenas objetos com operadores de condition válidos (`eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`, `contains`, `notContains`, `exists`, `notExists`, `matches`, `notMatches`, `startsWith`, `endsWith`) são detectados como conditions. Objetos com `op: "set"` ou outros operadores não são conditions e são tratados como literals.
199
+
200
+ ## Scope
201
+
202
+ O scope define quais funções estão disponíveis para `$fn`:
203
+
204
+ ```typescript
205
+ import * as R from '@statedelta-libs/operators';
206
+
207
+ // Todas as funções do operators
208
+ const scope = R;
209
+
210
+ // Ou seleção específica
211
+ const scope = {
212
+ add: R.add,
213
+ filter: R.filter,
214
+ map: R.map,
215
+ sum: R.sum,
216
+ // Funções custom
217
+ double: (n) => n * 2,
218
+ isActive: (item) => item.active
219
+ };
220
+
221
+ const { fn } = compile(expression, { scope });
222
+ ```
223
+
224
+ ## Path Syntax
225
+
226
+ | Path | Resultado |
227
+ |------|-----------|
228
+ | `user` | `data.user` |
229
+ | `user.name` | `data.user.name` |
230
+ | `items[0]` | `data.items[0]` |
231
+ | `items[*].price` | `data.items.map(i => i.price)` |
232
+
233
+ ## Cache
234
+
235
+ ```typescript
236
+ import { cache, cached } from '@statedelta-libs/expressions';
237
+
238
+ // Com scope
239
+ const compiled = cache.get(expression, { scope });
240
+
241
+ // Ou função helper
242
+ const compiled = cached(expression, { scope });
243
+
244
+ // Gerenciar
245
+ cache.size; // Tamanho atual
246
+ cache.clear(); // Limpar
247
+ ```
248
+
249
+ ## Performance
250
+
251
+ ### compile() - Closures
252
+
253
+ | Operação | Velocidade |
254
+ |----------|------------|
255
+ | Compile (literal) | ~6.5M ops/s |
256
+ | Compile (ref) | ~2.5M ops/s |
257
+ | Compile (fn nested) | ~550K ops/s |
258
+ | Compile (complex) | ~300K ops/s |
259
+ | Execute (ref) | ~28M ops/s |
260
+ | Execute (fn nested) | ~9M ops/s |
261
+
262
+ ### compileAST() - AST + new Function
263
+
264
+ | Operação | Velocidade |
265
+ |----------|------------|
266
+ | Compile (literal) | ~1.2M ops/s |
267
+ | Compile (ref) | ~800K ops/s |
268
+ | Compile (fn nested) | ~230K ops/s |
269
+ | Compile (complex) | ~130K ops/s |
270
+ | Execute (ref) | ~27M ops/s |
271
+ | Execute (fn nested) | ~25M ops/s ⚡ |
272
+
273
+ ### Comparação Execução
274
+
275
+ | Cenário | Closures | AST | Ganho AST |
276
+ |---------|----------|-----|-----------|
277
+ | fn nested | 9M ops/s | 25M ops/s | **+169%** |
278
+ | ref 4 níveis | 16M ops/s | 27M ops/s | **+69%** |
279
+ | conditional nested | 20M ops/s | 25M ops/s | **+25%** |
280
+
281
+ **Break-even:** ~8 execuções - após isso, `compileAST()` compensa o tempo extra de compilação.
282
+
283
+ ## Segurança
284
+
285
+ Ambas as abordagens são **seguras contra injeção de código**:
286
+
287
+ | Método | Proteção |
288
+ |--------|----------|
289
+ | `compile()` | Não gera código string - apenas compõe funções |
290
+ | `compileAST()` | Usa destructuring que valida identificadores automaticamente |
291
+
292
+ ```typescript
293
+ // Tentativa de injeção - FALHA em ambos
294
+ { $fn: "add; console.log('hacked'); //" }
295
+
296
+ // compile(): tenta acessar scope["add; console.log..."] → undefined
297
+ // compileAST(): destructuring inválido → SyntaxError
298
+ ```
299
+
300
+ Funções só são acessíveis se existirem no `scope` fornecido pelo desenvolvedor.
301
+
302
+ ## Type Detection
303
+
304
+ O compilador detecta automaticamente o tipo de expressão baseado na estrutura do objeto:
305
+
306
+ | Tipo | Detecção | Exemplo |
307
+ |------|----------|---------|
308
+ | Reference | `{ $ }` presente | `{ $: "user.name" }` |
309
+ | Conditional | `{ $if, then }` presentes | `{ $if: cond, then: x, else: y }` |
310
+ | Function | `{ $fn }` presente | `{ $fn: "add", args: [...] }` |
311
+ | Pipe | `{ $pipe }` presente | `{ $pipe: [...] }` |
312
+ | Condition | `{ path, op }` com operador válido | `{ path: "age", op: "gte", value: 18 }` |
313
+ | Literal | Nenhum dos acima | `{ foo: "bar" }`, `42`, `"hello"` |
314
+
315
+ ### Distinção entre Conditions e Effect Objects
316
+
317
+ Objetos com `path` e `op` só são tratados como conditions se `op` for um operador válido:
318
+
319
+ ```typescript
320
+ // ✓ Condition (op: "eq" é operador válido)
321
+ { path: "user.age", op: "eq", value: 18 }
322
+
323
+ // ✓ Literal object (op: "set" NÃO é operador de condition)
324
+ { resource: "state", op: "set", path: "currentPlayer", value: "X" }
325
+ ```
326
+
327
+ Isso permite que effect objects de handlers (que usam `{ resource, op: "set", path, value }`) sejam processados corretamente sem serem confundidos com conditions.
328
+
329
+ ## TypeScript
330
+
331
+ ```typescript
332
+ import type {
333
+ Expression,
334
+ CompiledExpression,
335
+ RefExpr,
336
+ ConditionalExpr,
337
+ FnExpr,
338
+ PipeExpr,
339
+ Scope,
340
+ CompileOptions,
341
+ } from '@statedelta-libs/expressions';
342
+
343
+ // Type guards
344
+ import {
345
+ isRef,
346
+ isConditional,
347
+ isFn,
348
+ isPipe,
349
+ isCondition,
350
+ isLiteral,
351
+ } from '@statedelta-libs/expressions';
352
+ ```
353
+
354
+ ## Migração de v0.1.x
355
+
356
+ ### Breaking Changes
357
+
358
+ 1. **Builtins removidos**: Funções não são mais hardcoded. Passe via `scope`:
359
+ ```typescript
360
+ // Antes
361
+ compile({ $fn: "add", args: [1, 2] })
362
+
363
+ // Depois
364
+ compile({ $fn: "add", args: [1, 2] }, { scope: { add } })
365
+ ```
366
+
367
+ 2. **$fn sem args retorna função**: Para chamar sem argumentos, use `args: []`:
368
+ ```typescript
369
+ // Retorna a função
370
+ { $fn: "sum" }
371
+
372
+ // Chama a função
373
+ { $fn: "getTime", args: [] }
374
+ ```
375
+
376
+ 3. **Removidos**: `registerFunction`, `hasFunction`, `getFunctionNames`
377
+
378
+ 4. **Novo**: `$pipe` como sintaxe DSL para composição
379
+
380
+ ## Licença
381
+
382
+ MIT © Anderson D. Rosa
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ 'use strict';var conditions=require('@statedelta-libs/conditions'),omniAst=require('omni-ast');var m=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,h=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,E=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),M=new Set(["eq","neq","gt","gte","lt","lte","in","notIn","contains","notContains","exists","notExists","matches","notMatches","startsWith","endsWith"]),g=n=>n!==null&&typeof n=="object"&&"path"in n&&"op"in n&&M.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),y=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,H=n=>g(n)||y(n),W=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 t=n,o="path"in t&&"op"in t&&M.has(t.op);return !("$"in t)&&!("$if"in t)&&!("$fn"in t)&&!("$pipe"in t)&&!o&&!("logic"in t)}return false};var R=new Map;function I(n){let e=[],t=n.length,o=0,i="";for(;o<t;){let s=n[o];if(s===".")i&&(e.push({type:"key",value:i}),i=""),o++;else if(s==="["){i&&(e.push({type:"key",value:i}),i=""),o++;let r=o;for(;o<t&&n[o]!=="]";)o++;let c=n.slice(r,o);if(o++,c==="*")e.push({type:"wildcard",value:"*"});else {let f=parseInt(c,10);e.push({type:"index",value:isNaN(f)?c:f});}}else i+=s,o++;}return i&&e.push({type:"key",value:i}),e}function V(n){return n.includes("[*]")}function x(n){let e=R.get(n);return e||(e=V(n)?U(n):Q(n),R.set(n,e),e)}function Q(n){if(!n.includes(".")&&!n.includes("["))return i=>i?.[n];let e=I(n),t=e.length;if(t===2){let[i,s]=e,r=i.value,c=s.value;return f=>f?.[r]?.[c]}if(t===3){let[i,s,r]=e,c=i.value,f=s.value,a=r.value;return u=>u?.[c]?.[f]?.[a]}let o=e.map(i=>i.value);return i=>{let s=i;for(let r=0;r<t&&s!=null;r++)s=s[o[r]];return s}}function U(n){let e=I(n),t=[];for(let o=0;o<e.length;o++)e[o].type==="wildcard"&&t.push(o);return t.length===1?X(e,t[0]):Z(e,t)}function X(n,e){let t=n.slice(0,e).map(r=>r.value),o=n.slice(e+1).map(r=>r.value),i=t.length,s=o.length;if(s===0){if(i===1){let r=t[0];return c=>c?.[r]}return r=>{let c=r;for(let f=0;f<i&&c!=null;f++)c=c[t[f]];return c}}if(s===1){let r=o[0];if(i===1){let c=t[0];return f=>{let a=f?.[c];if(Array.isArray(a))return a.map(u=>u?.[r])}}return c=>{let f=c;for(let a=0;a<i&&f!=null;a++)f=f[t[a]];if(Array.isArray(f))return f.map(a=>a?.[r])}}return r=>{let c=r;for(let f=0;f<i&&c!=null;f++)c=c[t[f]];if(Array.isArray(c))return c.map(f=>{let a=f;for(let u=0;u<s&&a!=null;u++)a=a[o[u]];return a})}}function Z(n,e){let t=[],o=0;for(let s=0;s<e.length;s++){let r=e[s],c=s===e.length-1,f=n.slice(o,r).map(a=>a.value);f.length>0&&t.push({type:"access",keys:f}),t.push({type:c?"map":"flatMap",keys:[]}),o=r+1;}let i=n.slice(o).map(s=>s.value);return s=>{let r=s;for(let c of t){if(r==null)return;if(c.type==="access")for(let f of c.keys){if(r==null)return;r=r[f];}else if(c.type==="flatMap"){if(!Array.isArray(r))return;r=r.flatMap(f=>{let a=f;return Array.isArray(a)?a:[a]});}else if(c.type==="map"){if(!Array.isArray(r))return;i.length>0&&(r=r.map(f=>{let a=f;for(let u of i){if(a==null)return;a=a[u];}return a}));}}return r}}function nn(n,e){return x(e)(n)}function k(n){let e=n.indexOf("[*]");return e===-1?n:n.slice(0,e)}function en(){R.clear();}function tn(){return R.size}function T(n){let e=new Set;return A(n,e),Array.from(e)}function A(n,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let i=0;i<n.length;i++)A(n[i],e);return}if(m(n)){e.add(k(n.$));return}if(h(n)){if(typeof n.$if=="string"){let i=n.$if.startsWith("!")?n.$if.slice(1):n.$if;e.add(k(i));}else A(n.$if,e);A(n.then,e),n.else!==void 0&&A(n.else,e);return}if(C(n)){for(let i=0;i<n.$pipe.length;i++)A(n.$pipe[i],e);return}if(E(n)){if(n.args)for(let i=0;i<n.args.length;i++)A(n.args[i],e);return}if(g(n)){e.add(k(n.path)),n.value!==void 0&&conditions.isRef(n.value)&&e.add(k(n.value.$));return}if(y(n)){for(let i=0;i<n.conditions.length;i++)A(n.conditions[i],e);return}let t=n,o=Object.keys(t);for(let i=0;i<o.length;i++)A(t[o[i]],e);}function rn(n){return T(n).length>0}function sn(n){return T(n).length===0}function ln(n){return JSON.stringify(n)}function O(n,e={}){let t=e.scope??{},o=b(n,t),i=T(n),s=ln(n);return {fn:o,deps:i,hash:s}}function b(n,e){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let t=n.map(o=>b(o,e));return o=>t.map(i=>i(o))}if(m(n))return cn(n);if(h(n))return fn(n,e);if(C(n))return an(n,e);if(E(n))return un(n,e);if(g(n))return conditions.compile(n);if(y(n))return conditions.compile(n);if(W(n)){let t=n,o=Object.keys(t),i=o.map(s=>b(t[s],e));return s=>{let r={};for(let c=0;c<o.length;c++)r[o[c]]=i[c](s);return r}}return ()=>n}function cn(n){return x(n.$)}function fn(n,e){let t;if(typeof n.$if=="string"){let s=n.$if.startsWith("!")?n.$if.slice(1):n.$if,r=x(s);t=n.$if.startsWith("!")?f=>!r(f):f=>!!r(f);}else {let s=b(n.$if,e);t=r=>!!s(r);}let o=b(n.then,e),i=n.else!==void 0?b(n.else,e):()=>{};return s=>t(s)?o(s):i(s)}function an(n,e){let t=n.$pipe;if(t.length===0)return ()=>{};if(t.length===1)return b(t[0],e);let o=b(t[0],e),i=t.slice(1).map(r=>b(r,e)),s=i.length;if(s===1){let[r]=i;return c=>{let f=o(c),a=r(c);return typeof a=="function"?a(f):a}}if(s===2){let[r,c]=i;return f=>{let a=o(f),u=r(f);return a=typeof u=="function"?u(a):u,u=c(f),typeof u=="function"?u(a):u}}if(s===3){let[r,c,f]=i;return a=>{let u=o(a),p=r(a);return u=typeof p=="function"?p(u):p,p=c(a),u=typeof p=="function"?p(u):p,p=f(a),typeof p=="function"?p(u):p}}return r=>{let c=o(r);for(let f=0;f<s;f++){let a=i[f](r);c=typeof a=="function"?a(c):a;}return c}}function un(n,e){let t=n.$fn,o=n.args;if(o===void 0)return ()=>{let r=e[t];if(!r)throw new Error(`Function not found in scope: ${t}`);return r};let i=o.map(r=>b(r,e)),s=i.length;if(s===0)return r=>{let c=e[t];if(!c)throw new Error(`Function not found in scope: ${t}`);return c()};if(s===1){let[r]=i;return c=>{let f=e[t];if(!f)throw new Error(`Function not found in scope: ${t}`);return f(r(c))}}if(s===2){let[r,c]=i;return f=>{let a=e[t];if(!a)throw new Error(`Function not found in scope: ${t}`);return a(r(f),c(f))}}if(s===3){let[r,c,f]=i;return a=>{let u=e[t];if(!u)throw new Error(`Function not found in scope: ${t}`);return u(r(a),c(a),f(a))}}return r=>{let c=e[t];if(!c)throw new Error(`Function not found in scope: ${t}`);return c(...i.map(f=>f(r)))}}function pn(n,e,t={}){return O(n,t).fn(e)}var v=class{constructor(e=1e3){this.cache=new Map,this._maxSize=e;}get(e,t={}){let o=JSON.stringify(e),i=this.cache.get(o);if(i)return this.cache.delete(o),this.cache.set(o,i),i;let s=O(e,t);if(this.cache.size>=this._maxSize){let r=this.cache.keys().next().value;r&&this.cache.delete(r);}return this.cache.set(o,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 t=this.cache.keys().next().value;t&&this.cache.delete(t);}}},_=new v;function dn(n,e={}){return _.get(n,e)}function z(n,e="root",t={}){let o=[];return $(n,e,o,t),{valid:o.length===0,errors:o}}function $(n,e,t,o){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r=0;r<n.length;r++)$(n[r],`${e}[${r}]`,t,o);return}if(m(n)){(!n.$||typeof n.$!="string")&&t.push(`${e}: invalid reference, $ must be non-empty string`);return}if(h(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||t.push(`${e}.$if: empty path in string shorthand`):$(n.$if,`${e}.$if`,t,o),$(n.then,`${e}.then`,t,o),n.else!==void 0&&$(n.else,`${e}.else`,t,o);return}if(C(n)){if(!Array.isArray(n.$pipe)){t.push(`${e}.$pipe: must be an array`);return}if(n.$pipe.length===0){t.push(`${e}.$pipe: must have at least one element`);return}for(let r=0;r<n.$pipe.length;r++)$(n.$pipe[r],`${e}.$pipe[${r}]`,t,o);return}if(E(n)){if(!n.$fn||typeof n.$fn!="string"){t.push(`${e}: invalid function, $fn must be non-empty string`);return}if(o.scope&&!(n.$fn in o.scope)&&t.push(`${e}: function "${n.$fn}" not found in scope`),n.args!==void 0)if(!Array.isArray(n.args))t.push(`${e}.args: must be an array`);else for(let r=0;r<n.args.length;r++)$(n.args[r],`${e}.args[${r}]`,t,o);return}if(g(n)){let r=conditions.validate(n,e);r.valid||t.push(...r.errors);return}if(y(n)){let r=conditions.validate(n,e);r.valid||t.push(...r.errors);return}let i=n,s=Object.keys(i);for(let r=0;r<s.length;r++){let c=s[r];$(i[c],`${e}.${c}`,t,o);}}function mn(n,e={}){let t=z(n,"root",e);if(!t.valid)throw new Error(`Invalid expression: ${t.errors.join("; ")}`)}function gn(n,e={}){return z(n,"root",e).valid}var P="data",J="scope",yn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function N(n,e={}){let{dataParam:t=P,scopeParam:o=J,noPrefixes:i=false}=e;return d(n,t,o,i)}function d(n,e,t,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=>d(i,e,t,o)));if(m(n))return hn(n.$,e,o);if(h(n))return Cn(n,e,t,o);if(C(n))return Sn(n.$pipe,e,t,o);if(E(n))return bn(n,e,t,o);if(g(n))return An(n,e,t,o);if(y(n))return $n(n,e,t,o);if(typeof n=="object"){let s=Object.entries(n).map(([r,c])=>omniAst.builders.property(omniAst.builders.identifier(r),d(c,e,t,o)));return omniAst.builders.objectExpression(s)}return omniAst.builders.literal(null)}function hn(n,e,t){return n.includes("[*]")?En(n,e,t):w(n,e,t)}function w(n,e,t){let o=F(n);if(o.length===0)return t?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(e);let i;if(t){let s=o[0];i=omniAst.builders.identifier(s.value);for(let r=1;r<o.length;r++){let c=o[r];c.type==="key"?i=omniAst.builders.memberExpression(i,omniAst.builders.identifier(c.value),false,true):i=omniAst.builders.memberExpression(i,omniAst.builders.literal(c.value),true,true);}}else {i=omniAst.builders.identifier(e);for(let s of o)s.type==="key"?i=omniAst.builders.memberExpression(i,omniAst.builders.identifier(s.value),false,true):i=omniAst.builders.memberExpression(i,omniAst.builders.literal(s.value),true,true);}return i}function En(n,e,t){let o=n.indexOf("[*]"),i=n.slice(0,o),s=n.slice(o+3),r;if(i?r=w(i,e,t):r=t?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(e),!s||s==="")return r;if(s.includes("[*]"))return B(r,s);let c="_i",f=s.startsWith(".")?s.slice(1):s,a=omniAst.builders.identifier(c);if(f){let u=F(f);for(let p of u)p.type==="key"?a=omniAst.builders.memberExpression(a,omniAst.builders.identifier(p.value),false,true):a=omniAst.builders.memberExpression(a,omniAst.builders.literal(p.value),true,true);}return omniAst.builders.callExpression(omniAst.builders.memberExpression(r,omniAst.builders.identifier("map"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(c)],a)])}function B(n,e){let t=e.indexOf("[*]"),o=e.slice(0,t),i=e.slice(t+3),s="_i",r=o.startsWith(".")?o.slice(1):o,c=omniAst.builders.identifier(s);if(r){let a=F(r);for(let u of a)u.type==="key"&&(c=omniAst.builders.memberExpression(c,omniAst.builders.identifier(u.value),false,true));}if(i.includes("[*]")){let a=B(c,i);return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(s)],a)])}let f=i.startsWith(".")?i.slice(1):i;if(f){let a=F(f);for(let u of a)u.type==="key"&&(c=omniAst.builders.memberExpression(c,omniAst.builders.identifier(u.value),false,true));}return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(s)],c)])}function Cn(n,e,t,o){let i;if(typeof n.$if=="string"){let c=n.$if.startsWith("!"),f=c?n.$if.slice(1):n.$if,a=w(f,e,o);i=c?omniAst.builders.unaryExpression("!",a):a;}else i=d(n.$if,e,t,o);let s=d(n.then,e,t,o),r=n.else!==void 0?d(n.else,e,t,o):omniAst.builders.identifier("undefined");return omniAst.builders.conditionalExpression(i,s,r)}function bn(n,e,t,o){let i=o?omniAst.builders.identifier(n.$fn):omniAst.builders.memberExpression(omniAst.builders.identifier(t),omniAst.builders.identifier(n.$fn),false,false);if(n.args===void 0)return i;let s=n.args.map(r=>d(r,e,t,o));return omniAst.builders.callExpression(i,s)}function Sn(n,e,t,o){if(n.length===0)return omniAst.builders.identifier("undefined");if(n.length===1)return d(n[0],e,t,o);let i=d(n[0],e,t,o);for(let s=1;s<n.length;s++){let r=d(n[s],e,t,o);i=omniAst.builders.callExpression(r,[i]);}return i}function An(n,e,t,o){let i=w(n.path,e,o),s=n.value!==void 0?m(n.value)?w(n.value.$,e,o):d(n.value,e,t,o):omniAst.builders.literal(null),r=yn[n.op];if(r)return omniAst.builders.binaryExpression(r,i,s);switch(n.op){case "in":return omniAst.builders.callExpression(omniAst.builders.memberExpression(s,omniAst.builders.identifier("includes")),[i]);case "notIn":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(s,omniAst.builders.identifier("includes")),[i]));case "contains":return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("includes"),false,true),[s]);case "notContains":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("includes"),false,true),[s]));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"),[s]),omniAst.builders.identifier("test")),[i]);case "notMatches":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[s]),omniAst.builders.identifier("test")),[i]));case "startsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("startsWith"),false,true),[s]);case "endsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(i,omniAst.builders.identifier("endsWith"),false,true),[s]);default:return omniAst.builders.binaryExpression("===",i,s)}}function $n(n,e,t,o){let{logic:i,conditions:s}=n,r=i==="AND"?"&&":"||";if(s.length===0)return omniAst.builders.literal(i==="AND");if(s.length===1)return d(s[0],e,t,o);let c=d(s[0],e,t,o);for(let f=1;f<s.length;f++){let a=d(s[f],e,t,o);c=omniAst.builders.logicalExpression(r,c,a);}return c}function F(n){let e=[],t=n.length,o=0,i="";for(;o<t;){let s=n[o];if(s===".")i&&(e.push({type:"key",value:i}),i=""),o++;else if(s==="["){i&&(e.push({type:"key",value:i}),i=""),o++;let r=o;for(;o<t&&n[o]!=="]";)o++;let c=n.slice(r,o);if(o++,c!=="*"){let f=parseInt(c,10);e.push({type:"index",value:isNaN(f)?c:f});}}else i+=s,o++;}return i&&e.push({type:"key",value:i}),e}function K(n,e=[P]){return omniAst.builders.arrowFunctionExpression(e.map(t=>omniAst.builders.identifier(t)),n)}function j(n){let e=new Set;return S(n,e),e}function S(n,e){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let o of n)S(o,e);return}if(m(n))return;if(h(n)){S(n.$if,e),S(n.then,e),n.else!==void 0&&S(n.else,e);return}if(C(n)){for(let o of n.$pipe)S(o,e);return}if(E(n)){if(e.add(n.$fn),n.args)for(let o of n.args)S(o,e);return}if(g(n)){n.value!==void 0&&typeof n.value=="object"&&S(n.value,e);return}if(y(n)){for(let o of n.conditions)S(o,e);return}let t=n;for(let o of Object.keys(t))S(t[o],e);}function G(n){let e=new Set;for(let t of n){let o=t.indexOf("."),i=t.indexOf("["),s=t.length;o!==-1&&(s=Math.min(s,o)),i!==-1&&(s=Math.min(s,i));let r=t.slice(0,s);r&&e.add(r);}return e}function kn(n){return JSON.stringify(n)}function xn(n,e,t){let o=N(n,{noPrefixes:true}),i=omniAst.generate(o),s=e.size>0?`const{${[...e].join(",")}}=data??{};`:"",r=t.size>0?`const{${[...t].join(",")}}=scope;`:"";return r?`(function(scope){${r}return function(data){${s}return ${i}}})`:`(function(){return function(data){${s}return ${i}}})`}function D(n,e={}){let{scope:t={},returnCode:o=false}=e,i=T(n),s=G(i),r=j(n),c=kn(n),f=xn(n,s,r);if(o)return {code:f,deps:i,hash:c,dataRoots:[...s],scopeFns:[...r]};let a;try{a=new Function(`return ${f}`)()(t);}catch(u){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${u instanceof Error?u.message:String(u)}`)}return {fn:a,deps:i,hash:c}}function Y(n,e,t={}){let{fn:o}=D(n,t);return o(e)}var ie="0.0.1";exports.ExpressionCache=v;exports.VERSION=ie;exports.assertValid=mn;exports.cache=_;exports.cached=dn;exports.clearPathCache=en;exports.compile=O;exports.compileAST=D;exports.compilePath=x;exports.dslToAST=N;exports.evaluate=pn;exports.evaluateAST=Y;exports.extractDataRoots=G;exports.extractDeps=T;exports.extractScopeFns=j;exports.get=nn;exports.getPathCacheSize=tn;exports.hasDeps=rn;exports.hasWildcard=V;exports.isCondition=g;exports.isConditionExpr=H;exports.isConditionGroup=y;exports.isConditional=h;exports.isFn=E;exports.isLiteral=W;exports.isPipe=C;exports.isPure=sn;exports.isRef=m;exports.isValid=gn;exports.normalizePath=k;exports.validate=z;exports.wrapInFunction=K;