@statedelta-libs/expressions 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,13 +10,16 @@
10
10
  - **DSL Puro** - 100% JSON-serializável, sem callbacks inline
11
11
  - **Compilação** - Compila uma vez, executa milhões de vezes
12
12
  - **Alta performance** - ~25-30M ops/s após compilação
13
- - **Scope externo** - Funções vêm via scope, não hardcoded
13
+ - **Scope externo** - Funções puras vêm via scope, não hardcoded
14
+ - **Context externo** - HOCs de continuidade via context (`tryCatch`, `transaction`, etc.)
14
15
  - **Accessor customizado** - Suporte a `ctx.get(path)` para objetos especiais
15
16
  - **$pipe** - Composição com valor inicial (sintaxe DSL)
17
+ - **$cb** - Callback expressions para HOCs de continuidade
16
18
  - **Path syntax** - Suporte a wildcards (`items[*].price`)
17
19
  - **Dependency extraction** - Para dirty tracking/reatividade
18
20
  - **Conditions nativo** - Condicionais integradas com expressions nos lados
19
21
  - **normalize()** - Helper externo para custom transforms (`$query`, `$mapper`, etc.)
22
+ - **resolveBoundaries()** - Resolve boundaries customizados (`$simulate`, `$context`, etc.) com compilação independente
20
23
  - **Type-safe** - TypeScript nativo com inferência
21
24
 
22
25
  ## Instalação
@@ -297,6 +300,76 @@ Condicionais compiladas internamente. Ambos os lados aceitam qualquer expressão
297
300
 
298
301
  **Operadores:** `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`, `contains`, `notContains`, `exists`, `notExists`, `matches`, `notMatches`, `startsWith`, `endsWith`
299
302
 
303
+ ### Callback ($cb)
304
+
305
+ HOC de continuidade - executa body dentro de um context function.
306
+
307
+ ```typescript
308
+ // Básico - tryCatch
309
+ { $cb: "tryCatch", body: { $fn: "query" } }
310
+
311
+ // Com parâmetros
312
+ { $cb: "transaction", body: { $fn: "save" }, params: { isolation: "serializable" } }
313
+
314
+ // Aninhado
315
+ {
316
+ $cb: "tryCatch",
317
+ body: {
318
+ $cb: "transaction",
319
+ body: { $fn: "save" }
320
+ }
321
+ }
322
+ ```
323
+
324
+ ## Context
325
+
326
+ O context define HOCs disponíveis para `$cb`. Diferente de scope (funções puras), context functions controlam a execução do body:
327
+
328
+ ```typescript
329
+ import type { Context, ContextFn } from '@statedelta-libs/expressions';
330
+
331
+ const tryCatch: ContextFn = (cb, data, get, params) => {
332
+ try {
333
+ return cb(data, get);
334
+ } catch {
335
+ return params?.fallback ?? null;
336
+ }
337
+ };
338
+
339
+ const transaction: ContextFn = (cb, data, get, params) => {
340
+ const tx = db.beginTransaction(params);
341
+ try {
342
+ const result = cb({ ...data, tx }, get);
343
+ tx.commit();
344
+ return result;
345
+ } catch (e) {
346
+ tx.rollback();
347
+ throw e;
348
+ }
349
+ };
350
+
351
+ // Context function pode ignorar o cb e retornar outro valor
352
+ const cached: ContextFn = (cb, data, get, params) => {
353
+ if (cache.has(params?.key)) {
354
+ return cache.get(params.key); // Não executa cb
355
+ }
356
+ return cb(data, get);
357
+ };
358
+
359
+ const context: Context = { tryCatch, transaction, cached };
360
+
361
+ compile(expression, { scope, context });
362
+ ```
363
+
364
+ **Parâmetros do ContextFn:**
365
+
366
+ | Parâmetro | Tipo | Descrição |
367
+ |-----------|------|-----------|
368
+ | `cb` | `(data, get) => R` | Body compilado como callback |
369
+ | `data` | `T` | Dados do runtime |
370
+ | `get` | `(path) => unknown` | Resolver de paths |
371
+ | `params` | `unknown` | Parâmetros do `$cb.params` |
372
+
300
373
  ## Scope
301
374
 
302
375
  O scope define quais funções estão disponíveis para `$fn`:
@@ -392,6 +465,156 @@ normalize({ $loop: "test" }, badTransforms);
392
465
  // Error: Transform "$loop" returned object with same key — infinite loop
393
466
  ```
394
467
 
468
+ ## Boundaries (resolveBoundaries)
469
+
470
+ Para DSL customizados que precisam de **compilação independente** dos slots internos, use `resolveBoundaries()`. Diferente de `normalize()` (que apenas transforma), boundaries param o fluxo de compilação e delegam para um resolver externo.
471
+
472
+ ### Conceito
473
+
474
+ Um **boundary** é um "corpo estranho" no DSL que:
475
+ 1. **Para** o fluxo normal de compilação
476
+ 2. **Delega** para um resolver customizado
477
+ 3. O resolver **compila slots internos** independentemente
478
+ 4. **Substitui** por uma referência no scope
479
+
480
+ ```
481
+ DSL "rico" DSL puro
482
+ { $simulate: {...} } → { $fn: "__simulate_0", args: [] }
483
+ + scope["__simulate_0"] = fn compilada
484
+ ```
485
+
486
+ ### Uso básico
487
+
488
+ ```typescript
489
+ import { resolveBoundaries, compile, type BoundaryResolvers } from '@statedelta-libs/expressions';
490
+
491
+ const resolvers: BoundaryResolvers = {
492
+ $context: (node, { compile: compileFn, genId, scope }) => {
493
+ const id = `__context_${genId()}`;
494
+ const body = (node.$context as { body: Expression }).body;
495
+
496
+ // Compila o body internamente
497
+ const bodyFn = compileFn(body, { scope }).fn;
498
+
499
+ // Retorna função com lifecycle begin/end
500
+ const contextFn = () => (data: unknown) => {
501
+ console.log("begin");
502
+ try {
503
+ return bodyFn(data);
504
+ } finally {
505
+ console.log("end");
506
+ }
507
+ };
508
+
509
+ return {
510
+ expr: { $fn: id, args: [] },
511
+ scopeEntry: [id, contextFn],
512
+ };
513
+ },
514
+ };
515
+
516
+ // 1. Resolve boundaries (extrai e compila internamente)
517
+ const { expr, scope } = resolveBoundaries(
518
+ { $context: { body: { $fn: "add", args: [{ $: "a" }, { $: "b" }] } } },
519
+ { resolvers, scope: { add: (a, b) => a + b } }
520
+ );
521
+
522
+ // 2. Compila DSL puro resultante
523
+ const { fn } = compile(expr, { scope });
524
+
525
+ // 3. Executa
526
+ const contextFn = fn({}); // Retorna a função com lifecycle
527
+ const result = contextFn({ a: 1, b: 2 }); // "begin" → 3 → "end"
528
+ ```
529
+
530
+ ### Caso de uso: $simulate com múltiplos slots
531
+
532
+ ```typescript
533
+ interface SimulateNode {
534
+ $simulate: {
535
+ effects: Expression[];
536
+ query: Expression;
537
+ };
538
+ }
539
+
540
+ const resolvers: BoundaryResolvers = {
541
+ $simulate: (node, { compile: compileFn, genId, scope }) => {
542
+ const id = `__simulate_${genId()}`;
543
+ const sim = (node as unknown as SimulateNode).$simulate;
544
+
545
+ // Compila cada slot independentemente
546
+ const effectFns = sim.effects.map((e) => compileFn(e, { scope }).fn);
547
+ const queryFn = compileFn(sim.query, { scope }).fn;
548
+
549
+ // Cria função que orquestra a execução
550
+ const simulateFn = () => (data: unknown) => {
551
+ const effects = effectFns.map((fn) => fn(data));
552
+ const query = queryFn(data);
553
+ return { effects, query };
554
+ };
555
+
556
+ return {
557
+ expr: { $fn: id, args: [] },
558
+ scopeEntry: [id, simulateFn],
559
+ };
560
+ },
561
+ };
562
+
563
+ const { expr, scope } = resolveBoundaries(
564
+ {
565
+ $simulate: {
566
+ effects: [
567
+ { $fn: "increment", args: [{ $: "hp" }] },
568
+ { $fn: "decrement", args: [{ $: "mp" }] },
569
+ ],
570
+ query: { $fn: "isAlive", args: [{ $: "hp" }] },
571
+ },
572
+ },
573
+ { resolvers, scope: myScope }
574
+ );
575
+ ```
576
+
577
+ ### Contexto do resolver
578
+
579
+ O resolver recebe um contexto com:
580
+
581
+ | Propriedade | Tipo | Descrição |
582
+ |-------------|------|-----------|
583
+ | `compile` | `typeof compile` | Mesmo compilador do fluxo principal |
584
+ | `genId` | `() => string` | Gerador de IDs únicos |
585
+ | `scope` | `Scope` | Scope atual (read-only) |
586
+ | `options` | `CompileOptions` | Opções de compilação |
587
+
588
+ ### ID Generator customizado
589
+
590
+ Por padrão, IDs são gerados como `"0"`, `"1"`, `"2"`... Para IDs únicos globais, passe um `genId` customizado:
591
+
592
+ ```typescript
593
+ import { nanoid } from 'nanoid';
594
+
595
+ const { expr, scope } = resolveBoundaries(expr, {
596
+ resolvers,
597
+ scope: baseScope,
598
+ genId: () => nanoid(), // IDs únicos globais
599
+ });
600
+ ```
601
+
602
+ ### Diferença entre normalize e resolveBoundaries
603
+
604
+ | | `normalize()` | `resolveBoundaries()` |
605
+ |---|---|---|
606
+ | **Propósito** | Transformar sintaxe | Compilação independente |
607
+ | **Retorno** | `Expression` | `{ expr, scope }` |
608
+ | **Compila slots** | Não | Sim (via `ctx.compile`) |
609
+ | **Acumula scope** | Não | Sim |
610
+ | **Uso típico** | `$query` → `$fn` | `$simulate`, `$context` |
611
+
612
+ Use `normalize()` para sugar syntax simples. Use `resolveBoundaries()` quando precisar:
613
+ - Compilar múltiplos slots independentemente
614
+ - Controlar ordem/momento de execução
615
+ - Adicionar lógica de lifecycle (begin/end, try/finally)
616
+ - DSL completamente diferente internamente
617
+
395
618
  ## Builders
396
619
 
397
620
  Funções declarativas para construir expressões:
@@ -399,7 +622,7 @@ Funções declarativas para construir expressões:
399
622
  ```typescript
400
623
  import { builders } from '@statedelta-libs/expressions';
401
624
 
402
- const { $, $fn, $if, $pipe, $cond } = builders;
625
+ const { $, $fn, $if, $pipe, $cond, $cb } = builders;
403
626
 
404
627
  // Path reference
405
628
  $("player.hp") // { $: "player.hp" }
