@codehz/json-expr 0.3.0 → 0.5.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/dist/index.mjs CHANGED
@@ -194,6 +194,8 @@ var Parser = class Parser {
194
194
  if (ch === "[") return this.parseArray();
195
195
  if (ch === "{") return this.parseObject();
196
196
  if (ch === "(") {
197
+ const arrowFunc = this.tryParseArrowFunction();
198
+ if (arrowFunc) return arrowFunc;
197
199
  this.advance();
198
200
  this.skipWhitespace();
199
201
  const expr = this.parseExpression();
@@ -214,7 +216,11 @@ var Parser = class Parser {
214
216
  type: "Identifier",
215
217
  name: "undefined"
216
218
  };
217
- if (this.isIdentifierStart(ch)) return this.parseIdentifier();
219
+ if (this.isIdentifierStart(ch)) {
220
+ const arrowFunc = this.tryParseSingleParamArrowFunction();
221
+ if (arrowFunc) return arrowFunc;
222
+ return this.parseIdentifier();
223
+ }
218
224
  throw new Error(`Unexpected character at position ${this.pos}: ${ch}`);
219
225
  }
220
226
  parseNumber() {
@@ -359,6 +365,63 @@ var Parser = class Parser {
359
365
  name
360
366
  };
361
367
  }
368
+ /**
369
+ * 尝试解析带括号的箭头函数: (a, b) => expr
370
+ * 使用回溯机制
371
+ */
372
+ tryParseArrowFunction() {
373
+ const savedPos = this.pos;
374
+ try {
375
+ this.expect("(");
376
+ this.skipWhitespace();
377
+ const params = [];
378
+ while (this.peek() !== ")") {
379
+ if (!this.isIdentifierStart(this.peek())) throw new Error("Expected identifier");
380
+ params.push(this.parseIdentifier());
381
+ this.skipWhitespace();
382
+ if (this.peek() === ",") {
383
+ this.advance();
384
+ this.skipWhitespace();
385
+ } else break;
386
+ }
387
+ this.expect(")");
388
+ this.skipWhitespace();
389
+ if (this.source.slice(this.pos, this.pos + 2) !== "=>") throw new Error("Expected =>");
390
+ this.pos += 2;
391
+ this.skipWhitespace();
392
+ return {
393
+ type: "ArrowFunctionExpr",
394
+ params,
395
+ body: this.parseExpression()
396
+ };
397
+ } catch {
398
+ this.pos = savedPos;
399
+ return null;
400
+ }
401
+ }
402
+ /**
403
+ * 尝试解析单参数无括号的箭头函数: a => expr
404
+ * 使用回溯机制
405
+ */
406
+ tryParseSingleParamArrowFunction() {
407
+ const savedPos = this.pos;
408
+ try {
409
+ const param = this.parseIdentifier();
410
+ this.skipWhitespace();
411
+ if (this.source.slice(this.pos, this.pos + 2) !== "=>") throw new Error("Expected =>");
412
+ this.pos += 2;
413
+ this.skipWhitespace();
414
+ const body = this.parseExpression();
415
+ return {
416
+ type: "ArrowFunctionExpr",
417
+ params: [param],
418
+ body
419
+ };
420
+ } catch {
421
+ this.pos = savedPos;
422
+ return null;
423
+ }
424
+ }
362
425
  parseArguments() {
363
426
  const args = [];
364
427
  this.skipWhitespace();
@@ -496,6 +559,27 @@ function generate(node) {
496
559
  case "CallExpr": {
497
560
  const callee = wrapIfNeeded(node.callee, node, "callee");
498
561
  const args = node.arguments.map(generate).join(",");
562
+ if (node.callee.type === "Identifier" && [
563
+ "Date",
564
+ "RegExp",
565
+ "URL",
566
+ "URLSearchParams",
567
+ "Map",
568
+ "Set",
569
+ "Int8Array",
570
+ "Uint8Array",
571
+ "Uint8ClampedArray",
572
+ "Int16Array",
573
+ "Uint16Array",
574
+ "Int32Array",
575
+ "Uint32Array",
576
+ "Float32Array",
577
+ "Float64Array",
578
+ "BigInt64Array",
579
+ "BigUint64Array",
580
+ "ArrayBuffer",
581
+ "DataView"
582
+ ].includes(node.callee.name)) return node.optional ? `new ${callee}?.(${args})` : `new ${callee}(${args})`;
499
583
  return node.optional ? `${callee}?.(${args})` : `${callee}(${args})`;
500
584
  }
501
585
  case "ArrayExpr": return `[${node.elements.map(generate).join(",")}]`;
@@ -503,6 +587,13 @@ function generate(node) {
503
587
  if (prop.shorthand) return generate(prop.key);
504
588
  return `${prop.computed ? `[${generate(prop.key)}]` : generate(prop.key)}:${generate(prop.value)}`;
505
589
  }).join(",")}}`;
590
+ case "ArrowFunctionExpr": {
591
+ const params = node.params.map((p) => p.name).join(",");
592
+ let body = generate(node.body);
593
+ if (node.body.type === "ObjectExpr") body = `(${body})`;
594
+ if (node.params.length === 1) return `${params}=>${body}`;
595
+ return `(${params})=>${body}`;
596
+ }
506
597
  default: {
507
598
  const nodeType = node.type ?? "unknown";
508
599
  throw new Error(`Unknown node type: ${nodeType}`);
@@ -538,190 +629,642 @@ function needsParens(child, parent, position) {
538
629
  return false;
539
630
  }
540
631
  /**
541
- * 收集 AST 中所有使用的标识符名称
632
+ * 转换 AST 中的标识符
633
+ * 回调函数可以返回:
634
+ * - string: 替换标识符名称
635
+ * - ASTNode: 内联该 AST 节点(用于子表达式内联)
636
+ */
637
+ function transformIdentifiers(node, transform) {
638
+ switch (node.type) {
639
+ case "Identifier": {
640
+ const result = transform(node.name);
641
+ return typeof result === "string" ? {
642
+ ...node,
643
+ name: result
644
+ } : result;
645
+ }
646
+ case "BinaryExpr": return {
647
+ ...node,
648
+ left: transformIdentifiers(node.left, transform),
649
+ right: transformIdentifiers(node.right, transform)
650
+ };
651
+ case "UnaryExpr": return {
652
+ ...node,
653
+ argument: transformIdentifiers(node.argument, transform)
654
+ };
655
+ case "ConditionalExpr": return {
656
+ ...node,
657
+ test: transformIdentifiers(node.test, transform),
658
+ consequent: transformIdentifiers(node.consequent, transform),
659
+ alternate: transformIdentifiers(node.alternate, transform)
660
+ };
661
+ case "MemberExpr": return {
662
+ ...node,
663
+ object: transformIdentifiers(node.object, transform),
664
+ property: node.computed ? transformIdentifiers(node.property, transform) : node.property
665
+ };
666
+ case "CallExpr": return {
667
+ ...node,
668
+ callee: transformIdentifiers(node.callee, transform),
669
+ arguments: node.arguments.map((arg) => transformIdentifiers(arg, transform))
670
+ };
671
+ case "ArrayExpr": return {
672
+ ...node,
673
+ elements: node.elements.map((el) => transformIdentifiers(el, transform))
674
+ };
675
+ case "ObjectExpr": return {
676
+ ...node,
677
+ properties: node.properties.map((prop) => ({
678
+ ...prop,
679
+ key: prop.computed ? transformIdentifiers(prop.key, transform) : prop.key,
680
+ value: transformIdentifiers(prop.value, transform)
681
+ }))
682
+ };
683
+ case "ArrowFunctionExpr": {
684
+ const paramNames = new Set(node.params.map((p) => p.name));
685
+ return {
686
+ ...node,
687
+ body: transformIdentifiers(node.body, (name) => paramNames.has(name) ? name : transform(name))
688
+ };
689
+ }
690
+ default: return node;
691
+ }
692
+ }
693
+
694
+ //#endregion
695
+ //#region src/proxy-metadata.ts
696
+ /**
697
+ * 全局 WeakMap 存储
698
+ */
699
+ const proxyMetadata = /* @__PURE__ */ new WeakMap();
700
+ /**
701
+ * 设置 Proxy 元数据
702
+ */
703
+ function setProxyMetadata(proxy, metadata) {
704
+ proxyMetadata.set(proxy, metadata);
705
+ }
706
+ /**
707
+ * 获取 Proxy 元数据
708
+ */
709
+ function getProxyMetadata(proxy) {
710
+ return proxyMetadata.get(proxy);
711
+ }
712
+ /**
713
+ * 检查对象是否是 Proxy variable
714
+ */
715
+ function isProxyVariable(obj) {
716
+ if (typeof obj !== "object" && typeof obj !== "function" || obj === null) return false;
717
+ return proxyMetadata.get(obj)?.type === "variable";
718
+ }
719
+ /**
720
+ * 检查对象是否是 Proxy expression
721
+ */
722
+ function isProxyExpression(obj) {
723
+ if (typeof obj !== "object" && typeof obj !== "function" || obj === null) return false;
724
+ return proxyMetadata.get(obj)?.type === "expression";
725
+ }
726
+ /**
727
+ * 检查对象是否是任意 Proxy (variable 或 expression)
542
728
  */
543
- function collectIdentifiers(node) {
544
- const identifiers = /* @__PURE__ */ new Set();
545
- function visit(n) {
546
- switch (n.type) {
547
- case "Identifier":
548
- identifiers.add(n.name);
549
- break;
550
- case "BinaryExpr":
551
- visit(n.left);
552
- visit(n.right);
553
- break;
554
- case "UnaryExpr":
555
- visit(n.argument);
556
- break;
557
- case "ConditionalExpr":
558
- visit(n.test);
559
- visit(n.consequent);
560
- visit(n.alternate);
561
- break;
562
- case "MemberExpr":
563
- visit(n.object);
564
- if (n.computed) visit(n.property);
565
- break;
566
- case "CallExpr":
567
- visit(n.callee);
568
- n.arguments.forEach(visit);
569
- break;
570
- case "ArrayExpr":
571
- n.elements.forEach(visit);
572
- break;
573
- case "ObjectExpr":
574
- n.properties.forEach((prop) => {
575
- if (prop.computed) visit(prop.key);
576
- visit(prop.value);
729
+ function isProxy(obj) {
730
+ if (typeof obj !== "object" && typeof obj !== "function" || obj === null) return false;
731
+ return proxyMetadata.has(obj);
732
+ }
733
+
734
+ //#endregion
735
+ //#region src/proxy-variable.ts
736
+ /**
737
+ * 使用 Symbol.description 生成占位符
738
+ * 用于在表达式源码中标识变量
739
+ */
740
+ function getVariablePlaceholder$1(id) {
741
+ return `$$VAR_${id.description}$$`;
742
+ }
743
+ /**
744
+ * 序列化参数为 AST 节点
745
+ * - Proxy Variable/Expression:使用 ast 或占位符标识符
746
+ * - 数组:返回 ArrayExpr 节点
747
+ * - 对象:返回 ObjectExpr 节点
748
+ * - 原始值:返回对应的字面量节点
749
+ * - Date, RegExp, BigInt, URL, URLSearchParams, Map, Set, TypedArray, DataView: 构造函数调用
750
+ */
751
+ function serializeArgumentToAST(arg) {
752
+ if ((typeof arg === "object" || typeof arg === "function") && arg !== null) {
753
+ const meta = getProxyMetadata(arg);
754
+ if (meta) {
755
+ if (meta.ast) return meta.ast;
756
+ if (meta.rootVariable) return {
757
+ type: "Identifier",
758
+ name: getVariablePlaceholder$1(meta.rootVariable)
759
+ };
760
+ }
761
+ }
762
+ if (Array.isArray(arg)) return {
763
+ type: "ArrayExpr",
764
+ elements: arg.map(serializeArgumentToAST)
765
+ };
766
+ if (typeof arg === "object" && arg !== null) {
767
+ if (arg instanceof Date) return {
768
+ type: "CallExpr",
769
+ callee: {
770
+ type: "Identifier",
771
+ name: "Date"
772
+ },
773
+ arguments: [{
774
+ type: "NumberLiteral",
775
+ value: arg.getTime(),
776
+ raw: String(arg.getTime())
777
+ }],
778
+ optional: false
779
+ };
780
+ if (arg instanceof RegExp) {
781
+ const args = [{
782
+ type: "StringLiteral",
783
+ value: arg.source,
784
+ quote: "\""
785
+ }];
786
+ if (arg.flags) args.push({
787
+ type: "StringLiteral",
788
+ value: arg.flags,
789
+ quote: "\""
790
+ });
791
+ return {
792
+ type: "CallExpr",
793
+ callee: {
794
+ type: "Identifier",
795
+ name: "RegExp"
796
+ },
797
+ arguments: args,
798
+ optional: false
799
+ };
800
+ }
801
+ if (typeof URL !== "undefined" && arg instanceof URL) return {
802
+ type: "CallExpr",
803
+ callee: {
804
+ type: "Identifier",
805
+ name: "URL"
806
+ },
807
+ arguments: [{
808
+ type: "StringLiteral",
809
+ value: arg.href,
810
+ quote: "\""
811
+ }],
812
+ optional: false
813
+ };
814
+ if (typeof URLSearchParams !== "undefined" && arg instanceof URLSearchParams) {
815
+ const entries = [];
816
+ arg.forEach((value, key) => {
817
+ entries.push({
818
+ type: "ArrayExpr",
819
+ elements: [{
820
+ type: "StringLiteral",
821
+ value: key,
822
+ quote: "\""
823
+ }, {
824
+ type: "StringLiteral",
825
+ value,
826
+ quote: "\""
827
+ }]
577
828
  });
578
- break;
829
+ });
830
+ return {
831
+ type: "CallExpr",
832
+ callee: {
833
+ type: "Identifier",
834
+ name: "URLSearchParams"
835
+ },
836
+ arguments: [{
837
+ type: "ArrayExpr",
838
+ elements: entries
839
+ }],
840
+ optional: false
841
+ };
842
+ }
843
+ if (arg instanceof Map) {
844
+ const entries = [];
845
+ arg.forEach((value, key) => {
846
+ entries.push({
847
+ type: "ArrayExpr",
848
+ elements: [serializeArgumentToAST(key), serializeArgumentToAST(value)]
849
+ });
850
+ });
851
+ return {
852
+ type: "CallExpr",
853
+ callee: {
854
+ type: "Identifier",
855
+ name: "Map"
856
+ },
857
+ arguments: [{
858
+ type: "ArrayExpr",
859
+ elements: entries
860
+ }],
861
+ optional: false
862
+ };
863
+ }
864
+ if (arg instanceof Set) {
865
+ const values = [];
866
+ arg.forEach((value) => {
867
+ values.push(serializeArgumentToAST(value));
868
+ });
869
+ return {
870
+ type: "CallExpr",
871
+ callee: {
872
+ type: "Identifier",
873
+ name: "Set"
874
+ },
875
+ arguments: [{
876
+ type: "ArrayExpr",
877
+ elements: values
878
+ }],
879
+ optional: false
880
+ };
881
+ }
882
+ for (const constructorName of [
883
+ "Int8Array",
884
+ "Uint8Array",
885
+ "Uint8ClampedArray",
886
+ "Int16Array",
887
+ "Uint16Array",
888
+ "Int32Array",
889
+ "Uint32Array",
890
+ "Float32Array",
891
+ "Float64Array",
892
+ "BigInt64Array",
893
+ "BigUint64Array"
894
+ ]) if (typeof globalThis[constructorName] !== "undefined") {
895
+ if (arg instanceof globalThis[constructorName]) {
896
+ const values = [...arg].map((val) => serializeArgumentToAST(val));
897
+ return {
898
+ type: "CallExpr",
899
+ callee: {
900
+ type: "Identifier",
901
+ name: constructorName
902
+ },
903
+ arguments: [{
904
+ type: "ArrayExpr",
905
+ elements: values
906
+ }],
907
+ optional: false
908
+ };
909
+ }
910
+ }
911
+ if (arg instanceof ArrayBuffer) {
912
+ const uint8Array = new Uint8Array(arg);
913
+ return {
914
+ type: "MemberExpr",
915
+ object: {
916
+ type: "CallExpr",
917
+ callee: {
918
+ type: "Identifier",
919
+ name: "Uint8Array"
920
+ },
921
+ arguments: [{
922
+ type: "ArrayExpr",
923
+ elements: Array.from(uint8Array).map((val) => serializeArgumentToAST(val))
924
+ }],
925
+ optional: false
926
+ },
927
+ property: {
928
+ type: "Identifier",
929
+ name: "buffer"
930
+ },
931
+ computed: false,
932
+ optional: false
933
+ };
579
934
  }
935
+ if (arg instanceof DataView) return {
936
+ type: "CallExpr",
937
+ callee: {
938
+ type: "Identifier",
939
+ name: "DataView"
940
+ },
941
+ arguments: [serializeArgumentToAST(arg.buffer)],
942
+ optional: false
943
+ };
944
+ }
945
+ if (typeof arg === "object" && arg !== null) return {
946
+ type: "ObjectExpr",
947
+ properties: Object.entries(arg).map(([k, v]) => {
948
+ return {
949
+ key: /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k) ? {
950
+ type: "Identifier",
951
+ name: k
952
+ } : {
953
+ type: "StringLiteral",
954
+ value: k,
955
+ quote: "\""
956
+ },
957
+ value: serializeArgumentToAST(v),
958
+ computed: false,
959
+ shorthand: false
960
+ };
961
+ })
962
+ };
963
+ if (arg === null) return { type: "NullLiteral" };
964
+ if (arg === void 0) return {
965
+ type: "Identifier",
966
+ name: "undefined"
967
+ };
968
+ if (typeof arg === "boolean") return {
969
+ type: "BooleanLiteral",
970
+ value: arg
971
+ };
972
+ if (typeof arg === "number") return {
973
+ type: "NumberLiteral",
974
+ value: arg,
975
+ raw: String(arg)
976
+ };
977
+ if (typeof arg === "string") return {
978
+ type: "StringLiteral",
979
+ value: arg,
980
+ quote: "\""
981
+ };
982
+ if (typeof arg === "bigint") return {
983
+ type: "CallExpr",
984
+ callee: {
985
+ type: "Identifier",
986
+ name: "BigInt"
987
+ },
988
+ arguments: [{
989
+ type: "StringLiteral",
990
+ value: arg.toString(),
991
+ quote: "\""
992
+ }],
993
+ optional: false
994
+ };
995
+ throw new Error(`Unsupported argument type: ${typeof arg}`);
996
+ }
997
+ /**
998
+ * 从参数中收集依赖的 Symbol
999
+ * 递归遍历数组和对象,收集所有 Proxy 的依赖
1000
+ */
1001
+ function collectDepsFromArgs(args, deps) {
1002
+ for (const arg of args) if ((typeof arg === "object" || typeof arg === "function") && arg !== null) {
1003
+ const meta = getProxyMetadata(arg);
1004
+ if (meta?.dependencies) for (const dep of meta.dependencies) deps.add(dep);
1005
+ else if (Array.isArray(arg)) collectDepsFromArgs(arg, deps);
1006
+ else if (typeof arg === "object") collectDepsFromArgs(Object.values(arg), deps);
580
1007
  }
581
- visit(node);
582
- return identifiers;
1008
+ }
1009
+ /**
1010
+ * 创建根 Variable Proxy
1011
+ * 拦截属性访问,返回新的 expression proxy
1012
+ * 不可直接调用(apply 应该只在链式调用后可用)
1013
+ *
1014
+ * @param id - 变量的唯一标识 Symbol
1015
+ * @returns Proxy 包装的 Variable
1016
+ */
1017
+ function createProxyVariable(id) {
1018
+ const deps = new Set([id]);
1019
+ const proxy = new Proxy(function() {}, {
1020
+ get(_target, prop) {
1021
+ if (typeof prop === "symbol") return void 0;
1022
+ return createProxyExpression(id, [String(prop)], deps);
1023
+ },
1024
+ apply() {
1025
+ throw new Error("Variable cannot be called directly");
1026
+ }
1027
+ });
1028
+ setProxyMetadata(proxy, {
1029
+ type: "variable",
1030
+ path: [],
1031
+ rootVariable: id,
1032
+ dependencies: deps
1033
+ });
1034
+ return proxy;
1035
+ }
1036
+ /**
1037
+ * 创建属性访问后的 Proxy
1038
+ * 继续拦截属性访问(链式访问)
1039
+ * 拦截 apply 进行方法调用
1040
+ *
1041
+ * @param rootId - 根变量的 Symbol
1042
+ * @param path - 属性访问路径
1043
+ * @param deps - 依赖集合
1044
+ * @returns Proxy 包装的 Expression
1045
+ */
1046
+ function createProxyExpression(rootId, path, deps) {
1047
+ let ast = {
1048
+ type: "Identifier",
1049
+ name: getVariablePlaceholder$1(rootId)
1050
+ };
1051
+ for (const prop of path) ast = {
1052
+ type: "MemberExpr",
1053
+ object: ast,
1054
+ property: {
1055
+ type: "Identifier",
1056
+ name: prop
1057
+ },
1058
+ computed: false,
1059
+ optional: false
1060
+ };
1061
+ const proxy = new Proxy(function() {}, {
1062
+ get(_target, prop) {
1063
+ if (typeof prop === "symbol") return void 0;
1064
+ return createProxyExpression(rootId, [...path, String(prop)], deps);
1065
+ },
1066
+ apply(_target, _thisArg, args) {
1067
+ const callAst = {
1068
+ type: "CallExpr",
1069
+ callee: ast,
1070
+ arguments: args.map(serializeArgumentToAST),
1071
+ optional: false
1072
+ };
1073
+ const newDeps = new Set(deps);
1074
+ collectDepsFromArgs(args, newDeps);
1075
+ return createProxyExpressionWithAST(callAst, newDeps);
1076
+ }
1077
+ });
1078
+ setProxyMetadata(proxy, {
1079
+ type: "expression",
1080
+ path,
1081
+ rootVariable: rootId,
1082
+ ast,
1083
+ dependencies: deps
1084
+ });
1085
+ return proxy;
1086
+ }
1087
+ /**
1088
+ * 创建带完整 AST 的 Proxy(方法调用后)
1089
+ * 可以继续链式访问和调用
1090
+ *
1091
+ * @param ast - 完整的表达式 AST
1092
+ * @param deps - 依赖集合
1093
+ * @returns Proxy 包装的 Expression
1094
+ */
1095
+ function createProxyExpressionWithAST(ast, deps) {
1096
+ const proxy = new Proxy(function() {}, {
1097
+ get(_target, prop) {
1098
+ if (typeof prop === "symbol") return void 0;
1099
+ return createProxyExpressionWithAST({
1100
+ type: "MemberExpr",
1101
+ object: ast,
1102
+ property: {
1103
+ type: "Identifier",
1104
+ name: String(prop)
1105
+ },
1106
+ computed: false,
1107
+ optional: false
1108
+ }, deps);
1109
+ },
1110
+ apply(_target, _thisArg, args) {
1111
+ const callAst = {
1112
+ type: "CallExpr",
1113
+ callee: ast,
1114
+ arguments: args.map(serializeArgumentToAST),
1115
+ optional: false
1116
+ };
1117
+ const newDeps = new Set(deps);
1118
+ collectDepsFromArgs(args, newDeps);
1119
+ return createProxyExpressionWithAST(callAst, newDeps);
1120
+ }
1121
+ });
1122
+ setProxyMetadata(proxy, {
1123
+ type: "expression",
1124
+ path: [],
1125
+ ast,
1126
+ dependencies: deps
1127
+ });
1128
+ return proxy;
1129
+ }
1130
+
1131
+ //#endregion
1132
+ //#region src/variable.ts
1133
+ /**
1134
+ * 跟踪每个 variable 的唯一 Symbol ID
1135
+ */
1136
+ const variableIds = /* @__PURE__ */ new WeakMap();
1137
+ /**
1138
+ * 计数器用于生成唯一变量 ID
1139
+ */
1140
+ let variableCounter = 0;
1141
+ /**
1142
+ * 创建一个类型化变量
1143
+ * 返回 Proxy 对象,支持链式属性访问和方法调用
1144
+ *
1145
+ * @example
1146
+ * ```ts
1147
+ * const x = variable<number>();
1148
+ * const config = variable<{ timeout: number }>();
1149
+ * const timeout = config.timeout; // Proxy expression
1150
+ * ```
1151
+ */
1152
+ function variable() {
1153
+ const id = Symbol(`var_${variableCounter++}`);
1154
+ const proxy = createProxyVariable(id);
1155
+ variableIds.set(proxy, id);
1156
+ return proxy;
1157
+ }
1158
+ /**
1159
+ * 获取 variable 的唯一 Symbol ID
1160
+ */
1161
+ function getVariableId(variable) {
1162
+ if (typeof variable !== "object" && typeof variable !== "function" || variable === null) return void 0;
1163
+ return variableIds.get(variable);
1164
+ }
1165
+ /**
1166
+ * 生成变量占位符字符串
1167
+ * 格式:$$VAR_var_N$$
1168
+ */
1169
+ function getVariablePlaceholder(id) {
1170
+ return `$$VAR_${id.description}$$`;
583
1171
  }
584
1172
 
585
1173
  //#endregion
586
1174
  //#region src/compile.ts
1175
+ const ALLOWED_GLOBALS = new Set([
1176
+ "Math",
1177
+ "JSON",
1178
+ "Date",
1179
+ "RegExp",
1180
+ "Number",
1181
+ "String",
1182
+ "Boolean",
1183
+ "Array",
1184
+ "Object",
1185
+ "undefined",
1186
+ "NaN",
1187
+ "Infinity",
1188
+ "isNaN",
1189
+ "isFinite",
1190
+ "parseInt",
1191
+ "parseFloat",
1192
+ "BigInt",
1193
+ "URL",
1194
+ "URLSearchParams",
1195
+ "Map",
1196
+ "Set",
1197
+ "Int8Array",
1198
+ "Uint8Array",
1199
+ "Uint8ClampedArray",
1200
+ "Int16Array",
1201
+ "Uint16Array",
1202
+ "Int32Array",
1203
+ "Uint32Array",
1204
+ "Float32Array",
1205
+ "Float64Array",
1206
+ "BigInt64Array",
1207
+ "BigUint64Array",
1208
+ "ArrayBuffer",
1209
+ "DataView"
1210
+ ]);
587
1211
  /**
588
- * 将表达式树编译为可序列化的 JSON 结构
1212
+ * Proxy Expression 编译为可序列化的 JSON 结构
589
1213
  *
590
1214
  * @template TResult - 表达式结果类型
591
- * @param expression - 根表达式
1215
+ * @param expression - Proxy Expression,或包含 Proxy 的对象/数组/原始值
592
1216
  * @param variables - 所有使用的变量定义
593
1217
  * @param options - 编译选项
594
1218
  * @returns 编译后的数据结构 [变量名列表, 表达式1, 表达式2, ...]
595
1219
  *
596
- * @throws 如果检测到循环依赖或未定义的变量引用
1220
+ * @throws 如果传入无效的表达式或未定义的变量引用
597
1221
  *
598
1222
  * @example
599
1223
  * ```ts