@@ -420,6 +643,10 @@ $pipe(
420
643
 
421
644
  // Condition
422
645
  $cond($("age"), "gte", 18) // { left: ..., op: "gte", right: 18 }
646
+
647
+ // Callback (context)
648
+ $cb("tryCatch", $fn("query")) // { $cb: "tryCatch", body: {...} }
649
+ $cb("transaction", $fn("save"), { isolation: "serializable" })
423
650
  ```
424
651
 
425
652
  ## TypeScript
@@ -432,15 +659,27 @@ import type {
432
659
  ConditionalExpr,
433
660
  FnExpr,
434
661
  PipeExpr,
662
+ CbExpr,
435
663
  Condition,
436
664
  ConditionGroup,
437
665
  ConditionExpr,
438
666
  ConditionOp,
439
667
  Scope,
668
+ Context,
669
+ ContextFn,
670
+ PathGetterFn,
440
671
  CompileOptions,
441
672
  AccessorFn,
442
673
  TransformFn,
443
674
  Transforms,
675
+ // Boundaries
676
+ BoundaryResolver,
677
+ BoundaryResolvers,
678
+ ResolverContext,
679
+ ResolverResult,
680
+ ResolveBoundariesOptions,
681
+ ResolveBoundariesResult,
682
+ IdGenerator,
444
683
  } from '@statedelta-libs/expressions';
445
684
 
446
685
  // Type guards
@@ -449,6 +688,7 @@ import {
449
688
  isConditional,
450
689
  isFn,
451
690
  isPipe,
691
+ isCb,
452
692
  isCondition,
453
693
  isLiteral,
454
694
  } from '@statedelta-libs/expressions';
@@ -505,6 +745,40 @@ Funções só são acessíveis se existirem no `scope` fornecido pelo desenvolve
505
745
 
506
746
  4. **Novos tipos**: `Transforms` (alias para `Record<string, TransformFn>`)
507
747
 
748
+ ### v1.2 → v2.0
749
+
750
+ 1. **Novo tipo `$cb`**: HOC de continuidade para wrapping contextual:
751
+ ```typescript
752
+ // tryCatch, transaction, cached, etc.
753
+ { $cb: "tryCatch", body: { $fn: "query" }, params: { fallback: [] } }
754
+ ```
755
+
756
+ 2. **Novo `context` em CompileOptions**: Separado de `scope` para HOCs:
757
+ ```typescript
758
+ compile(expr, { scope, context });
759
+ compileAST(expr, { scope, context });
760
+ ```
761
+
762
+ 3. **Novos tipos**: `CbExpr`, `Context`, `ContextFn`, `PathGetterFn`
763
+
764
+ 4. **Novo type guard**: `isCb()`
765
+
766
+ 5. **Novo builder**: `$cb(name, body, params?)`
767
+
768
+ 6. **Novo extractor**: `extractContextFns()`
769
+
770
+ 7. **Novo `resolveBoundaries()`**: Para DSL customizados com compilação independente de slots:
771
+ ```typescript
772
+ const { expr, scope } = resolveBoundaries(richExpr, {
773
+ resolvers: { $simulate: (node, ctx) => ... },
774
+ scope: baseScope,
775
+ genId: () => nanoid(), // opcional
776
+ });
777
+ compile(expr, { scope });
778
+ ```
779
+
780
+ 8. **Novos tipos**: `BoundaryResolver`, `BoundaryResolvers`, `ResolverContext`, `ResolverResult`, `ResolveBoundariesOptions`, `ResolveBoundariesResult`, `IdGenerator`
781
+
508
782
  ## Licença
509
783
 
510
784
  MIT © Anderson D. Rosa
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var omniAst=require('omni-ast');var rn=Object.defineProperty;var sn=(n,t)=>{for(var s in t)rn(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"]),E=n=>n!==null&&typeof n=="object"&&"left"in n&&"op"in n&&x.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),h=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,fn=n=>E(n)||h(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,i="left"in s&&"op"in s&&x.has(s.op);return !("$"in s)&&!("$if"in s)&&!("$fn"in s)&&!("$pipe"in s)&&!i&&!("logic"in s)}return false};var R=new Map;function J(n){let t=[],s=n.length,i=0,r="";for(;i<s;){let o=n[i];if(o===".")r&&(t.push({type:"key",value:r}),r=""),i++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),i++;let e=i;for(;i<s&&n[i]!=="]";)i++;let f=n.slice(e,i);if(i++,f==="*")t.push({type:"wildcard",value:"*"});else {let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,i++;}return r&&t.push({type:"key",value:r}),t}function B(n){return n.includes("[*]")}function O(n){let t=R.get(n);return t||(t=B(n)?ln(n):un(n),R.set(n,t),t)}function un(n){if(!n.includes(".")&&!n.includes("["))return r=>r?.[n];let t=J(n),s=t.length;if(s===2){let[r,o]=t,e=r.value,f=o.value;return l=>l?.[e]?.[f]}if(s===3){let[r,o,e]=t,f=r.value,l=o.value,c=e.value;return a=>a?.[f]?.[l]?.[c]}let i=t.map(r=>r.value);return r=>{let o=r;for(let e=0;e<s&&o!=null;e++)o=o[i[e]];return o}}function ln(n){let t=J(n),s=[];for(let i=0;i<t.length;i++)t[i].type==="wildcard"&&s.push(i);return s.length===1?cn(t,s[0]):an(t,s)}function cn(n,t){let s=n.slice(0,t).map(e=>e.value),i=n.slice(t+1).map(e=>e.value),r=s.length,o=i.length;if(o===0){if(r===1){let e=s[0];return f=>f?.[e]}return e=>{let f=e;for(let l=0;l<r&&f!=null;l++)f=f[s[l]];return f}}if(o===1){let e=i[0];if(r===1){let f=s[0];return l=>{let c=l?.[f];if(Array.isArray(c))return c.map(a=>a?.[e])}}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?.[e])}}return e=>{let f=e;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[i[a]];return c})}}function an(n,t){let s=[],i=0;for(let o=0;o<t.length;o++){let e=t[o],f=o===t.length-1,l=n.slice(i,e).map(c=>c.value);l.length>0&&s.push({type:"access",keys:l}),s.push({type:f?"map":"flatMap",keys:[]}),i=e+1;}let r=n.slice(i).map(o=>o.value);return o=>{let e=o;for(let f of s){if(e==null)return;if(f.type==="access")for(let l of f.keys){if(e==null)return;e=e[l];}else if(f.type==="flatMap"){if(!Array.isArray(e))return;e=e.flatMap(l=>{let c=l;return Array.isArray(c)?c:[c]});}else if(f.type==="map"){if(!Array.isArray(e))return;r.length>0&&(e=e.map(l=>{let c=l;for(let a of r){if(c==null)return;c=c[a];}return c}));}}return e}}function pn(n,t){return O(t)(n)}function F(n){let t=n.indexOf("[*]");return t===-1?n:n.slice(0,t)}function dn(){R.clear();}function gn(){return R.size}function w(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++)A(n.args[r],t);return}if(E(n)){A(n.left,t),n.right!==void 0&&A(n.right,t);return}if(h(n)){for(let r=0;r<n.conditions.length;r++)A(n.conditions[r],t);return}let s=n,i=Object.keys(s);for(let r=0;r<i.length;r++)A(s[i[r]],t);}function mn(n){return w(n).length>0}function yn(n){return w(n).length===0}function En(n){return JSON.stringify(n)}function N(n,t={}){let s=t.scope??{},i=t.accessor,r=m(n,s,i),o=w(n),e=En(n);return {fn:r,deps:o,hash:e}}function m(n,t,s){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let i=n.map(r=>m(r,t,s));return r=>i.map(o=>o(r))}if(y(n))return hn(n,s);if(T(n))return Tn(n,t,s);if(C(n))return bn(n,t,s);if(b(n))return Cn(n,t,s);if(E(n))return An(n,t,s);if(h(n))return $n(n,t,s);if(I(n)){let i=n,r=Object.keys(i),o=r.map(e=>m(i[e],t,s));return e=>{let f={};for(let l=0;l<r.length;l++)f[r[l]]=o[l](e);return f}}return ()=>n}function K(n,t){return t?s=>t(n,s):O(n)}function hn(n,t){return K(n.$,t)}function Tn(n,t,s){let i;if(typeof n.$if=="string"){let e=n.$if.startsWith("!")?n.$if.slice(1):n.$if,f=K(e,s);i=n.$if.startsWith("!")?c=>!f(c):c=>!!f(c);}else {let e=m(n.$if,t,s);i=f=>!!e(f);}let r=m(n.then,t,s),o=n.else!==void 0?m(n.else,t,s):()=>{};return e=>i(e)?r(e):o(e)}function bn(n,t,s){let i=n.$pipe;if(i.length===0)return ()=>{};if(i.length===1)return m(i[0],t,s);let r=m(i[0],t,s),o=i.slice(1).map(f=>m(f,t,s)),e=o.length;if(e===1){let[f]=o;return l=>{let c=r(l),a=f(l);return typeof a=="function"?a(c):a}}if(e===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(e===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<e;c++){let a=o[c](f);l=typeof a=="function"?a(l):a;}return l}}function Cn(n,t,s){let i=n.$fn,r=n.args;if(r===void 0)return ()=>{let f=t[i];if(!f)throw new Error(`Function not found in scope: ${i}`);return f};let o=r.map(f=>m(f,t,s)),e=o.length;if(e===0)return f=>{let l=t[i];if(!l)throw new Error(`Function not found in scope: ${i}`);return l()};if(e===1){let[f]=o;return l=>{let c=t[i];if(!c)throw new Error(`Function not found in scope: ${i}`);return c(f(l))}}if(e===2){let[f,l]=o;return c=>{let a=t[i];if(!a)throw new Error(`Function not found in scope: ${i}`);return a(f(c),l(c))}}if(e===3){let[f,l,c]=o;return a=>{let p=t[i];if(!p)throw new Error(`Function not found in scope: ${i}`);return p(f(a),l(a),c(a))}}return f=>{let l=t[i];if(!l)throw new Error(`Function not found in scope: ${i}`);return l(...o.map(c=>c(f)))}}function An(n,t,s){let i=m(n.left,t,s),r=n.right!==void 0?m(n.right,t,s):()=>{};switch(n.op){case "eq":return o=>i(o)===r(o);case "neq":return o=>i(o)!==r(o);case "gt":return o=>i(o)>r(o);case "gte":return o=>i(o)>=r(o);case "lt":return o=>i(o)<r(o);case "lte":return o=>i(o)<=r(o);case "in":return o=>{let e=r(o);return Array.isArray(e)&&e.includes(i(o))};case "notIn":return o=>{let e=r(o);return !Array.isArray(e)||!e.includes(i(o))};case "contains":return o=>{let e=i(o);return Array.isArray(e)&&e.includes(r(o))};case "notContains":return o=>{let e=i(o);return !Array.isArray(e)||!e.includes(r(o))};case "exists":return o=>i(o)!==void 0;case "notExists":return o=>i(o)===void 0;case "matches":return o=>{let e=i(o),f=r(o);return typeof e!="string"||typeof f!="string"?false:new RegExp(f).test(e)};case "notMatches":return o=>{let e=i(o),f=r(o);return typeof e!="string"||typeof f!="string"?true:!new RegExp(f).test(e)};case "startsWith":return o=>{let e=i(o),f=r(o);return typeof e=="string"&&typeof f=="string"&&e.startsWith(f)};case "endsWith":return o=>{let e=i(o),f=r(o);return typeof e=="string"&&typeof f=="string"&&e.endsWith(f)}}}function $n(n,t,s){let i=n.conditions.map(o=>m(o,t,s)),r=i.length;if(r===1)return o=>!!i[0](o);if(r===2){let[o,e]=i;return n.logic==="AND"?f=>!!o(f)&&!!e(f):f=>!!o(f)||!!e(f)}if(r===3){let[o,e,f]=i;return n.logic==="AND"?l=>!!o(l)&&!!e(l)&&!!f(l):l=>!!o(l)||!!e(l)||!!f(l)}return n.logic==="AND"?o=>{for(let e=0;e<r;e++)if(!i[e](o))return false;return true}:o=>{for(let e=0;e<r;e++)if(i[e](o))return true;return false}}function Sn(n,t,s={}){return N(n,s).fn(t)}var j=class{constructor(t=1e3){this.cache=new Map,this._maxSize=t;}get(t,s={}){let i=JSON.stringify(t),r=this.cache.get(i);if(r)return this.cache.delete(i),this.cache.set(i,r),r;let o=N(t,s);if(this.cache.size>=this._maxSize){let e=this.cache.keys().next().value;e&&this.cache.delete(e);}return this.cache.set(i,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);}}},P=new j;function wn(n,t={}){return P.get(n,t)}function M(n,t="root",s={}){let i=[];return $(n,t,i,s),{valid:i.length===0,errors:i}}function $(n,t,s,i){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let e=0;e<n.length;e++)$(n[e],`${t}[${e}]`,s,i);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,i),$(n.then,`${t}.then`,s,i),n.else!==void 0&&$(n.else,`${t}.else`,s,i);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 e=0;e<n.$pipe.length;e++)$(n.$pipe[e],`${t}.$pipe[${e}]`,s,i);return}if(b(n)){if(!n.$fn||typeof n.$fn!="string"){s.push(`${t}: invalid function, $fn must be non-empty string`);return}if(i.scope&&!(n.$fn in i.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 e=0;e<n.args.length;e++)$(n.args[e],`${t}.args[${e}]`,s,i);return}if(E(n)){x.has(n.op)||s.push(`${t}: invalid operator "${n.op}"`),$(n.left,`${t}.left`,s,i),n.right!==void 0&&$(n.right,`${t}.right`,s,i);return}if(h(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 e=0;e<n.conditions.length;e++)$(n.conditions[e],`${t}.conditions[${e}]`,s,i);return}let r=n,o=Object.keys(r);for(let e=0;e<o.length;e++){let f=o[e];$(r[f],`${t}.${f}`,s,i);}}function kn(n,t={}){let s=M(n,"root",t);if(!s.valid)throw new Error(`Invalid expression: ${s.errors.join("; ")}`)}function xn(n,t={}){return M(n,"root",t).valid}var X={};sn(X,{$:()=>Y,$cond:()=>U,$fn:()=>H,$if:()=>Fn,$pipe:()=>Q,cond:()=>jn,fn:()=>On,pipe:()=>Nn,ref:()=>Rn});function Y(n){return {$:n}}var Rn=Y;function H(n,t){return t===void 0||t.length===0?{$fn:n}:{$fn:n,args:t}}var On=H;function Fn(n,t,s){return s===void 0?{$if:n,then:t}:{$if:n,then:t,else:s}}function Q(...n){return {$pipe:n}}var Nn=Q;function U(n,t,s){return s===void 0?{left:n,op:t}:{left:n,op:t,right:s}}var jn=U;var V="data",nn="scope",vn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function G(n,t={}){let{dataParam:s=V,scopeParam:i=nn,noPrefixes:r=false,useAccessor:o=false,lexicalPrefix:e}=t;return g(n,s,i,r,o,e)}function g(n,t,s,i,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(e=>g(e,t,s,i,r,o)));if(y(n))return Gn(n.$,t,i,r,o);if(T(n))return Dn(n,t,s,i,r,o);if(C(n))return In(n.$pipe,t,s,i,r,o);if(b(n))return zn(n,t,s,i,r,o);if(E(n))return Mn(n,t,s,i,r,o);if(h(n))return Vn(n,t,s,i,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,i,r,o)));return omniAst.builders.objectExpression(f)}return omniAst.builders.literal(null)}var _="accessor";function L(n,t){return t?n===t||n.startsWith(t+"."):false}function Gn(n,t,s,i,r){return i?L(n,r)?k(n,t,true):omniAst.builders.callExpression(omniAst.builders.identifier(_),[omniAst.builders.literal(n),omniAst.builders.identifier(t)]):n.includes("[*]")?Wn(n,t,s):k(n,t,s)}function k(n,t,s){let i=v(n);if(i.length===0)return s?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(t);let r;if(s){let o=i[0];r=omniAst.builders.identifier(o.value);for(let e=1;e<i.length;e++){let f=i[e];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 i)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 Wn(n,t,s){let i=n.indexOf("[*]"),r=n.slice(0,i),o=n.slice(i+3),e;if(r?e=k(r,t,s):e=s?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(t),!o||o==="")return e;if(o.includes("[*]"))return tn(e,o);let f="_i",l=o.startsWith(".")?o.slice(1):o,c=omniAst.builders.identifier(f);if(l){let a=v(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(e,omniAst.builders.identifier("map"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(f)],c)])}function tn(n,t){let s=t.indexOf("[*]"),i=t.slice(0,s),r=t.slice(s+3),o="_i",e=i.startsWith(".")?i.slice(1):i,f=omniAst.builders.identifier(o);if(e){let c=v(e);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=tn(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=v(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 Dn(n,t,s,i,r,o){let e;if(typeof n.$if=="string"){let c=n.$if.startsWith("!"),a=c?n.$if.slice(1):n.$if,p;r?L(a,o)?p=k(a,t,true):p=omniAst.builders.callExpression(omniAst.builders.identifier(_),[omniAst.builders.literal(a),omniAst.builders.identifier(t)]):p=k(a,t,i),e=c?omniAst.builders.unaryExpression("!",p):p;}else e=g(n.$if,t,s,i,r,o);let f=g(n.then,t,s,i,r,o),l=n.else!==void 0?g(n.else,t,s,i,r,o):omniAst.builders.identifier("undefined");return omniAst.builders.conditionalExpression(e,f,l)}function zn(n,t,s,i,r,o){let e=i?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 e;let f=n.args.map(l=>g(l,t,s,i,r,o));return omniAst.builders.callExpression(e,f)}function In(n,t,s,i,r,o){if(n.length===0)return omniAst.builders.identifier("undefined");if(n.length===1)return g(n[0],t,s,i,r,o);let e=g(n[0],t,s,i,r,o);for(let f=1;f<n.length;f++){let l=g(n[f],t,s,i,r,o);e=omniAst.builders.callExpression(l,[e]);}return e}function Z(n,t,s,i,r,o){if(y(n)){let e=n.$;return r?L(e,o)?k(e,t,true):omniAst.builders.callExpression(omniAst.builders.identifier(_),[omniAst.builders.literal(e),omniAst.builders.identifier(t)]):k(e,t,i)}return g(n,t,s,i,r,o)}function Mn(n,t,s,i,r,o){let e=Z(n.left,t,s,i,r,o),f=n.right!==void 0?Z(n.right,t,s,i,r,o):omniAst.builders.literal(null),l=vn[n.op];if(l)return omniAst.builders.binaryExpression(l,e,f);switch(n.op){case "in":return omniAst.builders.callExpression(omniAst.builders.memberExpression(f,omniAst.builders.identifier("includes")),[e]);case "notIn":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(f,omniAst.builders.identifier("includes")),[e]));case "contains":return omniAst.builders.callExpression(omniAst.builders.memberExpression(e,omniAst.builders.identifier("includes"),false,true),[f]);case "notContains":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(e,omniAst.builders.identifier("includes"),false,true),[f]));case "exists":return omniAst.builders.binaryExpression("!=",e,omniAst.builders.literal(null));case "notExists":return omniAst.builders.binaryExpression("==",e,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")),[e]);case "notMatches":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[f]),omniAst.builders.identifier("test")),[e]));case "startsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(e,omniAst.builders.identifier("startsWith"),false,true),[f]);case "endsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(e,omniAst.builders.identifier("endsWith"),false,true),[f]);default:return omniAst.builders.binaryExpression("===",e,f)}}function Vn(n,t,s,i,r,o){let{logic:e,conditions:f}=n,l=e==="AND"?"&&":"||";if(f.length===0)return omniAst.builders.literal(e==="AND");if(f.length===1)return g(f[0],t,s,i,r,o);let c=g(f[0],t,s,i,r,o);for(let a=1;a<f.length;a++){let p=g(f[a],t,s,i,r,o);c=omniAst.builders.logicalExpression(l,c,p);}return c}function v(n){let t=[],s=n.length,i=0,r="";for(;i<s;){let o=n[i];if(o===".")r&&(t.push({type:"key",value:r}),r=""),i++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),i++;let e=i;for(;i<s&&n[i]!=="]";)i++;let f=n.slice(e,i);if(i++,f!=="*"){let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,i++;}return r&&t.push({type:"key",value:r}),t}function en(n,t=[V]){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 i of n)S(i,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 i of n.$pipe)S(i,t);return}if(b(n)){if(t.add(n.$fn),n.args)for(let i of n.args)S(i,t);return}if(E(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(h(n)){for(let i of n.conditions)S(i,t);return}let s=n;for(let i of Object.keys(s))S(s[i],t);}function D(n){let t=new Set;for(let s of n){let i=s.indexOf("."),r=s.indexOf("["),o=s.length;i!==-1&&(o=Math.min(o,i)),r!==-1&&(o=Math.min(o,r));let e=s.slice(0,o);e&&t.add(e);}return t}function Ln(n){return JSON.stringify(n)}function qn(n,t,s,i,r){let o=G(n,{noPrefixes:true,useAccessor:i,lexicalPrefix:r}),e=omniAst.generate(o),f="";i?r&&(f=`const{${r}}=data??{};`):t.size>0&&(f=`const{${[...t].join(",")}}=data??{};`);let l=i?new Set([...s,"accessor"]):s,c=l.size>0?`const{${[...l].join(",")}}=scope;`:"";return c?`(function(scope){${c}return function(data){${f}return ${e}}})`:`(function(){return function(data){${f}return ${e}}})`}function q(n,t={}){let{scope:s={},returnCode:i=false,useAccessor:r=false,lexicalPrefix:o}=t,e=w(n),f=D(e),l=W(n),c=Ln(n),a=qn(n,f,l,r,o);if(i)return {code:a,deps:e,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:e,hash:c}}function on(n,t,s={}){let{fn:i}=q(n,s);return i(t)}function Jn(n,t){return z(n,t)}function z(n,t){if(n===null)return null;if(typeof n!="object")return n;if(Array.isArray(n))return n.map(o=>z(o,t));let s=n,i=Object.keys(s);for(let o of i)if(o in t){let e=t[o](s);if(typeof e=="object"&&e!==null&&o in e)throw new Error(`Transform "${o}" returned object with same key \u2014 infinite loop`);return z(e,t)}let r={};for(let o of i)r[o]=z(s[o],t);return r}var bt="2.0.0";exports.ExpressionCache=j;exports.VERSION=bt;exports.assertValid=kn;exports.builders=X;exports.cache=P;exports.cached=wn;exports.clearPathCache=dn;exports.compile=N;exports.compileAST=q;exports.compilePath=O;exports.dslToAST=G;exports.evaluate=Sn;exports.evaluateAST=on;exports.extractDataRoots=D;exports.extractDeps=w;exports.extractScopeFns=W;exports.get=pn;exports.getPathCacheSize=gn;exports.hasDeps=mn;exports.hasWildcard=B;exports.isCondition=E;exports.isConditionExpr=fn;exports.isConditionGroup=h;exports.isConditional=T;exports.isFn=b;exports.isLiteral=I;exports.isPipe=C;exports.isPure=yn;exports.isRef=y;exports.isValid=xn;exports.normalize=Jn;exports.normalizePath=F;exports.validate=M;exports.wrapInFunction=en;
1
+ 'use strict';var omniAst=require('omni-ast');var mn=Object.defineProperty;var En=(n,t)=>{for(var o in t)mn(n,o,{get:t[o],enumerable:true});};var E=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,S=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,k=n=>n!==null&&typeof n=="object"&&"$fn"in n&&typeof n.$fn=="string",x=n=>n!==null&&typeof n=="object"&&"$pipe"in n&&Array.isArray(n.$pipe),R=n=>n!==null&&typeof n=="object"&&"$cb"in n&&typeof n.$cb=="string"&&"body"in n,G=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&&G.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),b=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,hn=n=>h(n)||b(n),q=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 o=n,r="left"in o&&"op"in o&&G.has(o.op);return !("$"in o)&&!("$if"in o)&&!("$fn"in o)&&!("$pipe"in o)&&!("$cb"in o)&&!r&&!("logic"in o)}return false};var I=new Map;function Q(n){let t=[],o=n.length,r=0,i="";for(;r<o;){let s=n[r];if(s===".")i&&(t.push({type:"key",value:i}),i=""),r++;else if(s==="["){i&&(t.push({type:"key",value:i}),i=""),r++;let e=r;for(;r<o&&n[r]!=="]";)r++;let f=n.slice(e,r);if(r++,f==="*")t.push({type:"wildcard",value:"*"});else {let u=parseInt(f,10);t.push({type:"index",value:isNaN(u)?f:u});}}else i+=s,r++;}return i&&t.push({type:"key",value:i}),t}function U(n){return n.includes("[*]")}function N(n){let t=I.get(n);return t||(t=U(n)?Cn(n):bn(n),I.set(n,t),t)}function bn(n){if(!n.includes(".")&&!n.includes("["))return i=>i?.[n];let t=Q(n),o=t.length;if(o===2){let[i,s]=t,e=i.value,f=s.value;return u=>u?.[e]?.[f]}if(o===3){let[i,s,e]=t,f=i.value,u=s.value,l=e.value;return a=>a?.[f]?.[u]?.[l]}let r=t.map(i=>i.value);return i=>{let s=i;for(let e=0;e<o&&s!=null;e++)s=s[r[e]];return s}}function Cn(n){let t=Q(n),o=[];for(let r=0;r<t.length;r++)t[r].type==="wildcard"&&o.push(r);return o.length===1?Tn(t,o[0]):$n(t,o)}function Tn(n,t){let o=n.slice(0,t).map(e=>e.value),r=n.slice(t+1).map(e=>e.value),i=o.length,s=r.length;if(s===0){if(i===1){let e=o[0];return f=>f?.[e]}return e=>{let f=e;for(let u=0;u<i&&f!=null;u++)f=f[o[u]];return f}}if(s===1){let e=r[0];if(i===1){let f=o[0];return u=>{let l=u?.[f];if(Array.isArray(l))return l.map(a=>a?.[e])}}return f=>{let u=f;for(let l=0;l<i&&u!=null;l++)u=u[o[l]];if(Array.isArray(u))return u.map(l=>l?.[e])}}return e=>{let f=e;for(let u=0;u<i&&f!=null;u++)f=f[o[u]];if(Array.isArray(f))return f.map(u=>{let l=u;for(let a=0;a<s&&l!=null;a++)l=l[r[a]];return l})}}function $n(n,t){let o=[],r=0;for(let s=0;s<t.length;s++){let e=t[s],f=s===t.length-1,u=n.slice(r,e).map(l=>l.value);u.length>0&&o.push({type:"access",keys:u}),o.push({type:f?"map":"flatMap",keys:[]}),r=e+1;}let i=n.slice(r).map(s=>s.value);return s=>{let e=s;for(let f of o){if(e==null)return;if(f.type==="access")for(let u of f.keys){if(e==null)return;e=e[u];}else if(f.type==="flatMap"){if(!Array.isArray(e))return;e=e.flatMap(u=>{let l=u;return Array.isArray(l)?l:[l]});}else if(f.type==="map"){if(!Array.isArray(e))return;i.length>0&&(e=e.map(u=>{let l=u;for(let a of i){if(l==null)return;l=l[a];}return l}));}}return e}}function An(n,t){return N(t)(n)}function W(n){let t=n.indexOf("[*]");return t===-1?n:n.slice(0,t)}function Sn(){I.clear();}function kn(){return I.size}function F(n){let t=new Set;return C(n,t),Array.from(t)}function C(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let i=0;i<n.length;i++)C(n[i],t);return}if(E(n)){t.add(W(n.$));return}if(S(n)){if(typeof n.$if=="string"){let i=n.$if.startsWith("!")?n.$if.slice(1):n.$if;t.add(W(i));}else C(n.$if,t);C(n.then,t),n.else!==void 0&&C(n.else,t);return}if(x(n)){for(let i=0;i<n.$pipe.length;i++)C(n.$pipe[i],t);return}if(k(n)){if(n.args)for(let i=0;i<n.args.length;i++)C(n.args[i],t);return}if(R(n)){C(n.body,t),n.params!==void 0&&C(n.params,t);return}if(h(n)){C(n.left,t),n.right!==void 0&&C(n.right,t);return}if(b(n)){for(let i=0;i<n.conditions.length;i++)C(n.conditions[i],t);return}let o=n,r=Object.keys(o);for(let i=0;i<r.length;i++)C(o[r[i]],t);}function xn(n){return F(n).length>0}function Rn(n){return F(n).length===0}function wn(n){return JSON.stringify(n)}function j(n,t={}){let o=t.scope??{},r=t.accessor,i=t.context??{},s=m(n,o,r,i),e=F(n),f=wn(n);return {fn:s,deps:e,hash:f}}function m(n,t,o,r){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let i=n.map(s=>m(s,t,o,r));return s=>i.map(e=>e(s))}if(E(n))return Fn(n,o);if(S(n))return On(n,t,o,r);if(x(n))return vn(n,t,o,r);if(k(n))return jn(n,t,o,r);if(R(n))return Nn(n,t,o,r);if(h(n))return Gn(n,t,o,r);if(b(n))return In(n,t,o,r);if(q(n)){let i=n,s=Object.keys(i),e=s.map(f=>m(i[f],t,o,r));return f=>{let u={};for(let l=0;l<s.length;l++)u[s[l]]=e[l](f);return u}}return ()=>n}function Z(n,t){return t?o=>t(n,o):N(n)}function Fn(n,t){return Z(n.$,t)}function On(n,t,o,r){let i;if(typeof n.$if=="string"){let f=n.$if.startsWith("!")?n.$if.slice(1):n.$if,u=Z(f,o);i=n.$if.startsWith("!")?a=>!u(a):a=>!!u(a);}else {let f=m(n.$if,t,o,r);i=u=>!!f(u);}let s=m(n.then,t,o,r),e=n.else!==void 0?m(n.else,t,o,r):()=>{};return f=>i(f)?s(f):e(f)}function vn(n,t,o,r){let i=n.$pipe;if(i.length===0)return ()=>{};if(i.length===1)return m(i[0],t,o,r);let s=m(i[0],t,o,r),e=i.slice(1).map(u=>m(u,t,o,r)),f=e.length;if(f===1){let[u]=e;return l=>{let a=s(l),p=u(l);return typeof p=="function"?p(a):p}}if(f===2){let[u,l]=e;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(f===3){let[u,l,a]=e;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<f;a++){let p=e[a](u);l=typeof p=="function"?p(l):p;}return l}}function jn(n,t,o,r){let i=n.$fn,s=n.args;if(s===void 0)return ()=>{let u=t[i];if(!u)throw new Error(`Function not found in scope: ${i}`);return u};let e=s.map(u=>m(u,t,o,r)),f=e.length;if(f===0)return ()=>{let u=t[i];if(!u)throw new Error(`Function not found in scope: ${i}`);return u()};if(f===1){let[u]=e;return l=>{let a=t[i];if(!a)throw new Error(`Function not found in scope: ${i}`);return a(u(l))}}if(f===2){let[u,l]=e;return a=>{let p=t[i];if(!p)throw new Error(`Function not found in scope: ${i}`);return p(u(a),l(a))}}if(f===3){let[u,l,a]=e;return p=>{let d=t[i];if(!d)throw new Error(`Function not found in scope: ${i}`);return d(u(p),l(p),a(p))}}return u=>{let l=t[i];if(!l)throw new Error(`Function not found in scope: ${i}`);return l(...e.map(a=>a(u)))}}function Nn(n,t,o,r){let i=n.$cb,s=m(n.body,t,o,r),e=n.params?m(n.params,t,o,r):void 0,f=u=>o?l=>o(l,u):l=>N(l)(u);return u=>{let l=r?.[i];if(!l)throw new Error(`Context function not found: ${i}`);let a=(g,w)=>s(g),p=f(u),d=e?e(u):void 0;return l(a,u,p,d)}}function Gn(n,t,o,r){let i=m(n.left,t,o,r),s=n.right!==void 0?m(n.right,t,o,r):()=>{};switch(n.op){case "eq":return e=>i(e)===s(e);case "neq":return e=>i(e)!==s(e);case "gt":return e=>i(e)>s(e);case "gte":return e=>i(e)>=s(e);case "lt":return e=>i(e)<s(e);case "lte":return e=>i(e)<=s(e);case "in":return e=>{let f=s(e);return Array.isArray(f)&&f.includes(i(e))};case "notIn":return e=>{let f=s(e);return !Array.isArray(f)||!f.includes(i(e))};case "contains":return e=>{let f=i(e);return Array.isArray(f)&&f.includes(s(e))};case "notContains":return e=>{let f=i(e);return !Array.isArray(f)||!f.includes(s(e))};case "exists":return e=>i(e)!==void 0;case "notExists":return e=>i(e)===void 0;case "matches":return e=>{let f=i(e),u=s(e);return typeof f!="string"||typeof u!="string"?false:new RegExp(u).test(f)};case "notMatches":return e=>{let f=i(e),u=s(e);return typeof f!="string"||typeof u!="string"?true:!new RegExp(u).test(f)};case "startsWith":return e=>{let f=i(e),u=s(e);return typeof f=="string"&&typeof u=="string"&&f.startsWith(u)};case "endsWith":return e=>{let f=i(e),u=s(e);return typeof f=="string"&&typeof u=="string"&&f.endsWith(u)}}}function In(n,t,o,r){let i=n.conditions.map(e=>m(e,t,o,r)),s=i.length;if(s===1)return e=>!!i[0](e);if(s===2){let[e,f]=i;return n.logic==="AND"?u=>!!e(u)&&!!f(u):u=>!!e(u)||!!f(u)}if(s===3){let[e,f,u]=i;return n.logic==="AND"?l=>!!e(l)&&!!f(l)&&!!u(l):l=>!!e(l)||!!f(l)||!!u(l)}return n.logic==="AND"?e=>{for(let f=0;f<s;f++)if(!i[f](e))return false;return true}:e=>{for(let f=0;f<s;f++)if(i[f](e))return true;return false}}function Wn(n,t,o={}){return j(n,o).fn(t)}var z=class{constructor(t=1e3){this.cache=new Map,this._maxSize=t;}get(t,o={}){let r=JSON.stringify(t),i=this.cache.get(r);if(i)return this.cache.delete(r),this.cache.set(r,i),i;let s=j(t,o);if(this.cache.size>=this._maxSize){let e=this.cache.keys().next().value;e&&this.cache.delete(e);}return this.cache.set(r,s),s}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 o=this.cache.keys().next().value;o&&this.cache.delete(o);}}},nn=new z;function zn(n,t={}){return nn.get(n,t)}function J(n,t="root",o={}){let r=[];return T(n,t,r,o),{valid:r.length===0,errors:r}}function T(n,t,o,r){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let e=0;e<n.length;e++)T(n[e],`${t}[${e}]`,o,r);return}if(E(n)){(!n.$||typeof n.$!="string")&&o.push(`${t}: invalid reference, $ must be non-empty string`);return}if(S(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||o.push(`${t}.$if: empty path in string shorthand`):T(n.$if,`${t}.$if`,o,r),T(n.then,`${t}.then`,o,r),n.else!==void 0&&T(n.else,`${t}.else`,o,r);return}if(x(n)){if(!Array.isArray(n.$pipe)){o.push(`${t}.$pipe: must be an array`);return}if(n.$pipe.length===0){o.push(`${t}.$pipe: must have at least one element`);return}for(let e=0;e<n.$pipe.length;e++)T(n.$pipe[e],`${t}.$pipe[${e}]`,o,r);return}if(k(n)){if(!n.$fn||typeof n.$fn!="string"){o.push(`${t}: invalid function, $fn must be non-empty string`);return}if(r.scope&&!(n.$fn in r.scope)&&o.push(`${t}: function "${n.$fn}" not found in scope`),n.args!==void 0)if(!Array.isArray(n.args))o.push(`${t}.args: must be an array`);else for(let e=0;e<n.args.length;e++)T(n.args[e],`${t}.args[${e}]`,o,r);return}if(R(n)){if(!n.$cb||typeof n.$cb!="string"){o.push(`${t}: invalid callback, $cb must be non-empty string`);return}r.context&&!(n.$cb in r.context)&&o.push(`${t}: context function "${n.$cb}" not found`),T(n.body,`${t}.body`,o,r),n.params!==void 0&&T(n.params,`${t}.params`,o,r);return}if(h(n)){G.has(n.op)||o.push(`${t}: invalid operator "${n.op}"`),T(n.left,`${t}.left`,o,r),n.right!==void 0&&T(n.right,`${t}.right`,o,r);return}if(b(n)){if(n.logic!=="AND"&&n.logic!=="OR"&&o.push(`${t}: invalid logic "${n.logic}", must be "AND" or "OR"`),!Array.isArray(n.conditions)){o.push(`${t}.conditions: must be an array`);return}for(let e=0;e<n.conditions.length;e++)T(n.conditions[e],`${t}.conditions[${e}]`,o,r);return}let i=n,s=Object.keys(i);for(let e=0;e<s.length;e++){let f=s[e];T(i[f],`${t}.${f}`,o,r);}}function Dn(n,t={}){let o=J(n,"root",t);if(!o.valid)throw new Error(`Invalid expression: ${o.errors.join("; ")}`)}function Mn(n,t={}){return J(n,"root",t).valid}var un={};En(un,{$:()=>tn,$call:()=>fn,$cb:()=>sn,$cond:()=>rn,$fn:()=>en,$if:()=>Vn,$pipe:()=>on,call:()=>Kn,cb:()=>Jn,cond:()=>qn,fn:()=>_n,pipe:()=>Ln,ref:()=>Bn});function tn(n){return {$:n}}var Bn=tn;function en(n,t){return t===void 0||t.length===0?{$fn:n}:{$fn:n,args:t}}var _n=en;function Vn(n,t,o){return o===void 0?{$if:n,then:t}:{$if:n,then:t,else:o}}function on(...n){return {$pipe:n}}var Ln=on;function rn(n,t,o){return o===void 0?{left:n,op:t}:{left:n,op:t,right:o}}var qn=rn;function sn(n,t,o){return o===void 0?{$cb:n,body:t}:{$cb:n,body:t,params:o}}var Jn=sn;function fn(n,t=[]){return {$fn:n,args:t}}var Kn=fn;var K="data",ln="scope",Xn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function M(n,t={}){let{dataParam:o=K,scopeParam:r=ln,noPrefixes:i=false,useAccessor:s=false,lexicalPrefix:e}=t;return y(n,o,r,i,s,e)}function y(n,t,o,r,i,s){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(e=>y(e,t,o,r,i,s)));if(E(n))return Yn(n.$,t,r,i,s);if(S(n))return Pn(n,t,o,r,i,s);if(x(n))return nt(n.$pipe,t,o,r,i,s);if(k(n))return Qn(n,t,o,r,i,s);if(R(n))return Zn(n,t,o,r,i,s);if(h(n))return tt(n,t,o,r,i,s);if(b(n))return et(n,t,o,r,i,s);if(typeof n=="object"){let f=Object.entries(n).map(([u,l])=>omniAst.builders.property(omniAst.builders.identifier(u),y(l,t,o,r,i,s)));return omniAst.builders.objectExpression(f)}return omniAst.builders.literal(null)}var X="accessor";function Y(n,t){return t?n===t||n.startsWith(t+"."):false}function Yn(n,t,o,r,i){return r?Y(n,i)?O(n,t,true):omniAst.builders.callExpression(omniAst.builders.identifier(X),[omniAst.builders.literal(n),omniAst.builders.identifier(t)]):n.includes("[*]")?Hn(n,t,o):O(n,t,o)}function O(n,t,o){let r=D(n);if(r.length===0)return o?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(t);let i;if(o){let s=r[0];i=omniAst.builders.identifier(s.value);for(let e=1;e<r.length;e++){let f=r[e];f.type==="key"?i=omniAst.builders.memberExpression(i,omniAst.builders.identifier(f.value),false,true):i=omniAst.builders.memberExpression(i,omniAst.builders.literal(f.value),true,true);}}else {i=omniAst.builders.identifier(t);for(let s of r)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 Hn(n,t,o){let r=n.indexOf("[*]"),i=n.slice(0,r),s=n.slice(r+3),e;if(i?e=O(i,t,o):e=o?omniAst.builders.identifier("undefined"):omniAst.builders.identifier(t),!s||s==="")return e;if(s.includes("[*]"))return an(e,s);let f="_i",u=s.startsWith(".")?s.slice(1):s,l=omniAst.builders.identifier(f);if(u){let a=D(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(e,omniAst.builders.identifier("map"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(f)],l)])}function an(n,t){let o=t.indexOf("[*]"),r=t.slice(0,o),i=t.slice(o+3),s="_i",e=r.startsWith(".")?r.slice(1):r,f=omniAst.builders.identifier(s);if(e){let l=D(e);for(let a of l)a.type==="key"&&(f=omniAst.builders.memberExpression(f,omniAst.builders.identifier(a.value),false,true));}if(i.includes("[*]")){let l=an(f,i);return omniAst.builders.callExpression(omniAst.builders.memberExpression(n,omniAst.builders.identifier("flatMap"),false,true),[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(s)],l)])}let u=i.startsWith(".")?i.slice(1):i;if(u){let l=D(u);for(let a of l)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(s)],f)])}function Pn(n,t,o,r,i,s){let e;if(typeof n.$if=="string"){let l=n.$if.startsWith("!"),a=l?n.$if.slice(1):n.$if,p;i?Y(a,s)?p=O(a,t,true):p=omniAst.builders.callExpression(omniAst.builders.identifier(X),[omniAst.builders.literal(a),omniAst.builders.identifier(t)]):p=O(a,t,r),e=l?omniAst.builders.unaryExpression("!",p):p;}else e=y(n.$if,t,o,r,i,s);let f=y(n.then,t,o,r,i,s),u=n.else!==void 0?y(n.else,t,o,r,i,s):omniAst.builders.identifier("undefined");return omniAst.builders.conditionalExpression(e,f,u)}function Qn(n,t,o,r,i,s){let e=r?omniAst.builders.identifier(n.$fn):omniAst.builders.memberExpression(omniAst.builders.identifier(o),omniAst.builders.identifier(n.$fn),false,false);if(n.args===void 0)return e;let f=n.args.map(u=>y(u,t,o,r,i,s));return omniAst.builders.callExpression(e,f)}var Un="context";function Zn(n,t,o,r,i,s){let e=r?omniAst.builders.identifier(n.$cb):omniAst.builders.memberExpression(omniAst.builders.identifier(Un),omniAst.builders.identifier(n.$cb),false,false),f=y(n.body,t,o,r,i,s),l=[omniAst.builders.arrowFunctionExpression([omniAst.builders.identifier(t),omniAst.builders.identifier("get")],f),omniAst.builders.identifier(t),omniAst.builders.identifier("get")];if(n.params!==void 0){let a=y(n.params,t,o,r,i,s);l.push(a);}return omniAst.builders.callExpression(e,l)}function nt(n,t,o,r,i,s){if(n.length===0)return omniAst.builders.identifier("undefined");if(n.length===1)return y(n[0],t,o,r,i,s);let e=y(n[0],t,o,r,i,s);for(let f=1;f<n.length;f++){let u=y(n[f],t,o,r,i,s);e=omniAst.builders.callExpression(u,[e]);}return e}function cn(n,t,o,r,i,s){if(E(n)){let e=n.$;return i?Y(e,s)?O(e,t,true):omniAst.builders.callExpression(omniAst.builders.identifier(X),[omniAst.builders.literal(e),omniAst.builders.identifier(t)]):O(e,t,r)}return y(n,t,o,r,i,s)}function tt(n,t,o,r,i,s){let e=cn(n.left,t,o,r,i,s),f=n.right!==void 0?cn(n.right,t,o,r,i,s):omniAst.builders.literal(null),u=Xn[n.op];if(u)return omniAst.builders.binaryExpression(u,e,f);switch(n.op){case "in":return omniAst.builders.callExpression(omniAst.builders.memberExpression(f,omniAst.builders.identifier("includes")),[e]);case "notIn":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(f,omniAst.builders.identifier("includes")),[e]));case "contains":return omniAst.builders.callExpression(omniAst.builders.memberExpression(e,omniAst.builders.identifier("includes"),false,true),[f]);case "notContains":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(e,omniAst.builders.identifier("includes"),false,true),[f]));case "exists":return omniAst.builders.binaryExpression("!=",e,omniAst.builders.literal(null));case "notExists":return omniAst.builders.binaryExpression("==",e,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")),[e]);case "notMatches":return omniAst.builders.unaryExpression("!",omniAst.builders.callExpression(omniAst.builders.memberExpression(omniAst.builders.newExpression(omniAst.builders.identifier("RegExp"),[f]),omniAst.builders.identifier("test")),[e]));case "startsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(e,omniAst.builders.identifier("startsWith"),false,true),[f]);case "endsWith":return omniAst.builders.callExpression(omniAst.builders.memberExpression(e,omniAst.builders.identifier("endsWith"),false,true),[f]);default:return omniAst.builders.binaryExpression("===",e,f)}}function et(n,t,o,r,i,s){let{logic:e,conditions:f}=n,u=e==="AND"?"&&":"||";if(f.length===0)return omniAst.builders.literal(e==="AND");if(f.length===1)return y(f[0],t,o,r,i,s);let l=y(f[0],t,o,r,i,s);for(let a=1;a<f.length;a++){let p=y(f[a],t,o,r,i,s);l=omniAst.builders.logicalExpression(u,l,p);}return l}function D(n){let t=[],o=n.length,r=0,i="";for(;r<o;){let s=n[r];if(s===".")i&&(t.push({type:"key",value:i}),i=""),r++;else if(s==="["){i&&(t.push({type:"key",value:i}),i=""),r++;let e=r;for(;r<o&&n[r]!=="]";)r++;let f=n.slice(e,r);if(r++,f!=="*"){let u=parseInt(f,10);t.push({type:"index",value:isNaN(u)?f:u});}}else i+=s,r++;}return i&&t.push({type:"key",value:i}),t}function pn(n,t=[K]){return omniAst.builders.arrowFunctionExpression(t.map(o=>omniAst.builders.identifier(o)),n)}function B(n){let t=new Set;return $(n,t),t}function $(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r of n)$(r,t);return}if(E(n))return;if(S(n)){$(n.$if,t),$(n.then,t),n.else!==void 0&&$(n.else,t);return}if(x(n)){for(let r of n.$pipe)$(r,t);return}if(k(n)){if(t.add(n.$fn),n.args)for(let r of n.args)$(r,t);return}if(R(n)){$(n.body,t),n.params!==void 0&&$(n.params,t);return}if(h(n)){n.left!==void 0&&typeof n.left=="object"&&$(n.left,t),n.right!==void 0&&typeof n.right=="object"&&$(n.right,t);return}if(b(n)){for(let r of n.conditions)$(r,t);return}let o=n;for(let r of Object.keys(o))$(o[r],t);}function _(n){let t=new Set;return A(n,t),t}function A(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r of n)A(r,t);return}if(E(n))return;if(S(n)){A(n.$if,t),A(n.then,t),n.else!==void 0&&A(n.else,t);return}if(x(n)){for(let r of n.$pipe)A(r,t);return}if(k(n)){if(n.args)for(let r of n.args)A(r,t);return}if(R(n)){t.add(n.$cb),A(n.body,t),n.params!==void 0&&A(n.params,t);return}if(h(n)){n.left!==void 0&&typeof n.left=="object"&&A(n.left,t),n.right!==void 0&&typeof n.right=="object"&&A(n.right,t);return}if(b(n)){for(let r of n.conditions)A(r,t);return}let o=n;for(let r of Object.keys(o))A(o[r],t);}function V(n){let t=new Set;for(let o of n){let r=o.indexOf("."),i=o.indexOf("["),s=o.length;r!==-1&&(s=Math.min(s,r)),i!==-1&&(s=Math.min(s,i));let e=o.slice(0,s);e&&t.add(e);}return t}function ot(n){return JSON.stringify(n)}function rt(n,t,o,r,i,s){let e=M(n,{noPrefixes:true,useAccessor:i,lexicalPrefix:s}),f=omniAst.generate(e),u="";i?s&&(u=`const{${s}}=data??{};`):t.size>0&&(u=`const{${[...t].join(",")}}=data??{};`);let l=i?new Set([...o,"accessor"]):o,a=l.size>0?`const{${[...l].join(",")}}=scope;`:"",p=r.size>0?`const{${[...r].join(",")}}=context;`:"",d=r.size>0,g="";d&&(i?g="const get=(path)=>accessor(path,data);":g="const get=(path)=>path.split('.').reduce((o,k)=>o?.[k],data);");let w=l.size>0,v;if(w||d){let gn=d?"scope,context":"scope",yn=`${u}${g}return ${f}`;v=`(function(${gn}){${a}${p}return function(data){${yn}}})`;}else v=`(function(){return function(data){${u}return ${f}}})`;return v}function H(n,t={}){let{scope:o={},context:r={},returnCode:i=false,useAccessor:s=false,lexicalPrefix:e}=t,f=F(n),u=V(f),l=B(n),a=_(n),p=ot(n),d=rt(n,u,l,a,s,e);if(i)return {code:d,deps:f,hash:p,dataRoots:[...u],scopeFns:[...l],contextFns:[...a]};let g;try{let w=a.size>0,v=new Function(`return ${d}`)();g=w?v(o,r):v(o);}catch(w){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${w instanceof Error?w.message:String(w)}`)}return {fn:g,deps:f,hash:p}}function dn(n,t,o={}){let{fn:r}=H(n,o);return r(t)}function st(n,t){return L(n,t)}function L(n,t){if(n===null)return null;if(typeof n!="object")return n;if(Array.isArray(n))return n.map(s=>L(s,t));let o=n,r=Object.keys(o);for(let s of r)if(s in t){let e=t[s](o);if(typeof e=="object"&&e!==null&&s in e)throw new Error(`Transform "${s}" returned object with same key \u2014 infinite loop`);return L(e,t)}let i={};for(let s of r)i[s]=L(o[s],t);return i}var ft=new Set(["$","$if","$fn","$pipe","$cb"]);function ut(){let n=0;return ()=>String(n++)}function ct(n,t){let{resolvers:o,scope:r={},genId:i,...s}=t,e=Object.keys(o);if(e.length===0)return {expr:n,scope:r};let f=new Set(e),u=[],l={compile:j,genId:i??ut(),scope:r,options:s},a=P(n,f,o,l,u),p={...r};for(let d=0;d<u.length;d++){let[g,w]=u[d];p[g]=w;}return {expr:a,scope:p}}function P(n,t,o,r,i){if(n===null)return null;if(typeof n!="object")return n;if(Array.isArray(n)){let l=n.length,a=new Array(l);for(let p=0;p<l;p++)a[p]=P(n[p],t,o,r,i);return a}let s=n,e=Object.keys(s),f=e.length;for(let l=0;l<f;l++){let a=e[l];if(a[0]==="$"&&!ft.has(a)&&t.has(a)){let p=o[a],d=p(s,r);return d.scopeEntry&&i.push(d.scopeEntry),d.expr}}let u={};for(let l=0;l<f;l++){let a=e[l];u[a]=P(s[a],t,o,r,i);}return u}var _t="2.0.0";exports.ExpressionCache=z;exports.VERSION=_t;exports.assertValid=Dn;exports.builders=un;exports.cache=nn;exports.cached=zn;exports.clearPathCache=Sn;exports.compile=j;exports.compileAST=H;exports.compilePath=N;exports.dslToAST=M;exports.evaluate=Wn;exports.evaluateAST=dn;exports.extractContextFns=_;exports.extractDataRoots=V;exports.extractDeps=F;exports.extractScopeFns=B;exports.get=An;exports.getPathCacheSize=kn;exports.hasDeps=xn;exports.hasWildcard=U;exports.isCb=R;exports.isCondition=h;exports.isConditionExpr=hn;exports.isConditionGroup=b;exports.isConditional=S;exports.isFn=k;exports.isLiteral=q;exports.isPipe=x;exports.isPure=Rn;exports.isRef=E;exports.isValid=Mn;exports.normalize=st;exports.normalizePath=W;exports.resolveBoundaries=ct;exports.validate=J;exports.wrapInFunction=pn;
package/dist/index.d.cts CHANGED
@@ -44,6 +44,17 @@ interface FnExpr {
44
44
  interface PipeExpr {
45
45
  $pipe: Expression[];
46
46
  }
47
+ /**
48
+ * Callback expression - HOC de continuidade
49
+ * Executa body dentro de um context function (tryCatch, transaction, etc.)
50
+ * @example { $cb: "tryCatch", body: { $fn: "query" } }
51
+ * @example { $cb: "transaction", params: { isolation: "serializable" }, body: { $fn: "query" } }
52
+ */
53
+ interface CbExpr {
54
+ $cb: string;
55
+ body: Expression;
56
+ params?: Expression;
57
+ }
47
58
  /**
48
59
  * Literal values (primitives, arrays, plain objects)
49
60
  */
@@ -75,7 +86,7 @@ type ConditionExpr = Condition | ConditionGroup;
75
86
  /**
76
87
  * Union of all expression types
77
88
  */
78
- type Expression = Literal | RefExpr | ConditionalExpr | FnExpr | PipeExpr | ConditionExpr;
89
+ type Expression = Literal | RefExpr | ConditionalExpr | FnExpr | PipeExpr | CbExpr | ConditionExpr;
79
90
  /**
80
91
  * Compiled expression function
81
92
  */
@@ -122,6 +133,50 @@ interface ValidationResult {
122
133
  * @example { add, subtract, multiply, filter, map, sum }
123
134
  */
124
135
  type Scope = Record<string, (...args: any[]) => any>;
136
+ /**
137
+ * Path getter function for context callbacks
138
+ */
139
+ type PathGetterFn = (path: string) => unknown;
140
+ /**
141
+ * Context function - HOC que controla execução do body.
142
+ * Recebe o body como callback e decide quando/se executá-lo.
143
+ *
144
+ * @param cb - Body compilado como callback (recebe data e get)
145
+ * @param data - Dados do runtime
146
+ * @param get - Resolver de paths (accessor)
147
+ * @param params - Parâmetros extras para o context (opcional)
148
+ *
149
+ * @example
150
+ * ```ts
151
+ * const tryCatch: ContextFn = (cb, data, get, params) => {
152
+ * try {
153
+ * return cb(data, get);
154
+ * } catch (e) {
155
+ * return params?.fallback ?? null;
156
+ * }
157
+ * };
158
+ *
159
+ * const transaction: ContextFn = (cb, data, get, params) => {
160
+ * const tx = db.beginTransaction(params);
161
+ * try {
162
+ * const result = cb({ ...data, tx }, get);
163
+ * tx.commit();
164
+ * return result;
165
+ * } catch (e) {
166
+ * tx.rollback();
167
+ * throw e;
168
+ * }
169
+ * };
170
+ * ```
171
+ */
172
+ type ContextFn<T = any, R = any> = (cb: (data: T, get: PathGetterFn) => R, data: T, get: PathGetterFn, params?: unknown) => R;
173
+ /**
174
+ * Context registry - HOC functions available to $cb expressions.
175
+ * Separate from scope because context functions have different signature.
176
+ *
177
+ * @example { tryCatch, transaction, withRetry }
178
+ */
179
+ type Context = Record<string, ContextFn>;
125
180
  /**
126
181
  * Options for compilation
127
182
  */
@@ -137,6 +192,18 @@ interface CompileOptions<T = unknown> {
137
192
  * compile(expr, { accessor: (path, ctx) => ctx.get(path) })
138
193
  */
139
194
  accessor?: AccessorFn<T>;
195
+ /**
196
+ * Context functions available to $cb expressions.
197
+ * HOC functions that control body execution (tryCatch, transaction, etc.).
198
+ *
199
+ * @example
200
+ * compile(expr, {
201
+ * context: {
202
+ * tryCatch: (cb, data, get) => { try { return cb(data, get); } catch { return null; } }
203
+ * }
204
+ * })
205
+ */
206
+ context?: Context;
140
207
  }
141
208
  /**
142
209
  * Check if value is a reference expression
@@ -154,6 +221,10 @@ declare const isFn: (v: unknown) => v is FnExpr;
154
221
  * Check if value is a pipe expression
155
222
  */
156
223
  declare const isPipe: (v: unknown) => v is PipeExpr;
224
+ /**
225
+ * Check if value is a callback expression
226
+ */
227
+ declare const isCb: (v: unknown) => v is CbExpr;
157
228
  /**
158
229
  * Check if value is a condition expression
159
230
  *
@@ -359,6 +430,8 @@ declare function cached<T = unknown, R = unknown>(expr: Expression, options?: Co
359
430
  interface ValidateOptions {
360
431
  /** Scope to validate function names against (optional) */
361
432
  scope?: Scope;
433
+ /** Context to validate $cb function names against (optional) */
434
+ context?: Context;
362
435
  }
363
436
  /**
364
437
  * Validate expression structure
@@ -481,18 +554,60 @@ declare function $cond(left: Expression, op: ConditionOp, right?: Expression): C
481
554
  * Alias for $cond (condition builder)
482
555
  */
483
556
  declare const cond: typeof $cond;
557
+ /**
558
+ * Create a callback expression (HOC de continuidade).
559
+ *
560
+ * @param name - Context function name (from context)
561
+ * @param body - Expression to execute inside the context
562
+ * @param params - Optional parameters for the context function
563
+ * @returns CbExpr
564
+ *
565
+ * @example
566
+ * $cb("tryCatch", $fn("query"))
567
+ * // { $cb: "tryCatch", body: { $fn: "query" } }
568
+ *
569
+ * $cb("transaction", $fn("saveUser"), { isolation: "serializable" })
570
+ * // { $cb: "transaction", body: {...}, params: {...} }
571
+ */
572
+ declare function $cb(name: string, body: Expression, params?: Expression): CbExpr;
573
+ /**
574
+ * Alias for $cb (callback builder)
575
+ */
576
+ declare const cb: typeof $cb;
577
+ /**
578
+ * Create a function call expression that always calls the function.
579
+ * Unlike $fn which returns function reference when args is empty/undefined,
580
+ * $call always includes args (defaults to empty array).
581
+ *
582
+ * @param name - Function name (from scope)
583
+ * @param args - Arguments (can be expressions, defaults to [])
584
+ * @returns FnExpr with args always present
585
+ *
586
+ * @example
587
+ * $call("now") // { $fn: "now", args: [] } - calls function
588
+ * $call("add", [$("a"), 1]) // { $fn: "add", args: [...] }
589
+ */
590
+ declare function $call(name: string, args?: Expression[]): FnExpr;
591
+ /**
592
+ * Alias for $call (call builder)
593
+ */
594
+ declare const call: typeof $call;
484
595
 
485
596
  declare const builders_$: typeof $;
597
+ declare const builders_$call: typeof $call;
598
+ declare const builders_$cb: typeof $cb;
486
599
  declare const builders_$cond: typeof $cond;
487
600
  declare const builders_$fn: typeof $fn;
488
601
  declare const builders_$if: typeof $if;
489
602
  declare const builders_$pipe: typeof $pipe;
603
+ declare const builders_call: typeof call;
604
+ declare const builders_cb: typeof cb;
490
605
  declare const builders_cond: typeof cond;
491
606
  declare const builders_fn: typeof fn;
492
607
  declare const builders_pipe: typeof pipe;
493
608
  declare const builders_ref: typeof ref;
494
609
  declare namespace builders {
495
- export { builders_$ as $, builders_$cond as $cond, builders_$fn as $fn, builders_$if as $if, builders_$pipe as $pipe, builders_cond as cond, builders_fn as fn, builders_pipe as pipe, builders_ref as ref };
610
+ export { builders_$ as $, builders_$call as $call, builders_$cb as $cb, builders_$cond as $cond, builders_$fn as $fn, builders_$if as $if, builders_$pipe as $pipe, builders_call as call, builders_cb as cb, builders_cond as cond, builders_fn as fn, builders_pipe as pipe, builders_ref as ref };
496
611
  }
497
612
 
498
613
  /**
@@ -590,6 +705,19 @@ declare function wrapInFunction(bodyAst: ASTNode, params?: string[]): ASTNode;
590
705
  * ```
591
706
  */
592
707
  declare function extractScopeFns(expr: Expression): Set<string>;
708
+ /**
709
+ * Extract all context function names used in an expression
710
+ *
711
+ * @param expr - DSL expression to analyze
712
+ * @returns Set of context function names used
713
+ *
714
+ * @example
715
+ * ```ts
716
+ * extractContextFns({ $cb: "tryCatch", body: { $fn: "query" } })
717
+ * // Set { "tryCatch" }
718
+ * ```
719
+ */
720
+ declare function extractContextFns(expr: Expression): Set<string>;
593
721
  /**
594
722
  * Extract root-level data dependencies from paths
595
723
  *
@@ -618,6 +746,8 @@ declare function extractDataRoots(deps: string[]): Set<string>;
618
746
  interface CompileASTOptions {
619
747
  /** Scope with functions available to the expression */
620
748
  scope?: Scope;
749
+ /** Context with HOC functions available to $cb expressions */
750
+ context?: Context;
621
751
  /** Return generated code instead of function (for debugging) */
622
752
  returnCode?: boolean;
623
753
  /**
@@ -639,6 +769,7 @@ interface CompileASTCodeResult {
639
769
  hash: string;
640
770
  dataRoots: string[];
641
771
  scopeFns: string[];
772
+ contextFns: string[];
642
773
  }
643
774
  /**
644
775
  * Compile DSL expression to optimized function using AST generation
@@ -746,6 +877,112 @@ type Transforms = Record<string, TransformFn>;
746
877
  */
747
878
  declare function normalize(expr: unknown, transforms: Transforms): Expression;
748
879
 
880
+ /**
881
+ * @statedelta-libs/expressions - Boundaries
882
+ *
883
+ * Resolve custom boundaries ($simulate, $query, etc.) before compilation.
884
+ * Boundaries are "foreign bodies" that stop the expression flow and delegate
885
+ * to external handlers. The handler can compile internal slots independently.
886
+ *
887
+ * @example
888
+ * ```ts
889
+ * const { expr, scope } = resolveBoundaries(
890
+ * { $simulate: { effects: [...], query: {...} } },
891
+ * {
892
+ * scope: baseScope,
893
+ * resolvers: {
894
+ * $simulate: (node, { compile, genId }) => {
895
+ * const id = `__simulate_${genId()}`;
896
+ * const fn = buildSimulateFn(node, compile);
897
+ * return {
898
+ * expr: { $fn: id },
899
+ * scopeEntry: [id, fn]
900
+ * };
901
+ * }
902
+ * }
903
+ * }
904
+ * );
905
+ *
906
+ * compile(expr, { scope });
907
+ * ```
908
+ */
909
+
910
+ /**
911
+ * Result returned by a boundary resolver
912
+ */
913
+ interface ResolverResult {
914
+ /** Expression to replace the boundary with */
915
+ expr: Expression;
916
+ /** Optional entry to add to scope [key, value] */
917
+ scopeEntry?: [string, unknown];
918
+ }
919
+ /**
920
+ * Context provided to boundary resolvers
921
+ */
922
+ interface ResolverContext {
923
+ /** Compile function for compiling internal slots */
924
+ compile: typeof compile;
925
+ /** Generate unique ID for scope entries */
926
+ genId: () => string;
927
+ /** Current scope (read-only reference) */
928
+ scope: Readonly<Scope>;
929
+ /** Compile options passed to resolveBoundaries */
930
+ options: Readonly<CompileOptions>;
931
+ }
932
+ /**
933
+ * Boundary resolver function.
934
+ * Receives the raw node and context, returns replacement expression.
935
+ */
936
+ type BoundaryResolver = (node: Record<string, unknown>, ctx: ResolverContext) => ResolverResult;
937
+ /**
938
+ * Map of boundary resolvers keyed by marker (e.g. "$simulate", "$query")
939
+ */
940
+ type BoundaryResolvers = Record<string, BoundaryResolver>;
941
+ /**
942
+ * ID generator function
943
+ */
944
+ type IdGenerator = () => string;
945
+ /**
946
+ * Options for resolveBoundaries
947
+ */
948
+ interface ResolveBoundariesOptions extends CompileOptions {
949
+ /** Map of boundary resolvers */
950
+ resolvers: BoundaryResolvers;
951
+ /** Custom ID generator. Default: simple counter ("0", "1", "2"...) */
952
+ genId?: IdGenerator;
953
+ }
954
+ /**
955
+ * Result of resolveBoundaries
956
+ */
957
+ interface ResolveBoundariesResult {
958
+ /** Pure expression with boundaries replaced */
959
+ expr: Expression;
960
+ /** Enriched scope with boundary handlers */
961
+ scope: Scope;
962
+ }
963
+ /**
964
+ * Resolve boundaries in an expression tree.
965
+ *
966
+ * Boundaries are custom DSL nodes ($simulate, $query, etc.) that stop the
967
+ * normal expression compilation flow. Each boundary is extracted, processed
968
+ * by its resolver, and replaced with a standard expression.
969
+ *
970
+ * The resolver receives:
971
+ * - `node`: The raw boundary object (e.g. { $simulate: {...}, effects: [...] })
972
+ * - `ctx.compile`: Compile function for internal slots
973
+ * - `ctx.genId`: Unique ID generator
974
+ * - `ctx.scope`: Current scope (read-only)
975
+ *
976
+ * The resolver returns:
977
+ * - `expr`: Replacement expression (typically { $fn: "__id" })
978
+ * - `scopeEntry`: Optional [key, fn] to add to scope
979
+ *
980
+ * @param expr - Expression (possibly with boundaries)
981
+ * @param options - Resolvers, scope, and compile options
982
+ * @returns Pure expression and enriched scope
983
+ */
984
+ declare function resolveBoundaries(expr: unknown, options: ResolveBoundariesOptions): ResolveBoundariesResult;
985
+
749
986
  /**
750
987
  * @statedelta-libs/expressions
751
988
  *
@@ -781,4 +1018,4 @@ declare function normalize(expr: unknown, transforms: Transforms): Expression;
781
1018
  */
782
1019
  declare const VERSION = "2.0.0";
783
1020
 
784
- export { type AccessorFn, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, type Condition, type ConditionExpr, type ConditionGroup, type ConditionOp, type ConditionalExpr, type Expression, ExpressionCache, type FnExpr, type Literal, type PathGetter, type PipeExpr, type RefExpr, type Scope, type TransformFn, type TransformOptions, type Transforms, 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, normalize, normalizePath, validate, wrapInFunction };
1021
+ export { type AccessorFn, type BoundaryResolver, type BoundaryResolvers, type CbExpr, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, type Condition, type ConditionExpr, type ConditionGroup, type ConditionOp, type ConditionalExpr, type Context, type ContextFn, type Expression, ExpressionCache, type FnExpr, type IdGenerator, type Literal, type PathGetter, type PathGetterFn, type PipeExpr, type RefExpr, type ResolveBoundariesOptions, type ResolveBoundariesResult, type ResolverContext, type ResolverResult, type Scope, type TransformFn, type TransformOptions, type Transforms, VERSION, type ValidateOptions, type ValidationResult, assertValid, builders, cache, cached, clearPathCache, compile, compileAST, compilePath, dslToAST, evaluate, evaluateAST, extractContextFns, extractDataRoots, extractDeps, extractScopeFns, get, getPathCacheSize, hasDeps, hasWildcard, isCb, isCondition, isConditionExpr, isConditionGroup, isConditional, isFn, isLiteral, isPipe, isPure, isRef, isValid, normalize, normalizePath, resolveBoundaries, validate, wrapInFunction };
package/dist/index.d.ts CHANGED
@@ -44,6 +44,17 @@ interface FnExpr {
44
44
  interface PipeExpr {
45
45
  $pipe: Expression[];
46
46
  }
47
+ /**
48
+ * Callback expression - HOC de continuidade
49
+ * Executa body dentro de um context function (tryCatch, transaction, etc.)
50
+ * @example { $cb: "tryCatch", body: { $fn: "query" } }
51
+ * @example { $cb: "transaction", params: { isolation: "serializable" }, body: { $fn: "query" } }
52
+ */
53
+ interface CbExpr {
54
+ $cb: string;
55
+ body: Expression;
56
+ params?: Expression;
57
+ }
47
58
  /**
48
59
  * Literal values (primitives, arrays, plain objects)
49
60
  */
@@ -75,7 +86,7 @@ type ConditionExpr = Condition | ConditionGroup;
75
86
  /**
76
87
  * Union of all expression types
77
88
  */
78
- type Expression = Literal | RefExpr | ConditionalExpr | FnExpr | PipeExpr | ConditionExpr;
89
+ type Expression = Literal | RefExpr | ConditionalExpr | FnExpr | PipeExpr | CbExpr | ConditionExpr;
79
90
  /**
80
91
  * Compiled expression function
81
92
  */
@@ -122,6 +133,50 @@ interface ValidationResult {
122
133
  * @example { add, subtract, multiply, filter, map, sum }
123
134
  */
124
135
  type Scope = Record<string, (...args: any[]) => any>;
136
+ /**
137
+ * Path getter function for context callbacks
138
+ */
139
+ type PathGetterFn = (path: string) => unknown;
140
+ /**
141
+ * Context function - HOC que controla execução do body.
142
+ * Recebe o body como callback e decide quando/se executá-lo.
143
+ *
144
+ * @param cb - Body compilado como callback (recebe data e get)
145
+ * @param data - Dados do runtime
146
+ * @param get - Resolver de paths (accessor)
147
+ * @param params - Parâmetros extras para o context (opcional)
148
+ *
149
+ * @example
150
+ * ```ts
151
+ * const tryCatch: ContextFn = (cb, data, get, params) => {
152
+ * try {
153
+ * return cb(data, get);
154
+ * } catch (e) {
155
+ * return params?.fallback ?? null;
156
+ * }
157
+ * };
158
+ *
159
+ * const transaction: ContextFn = (cb, data, get, params) => {
160
+ * const tx = db.beginTransaction(params);
161
+ * try {
162
+ * const result = cb({ ...data, tx }, get);
163
+ * tx.commit();
164
+ * return result;
165
+ * } catch (e) {
166
+ * tx.rollback();
167
+ * throw e;
168
+ * }
169
+ * };
170
+ * ```
171
+ */
172
+ type ContextFn<T = any, R = any> = (cb: (data: T, get: PathGetterFn) => R, data: T, get: PathGetterFn, params?: unknown) => R;
173
+ /**
174
+ * Context registry - HOC functions available to $cb expressions.
175
+ * Separate from scope because context functions have different signature.
176
+ *
177
+ * @example { tryCatch, transaction, withRetry }
178
+ */
179
+ type Context = Record<string, ContextFn>;
125
180
  /**
126
181
  * Options for compilation
127
182
  */
@@ -137,6 +192,18 @@ interface CompileOptions<T = unknown> {
137
192
  * compile(expr, { accessor: (path, ctx) => ctx.get(path) })
138
193
  */
139
194
  accessor?: AccessorFn<T>;
195
+ /**
196
+ * Context functions available to $cb expressions.
197
+ * HOC functions that control body execution (tryCatch, transaction, etc.).
198
+ *
199
+ * @example
200
+ * compile(expr, {
201
+ * context: {
202
+ * tryCatch: (cb, data, get) => { try { return cb(data, get); } catch { return null; } }
203
+ * }
204
+ * })
205
+ */
206
+ context?: Context;
140
207
  }
141
208
  /**
142
209
  * Check if value is a reference expression
@@ -154,6 +221,10 @@ declare const isFn: (v: unknown) => v is FnExpr;
154
221
  * Check if value is a pipe expression
155
222
  */
156
223
  declare const isPipe: (v: unknown) => v is PipeExpr;
224
+ /**
225
+ * Check if value is a callback expression
226
+ */
227
+ declare const isCb: (v: unknown) => v is CbExpr;
157
228
  /**
158
229
  * Check if value is a condition expression
159
230
  *
@@ -359,6 +430,8 @@ declare function cached<T = unknown, R = unknown>(expr: Expression, options?: Co
359
430
  interface ValidateOptions {
360
431
  /** Scope to validate function names against (optional) */
361
432
  scope?: Scope;
433
+ /** Context to validate $cb function names against (optional) */
434
+ context?: Context;
362
435
  }
363
436
  /**
364
437
  * Validate expression structure
@@ -481,18 +554,60 @@ declare function $cond(left: Expression, op: ConditionOp, right?: Expression): C
481
554
  * Alias for $cond (condition builder)
482
555
  */
483
556
  declare const cond: typeof $cond;
557
+ /**
558
+ * Create a callback expression (HOC de continuidade).
559
+ *
560
+ * @param name - Context function name (from context)
561
+ * @param body - Expression to execute inside the context
562
+ * @param params - Optional parameters for the context function
563
+ * @returns CbExpr
564
+ *
565
+ * @example
566
+ * $cb("tryCatch", $fn("query"))
567
+ * // { $cb: "tryCatch", body: { $fn: "query" } }
568
+ *
569
+ * $cb("transaction", $fn("saveUser"), { isolation: "serializable" })
570
+ * // { $cb: "transaction", body: {...}, params: {...} }
571
+ */
572
+ declare function $cb(name: string, body: Expression, params?: Expression): CbExpr;
573
+ /**
574
+ * Alias for $cb (callback builder)
575
+ */
576
+ declare const cb: typeof $cb;
577
+ /**
578
+ * Create a function call expression that always calls the function.
579
+ * Unlike $fn which returns function reference when args is empty/undefined,
580
+ * $call always includes args (defaults to empty array).
581
+ *
582
+ * @param name - Function name (from scope)
583
+ * @param args - Arguments (can be expressions, defaults to [])
584
+ * @returns FnExpr with args always present
585
+ *
586
+ * @example
587
+ * $call("now") // { $fn: "now", args: [] } - calls function
588
+ * $call("add", [$("a"), 1]) // { $fn: "add", args: [...] }
589
+ */
590
+ declare function $call(name: string, args?: Expression[]): FnExpr;
591
+ /**
592
+ * Alias for $call (call builder)
593
+ */
594
+ declare const call: typeof $call;
484
595
 
485
596
  declare const builders_$: typeof $;
597
+ declare const builders_$call: typeof $call;
598
+ declare const builders_$cb: typeof $cb;
486
599
  declare const builders_$cond: typeof $cond;
487
600
  declare const builders_$fn: typeof $fn;
488
601
  declare const builders_$if: typeof $if;
489
602
  declare const builders_$pipe: typeof $pipe;
603
+ declare const builders_call: typeof call;
604
+ declare const builders_cb: typeof cb;
490
605
  declare const builders_cond: typeof cond;
491
606
  declare const builders_fn: typeof fn;
492
607
  declare const builders_pipe: typeof pipe;
493
608
  declare const builders_ref: typeof ref;
494
609
  declare namespace builders {
495
- export { builders_$ as $, builders_$cond as $cond, builders_$fn as $fn, builders_$if as $if, builders_$pipe as $pipe, builders_cond as cond, builders_fn as fn, builders_pipe as pipe, builders_ref as ref };
610
+ export { builders_$ as $, builders_$call as $call, builders_$cb as $cb, builders_$cond as $cond, builders_$fn as $fn, builders_$if as $if, builders_$pipe as $pipe, builders_call as call, builders_cb as cb, builders_cond as cond, builders_fn as fn, builders_pipe as pipe, builders_ref as ref };
496
611
  }
497
612
 
498
613
  /**
@@ -590,6 +705,19 @@ declare function wrapInFunction(bodyAst: ASTNode, params?: string[]): ASTNode;
590
705
  * ```
591
706
  */
592
707
  declare function extractScopeFns(expr: Expression): Set<string>;
708
+ /**
709
+ * Extract all context function names used in an expression
710
+ *
711
+ * @param expr - DSL expression to analyze
712
+ * @returns Set of context function names used
713
+ *
714
+ * @example
715
+ * ```ts
716
+ * extractContextFns({ $cb: "tryCatch", body: { $fn: "query" } })
717
+ * // Set { "tryCatch" }
718
+ * ```
719
+ */
720
+ declare function extractContextFns(expr: Expression): Set<string>;
593
721
  /**
594
722
  * Extract root-level data dependencies from paths
595
723
  *
@@ -618,6 +746,8 @@ declare function extractDataRoots(deps: string[]): Set<string>;
618
746
  interface CompileASTOptions {
619
747
  /** Scope with functions available to the expression */
620
748
  scope?: Scope;
749
+ /** Context with HOC functions available to $cb expressions */
750
+ context?: Context;
621
751
  /** Return generated code instead of function (for debugging) */
622
752
  returnCode?: boolean;
623
753
  /**
@@ -639,6 +769,7 @@ interface CompileASTCodeResult {
639
769
  hash: string;
640
770
  dataRoots: string[];
641
771
  scopeFns: string[];
772
+ contextFns: string[];
642
773
  }
643
774
  /**
644
775
  * Compile DSL expression to optimized function using AST generation
@@ -746,6 +877,112 @@ type Transforms = Record<string, TransformFn>;
746
877
  */
747
878
  declare function normalize(expr: unknown, transforms: Transforms): Expression;
748
879
 
880
+ /**
881
+ * @statedelta-libs/expressions - Boundaries
882
+ *
883
+ * Resolve custom boundaries ($simulate, $query, etc.) before compilation.
884
+ * Boundaries are "foreign bodies" that stop the expression flow and delegate
885
+ * to external handlers. The handler can compile internal slots independently.
886
+ *
887
+ * @example
888
+ * ```ts
889
+ * const { expr, scope } = resolveBoundaries(
890
+ * { $simulate: { effects: [...], query: {...} } },
891
+ * {
892
+ * scope: baseScope,
893
+ * resolvers: {
894
+ * $simulate: (node, { compile, genId }) => {
895
+ * const id = `__simulate_${genId()}`;
896
+ * const fn = buildSimulateFn(node, compile);
897
+ * return {
898
+ * expr: { $fn: id },
899
+ * scopeEntry: [id, fn]
900
+ * };
901
+ * }
902
+ * }
903
+ * }
904
+ * );
905
+ *
906
+ * compile(expr, { scope });
907
+ * ```
908
+ */
909
+
910
+ /**
911
+ * Result returned by a boundary resolver
912
+ */
913
+ interface ResolverResult {
914
+ /** Expression to replace the boundary with */
915
+ expr: Expression;
916
+ /** Optional entry to add to scope [key, value] */
917
+ scopeEntry?: [string, unknown];
918
+ }
919
+ /**
920
+ * Context provided to boundary resolvers
921
+ */
922
+ interface ResolverContext {
923
+ /** Compile function for compiling internal slots */
924
+ compile: typeof compile;
925
+ /** Generate unique ID for scope entries */
926
+ genId: () => string;
927
+ /** Current scope (read-only reference) */
928
+ scope: Readonly<Scope>;
929
+ /** Compile options passed to resolveBoundaries */
930
+ options: Readonly<CompileOptions>;
931
+ }
932
+ /**
933
+ * Boundary resolver function.
934
+ * Receives the raw node and context, returns replacement expression.
935
+ */
936
+ type BoundaryResolver = (node: Record<string, unknown>, ctx: ResolverContext) => ResolverResult;
937
+ /**
938
+ * Map of boundary resolvers keyed by marker (e.g. "$simulate", "$query")
939
+ */
940
+ type BoundaryResolvers = Record<string, BoundaryResolver>;
941
+ /**
942
+ * ID generator function
943
+ */
944
+ type IdGenerator = () => string;
945
+ /**
946
+ * Options for resolveBoundaries
947
+ */
948
+ interface ResolveBoundariesOptions extends CompileOptions {
949
+ /** Map of boundary resolvers */
950
+ resolvers: BoundaryResolvers;
951
+ /** Custom ID generator. Default: simple counter ("0", "1", "2"...) */
952
+ genId?: IdGenerator;
953
+ }
954
+ /**
955
+ * Result of resolveBoundaries
956
+ */
957
+ interface ResolveBoundariesResult {
958
+ /** Pure expression with boundaries replaced */
959
+ expr: Expression;
960
+ /** Enriched scope with boundary handlers */
961
+ scope: Scope;
962
+ }
963
+ /**
964
+ * Resolve boundaries in an expression tree.
965
+ *
966
+ * Boundaries are custom DSL nodes ($simulate, $query, etc.) that stop the
967
+ * normal expression compilation flow. Each boundary is extracted, processed
968
+ * by its resolver, and replaced with a standard expression.
969
+ *
970
+ * The resolver receives:
971
+ * - `node`: The raw boundary object (e.g. { $simulate: {...}, effects: [...] })
972
+ * - `ctx.compile`: Compile function for internal slots
973
+ * - `ctx.genId`: Unique ID generator
974
+ * - `ctx.scope`: Current scope (read-only)
975
+ *
976
+ * The resolver returns:
977
+ * - `expr`: Replacement expression (typically { $fn: "__id" })
978
+ * - `scopeEntry`: Optional [key, fn] to add to scope
979
+ *
980
+ * @param expr - Expression (possibly with boundaries)
981
+ * @param options - Resolvers, scope, and compile options
982
+ * @returns Pure expression and enriched scope
983
+ */
984
+ declare function resolveBoundaries(expr: unknown, options: ResolveBoundariesOptions): ResolveBoundariesResult;
985
+
749
986
  /**
750
987
  * @statedelta-libs/expressions
751
988
  *
@@ -781,4 +1018,4 @@ declare function normalize(expr: unknown, transforms: Transforms): Expression;
781
1018
  */
782
1019
  declare const VERSION = "2.0.0";
783
1020
 
784
- export { type AccessorFn, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, type Condition, type ConditionExpr, type ConditionGroup, type ConditionOp, type ConditionalExpr, type Expression, ExpressionCache, type FnExpr, type Literal, type PathGetter, type PipeExpr, type RefExpr, type Scope, type TransformFn, type TransformOptions, type Transforms, 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, normalize, normalizePath, validate, wrapInFunction };
1021
+ export { type AccessorFn, type BoundaryResolver, type BoundaryResolvers, type CbExpr, type CompileASTCodeResult, type CompileASTOptions, type CompileOptions, type CompiledExpression, type CompiledFn, type Condition, type ConditionExpr, type ConditionGroup, type ConditionOp, type ConditionalExpr, type Context, type ContextFn, type Expression, ExpressionCache, type FnExpr, type IdGenerator, type Literal, type PathGetter, type PathGetterFn, type PipeExpr, type RefExpr, type ResolveBoundariesOptions, type ResolveBoundariesResult, type ResolverContext, type ResolverResult, type Scope, type TransformFn, type TransformOptions, type Transforms, VERSION, type ValidateOptions, type ValidationResult, assertValid, builders, cache, cached, clearPathCache, compile, compileAST, compilePath, dslToAST, evaluate, evaluateAST, extractContextFns, extractDataRoots, extractDeps, extractScopeFns, get, getPathCacheSize, hasDeps, hasWildcard, isCb, isCondition, isConditionExpr, isConditionGroup, isConditional, isFn, isLiteral, isPipe, isPure, isRef, isValid, normalize, normalizePath, resolveBoundaries, validate, wrapInFunction };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import {builders,generate}from'omni-ast';var rn=Object.defineProperty;var sn=(n,t)=>{for(var s in t)rn(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"]),E=n=>n!==null&&typeof n=="object"&&"left"in n&&"op"in n&&x.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),h=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,fn=n=>E(n)||h(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,i="left"in s&&"op"in s&&x.has(s.op);return !("$"in s)&&!("$if"in s)&&!("$fn"in s)&&!("$pipe"in s)&&!i&&!("logic"in s)}return false};var R=new Map;function J(n){let t=[],s=n.length,i=0,r="";for(;i<s;){let o=n[i];if(o===".")r&&(t.push({type:"key",value:r}),r=""),i++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),i++;let e=i;for(;i<s&&n[i]!=="]";)i++;let f=n.slice(e,i);if(i++,f==="*")t.push({type:"wildcard",value:"*"});else {let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,i++;}return r&&t.push({type:"key",value:r}),t}function B(n){return n.includes("[*]")}function O(n){let t=R.get(n);return t||(t=B(n)?ln(n):un(n),R.set(n,t),t)}function un(n){if(!n.includes(".")&&!n.includes("["))return r=>r?.[n];let t=J(n),s=t.length;if(s===2){let[r,o]=t,e=r.value,f=o.value;return l=>l?.[e]?.[f]}if(s===3){let[r,o,e]=t,f=r.value,l=o.value,c=e.value;return a=>a?.[f]?.[l]?.[c]}let i=t.map(r=>r.value);return r=>{let o=r;for(let e=0;e<s&&o!=null;e++)o=o[i[e]];return o}}function ln(n){let t=J(n),s=[];for(let i=0;i<t.length;i++)t[i].type==="wildcard"&&s.push(i);return s.length===1?cn(t,s[0]):an(t,s)}function cn(n,t){let s=n.slice(0,t).map(e=>e.value),i=n.slice(t+1).map(e=>e.value),r=s.length,o=i.length;if(o===0){if(r===1){let e=s[0];return f=>f?.[e]}return e=>{let f=e;for(let l=0;l<r&&f!=null;l++)f=f[s[l]];return f}}if(o===1){let e=i[0];if(r===1){let f=s[0];return l=>{let c=l?.[f];if(Array.isArray(c))return c.map(a=>a?.[e])}}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?.[e])}}return e=>{let f=e;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[i[a]];return c})}}function an(n,t){let s=[],i=0;for(let o=0;o<t.length;o++){let e=t[o],f=o===t.length-1,l=n.slice(i,e).map(c=>c.value);l.length>0&&s.push({type:"access",keys:l}),s.push({type:f?"map":"flatMap",keys:[]}),i=e+1;}let r=n.slice(i).map(o=>o.value);return o=>{let e=o;for(let f of s){if(e==null)return;if(f.type==="access")for(let l of f.keys){if(e==null)return;e=e[l];}else if(f.type==="flatMap"){if(!Array.isArray(e))return;e=e.flatMap(l=>{let c=l;return Array.isArray(c)?c:[c]});}else if(f.type==="map"){if(!Array.isArray(e))return;r.length>0&&(e=e.map(l=>{let c=l;for(let a of r){if(c==null)return;c=c[a];}return c}));}}return e}}function pn(n,t){return O(t)(n)}function F(n){let t=n.indexOf("[*]");return t===-1?n:n.slice(0,t)}function dn(){R.clear();}function gn(){return R.size}function w(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++)A(n.args[r],t);return}if(E(n)){A(n.left,t),n.right!==void 0&&A(n.right,t);return}if(h(n)){for(let r=0;r<n.conditions.length;r++)A(n.conditions[r],t);return}let s=n,i=Object.keys(s);for(let r=0;r<i.length;r++)A(s[i[r]],t);}function mn(n){return w(n).length>0}function yn(n){return w(n).length===0}function En(n){return JSON.stringify(n)}function N(n,t={}){let s=t.scope??{},i=t.accessor,r=m(n,s,i),o=w(n),e=En(n);return {fn:r,deps:o,hash:e}}function m(n,t,s){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let i=n.map(r=>m(r,t,s));return r=>i.map(o=>o(r))}if(y(n))return hn(n,s);if(T(n))return Tn(n,t,s);if(C(n))return bn(n,t,s);if(b(n))return Cn(n,t,s);if(E(n))return An(n,t,s);if(h(n))return $n(n,t,s);if(I(n)){let i=n,r=Object.keys(i),o=r.map(e=>m(i[e],t,s));return e=>{let f={};for(let l=0;l<r.length;l++)f[r[l]]=o[l](e);return f}}return ()=>n}function K(n,t){return t?s=>t(n,s):O(n)}function hn(n,t){return K(n.$,t)}function Tn(n,t,s){let i;if(typeof n.$if=="string"){let e=n.$if.startsWith("!")?n.$if.slice(1):n.$if,f=K(e,s);i=n.$if.startsWith("!")?c=>!f(c):c=>!!f(c);}else {let e=m(n.$if,t,s);i=f=>!!e(f);}let r=m(n.then,t,s),o=n.else!==void 0?m(n.else,t,s):()=>{};return e=>i(e)?r(e):o(e)}function bn(n,t,s){let i=n.$pipe;if(i.length===0)return ()=>{};if(i.length===1)return m(i[0],t,s);let r=m(i[0],t,s),o=i.slice(1).map(f=>m(f,t,s)),e=o.length;if(e===1){let[f]=o;return l=>{let c=r(l),a=f(l);return typeof a=="function"?a(c):a}}if(e===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(e===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<e;c++){let a=o[c](f);l=typeof a=="function"?a(l):a;}return l}}function Cn(n,t,s){let i=n.$fn,r=n.args;if(r===void 0)return ()=>{let f=t[i];if(!f)throw new Error(`Function not found in scope: ${i}`);return f};let o=r.map(f=>m(f,t,s)),e=o.length;if(e===0)return f=>{let l=t[i];if(!l)throw new Error(`Function not found in scope: ${i}`);return l()};if(e===1){let[f]=o;return l=>{let c=t[i];if(!c)throw new Error(`Function not found in scope: ${i}`);return c(f(l))}}if(e===2){let[f,l]=o;return c=>{let a=t[i];if(!a)throw new Error(`Function not found in scope: ${i}`);return a(f(c),l(c))}}if(e===3){let[f,l,c]=o;return a=>{let p=t[i];if(!p)throw new Error(`Function not found in scope: ${i}`);return p(f(a),l(a),c(a))}}return f=>{let l=t[i];if(!l)throw new Error(`Function not found in scope: ${i}`);return l(...o.map(c=>c(f)))}}function An(n,t,s){let i=m(n.left,t,s),r=n.right!==void 0?m(n.right,t,s):()=>{};switch(n.op){case "eq":return o=>i(o)===r(o);case "neq":return o=>i(o)!==r(o);case "gt":return o=>i(o)>r(o);case "gte":return o=>i(o)>=r(o);case "lt":return o=>i(o)<r(o);case "lte":return o=>i(o)<=r(o);case "in":return o=>{let e=r(o);return Array.isArray(e)&&e.includes(i(o))};case "notIn":return o=>{let e=r(o);return !Array.isArray(e)||!e.includes(i(o))};case "contains":return o=>{let e=i(o);return Array.isArray(e)&&e.includes(r(o))};case "notContains":return o=>{let e=i(o);return !Array.isArray(e)||!e.includes(r(o))};case "exists":return o=>i(o)!==void 0;case "notExists":return o=>i(o)===void 0;case "matches":return o=>{let e=i(o),f=r(o);return typeof e!="string"||typeof f!="string"?false:new RegExp(f).test(e)};case "notMatches":return o=>{let e=i(o),f=r(o);return typeof e!="string"||typeof f!="string"?true:!new RegExp(f).test(e)};case "startsWith":return o=>{let e=i(o),f=r(o);return typeof e=="string"&&typeof f=="string"&&e.startsWith(f)};case "endsWith":return o=>{let e=i(o),f=r(o);return typeof e=="string"&&typeof f=="string"&&e.endsWith(f)}}}function $n(n,t,s){let i=n.conditions.map(o=>m(o,t,s)),r=i.length;if(r===1)return o=>!!i[0](o);if(r===2){let[o,e]=i;return n.logic==="AND"?f=>!!o(f)&&!!e(f):f=>!!o(f)||!!e(f)}if(r===3){let[o,e,f]=i;return n.logic==="AND"?l=>!!o(l)&&!!e(l)&&!!f(l):l=>!!o(l)||!!e(l)||!!f(l)}return n.logic==="AND"?o=>{for(let e=0;e<r;e++)if(!i[e](o))return false;return true}:o=>{for(let e=0;e<r;e++)if(i[e](o))return true;return false}}function Sn(n,t,s={}){return N(n,s).fn(t)}var j=class{constructor(t=1e3){this.cache=new Map,this._maxSize=t;}get(t,s={}){let i=JSON.stringify(t),r=this.cache.get(i);if(r)return this.cache.delete(i),this.cache.set(i,r),r;let o=N(t,s);if(this.cache.size>=this._maxSize){let e=this.cache.keys().next().value;e&&this.cache.delete(e);}return this.cache.set(i,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);}}},P=new j;function wn(n,t={}){return P.get(n,t)}function M(n,t="root",s={}){let i=[];return $(n,t,i,s),{valid:i.length===0,errors:i}}function $(n,t,s,i){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let e=0;e<n.length;e++)$(n[e],`${t}[${e}]`,s,i);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,i),$(n.then,`${t}.then`,s,i),n.else!==void 0&&$(n.else,`${t}.else`,s,i);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 e=0;e<n.$pipe.length;e++)$(n.$pipe[e],`${t}.$pipe[${e}]`,s,i);return}if(b(n)){if(!n.$fn||typeof n.$fn!="string"){s.push(`${t}: invalid function, $fn must be non-empty string`);return}if(i.scope&&!(n.$fn in i.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 e=0;e<n.args.length;e++)$(n.args[e],`${t}.args[${e}]`,s,i);return}if(E(n)){x.has(n.op)||s.push(`${t}: invalid operator "${n.op}"`),$(n.left,`${t}.left`,s,i),n.right!==void 0&&$(n.right,`${t}.right`,s,i);return}if(h(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 e=0;e<n.conditions.length;e++)$(n.conditions[e],`${t}.conditions[${e}]`,s,i);return}let r=n,o=Object.keys(r);for(let e=0;e<o.length;e++){let f=o[e];$(r[f],`${t}.${f}`,s,i);}}function kn(n,t={}){let s=M(n,"root",t);if(!s.valid)throw new Error(`Invalid expression: ${s.errors.join("; ")}`)}function xn(n,t={}){return M(n,"root",t).valid}var X={};sn(X,{$:()=>Y,$cond:()=>U,$fn:()=>H,$if:()=>Fn,$pipe:()=>Q,cond:()=>jn,fn:()=>On,pipe:()=>Nn,ref:()=>Rn});function Y(n){return {$:n}}var Rn=Y;function H(n,t){return t===void 0||t.length===0?{$fn:n}:{$fn:n,args:t}}var On=H;function Fn(n,t,s){return s===void 0?{$if:n,then:t}:{$if:n,then:t,else:s}}function Q(...n){return {$pipe:n}}var Nn=Q;function U(n,t,s){return s===void 0?{left:n,op:t}:{left:n,op:t,right:s}}var jn=U;var V="data",nn="scope",vn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function G(n,t={}){let{dataParam:s=V,scopeParam:i=nn,noPrefixes:r=false,useAccessor:o=false,lexicalPrefix:e}=t;return g(n,s,i,r,o,e)}function g(n,t,s,i,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(e=>g(e,t,s,i,r,o)));if(y(n))return Gn(n.$,t,i,r,o);if(T(n))return Dn(n,t,s,i,r,o);if(C(n))return In(n.$pipe,t,s,i,r,o);if(b(n))return zn(n,t,s,i,r,o);if(E(n))return Mn(n,t,s,i,r,o);if(h(n))return Vn(n,t,s,i,r,o);if(typeof n=="object"){let f=Object.entries(n).map(([l,c])=>builders.property(builders.identifier(l),g(c,t,s,i,r,o)));return builders.objectExpression(f)}return builders.literal(null)}var _="accessor";function L(n,t){return t?n===t||n.startsWith(t+"."):false}function Gn(n,t,s,i,r){return i?L(n,r)?k(n,t,true):builders.callExpression(builders.identifier(_),[builders.literal(n),builders.identifier(t)]):n.includes("[*]")?Wn(n,t,s):k(n,t,s)}function k(n,t,s){let i=v(n);if(i.length===0)return s?builders.identifier("undefined"):builders.identifier(t);let r;if(s){let o=i[0];r=builders.identifier(o.value);for(let e=1;e<i.length;e++){let f=i[e];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 i)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 Wn(n,t,s){let i=n.indexOf("[*]"),r=n.slice(0,i),o=n.slice(i+3),e;if(r?e=k(r,t,s):e=s?builders.identifier("undefined"):builders.identifier(t),!o||o==="")return e;if(o.includes("[*]"))return tn(e,o);let f="_i",l=o.startsWith(".")?o.slice(1):o,c=builders.identifier(f);if(l){let a=v(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(e,builders.identifier("map"),false,true),[builders.arrowFunctionExpression([builders.identifier(f)],c)])}function tn(n,t){let s=t.indexOf("[*]"),i=t.slice(0,s),r=t.slice(s+3),o="_i",e=i.startsWith(".")?i.slice(1):i,f=builders.identifier(o);if(e){let c=v(e);for(let a of c)a.type==="key"&&(f=builders.memberExpression(f,builders.identifier(a.value),false,true));}if(r.includes("[*]")){let c=tn(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=v(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 Dn(n,t,s,i,r,o){let e;if(typeof n.$if=="string"){let c=n.$if.startsWith("!"),a=c?n.$if.slice(1):n.$if,p;r?L(a,o)?p=k(a,t,true):p=builders.callExpression(builders.identifier(_),[builders.literal(a),builders.identifier(t)]):p=k(a,t,i),e=c?builders.unaryExpression("!",p):p;}else e=g(n.$if,t,s,i,r,o);let f=g(n.then,t,s,i,r,o),l=n.else!==void 0?g(n.else,t,s,i,r,o):builders.identifier("undefined");return builders.conditionalExpression(e,f,l)}function zn(n,t,s,i,r,o){let e=i?builders.identifier(n.$fn):builders.memberExpression(builders.identifier(s),builders.identifier(n.$fn),false,false);if(n.args===void 0)return e;let f=n.args.map(l=>g(l,t,s,i,r,o));return builders.callExpression(e,f)}function In(n,t,s,i,r,o){if(n.length===0)return builders.identifier("undefined");if(n.length===1)return g(n[0],t,s,i,r,o);let e=g(n[0],t,s,i,r,o);for(let f=1;f<n.length;f++){let l=g(n[f],t,s,i,r,o);e=builders.callExpression(l,[e]);}return e}function Z(n,t,s,i,r,o){if(y(n)){let e=n.$;return r?L(e,o)?k(e,t,true):builders.callExpression(builders.identifier(_),[builders.literal(e),builders.identifier(t)]):k(e,t,i)}return g(n,t,s,i,r,o)}function Mn(n,t,s,i,r,o){let e=Z(n.left,t,s,i,r,o),f=n.right!==void 0?Z(n.right,t,s,i,r,o):builders.literal(null),l=vn[n.op];if(l)return builders.binaryExpression(l,e,f);switch(n.op){case "in":return builders.callExpression(builders.memberExpression(f,builders.identifier("includes")),[e]);case "notIn":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(f,builders.identifier("includes")),[e]));case "contains":return builders.callExpression(builders.memberExpression(e,builders.identifier("includes"),false,true),[f]);case "notContains":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(e,builders.identifier("includes"),false,true),[f]));case "exists":return builders.binaryExpression("!=",e,builders.literal(null));case "notExists":return builders.binaryExpression("==",e,builders.literal(null));case "matches":return builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[f]),builders.identifier("test")),[e]);case "notMatches":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[f]),builders.identifier("test")),[e]));case "startsWith":return builders.callExpression(builders.memberExpression(e,builders.identifier("startsWith"),false,true),[f]);case "endsWith":return builders.callExpression(builders.memberExpression(e,builders.identifier("endsWith"),false,true),[f]);default:return builders.binaryExpression("===",e,f)}}function Vn(n,t,s,i,r,o){let{logic:e,conditions:f}=n,l=e==="AND"?"&&":"||";if(f.length===0)return builders.literal(e==="AND");if(f.length===1)return g(f[0],t,s,i,r,o);let c=g(f[0],t,s,i,r,o);for(let a=1;a<f.length;a++){let p=g(f[a],t,s,i,r,o);c=builders.logicalExpression(l,c,p);}return c}function v(n){let t=[],s=n.length,i=0,r="";for(;i<s;){let o=n[i];if(o===".")r&&(t.push({type:"key",value:r}),r=""),i++;else if(o==="["){r&&(t.push({type:"key",value:r}),r=""),i++;let e=i;for(;i<s&&n[i]!=="]";)i++;let f=n.slice(e,i);if(i++,f!=="*"){let l=parseInt(f,10);t.push({type:"index",value:isNaN(l)?f:l});}}else r+=o,i++;}return r&&t.push({type:"key",value:r}),t}function en(n,t=[V]){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 i of n)S(i,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 i of n.$pipe)S(i,t);return}if(b(n)){if(t.add(n.$fn),n.args)for(let i of n.args)S(i,t);return}if(E(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(h(n)){for(let i of n.conditions)S(i,t);return}let s=n;for(let i of Object.keys(s))S(s[i],t);}function D(n){let t=new Set;for(let s of n){let i=s.indexOf("."),r=s.indexOf("["),o=s.length;i!==-1&&(o=Math.min(o,i)),r!==-1&&(o=Math.min(o,r));let e=s.slice(0,o);e&&t.add(e);}return t}function Ln(n){return JSON.stringify(n)}function qn(n,t,s,i,r){let o=G(n,{noPrefixes:true,useAccessor:i,lexicalPrefix:r}),e=generate(o),f="";i?r&&(f=`const{${r}}=data??{};`):t.size>0&&(f=`const{${[...t].join(",")}}=data??{};`);let l=i?new Set([...s,"accessor"]):s,c=l.size>0?`const{${[...l].join(",")}}=scope;`:"";return c?`(function(scope){${c}return function(data){${f}return ${e}}})`:`(function(){return function(data){${f}return ${e}}})`}function q(n,t={}){let{scope:s={},returnCode:i=false,useAccessor:r=false,lexicalPrefix:o}=t,e=w(n),f=D(e),l=W(n),c=Ln(n),a=qn(n,f,l,r,o);if(i)return {code:a,deps:e,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:e,hash:c}}function on(n,t,s={}){let{fn:i}=q(n,s);return i(t)}function Jn(n,t){return z(n,t)}function z(n,t){if(n===null)return null;if(typeof n!="object")return n;if(Array.isArray(n))return n.map(o=>z(o,t));let s=n,i=Object.keys(s);for(let o of i)if(o in t){let e=t[o](s);if(typeof e=="object"&&e!==null&&o in e)throw new Error(`Transform "${o}" returned object with same key \u2014 infinite loop`);return z(e,t)}let r={};for(let o of i)r[o]=z(s[o],t);return r}var bt="2.0.0";export{j as ExpressionCache,bt as VERSION,kn as assertValid,X as builders,P as cache,wn as cached,dn as clearPathCache,N as compile,q as compileAST,O as compilePath,G as dslToAST,Sn as evaluate,on as evaluateAST,D as extractDataRoots,w as extractDeps,W as extractScopeFns,pn as get,gn as getPathCacheSize,mn as hasDeps,B as hasWildcard,E as isCondition,fn as isConditionExpr,h as isConditionGroup,T as isConditional,b as isFn,I as isLiteral,C as isPipe,yn as isPure,y as isRef,xn as isValid,Jn as normalize,F as normalizePath,M as validate,en as wrapInFunction};
1
+ import {builders,generate}from'omni-ast';var mn=Object.defineProperty;var En=(n,t)=>{for(var o in t)mn(n,o,{get:t[o],enumerable:true});};var E=n=>n!==null&&typeof n=="object"&&"$"in n&&typeof n.$=="string"&&Object.keys(n).length===1,S=n=>n!==null&&typeof n=="object"&&"$if"in n&&"then"in n,k=n=>n!==null&&typeof n=="object"&&"$fn"in n&&typeof n.$fn=="string",x=n=>n!==null&&typeof n=="object"&&"$pipe"in n&&Array.isArray(n.$pipe),R=n=>n!==null&&typeof n=="object"&&"$cb"in n&&typeof n.$cb=="string"&&"body"in n,G=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&&G.has(n.op)&&!("$"in n)&&!("$if"in n)&&!("$fn"in n),b=n=>n!==null&&typeof n=="object"&&"logic"in n&&"conditions"in n,hn=n=>h(n)||b(n),q=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 o=n,r="left"in o&&"op"in o&&G.has(o.op);return !("$"in o)&&!("$if"in o)&&!("$fn"in o)&&!("$pipe"in o)&&!("$cb"in o)&&!r&&!("logic"in o)}return false};var I=new Map;function Q(n){let t=[],o=n.length,r=0,i="";for(;r<o;){let s=n[r];if(s===".")i&&(t.push({type:"key",value:i}),i=""),r++;else if(s==="["){i&&(t.push({type:"key",value:i}),i=""),r++;let e=r;for(;r<o&&n[r]!=="]";)r++;let f=n.slice(e,r);if(r++,f==="*")t.push({type:"wildcard",value:"*"});else {let u=parseInt(f,10);t.push({type:"index",value:isNaN(u)?f:u});}}else i+=s,r++;}return i&&t.push({type:"key",value:i}),t}function U(n){return n.includes("[*]")}function N(n){let t=I.get(n);return t||(t=U(n)?Cn(n):bn(n),I.set(n,t),t)}function bn(n){if(!n.includes(".")&&!n.includes("["))return i=>i?.[n];let t=Q(n),o=t.length;if(o===2){let[i,s]=t,e=i.value,f=s.value;return u=>u?.[e]?.[f]}if(o===3){let[i,s,e]=t,f=i.value,u=s.value,l=e.value;return a=>a?.[f]?.[u]?.[l]}let r=t.map(i=>i.value);return i=>{let s=i;for(let e=0;e<o&&s!=null;e++)s=s[r[e]];return s}}function Cn(n){let t=Q(n),o=[];for(let r=0;r<t.length;r++)t[r].type==="wildcard"&&o.push(r);return o.length===1?Tn(t,o[0]):$n(t,o)}function Tn(n,t){let o=n.slice(0,t).map(e=>e.value),r=n.slice(t+1).map(e=>e.value),i=o.length,s=r.length;if(s===0){if(i===1){let e=o[0];return f=>f?.[e]}return e=>{let f=e;for(let u=0;u<i&&f!=null;u++)f=f[o[u]];return f}}if(s===1){let e=r[0];if(i===1){let f=o[0];return u=>{let l=u?.[f];if(Array.isArray(l))return l.map(a=>a?.[e])}}return f=>{let u=f;for(let l=0;l<i&&u!=null;l++)u=u[o[l]];if(Array.isArray(u))return u.map(l=>l?.[e])}}return e=>{let f=e;for(let u=0;u<i&&f!=null;u++)f=f[o[u]];if(Array.isArray(f))return f.map(u=>{let l=u;for(let a=0;a<s&&l!=null;a++)l=l[r[a]];return l})}}function $n(n,t){let o=[],r=0;for(let s=0;s<t.length;s++){let e=t[s],f=s===t.length-1,u=n.slice(r,e).map(l=>l.value);u.length>0&&o.push({type:"access",keys:u}),o.push({type:f?"map":"flatMap",keys:[]}),r=e+1;}let i=n.slice(r).map(s=>s.value);return s=>{let e=s;for(let f of o){if(e==null)return;if(f.type==="access")for(let u of f.keys){if(e==null)return;e=e[u];}else if(f.type==="flatMap"){if(!Array.isArray(e))return;e=e.flatMap(u=>{let l=u;return Array.isArray(l)?l:[l]});}else if(f.type==="map"){if(!Array.isArray(e))return;i.length>0&&(e=e.map(u=>{let l=u;for(let a of i){if(l==null)return;l=l[a];}return l}));}}return e}}function An(n,t){return N(t)(n)}function W(n){let t=n.indexOf("[*]");return t===-1?n:n.slice(0,t)}function Sn(){I.clear();}function kn(){return I.size}function F(n){let t=new Set;return C(n,t),Array.from(t)}function C(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let i=0;i<n.length;i++)C(n[i],t);return}if(E(n)){t.add(W(n.$));return}if(S(n)){if(typeof n.$if=="string"){let i=n.$if.startsWith("!")?n.$if.slice(1):n.$if;t.add(W(i));}else C(n.$if,t);C(n.then,t),n.else!==void 0&&C(n.else,t);return}if(x(n)){for(let i=0;i<n.$pipe.length;i++)C(n.$pipe[i],t);return}if(k(n)){if(n.args)for(let i=0;i<n.args.length;i++)C(n.args[i],t);return}if(R(n)){C(n.body,t),n.params!==void 0&&C(n.params,t);return}if(h(n)){C(n.left,t),n.right!==void 0&&C(n.right,t);return}if(b(n)){for(let i=0;i<n.conditions.length;i++)C(n.conditions[i],t);return}let o=n,r=Object.keys(o);for(let i=0;i<r.length;i++)C(o[r[i]],t);}function xn(n){return F(n).length>0}function Rn(n){return F(n).length===0}function wn(n){return JSON.stringify(n)}function j(n,t={}){let o=t.scope??{},r=t.accessor,i=t.context??{},s=m(n,o,r,i),e=F(n),f=wn(n);return {fn:s,deps:e,hash:f}}function m(n,t,o,r){if(n===null)return ()=>null;if(typeof n!="object")return ()=>n;if(Array.isArray(n)){let i=n.map(s=>m(s,t,o,r));return s=>i.map(e=>e(s))}if(E(n))return Fn(n,o);if(S(n))return On(n,t,o,r);if(x(n))return vn(n,t,o,r);if(k(n))return jn(n,t,o,r);if(R(n))return Nn(n,t,o,r);if(h(n))return Gn(n,t,o,r);if(b(n))return In(n,t,o,r);if(q(n)){let i=n,s=Object.keys(i),e=s.map(f=>m(i[f],t,o,r));return f=>{let u={};for(let l=0;l<s.length;l++)u[s[l]]=e[l](f);return u}}return ()=>n}function Z(n,t){return t?o=>t(n,o):N(n)}function Fn(n,t){return Z(n.$,t)}function On(n,t,o,r){let i;if(typeof n.$if=="string"){let f=n.$if.startsWith("!")?n.$if.slice(1):n.$if,u=Z(f,o);i=n.$if.startsWith("!")?a=>!u(a):a=>!!u(a);}else {let f=m(n.$if,t,o,r);i=u=>!!f(u);}let s=m(n.then,t,o,r),e=n.else!==void 0?m(n.else,t,o,r):()=>{};return f=>i(f)?s(f):e(f)}function vn(n,t,o,r){let i=n.$pipe;if(i.length===0)return ()=>{};if(i.length===1)return m(i[0],t,o,r);let s=m(i[0],t,o,r),e=i.slice(1).map(u=>m(u,t,o,r)),f=e.length;if(f===1){let[u]=e;return l=>{let a=s(l),p=u(l);return typeof p=="function"?p(a):p}}if(f===2){let[u,l]=e;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(f===3){let[u,l,a]=e;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<f;a++){let p=e[a](u);l=typeof p=="function"?p(l):p;}return l}}function jn(n,t,o,r){let i=n.$fn,s=n.args;if(s===void 0)return ()=>{let u=t[i];if(!u)throw new Error(`Function not found in scope: ${i}`);return u};let e=s.map(u=>m(u,t,o,r)),f=e.length;if(f===0)return ()=>{let u=t[i];if(!u)throw new Error(`Function not found in scope: ${i}`);return u()};if(f===1){let[u]=e;return l=>{let a=t[i];if(!a)throw new Error(`Function not found in scope: ${i}`);return a(u(l))}}if(f===2){let[u,l]=e;return a=>{let p=t[i];if(!p)throw new Error(`Function not found in scope: ${i}`);return p(u(a),l(a))}}if(f===3){let[u,l,a]=e;return p=>{let d=t[i];if(!d)throw new Error(`Function not found in scope: ${i}`);return d(u(p),l(p),a(p))}}return u=>{let l=t[i];if(!l)throw new Error(`Function not found in scope: ${i}`);return l(...e.map(a=>a(u)))}}function Nn(n,t,o,r){let i=n.$cb,s=m(n.body,t,o,r),e=n.params?m(n.params,t,o,r):void 0,f=u=>o?l=>o(l,u):l=>N(l)(u);return u=>{let l=r?.[i];if(!l)throw new Error(`Context function not found: ${i}`);let a=(g,w)=>s(g),p=f(u),d=e?e(u):void 0;return l(a,u,p,d)}}function Gn(n,t,o,r){let i=m(n.left,t,o,r),s=n.right!==void 0?m(n.right,t,o,r):()=>{};switch(n.op){case "eq":return e=>i(e)===s(e);case "neq":return e=>i(e)!==s(e);case "gt":return e=>i(e)>s(e);case "gte":return e=>i(e)>=s(e);case "lt":return e=>i(e)<s(e);case "lte":return e=>i(e)<=s(e);case "in":return e=>{let f=s(e);return Array.isArray(f)&&f.includes(i(e))};case "notIn":return e=>{let f=s(e);return !Array.isArray(f)||!f.includes(i(e))};case "contains":return e=>{let f=i(e);return Array.isArray(f)&&f.includes(s(e))};case "notContains":return e=>{let f=i(e);return !Array.isArray(f)||!f.includes(s(e))};case "exists":return e=>i(e)!==void 0;case "notExists":return e=>i(e)===void 0;case "matches":return e=>{let f=i(e),u=s(e);return typeof f!="string"||typeof u!="string"?false:new RegExp(u).test(f)};case "notMatches":return e=>{let f=i(e),u=s(e);return typeof f!="string"||typeof u!="string"?true:!new RegExp(u).test(f)};case "startsWith":return e=>{let f=i(e),u=s(e);return typeof f=="string"&&typeof u=="string"&&f.startsWith(u)};case "endsWith":return e=>{let f=i(e),u=s(e);return typeof f=="string"&&typeof u=="string"&&f.endsWith(u)}}}function In(n,t,o,r){let i=n.conditions.map(e=>m(e,t,o,r)),s=i.length;if(s===1)return e=>!!i[0](e);if(s===2){let[e,f]=i;return n.logic==="AND"?u=>!!e(u)&&!!f(u):u=>!!e(u)||!!f(u)}if(s===3){let[e,f,u]=i;return n.logic==="AND"?l=>!!e(l)&&!!f(l)&&!!u(l):l=>!!e(l)||!!f(l)||!!u(l)}return n.logic==="AND"?e=>{for(let f=0;f<s;f++)if(!i[f](e))return false;return true}:e=>{for(let f=0;f<s;f++)if(i[f](e))return true;return false}}function Wn(n,t,o={}){return j(n,o).fn(t)}var z=class{constructor(t=1e3){this.cache=new Map,this._maxSize=t;}get(t,o={}){let r=JSON.stringify(t),i=this.cache.get(r);if(i)return this.cache.delete(r),this.cache.set(r,i),i;let s=j(t,o);if(this.cache.size>=this._maxSize){let e=this.cache.keys().next().value;e&&this.cache.delete(e);}return this.cache.set(r,s),s}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 o=this.cache.keys().next().value;o&&this.cache.delete(o);}}},nn=new z;function zn(n,t={}){return nn.get(n,t)}function J(n,t="root",o={}){let r=[];return T(n,t,r,o),{valid:r.length===0,errors:r}}function T(n,t,o,r){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let e=0;e<n.length;e++)T(n[e],`${t}[${e}]`,o,r);return}if(E(n)){(!n.$||typeof n.$!="string")&&o.push(`${t}: invalid reference, $ must be non-empty string`);return}if(S(n)){typeof n.$if=="string"?(n.$if.startsWith("!")?n.$if.slice(1):n.$if)||o.push(`${t}.$if: empty path in string shorthand`):T(n.$if,`${t}.$if`,o,r),T(n.then,`${t}.then`,o,r),n.else!==void 0&&T(n.else,`${t}.else`,o,r);return}if(x(n)){if(!Array.isArray(n.$pipe)){o.push(`${t}.$pipe: must be an array`);return}if(n.$pipe.length===0){o.push(`${t}.$pipe: must have at least one element`);return}for(let e=0;e<n.$pipe.length;e++)T(n.$pipe[e],`${t}.$pipe[${e}]`,o,r);return}if(k(n)){if(!n.$fn||typeof n.$fn!="string"){o.push(`${t}: invalid function, $fn must be non-empty string`);return}if(r.scope&&!(n.$fn in r.scope)&&o.push(`${t}: function "${n.$fn}" not found in scope`),n.args!==void 0)if(!Array.isArray(n.args))o.push(`${t}.args: must be an array`);else for(let e=0;e<n.args.length;e++)T(n.args[e],`${t}.args[${e}]`,o,r);return}if(R(n)){if(!n.$cb||typeof n.$cb!="string"){o.push(`${t}: invalid callback, $cb must be non-empty string`);return}r.context&&!(n.$cb in r.context)&&o.push(`${t}: context function "${n.$cb}" not found`),T(n.body,`${t}.body`,o,r),n.params!==void 0&&T(n.params,`${t}.params`,o,r);return}if(h(n)){G.has(n.op)||o.push(`${t}: invalid operator "${n.op}"`),T(n.left,`${t}.left`,o,r),n.right!==void 0&&T(n.right,`${t}.right`,o,r);return}if(b(n)){if(n.logic!=="AND"&&n.logic!=="OR"&&o.push(`${t}: invalid logic "${n.logic}", must be "AND" or "OR"`),!Array.isArray(n.conditions)){o.push(`${t}.conditions: must be an array`);return}for(let e=0;e<n.conditions.length;e++)T(n.conditions[e],`${t}.conditions[${e}]`,o,r);return}let i=n,s=Object.keys(i);for(let e=0;e<s.length;e++){let f=s[e];T(i[f],`${t}.${f}`,o,r);}}function Dn(n,t={}){let o=J(n,"root",t);if(!o.valid)throw new Error(`Invalid expression: ${o.errors.join("; ")}`)}function Mn(n,t={}){return J(n,"root",t).valid}var un={};En(un,{$:()=>tn,$call:()=>fn,$cb:()=>sn,$cond:()=>rn,$fn:()=>en,$if:()=>Vn,$pipe:()=>on,call:()=>Kn,cb:()=>Jn,cond:()=>qn,fn:()=>_n,pipe:()=>Ln,ref:()=>Bn});function tn(n){return {$:n}}var Bn=tn;function en(n,t){return t===void 0||t.length===0?{$fn:n}:{$fn:n,args:t}}var _n=en;function Vn(n,t,o){return o===void 0?{$if:n,then:t}:{$if:n,then:t,else:o}}function on(...n){return {$pipe:n}}var Ln=on;function rn(n,t,o){return o===void 0?{left:n,op:t}:{left:n,op:t,right:o}}var qn=rn;function sn(n,t,o){return o===void 0?{$cb:n,body:t}:{$cb:n,body:t,params:o}}var Jn=sn;function fn(n,t=[]){return {$fn:n,args:t}}var Kn=fn;var K="data",ln="scope",Xn={eq:"===",neq:"!==",gt:">",gte:">=",lt:"<",lte:"<="};function M(n,t={}){let{dataParam:o=K,scopeParam:r=ln,noPrefixes:i=false,useAccessor:s=false,lexicalPrefix:e}=t;return y(n,o,r,i,s,e)}function y(n,t,o,r,i,s){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(e=>y(e,t,o,r,i,s)));if(E(n))return Yn(n.$,t,r,i,s);if(S(n))return Pn(n,t,o,r,i,s);if(x(n))return nt(n.$pipe,t,o,r,i,s);if(k(n))return Qn(n,t,o,r,i,s);if(R(n))return Zn(n,t,o,r,i,s);if(h(n))return tt(n,t,o,r,i,s);if(b(n))return et(n,t,o,r,i,s);if(typeof n=="object"){let f=Object.entries(n).map(([u,l])=>builders.property(builders.identifier(u),y(l,t,o,r,i,s)));return builders.objectExpression(f)}return builders.literal(null)}var X="accessor";function Y(n,t){return t?n===t||n.startsWith(t+"."):false}function Yn(n,t,o,r,i){return r?Y(n,i)?O(n,t,true):builders.callExpression(builders.identifier(X),[builders.literal(n),builders.identifier(t)]):n.includes("[*]")?Hn(n,t,o):O(n,t,o)}function O(n,t,o){let r=D(n);if(r.length===0)return o?builders.identifier("undefined"):builders.identifier(t);let i;if(o){let s=r[0];i=builders.identifier(s.value);for(let e=1;e<r.length;e++){let f=r[e];f.type==="key"?i=builders.memberExpression(i,builders.identifier(f.value),false,true):i=builders.memberExpression(i,builders.literal(f.value),true,true);}}else {i=builders.identifier(t);for(let s of r)s.type==="key"?i=builders.memberExpression(i,builders.identifier(s.value),false,true):i=builders.memberExpression(i,builders.literal(s.value),true,true);}return i}function Hn(n,t,o){let r=n.indexOf("[*]"),i=n.slice(0,r),s=n.slice(r+3),e;if(i?e=O(i,t,o):e=o?builders.identifier("undefined"):builders.identifier(t),!s||s==="")return e;if(s.includes("[*]"))return an(e,s);let f="_i",u=s.startsWith(".")?s.slice(1):s,l=builders.identifier(f);if(u){let a=D(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(e,builders.identifier("map"),false,true),[builders.arrowFunctionExpression([builders.identifier(f)],l)])}function an(n,t){let o=t.indexOf("[*]"),r=t.slice(0,o),i=t.slice(o+3),s="_i",e=r.startsWith(".")?r.slice(1):r,f=builders.identifier(s);if(e){let l=D(e);for(let a of l)a.type==="key"&&(f=builders.memberExpression(f,builders.identifier(a.value),false,true));}if(i.includes("[*]")){let l=an(f,i);return builders.callExpression(builders.memberExpression(n,builders.identifier("flatMap"),false,true),[builders.arrowFunctionExpression([builders.identifier(s)],l)])}let u=i.startsWith(".")?i.slice(1):i;if(u){let l=D(u);for(let a of l)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(s)],f)])}function Pn(n,t,o,r,i,s){let e;if(typeof n.$if=="string"){let l=n.$if.startsWith("!"),a=l?n.$if.slice(1):n.$if,p;i?Y(a,s)?p=O(a,t,true):p=builders.callExpression(builders.identifier(X),[builders.literal(a),builders.identifier(t)]):p=O(a,t,r),e=l?builders.unaryExpression("!",p):p;}else e=y(n.$if,t,o,r,i,s);let f=y(n.then,t,o,r,i,s),u=n.else!==void 0?y(n.else,t,o,r,i,s):builders.identifier("undefined");return builders.conditionalExpression(e,f,u)}function Qn(n,t,o,r,i,s){let e=r?builders.identifier(n.$fn):builders.memberExpression(builders.identifier(o),builders.identifier(n.$fn),false,false);if(n.args===void 0)return e;let f=n.args.map(u=>y(u,t,o,r,i,s));return builders.callExpression(e,f)}var Un="context";function Zn(n,t,o,r,i,s){let e=r?builders.identifier(n.$cb):builders.memberExpression(builders.identifier(Un),builders.identifier(n.$cb),false,false),f=y(n.body,t,o,r,i,s),l=[builders.arrowFunctionExpression([builders.identifier(t),builders.identifier("get")],f),builders.identifier(t),builders.identifier("get")];if(n.params!==void 0){let a=y(n.params,t,o,r,i,s);l.push(a);}return builders.callExpression(e,l)}function nt(n,t,o,r,i,s){if(n.length===0)return builders.identifier("undefined");if(n.length===1)return y(n[0],t,o,r,i,s);let e=y(n[0],t,o,r,i,s);for(let f=1;f<n.length;f++){let u=y(n[f],t,o,r,i,s);e=builders.callExpression(u,[e]);}return e}function cn(n,t,o,r,i,s){if(E(n)){let e=n.$;return i?Y(e,s)?O(e,t,true):builders.callExpression(builders.identifier(X),[builders.literal(e),builders.identifier(t)]):O(e,t,r)}return y(n,t,o,r,i,s)}function tt(n,t,o,r,i,s){let e=cn(n.left,t,o,r,i,s),f=n.right!==void 0?cn(n.right,t,o,r,i,s):builders.literal(null),u=Xn[n.op];if(u)return builders.binaryExpression(u,e,f);switch(n.op){case "in":return builders.callExpression(builders.memberExpression(f,builders.identifier("includes")),[e]);case "notIn":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(f,builders.identifier("includes")),[e]));case "contains":return builders.callExpression(builders.memberExpression(e,builders.identifier("includes"),false,true),[f]);case "notContains":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(e,builders.identifier("includes"),false,true),[f]));case "exists":return builders.binaryExpression("!=",e,builders.literal(null));case "notExists":return builders.binaryExpression("==",e,builders.literal(null));case "matches":return builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[f]),builders.identifier("test")),[e]);case "notMatches":return builders.unaryExpression("!",builders.callExpression(builders.memberExpression(builders.newExpression(builders.identifier("RegExp"),[f]),builders.identifier("test")),[e]));case "startsWith":return builders.callExpression(builders.memberExpression(e,builders.identifier("startsWith"),false,true),[f]);case "endsWith":return builders.callExpression(builders.memberExpression(e,builders.identifier("endsWith"),false,true),[f]);default:return builders.binaryExpression("===",e,f)}}function et(n,t,o,r,i,s){let{logic:e,conditions:f}=n,u=e==="AND"?"&&":"||";if(f.length===0)return builders.literal(e==="AND");if(f.length===1)return y(f[0],t,o,r,i,s);let l=y(f[0],t,o,r,i,s);for(let a=1;a<f.length;a++){let p=y(f[a],t,o,r,i,s);l=builders.logicalExpression(u,l,p);}return l}function D(n){let t=[],o=n.length,r=0,i="";for(;r<o;){let s=n[r];if(s===".")i&&(t.push({type:"key",value:i}),i=""),r++;else if(s==="["){i&&(t.push({type:"key",value:i}),i=""),r++;let e=r;for(;r<o&&n[r]!=="]";)r++;let f=n.slice(e,r);if(r++,f!=="*"){let u=parseInt(f,10);t.push({type:"index",value:isNaN(u)?f:u});}}else i+=s,r++;}return i&&t.push({type:"key",value:i}),t}function pn(n,t=[K]){return builders.arrowFunctionExpression(t.map(o=>builders.identifier(o)),n)}function B(n){let t=new Set;return $(n,t),t}function $(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r of n)$(r,t);return}if(E(n))return;if(S(n)){$(n.$if,t),$(n.then,t),n.else!==void 0&&$(n.else,t);return}if(x(n)){for(let r of n.$pipe)$(r,t);return}if(k(n)){if(t.add(n.$fn),n.args)for(let r of n.args)$(r,t);return}if(R(n)){$(n.body,t),n.params!==void 0&&$(n.params,t);return}if(h(n)){n.left!==void 0&&typeof n.left=="object"&&$(n.left,t),n.right!==void 0&&typeof n.right=="object"&&$(n.right,t);return}if(b(n)){for(let r of n.conditions)$(r,t);return}let o=n;for(let r of Object.keys(o))$(o[r],t);}function _(n){let t=new Set;return A(n,t),t}function A(n,t){if(n===null||typeof n!="object")return;if(Array.isArray(n)){for(let r of n)A(r,t);return}if(E(n))return;if(S(n)){A(n.$if,t),A(n.then,t),n.else!==void 0&&A(n.else,t);return}if(x(n)){for(let r of n.$pipe)A(r,t);return}if(k(n)){if(n.args)for(let r of n.args)A(r,t);return}if(R(n)){t.add(n.$cb),A(n.body,t),n.params!==void 0&&A(n.params,t);return}if(h(n)){n.left!==void 0&&typeof n.left=="object"&&A(n.left,t),n.right!==void 0&&typeof n.right=="object"&&A(n.right,t);return}if(b(n)){for(let r of n.conditions)A(r,t);return}let o=n;for(let r of Object.keys(o))A(o[r],t);}function V(n){let t=new Set;for(let o of n){let r=o.indexOf("."),i=o.indexOf("["),s=o.length;r!==-1&&(s=Math.min(s,r)),i!==-1&&(s=Math.min(s,i));let e=o.slice(0,s);e&&t.add(e);}return t}function ot(n){return JSON.stringify(n)}function rt(n,t,o,r,i,s){let e=M(n,{noPrefixes:true,useAccessor:i,lexicalPrefix:s}),f=generate(e),u="";i?s&&(u=`const{${s}}=data??{};`):t.size>0&&(u=`const{${[...t].join(",")}}=data??{};`);let l=i?new Set([...o,"accessor"]):o,a=l.size>0?`const{${[...l].join(",")}}=scope;`:"",p=r.size>0?`const{${[...r].join(",")}}=context;`:"",d=r.size>0,g="";d&&(i?g="const get=(path)=>accessor(path,data);":g="const get=(path)=>path.split('.').reduce((o,k)=>o?.[k],data);");let w=l.size>0,v;if(w||d){let gn=d?"scope,context":"scope",yn=`${u}${g}return ${f}`;v=`(function(${gn}){${a}${p}return function(data){${yn}}})`;}else v=`(function(){return function(data){${u}return ${f}}})`;return v}function H(n,t={}){let{scope:o={},context:r={},returnCode:i=false,useAccessor:s=false,lexicalPrefix:e}=t,f=F(n),u=V(f),l=B(n),a=_(n),p=ot(n),d=rt(n,u,l,a,s,e);if(i)return {code:d,deps:f,hash:p,dataRoots:[...u],scopeFns:[...l],contextFns:[...a]};let g;try{let w=a.size>0,v=new Function(`return ${d}`)();g=w?v(o,r):v(o);}catch(w){throw new Error(`AST compilation failed. If this is due to CSP, use the standard compile() function instead. Error: ${w instanceof Error?w.message:String(w)}`)}return {fn:g,deps:f,hash:p}}function dn(n,t,o={}){let{fn:r}=H(n,o);return r(t)}function st(n,t){return L(n,t)}function L(n,t){if(n===null)return null;if(typeof n!="object")return n;if(Array.isArray(n))return n.map(s=>L(s,t));let o=n,r=Object.keys(o);for(let s of r)if(s in t){let e=t[s](o);if(typeof e=="object"&&e!==null&&s in e)throw new Error(`Transform "${s}" returned object with same key \u2014 infinite loop`);return L(e,t)}let i={};for(let s of r)i[s]=L(o[s],t);return i}var ft=new Set(["$","$if","$fn","$pipe","$cb"]);function ut(){let n=0;return ()=>String(n++)}function ct(n,t){let{resolvers:o,scope:r={},genId:i,...s}=t,e=Object.keys(o);if(e.length===0)return {expr:n,scope:r};let f=new Set(e),u=[],l={compile:j,genId:i??ut(),scope:r,options:s},a=P(n,f,o,l,u),p={...r};for(let d=0;d<u.length;d++){let[g,w]=u[d];p[g]=w;}return {expr:a,scope:p}}function P(n,t,o,r,i){if(n===null)return null;if(typeof n!="object")return n;if(Array.isArray(n)){let l=n.length,a=new Array(l);for(let p=0;p<l;p++)a[p]=P(n[p],t,o,r,i);return a}let s=n,e=Object.keys(s),f=e.length;for(let l=0;l<f;l++){let a=e[l];if(a[0]==="$"&&!ft.has(a)&&t.has(a)){let p=o[a],d=p(s,r);return d.scopeEntry&&i.push(d.scopeEntry),d.expr}}let u={};for(let l=0;l<f;l++){let a=e[l];u[a]=P(s[a],t,o,r,i);}return u}var _t="2.0.0";export{z as ExpressionCache,_t as VERSION,Dn as assertValid,un as builders,nn as cache,zn as cached,Sn as clearPathCache,j as compile,H as compileAST,N as compilePath,M as dslToAST,Wn as evaluate,dn as evaluateAST,_ as extractContextFns,V as extractDataRoots,F as extractDeps,B as extractScopeFns,An as get,kn as getPathCacheSize,xn as hasDeps,U as hasWildcard,R as isCb,h as isCondition,hn as isConditionExpr,b as isConditionGroup,S as isConditional,k as isFn,q as isLiteral,x as isPipe,Rn as isPure,E as isRef,Mn as isValid,st as normalize,W as normalizePath,ct as resolveBoundaries,J as validate,pn as wrapInFunction};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statedelta-libs/expressions",
3
- "version": "2.0.1",
3
+ "version": "2.2.0",
4
4
  "description": "JSON DSL compiler for optimized functions - StateDelta expression engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",