600
- * const x = variable(z.number())
601
- * const y = variable(z.number())
602
- * const sum = expr({ x, y })<number>("x + y")
603
- * const result = expr({ sum })<number>("sum * 2")
1224
+ * const x = variable<number>()
1225
+ * const y = variable<number>()
1226
+ * const sum = expr({ x, y })("x + y")
1227
+ * const result = expr({ sum, x })("sum * x")
604
1228
  * const compiled = compile(result, { x, y })
605
- * // => [["x", "y"], "($0+$1)*2"] // 内联优化后
1229
+ * // => [["x", "y"], "($0+$1)*$0"]
606
1230
  * ```
607
1231
  */
608
1232
  function compile(expression, variables, options = {}) {
609
- const { inline = true, shortCircuit = true } = options;
610
- const context = {
611
- variableOrder: [],
612
- nodeToIndex: /* @__PURE__ */ new Map(),
613
- expressions: []
614
- };
615
- const exprIdMap = /* @__PURE__ */ new WeakMap();
616
- function getExprId(expr) {
617
- let id = exprIdMap.get(expr);
618
- if (id === void 0) {
619
- id = Symbol("expr");
620
- exprIdMap.set(expr, id);
621
- }
622
- return id;
1233
+ const { shortCircuit = true } = options;
1234
+ const ast = serializeArgumentToAST(expression);
1235
+ const variableOrder = [];
1236
+ const variableToIndex = /* @__PURE__ */ new Map();
1237
+ for (const name of Object.keys(variables)) if (!variableToIndex.has(name)) {
1238
+ variableToIndex.set(name, variableOrder.length);
1239
+ variableOrder.push(name);
623
1240
  }
624
- const nodeMap = /* @__PURE__ */ new Map();
625
- const variableNodes = /* @__PURE__ */ new Map();
626
- const visited = /* @__PURE__ */ new Set();
627
- const visiting = /* @__PURE__ */ new Set();
628
- for (const [name] of Object.entries(variables)) {
629
- const id = Symbol(`var:${name}`);
630
- const node = {
631
- id,
632
- tag: "variable"
633
- };
634
- nodeMap.set(id, node);
635
- variableNodes.set(name, node);
1241
+ const descToName = /* @__PURE__ */ new Map();
1242
+ for (const [name, value] of Object.entries(variables)) {
1243
+ const id = getVariableId(value);
1244
+ if (id && id.description) descToName.set(id.description, name);
636
1245
  }
637
- const exprNodes = /* @__PURE__ */ new Map();
638
- function collectNodes(expr) {
639
- const exprId = getExprId(expr);
640
- if (visited.has(exprId)) return nodeMap.get(exprId);
641
- if (visiting.has(exprId)) throw new Error("Circular dependency detected in expressions");
642
- visiting.add(exprId);
643
- const contextNodes = {};
644
- for (const [key, contextItem] of Object.entries(expr.context)) {
645
- const item = contextItem;
646
- if (item._tag === "variable") {
647
- const varNode = variableNodes.get(key);
648
- if (!varNode) throw new Error(`Undefined variable reference: ${key}`);
649
- contextNodes[key] = varNode;
650
- } else if (item._tag === "expression") contextNodes[key] = collectNodes(item);
1246
+ const undefinedVars = [];
1247
+ const transformed = transformIdentifiers(ast, (name) => {
1248
+ const placeholderMatch = name.match(/^\$\$VAR_(.+)\$\$$/);
1249
+ if (placeholderMatch) {
1250
+ const desc = placeholderMatch[1];
1251
+ const varName = descToName.get(desc);
1252
+ if (!varName) throw new Error(`Unknown variable placeholder: ${name}`);
1253
+ name = varName;
651
1254
  }
652
- const node = {
653
- id: exprId,
654
- tag: "expression",
655
- context: contextNodes,
656
- source: expr.source
657
- };
658
- nodeMap.set(exprId, node);
659
- exprNodes.set(exprId, node);
660
- visited.add(exprId);
661
- visiting.delete(exprId);
662
- return node;
663
- }
664
- const rootNode = collectNodes(expression);
665
- const sortedExprNodes = [];
666
- const exprVisited = /* @__PURE__ */ new Set();
667
- function topologicalSort(node) {
668
- if (exprVisited.has(node.id)) return;
669
- exprVisited.add(node.id);
670
- if (node.tag === "expression" && node.context) for (const contextNode of Object.values(node.context)) topologicalSort(contextNode);
671
- if (node.tag === "expression") sortedExprNodes.push(node);
672
- }
673
- topologicalSort(rootNode);
674
- for (const [name, varNode] of variableNodes.entries()) if (!context.nodeToIndex.has(varNode.id)) {
675
- context.nodeToIndex.set(varNode.id, context.variableOrder.length);
676
- context.variableOrder.push(name);
677
- }
678
- const refCount = /* @__PURE__ */ new Map();
679
- for (const exprNode of sortedExprNodes) refCount.set(exprNode.id, 0);
680
- for (const exprNode of sortedExprNodes) if (exprNode.context) {
681
- for (const contextNode of Object.values(exprNode.context)) if (contextNode.tag === "expression") refCount.set(contextNode.id, (refCount.get(contextNode.id) ?? 0) + 1);
682
- }
683
- function canInline(node) {
684
- if (!inline) return false;
685
- if (node.id === rootNode.id) return false;
686
- return (refCount.get(node.id) ?? 0) === 1;
687
- }
688
- let exprIndex = 0;
689
- for (const exprNode of sortedExprNodes) if (!canInline(exprNode)) {
690
- const index = context.variableOrder.length + exprIndex;
691
- context.nodeToIndex.set(exprNode.id, index);
692
- exprIndex++;
693
- }
694
- const nodeAstMap = /* @__PURE__ */ new Map();
695
- for (const [, varNode] of variableNodes.entries()) {
696
- const index = context.nodeToIndex.get(varNode.id);
697
- nodeAstMap.set(varNode.id, {
698
- type: "Identifier",
699
- name: `$${index}`
700
- });
701
- }
702
- for (const exprNode of sortedExprNodes) {
703
- if (!exprNode.context || !exprNode.source) throw new Error("Invalid expression node");
704
- const usedVariables = extractVariableNames(exprNode.source);
705
- for (const varName of usedVariables) if (!(varName in exprNode.context)) throw new Error(`Undefined variable reference: ${varName} (available: ${Object.keys(exprNode.context).join(", ")})`);
706
- const transformed = inlineTransform(parse(exprNode.source), (name) => {
707
- const contextNode = exprNode.context[name];
708
- if (!contextNode) return null;
709
- if (contextNode.tag === "variable") return nodeAstMap.get(contextNode.id) ?? null;
710
- else if (canInline(contextNode)) return nodeAstMap.get(contextNode.id) ?? null;
711
- else return {
712
- type: "Identifier",
713
- name: `$${context.nodeToIndex.get(contextNode.id)}`
714
- };
715
- });
716
- nodeAstMap.set(exprNode.id, transformed);
717
- }
1255
+ const index = variableToIndex.get(name);
1256
+ if (index !== void 0) return `$${index}`;
1257
+ if (!ALLOWED_GLOBALS.has(name)) undefinedVars.push(name);
1258
+ return name;
1259
+ });
1260
+ if (undefinedVars.length > 0) throw new Error(`Undefined variable(s): ${[...new Set(undefinedVars)].join(", ")}`);
1261
+ const expressions = [];
718
1262
  if (shortCircuit) {
719
- const expressions = [];
720
- let nextIndex = context.variableOrder.length;
721
- function compileAst(ast) {
722
- if (ast.type === "BinaryExpr" && (ast.operator === "||" || ast.operator === "&&" || ast.operator === "??")) return compileShortCircuit(ast);
723
- if (ast.type === "ConditionalExpr") return compileConditional(ast);
724
- const exprStr = generate(ast);
1263
+ let nextIndex = variableOrder.length;
1264
+ function compileAst(node) {
1265
+ if (node.type === "BinaryExpr" && (node.operator === "||" || node.operator === "&&" || node.operator === "??")) return compileShortCircuit(node);
1266
+ if (node.type === "ConditionalExpr") return compileConditional(node);
1267
+ const exprStr = generate(node);
725
1268
  const idx = nextIndex++;
726
1269
  expressions.push(exprStr);
727
1270
  return idx;
@@ -773,140 +1316,9 @@ function compile(expression, variables, options = {}) {
773
1316
  expressions.push(["phi"]);
774
1317
  return phiIdx;
775
1318
  }
776
- for (const exprNode of sortedExprNodes) if (!canInline(exprNode)) compileAst(nodeAstMap.get(exprNode.id));
777
- context.expressions = expressions;
778
- } else for (const exprNode of sortedExprNodes) if (!canInline(exprNode)) {
779
- const ast = nodeAstMap.get(exprNode.id);
780
- context.expressions.push(generate(ast));
781
- }
782
- return [context.variableOrder, ...context.expressions];
783
- }
784
- /**
785
- * 将 AST 中的标识符替换为对应的 AST 节点(用于内联优化)
786
- *
787
- * @param node - 要转换的 AST 节点
788
- * @param getReplacementAst - 根据标识符名称返回替换的 AST 节点,返回 null 表示不替换
789
- * @returns 转换后的 AST 节点
790
- */
791
- function inlineTransform(node, getReplacementAst) {
792
- switch (node.type) {
793
- case "Identifier": return getReplacementAst(node.name) ?? node;
794
- case "BinaryExpr": return {
795
- ...node,
796
- left: inlineTransform(node.left, getReplacementAst),
797
- right: inlineTransform(node.right, getReplacementAst)
798
- };
799
- case "UnaryExpr": return {
800
- ...node,
801
- argument: inlineTransform(node.argument, getReplacementAst)
802
- };
803
- case "ConditionalExpr": return {
804
- ...node,
805
- test: inlineTransform(node.test, getReplacementAst),
806
- consequent: inlineTransform(node.consequent, getReplacementAst),
807
- alternate: inlineTransform(node.alternate, getReplacementAst)
808
- };
809
- case "MemberExpr": return {
810
- ...node,
811
- object: inlineTransform(node.object, getReplacementAst),
812
- property: node.computed ? inlineTransform(node.property, getReplacementAst) : node.property
813
- };
814
- case "CallExpr": return {
815
- ...node,
816
- callee: inlineTransform(node.callee, getReplacementAst),
817
- arguments: node.arguments.map((arg) => inlineTransform(arg, getReplacementAst))
818
- };
819
- case "ArrayExpr": return {
820
- ...node,
821
- elements: node.elements.map((el) => inlineTransform(el, getReplacementAst))
822
- };
823
- case "ObjectExpr": return {
824
- ...node,
825
- properties: node.properties.map((prop) => ({
826
- ...prop,
827
- key: prop.computed ? inlineTransform(prop.key, getReplacementAst) : prop.key,
828
- value: inlineTransform(prop.value, getReplacementAst)
829
- }))
830
- };
831
- default: return node;
832
- }
833
- }
834
- /**
835
- * 允许在表达式中直接使用的全局对象
836
- * 这些对象不需要在上下文中定义
837
- */
838
- const ALLOWED_GLOBALS = new Set([
839
- "Math",
840
- "JSON",
841
- "Number",
842
- "String",
843
- "Boolean",
844
- "Array",
845
- "Object",
846
- "Date",
847
- "RegExp",
848
- "undefined",
849
- "NaN",
850
- "Infinity",
851
- "isNaN",
852
- "isFinite",
853
- "parseInt",
854
- "parseFloat"
855
- ]);
856
- /**
857
- * 从表达式源码中提取所有使用的变量名
858
- * 通过 AST 解析实现精确提取
859
- * 排除允许的全局对象
860
- *
861
- * @param source - 表达式源码字符串
862
- * @returns 使用的变量名列表(去重,不含全局对象)
863
- *
864
- * @example
865
- * ```ts
866
- * extractVariableNames("x + y * Math.PI")
867
- * // => ["x", "y"] // Math 被排除
868
- * ```
869
- */
870
- function extractVariableNames(source) {
871
- const identifiers = collectIdentifiers(parse(source));
872
- return Array.from(identifiers).filter((name) => !ALLOWED_GLOBALS.has(name));
873
- }
874
-
875
- //#endregion
876
- //#region src/constant.ts
877
- /**
878
- * 创建一个编译期常量表达式
879
- *
880
- * 这是 `expr({})(JSON.stringify(value))` 的快速路径,
881
- * 用于在表达式中嵌入静态值,避免在运行时传入或在多处重复编写。
882
- *
883
- * @template T - 常量值类型(必须是 JSON 可序列化的)
884
- * @param value - 要嵌入的常量值
885
- * @returns 返回一个 Expression 对象,其结果类型为 T
886
- *
887
- * @example
888
- * ```ts
889
- * // 创建一个数字常量
890
- * const PI = constant(3.14159)
891
- *
892
- * // 创建一个字符串常量
893
- * const greeting = constant("Hello, World!")
894
- *
895
- * // 创建一个对象常量
896
- * const config = constant({ maxRetries: 3, timeout: 5000 })
897
- *
898
- * // 在表达式中使用常量
899
- * const radius = variable(z.number())
900
- * const area = expr({ PI, radius })("PI * radius * radius")
901
- * ```
902
- */
903
- function constant(value) {
904
- return {
905
- _tag: "expression",
906
- context: {},
907
- source: JSON.stringify(value),
908
- _type: void 0
909
- };
1319
+ compileAst(transformed);
1320
+ } else expressions.push(generate(transformed));
1321
+ return [variableOrder, ...expressions];
910
1322
  }
911
1323
 
912
1324
  //#endregion
@@ -1035,11 +1447,12 @@ function buildEvaluatorFunctionBodyV2(expressions, variableCount) {
1035
1447
  //#endregion
1036
1448
  //#region src/expr.ts
1037
1449
  /**
1038
- * 创建一个表达式,支持编译时类型检查和返回类型自动推导
1450
+ * 创建表达式
1451
+ * 返回 Proxy Expression,可以继续链式调用
1039
1452
  *
1040
- * @template TContext - 表达式上下文类型(Variable 或 Expression 的映射)
1041
- * @param context - 包含 Variable 或 Expression 的上下文对象
1042
- * @returns 返回一个函数,该函数接收表达式源码字符串并返回 Expression 对象
1453
+ * @template TContext - 表达式上下文类型
1454
+ * @param context - 包含 Variable 或 Proxy Expression 的上下文对象
1455
+ * @returns 返回一个函数,该函数接收表达式源码字符串并返回 Proxy Expression
1043
1456
  *
1044
1457
  * 类型系统会:
1045
1458
  * 1. 验证表达式中使用的所有标识符都在 context 中定义
@@ -1047,8 +1460,8 @@ function buildEvaluatorFunctionBodyV2(expressions, variableCount) {
1047
1460
  *
1048
1461
  * @example
1049
1462
  * ```ts
1050
- * const x = variable(z.number())
1051
- * const y = variable(z.number())
1463
+ * const x = variable<number>();
1464
+ * const y = variable<number>();
1052
1465
  *
1053
1466
  * // 自动推导返回类型为 number
1054
1467
  * const sum = expr({ x, y })("x + y")
@@ -1062,40 +1475,177 @@ function buildEvaluatorFunctionBodyV2(expressions, variableCount) {
1062
1475
  */
1063
1476
  function expr(context) {
1064
1477
  return (source) => {
1065
- return {
1066
- _tag: "expression",
1067
- context,
1068
- source,
1069
- _type: void 0
1070
- };
1478
+ const deps = /* @__PURE__ */ new Set();
1479
+ const nameToId = /* @__PURE__ */ new Map();
1480
+ for (const [name, value] of Object.entries(context)) {
1481
+ let id = getVariableId(value);
1482
+ if (!id && (typeof value === "object" || typeof value === "function") && value !== null) {
1483
+ const meta = getProxyMetadata(value);
1484
+ if (meta?.type === "variable" && meta.rootVariable) id = meta.rootVariable;
1485
+ }
1486
+ if (id) {
1487
+ deps.add(id);
1488
+ nameToId.set(name, id);
1489
+ } else {
1490
+ const meta = (typeof value === "object" || typeof value === "function") && value !== null ? getProxyMetadata(value) : void 0;
1491
+ if (meta?.dependencies) for (const dep of meta.dependencies) deps.add(dep);
1492
+ }
1493
+ }
1494
+ const nameToExprAST = /* @__PURE__ */ new Map();
1495
+ for (const [name, value] of Object.entries(context)) if ((typeof value === "object" || typeof value === "function") && value !== null) {
1496
+ if (nameToId.has(name)) continue;
1497
+ const meta = getProxyMetadata(value);
1498
+ if (meta?.ast) nameToExprAST.set(name, meta.ast);
1499
+ }
1500
+ return createProxyExpressionWithAST(transformIdentifiers(parse(source), (name) => {
1501
+ const id = nameToId.get(name);
1502
+ if (id) return getVariablePlaceholder(id);
1503
+ const exprAST = nameToExprAST.get(name);
1504
+ if (exprAST) return exprAST;
1505
+ return name;
1506
+ }), deps);
1071
1507
  };
1072
1508
  }
1073
1509
 
1074
1510
  //#endregion
1075
- //#region src/variable.ts
1511
+ //#region src/lambda.ts
1076
1512
  /**
1077
- * 创建一个类型化变量
1513
+ * Lambda 参数计数器,用于生成唯一 ID
1514
+ */
1515
+ let lambdaParamCounter = 0;
1516
+ /**
1517
+ * Lambda 参数到索引的映射
1518
+ * 用于编译时确定参数位置
1519
+ */
1520
+ const lambdaParamIndices = /* @__PURE__ */ new WeakMap();
1521
+ /**
1522
+ * 创建 lambda 参数代理
1523
+ * 生成带特殊标记的 Proxy,用于在表达式中追踪参数
1524
+ *
1525
+ * @param index - 参数索引(0, 1, 2...)
1526
+ * @returns Lambda 参数代理
1527
+ */
1528
+ function createLambdaParam(index) {
1529
+ const proxy = createProxyVariable(Symbol(`lambda_param_${lambdaParamCounter++}_${index}`));
1530
+ lambdaParamIndices.set(proxy, index);
1531
+ return proxy;
1532
+ }
1533
+ /**
1534
+ * 创建类型安全的 lambda 表达式
1078
1535
  *
1079
- * @template T - 变量的值类型
1080
- * @returns 返回 Variable 对象,包含 _tag 标记
1536
+ * @template Args - 参数类型元组
1537
+ * @template R - 返回值类型
1538
+ * @param builder - Lambda 构建函数,接收参数代理,返回函数体表达式
1539
+ * @returns Lambda 表达式代理
1081
1540
  *
1082
1541
  * @example
1083
1542
  * ```ts
1084
- * const x = variable<number>()
1085
- * const name = variable<string>()
1086
- * const config = variable<{
1087
- * count: number,
1088
- * enabled: boolean
1089
- * }>()
1543
+ * const add = lambda<[number, number], number>(
1544
+ * (a, b) => expr({ a, b })("a + b")
1545
+ * );
1546
+ *
1547
+ * const numbers = variable<number[]>();
1548
+ * const sum = numbers.reduce(add, 0);
1090
1549
  * ```
1091
1550
  */
1092
- function variable() {
1093
- return {
1094
- _tag: "variable",
1095
- _type: void 0
1551
+ function lambda(builder) {
1552
+ const paramCount = builder.length;
1553
+ const params = [];
1554
+ const paramSymbols = [];
1555
+ for (let i = 0; i < paramCount; i++) {
1556
+ const param = createLambdaParam(i);
1557
+ params.push(param);
1558
+ const meta = getProxyMetadata(param);
1559
+ if (meta?.rootVariable) paramSymbols.push(meta.rootVariable);
1560
+ }
1561
+ const bodyExpr = builder(...params);
1562
+ let bodyAst;
1563
+ let bodyDeps;
1564
+ const meta = (typeof bodyExpr === "object" || typeof bodyExpr === "function") && bodyExpr !== null ? getProxyMetadata(bodyExpr) : void 0;
1565
+ if (meta?.ast) {
1566
+ bodyAst = meta.ast;
1567
+ bodyDeps = meta.dependencies ?? /* @__PURE__ */ new Set();
1568
+ } else {
1569
+ bodyAst = serializeArgumentToAST(bodyExpr);
1570
+ bodyDeps = /* @__PURE__ */ new Set();
1571
+ collectDepsFromArgs([bodyExpr], bodyDeps);
1572
+ }
1573
+ const transformedBodyAst = transformIdentifiers(bodyAst, (name) => {
1574
+ for (let i = 0; i < paramSymbols.length; i++) {
1575
+ const sym = paramSymbols[i];
1576
+ if (!sym) continue;
1577
+ if (name === `$$VAR_${sym.description}$$`) return `_${i}`;
1578
+ }
1579
+ return name;
1580
+ });
1581
+ const arrowFunctionAst = {
1582
+ type: "ArrowFunctionExpr",
1583
+ params: params.map((_, i) => ({
1584
+ type: "Identifier",
1585
+ name: `_${i}`
1586
+ })),
1587
+ body: transformedBodyAst
1588
+ };
1589
+ const closureDeps = /* @__PURE__ */ new Set();
1590
+ for (const dep of bodyDeps) if (!paramSymbols.includes(dep)) closureDeps.add(dep);
1591
+ const lambdaProxy = createProxyExpressionWithAST(arrowFunctionAst, closureDeps);
1592
+ const existingMeta = getProxyMetadata(lambdaProxy);
1593
+ if (existingMeta) setProxyMetadata(lambdaProxy, {
1594
+ ...existingMeta,
1595
+ type: "expression"
1596
+ });
1597
+ return lambdaProxy;
1598
+ }
1599
+
1600
+ //#endregion
1601
+ //#region src/template.ts
1602
+ /**
1603
+ * Tagged template 函数,用于创建包含变量的字符串表达式
1604
+ *
1605
+ * @example
1606
+ * ```ts
1607
+ * const name = variable<string>();
1608
+ * const count = variable<number>();
1609
+ *
1610
+ * const greeting = t`Hello, ${name}!`;
1611
+ * const message = t`You have ${count} items.`;
1612
+ *
1613
+ * const compiled = compile(greeting, { name });
1614
+ * const result = evaluate(compiled, { name: "Alice" }); // => "Hello, Alice!"
1615
+ * ```
1616
+ */
1617
+ function t(strings, ...values) {
1618
+ const deps = /* @__PURE__ */ new Set();
1619
+ collectDepsFromArgs(values, deps);
1620
+ const parts = [];
1621
+ for (let i = 0; i < strings.length; i++) {
1622
+ const str = strings[i];
1623
+ if (str.length > 0) parts.push({
1624
+ type: "StringLiteral",
1625
+ value: str,
1626
+ quote: "\""
1627
+ });
1628
+ if (i < values.length) {
1629
+ const ast = serializeArgumentToAST(values[i]);
1630
+ parts.push(ast);
1631
+ }
1632
+ }
1633
+ if (parts.length === 0) return createProxyExpressionWithAST({
1634
+ type: "StringLiteral",
1635
+ value: "",
1636
+ quote: "\""
1637
+ }, deps);
1638
+ if (parts.length === 1) return createProxyExpressionWithAST(parts[0], deps);
1639
+ let resultAst = parts[0];
1640
+ for (let i = 1; i < parts.length; i++) resultAst = {
1641
+ type: "BinaryExpr",
1642
+ operator: "+",
1643
+ left: resultAst,
1644
+ right: parts[i]
1096
1645
  };
1646
+ return createProxyExpressionWithAST(resultAst, deps);
1097
1647
  }
1098
1648
 
1099
1649
  //#endregion
1100
- export { compile, constant, evaluate, expr, variable };
1650
+ export { compile, evaluate, expr, getVariableId, isProxy, isProxyExpression, isProxyVariable, lambda, t, variable };
1101
1651
  //# sourceMappingURL=index.mjs.map