@codehz/json-expr 0.5.1 → 0.5.2

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
@@ -27,6 +27,27 @@ const PRECEDENCE = {
27
27
  "**": 11
28
28
  };
29
29
  const RIGHT_ASSOCIATIVE = new Set(["**"]);
30
+ const BUILTIN_CONSTRUCTORS = new Set([
31
+ "Date",
32
+ "RegExp",
33
+ "URL",
34
+ "URLSearchParams",
35
+ "Map",
36
+ "Set",
37
+ "Int8Array",
38
+ "Uint8Array",
39
+ "Uint8ClampedArray",
40
+ "Int16Array",
41
+ "Uint16Array",
42
+ "Int32Array",
43
+ "Uint32Array",
44
+ "Float32Array",
45
+ "Float64Array",
46
+ "BigInt64Array",
47
+ "BigUint64Array",
48
+ "ArrayBuffer",
49
+ "DataView"
50
+ ]);
30
51
  var Parser = class Parser {
31
52
  pos = 0;
32
53
  source;
@@ -546,41 +567,16 @@ function generate(node) {
546
567
  return `${node.operator}${arg}`;
547
568
  }
548
569
  return generate(node.argument) + node.operator;
549
- case "ConditionalExpr": return `${generate(node.test)}?${generate(node.consequent)}:${generate(node.alternate)}`;
570
+ case "ConditionalExpr": return `${wrapIfNeeded(node.test, node, "test")}?${wrapIfNeeded(node.consequent, node, "consequent")}:${wrapIfNeeded(node.alternate, node, "alternate")}`;
550
571
  case "MemberExpr": {
551
572
  const object = wrapIfNeeded(node.object, node, "object");
552
- if (node.computed) {
553
- const property = generate(node.property);
554
- return node.optional ? `${object}?.[${property}]` : `${object}[${property}]`;
555
- }
556
573
  const property = generate(node.property);
557
- return node.optional ? `${object}?.${property}` : `${object}.${property}`;
574
+ return node.computed ? `${object}${node.optional ? "?." : ""}[${property}]` : `${object}${node.optional ? "?." : "."}${property}`;
558
575
  }
559
576
  case "CallExpr": {
560
577
  const callee = wrapIfNeeded(node.callee, node, "callee");
561
578
  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})`;
583
- return node.optional ? `${callee}?.(${args})` : `${callee}(${args})`;
579
+ return `${node.callee.type === "Identifier" && BUILTIN_CONSTRUCTORS.has(node.callee.name) ? "new " : ""}${callee}${node.optional ? "?." : ""}(${args})`;
584
580
  }
585
581
  case "ArrayExpr": return `[${node.elements.map(generate).join(",")}]`;
586
582
  case "ObjectExpr": return `{${node.properties.map((prop) => {
@@ -589,10 +585,8 @@ function generate(node) {
589
585
  }).join(",")}}`;
590
586
  case "ArrowFunctionExpr": {
591
587
  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}`;
588
+ const body = node.body.type === "ObjectExpr" ? `(${generate(node.body)})` : generate(node.body);
589
+ return `${node.params.length === 1 ? params : `(${params})`}=>${body}`;
596
590
  }
597
591
  default: {
598
592
  const nodeType = node.type ?? "unknown";
@@ -612,21 +606,32 @@ function wrapIfNeeded(child, parent, position) {
612
606
  * 判断子节点是否需要括号
613
607
  */
614
608
  function needsParens(child, parent, position) {
615
- if (child.type === "ConditionalExpr" && parent.type === "BinaryExpr") return true;
616
- if (child.type === "BinaryExpr" && parent.type === "BinaryExpr") {
617
- const childPrec = PRECEDENCE[child.operator] || 0;
618
- const parentPrec = PRECEDENCE[parent.operator] || 0;
619
- if (childPrec < parentPrec) return true;
620
- if (childPrec === parentPrec && position === "right") {
621
- if (!RIGHT_ASSOCIATIVE.has(parent.operator)) return true;
622
- }
623
- }
624
- if ((child.type === "BinaryExpr" || child.type === "ConditionalExpr") && parent.type === "UnaryExpr" && position === "argument") return true;
625
- if (child.type === "UnaryExpr" && parent.type === "BinaryExpr") {
626
- if (parent.operator === "**" && position === "left") return true;
627
- return true;
609
+ switch (parent.type) {
610
+ case "BinaryExpr":
611
+ if (child.type === "ConditionalExpr" || child.type === "UnaryExpr") return true;
612
+ if (child.type === "BinaryExpr") {
613
+ const childPrec = PRECEDENCE[child.operator] ?? 0;
614
+ const parentPrec = PRECEDENCE[parent.operator] ?? 0;
615
+ if (childPrec < parentPrec) return true;
616
+ if (childPrec === parentPrec && position === "right" && !RIGHT_ASSOCIATIVE.has(parent.operator)) return true;
617
+ }
618
+ return false;
619
+ case "UnaryExpr": return position === "argument" && (child.type === "BinaryExpr" || child.type === "ConditionalExpr");
620
+ case "MemberExpr":
621
+ case "CallExpr":
622
+ if (position !== "object" && position !== "callee") return false;
623
+ if ([
624
+ "BinaryExpr",
625
+ "ConditionalExpr",
626
+ "UnaryExpr",
627
+ "ArrowFunctionExpr",
628
+ "ObjectExpr"
629
+ ].includes(child.type)) return true;
630
+ if (child.type === "NumberLiteral" && parent.type === "MemberExpr" && !parent.computed) return !child.raw.includes(".") && !child.raw.includes("e") && !child.raw.includes("x");
631
+ return false;
632
+ case "ConditionalExpr": return position === "test" && child.type === "ConditionalExpr";
633
+ default: return false;
628
634
  }
629
- return false;
630
635
  }
631
636
  /**
632
637
  * 转换 AST 中的标识符
@@ -733,6 +738,19 @@ function isProxy(obj) {
733
738
 
734
739
  //#endregion
735
740
  //#region src/proxy-variable.ts
741
+ const typedArrayConstructors = [
742
+ "Int8Array",
743
+ "Uint8Array",
744
+ "Uint8ClampedArray",
745
+ "Int16Array",
746
+ "Uint16Array",
747
+ "Int32Array",
748
+ "Uint32Array",
749
+ "Float32Array",
750
+ "Float64Array",
751
+ "BigInt64Array",
752
+ "BigUint64Array"
753
+ ];
736
754
  /**
737
755
  * 使用 Symbol.description 生成占位符
738
756
  * 用于在表达式源码中标识变量
@@ -741,6 +759,77 @@ function getVariablePlaceholder$1(id) {
741
759
  return `$$VAR_${id.description}$$`;
742
760
  }
743
761
  /**
762
+ * 创建标识符 AST 节点
763
+ */
764
+ function identifier(name) {
765
+ return {
766
+ type: "Identifier",
767
+ name
768
+ };
769
+ }
770
+ /**
771
+ * 创建数字字面量 AST 节点
772
+ */
773
+ function numberLiteral(value) {
774
+ return {
775
+ type: "NumberLiteral",
776
+ value,
777
+ raw: String(value)
778
+ };
779
+ }
780
+ /**
781
+ * 创建字符串字面量 AST 节点
782
+ */
783
+ function stringLiteral(value, quote = "\"") {
784
+ return {
785
+ type: "StringLiteral",
786
+ value,
787
+ quote
788
+ };
789
+ }
790
+ /**
791
+ * 创建成员表达式 AST 节点
792
+ */
793
+ function memberExpr(object, property) {
794
+ return {
795
+ type: "MemberExpr",
796
+ object,
797
+ property,
798
+ computed: false,
799
+ optional: false
800
+ };
801
+ }
802
+ /**
803
+ * 创建调用表达式 AST 节点
804
+ */
805
+ function callExpr(callee, arguments_) {
806
+ return {
807
+ type: "CallExpr",
808
+ callee,
809
+ arguments: arguments_,
810
+ optional: false
811
+ };
812
+ }
813
+ /**
814
+ * 创建数组表达式 AST 节点
815
+ */
816
+ function arrayExpr(elements) {
817
+ return {
818
+ type: "ArrayExpr",
819
+ elements
820
+ };
821
+ }
822
+ /**
823
+ * 检查对象是否为 TypedArray 实例
824
+ */
825
+ function getTypedArrayConstructor(value) {
826
+ for (const constructorName of typedArrayConstructors) {
827
+ const Constructor = globalThis[constructorName];
828
+ if (Constructor && value instanceof Constructor) return Constructor;
829
+ }
830
+ return null;
831
+ }
832
+ /**
744
833
  * 序列化参数为 AST 节点
745
834
  * - Proxy Variable/Expression:使用 ast 或占位符标识符
746
835
  * - 数组:返回 ArrayExpr 节点
@@ -753,245 +842,70 @@ function serializeArgumentToAST(arg) {
753
842
  const meta = getProxyMetadata(arg);
754
843
  if (meta) {
755
844
  if (meta.ast) return meta.ast;
756
- if (meta.rootVariable) return {
757
- type: "Identifier",
758
- name: getVariablePlaceholder$1(meta.rootVariable)
759
- };
845
+ if (meta.rootVariable) return identifier(getVariablePlaceholder$1(meta.rootVariable));
760
846
  }
761
847
  }
762
- if (Array.isArray(arg)) return {
763
- type: "ArrayExpr",
764
- elements: arg.map(serializeArgumentToAST)
765
- };
848
+ if (Array.isArray(arg)) return arrayExpr(arg.map(serializeArgumentToAST));
766
849
  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
- };
850
+ if (arg instanceof Date) return callExpr(identifier("Date"), [numberLiteral(arg.getTime())]);
780
851
  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
- };
852
+ const args = [stringLiteral(arg.source)];
853
+ if (arg.flags) args.push(stringLiteral(arg.flags));
854
+ return callExpr(identifier("RegExp"), args);
800
855
  }
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
- };
856
+ if (typeof URL !== "undefined" && arg instanceof URL) return callExpr(identifier("URL"), [stringLiteral(arg.href)]);
814
857
  if (typeof URLSearchParams !== "undefined" && arg instanceof URLSearchParams) {
815
858
  const entries = [];
816
859
  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
- }]
828
- });
860
+ entries.push(arrayExpr([stringLiteral(key), stringLiteral(value)]));
829
861
  });
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
- };
862
+ return callExpr(identifier("URLSearchParams"), [arrayExpr(entries)]);
842
863
  }
843
864
  if (arg instanceof Map) {
844
865
  const entries = [];
845
866
  arg.forEach((value, key) => {
846
- entries.push({
847
- type: "ArrayExpr",
848
- elements: [serializeArgumentToAST(key), serializeArgumentToAST(value)]
849
- });
867
+ entries.push(arrayExpr([serializeArgumentToAST(key), serializeArgumentToAST(value)]));
850
868
  });
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
- };
869
+ return callExpr(identifier("Map"), [arrayExpr(entries)]);
863
870
  }
864
871
  if (arg instanceof Set) {
865
872
  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
- };
873
+ arg.forEach((value) => values.push(serializeArgumentToAST(value)));
874
+ return callExpr(identifier("Set"), [arrayExpr(values)]);
881
875
  }
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
- }
876
+ const typedArrayConstructor = getTypedArrayConstructor(arg);
877
+ if (typedArrayConstructor) {
878
+ const values = [...arg].map(serializeArgumentToAST);
879
+ const constructorName = typedArrayConstructor.name;
880
+ return callExpr(identifier(constructorName), [arrayExpr(values)]);
910
881
  }
911
882
  if (arg instanceof ArrayBuffer) {
912
883
  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
- };
884
+ const values = Array.from(uint8Array).map(numberLiteral);
885
+ return memberExpr(callExpr(identifier("Uint8Array"), [arrayExpr(values)]), identifier("buffer"));
934
886
  }
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
887
+ if (arg instanceof DataView) return callExpr(identifier("DataView"), [serializeArgumentToAST(arg.buffer)]);
888
+ return {
889
+ type: "ObjectExpr",
890
+ properties: Object.entries(arg).map(([k, v]) => {
891
+ return {
892
+ key: /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k) ? identifier(k) : stringLiteral(k),
893
+ value: serializeArgumentToAST(v),
894
+ computed: false,
895
+ shorthand: false
896
+ };
897
+ })
943
898
  };
944
899
  }
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
900
  if (arg === null) return { type: "NullLiteral" };
964
- if (arg === void 0) return {
965
- type: "Identifier",
966
- name: "undefined"
967
- };
901
+ if (arg === void 0) return identifier("undefined");
968
902
  if (typeof arg === "boolean") return {
969
903
  type: "BooleanLiteral",
970
904
  value: arg
971
905
  };
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
- };
906
+ if (typeof arg === "number") return numberLiteral(arg);
907
+ if (typeof arg === "string") return stringLiteral(arg);
908
+ if (typeof arg === "bigint") return callExpr(identifier("BigInt"), [stringLiteral(arg.toString())]);
995
909
  throw new Error(`Unsupported argument type: ${typeof arg}`);
996
910
  }
997
911
  /**
@@ -1007,6 +921,31 @@ function collectDepsFromArgs(args, deps) {
1007
921
  }
1008
922
  }
1009
923
  /**
924
+ * 根据路径构建成员表达式 AST
925
+ */
926
+ function buildMemberExprAst(rootId, path) {
927
+ let ast = identifier(getVariablePlaceholder$1(rootId));
928
+ for (const prop of path) ast = memberExpr(ast, identifier(prop));
929
+ return ast;
930
+ }
931
+ /**
932
+ * 创建 Proxy 的公共 handler
933
+ */
934
+ function createProxyHandler(ast, deps) {
935
+ return {
936
+ get(_target, prop) {
937
+ if (typeof prop === "symbol") return void 0;
938
+ return createProxyExpressionWithAST(memberExpr(ast, identifier(String(prop))), deps);
939
+ },
940
+ apply(_target, _thisArg, args) {
941
+ const callAst = callExpr(ast, args.map(serializeArgumentToAST));
942
+ const newDeps = new Set(deps);
943
+ collectDepsFromArgs(args, newDeps);
944
+ return createProxyExpressionWithAST(callAst, newDeps);
945
+ }
946
+ };
947
+ }
948
+ /**
1010
949
  * 创建根 Variable Proxy
1011
950
  * 拦截属性访问,返回新的 expression proxy
1012
951
  * 不可直接调用(apply 应该只在链式调用后可用)
@@ -1019,7 +958,7 @@ function createProxyVariable(id) {
1019
958
  const proxy = new Proxy(function() {}, {
1020
959
  get(_target, prop) {
1021
960
  if (typeof prop === "symbol") return void 0;
1022
- return createProxyExpression(id, [String(prop)], deps);
961
+ return createProxyExpressionWithAST(buildMemberExprAst(id, [String(prop)]), deps);
1023
962
  },
1024
963
  apply() {
1025
964
  throw new Error("Variable cannot be called directly");
@@ -1034,57 +973,6 @@ function createProxyVariable(id) {
1034
973
  return proxy;
1035
974
  }
1036
975
  /**
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
976
  * 创建带完整 AST 的 Proxy(方法调用后)
1089
977
  * 可以继续链式访问和调用
1090
978
  *
@@ -1093,32 +981,7 @@ function createProxyExpression(rootId, path, deps) {
1093
981
  * @returns Proxy 包装的 Expression
1094
982
  */
1095
983
  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
- });
984
+ const proxy = new Proxy(function() {}, createProxyHandler(ast, deps));
1122
985
  setProxyMetadata(proxy, {
1123
986
  type: "expression",
1124
987
  path: [],
@@ -1234,30 +1097,29 @@ function compile(expression, variables, options = {}) {
1234
1097
  const ast = serializeArgumentToAST(expression);
1235
1098
  const variableOrder = [];
1236
1099
  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);
1240
- }
1241
1100
  const descToName = /* @__PURE__ */ new Map();
1242
1101
  for (const [name, value] of Object.entries(variables)) {
1102
+ if (!variableToIndex.has(name)) {
1103
+ variableToIndex.set(name, variableOrder.length);
1104
+ variableOrder.push(name);
1105
+ }
1243
1106
  const id = getVariableId(value);
1244
- if (id && id.description) descToName.set(id.description, name);
1107
+ if (id?.description) descToName.set(id.description, name);
1245
1108
  }
1246
1109
  const undefinedVars = [];
1247
1110
  const transformed = transformIdentifiers(ast, (name) => {
1248
1111
  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;
1254
- }
1255
- const index = variableToIndex.get(name);
1112
+ const resolvedName = placeholderMatch ? descToName.get(placeholderMatch[1]) : name;
1113
+ if (placeholderMatch && !resolvedName) throw new Error(`Unknown variable placeholder: ${name}`);
1114
+ const index = variableToIndex.get(resolvedName);
1256
1115
  if (index !== void 0) return `$${index}`;
1257
- if (!ALLOWED_GLOBALS.has(name)) undefinedVars.push(name);
1258
- return name;
1116
+ if (!ALLOWED_GLOBALS.has(resolvedName)) undefinedVars.push(resolvedName);
1117
+ return resolvedName;
1259
1118
  });
1260
- if (undefinedVars.length > 0) throw new Error(`Undefined variable(s): ${[...new Set(undefinedVars)].join(", ")}`);
1119
+ if (undefinedVars.length > 0) {
1120
+ const uniqueVars = [...new Set(undefinedVars)];
1121
+ throw new Error(`Undefined variable(s): ${uniqueVars.join(", ")}`);
1122
+ }
1261
1123
  const expressions = [];
1262
1124
  if (shortCircuit) {
1263
1125
  let nextIndex = variableOrder.length;
@@ -1265,26 +1127,20 @@ function compile(expression, variables, options = {}) {
1265
1127
  if (node.type === "BinaryExpr" && (node.operator === "||" || node.operator === "&&" || node.operator === "??")) return compileShortCircuit(node);
1266
1128
  if (node.type === "ConditionalExpr") return compileConditional(node);
1267
1129
  const exprStr = generate(node);
1268
- const idx = nextIndex++;
1269
1130
  expressions.push(exprStr);
1270
- return idx;
1131
+ return nextIndex++;
1271
1132
  }
1272
1133
  function compileShortCircuit(node) {
1273
1134
  const leftIdx = compileAst(node.left);
1274
- let branchCondition;
1275
- switch (node.operator) {
1276
- case "||":
1277
- branchCondition = `$${leftIdx}`;
1278
- break;
1279
- case "&&":
1280
- branchCondition = `!$${leftIdx}`;
1281
- break;
1282
- default: branchCondition = `$${leftIdx}!=null`;
1283
- }
1135
+ const branchConditions = {
1136
+ "||": `$${leftIdx}`,
1137
+ "&&": `!$${leftIdx}`,
1138
+ "??": `$${leftIdx}!=null`
1139
+ };
1284
1140
  const branchIdx = expressions.length;
1285
1141
  expressions.push([
1286
1142
  "br",
1287
- branchCondition,
1143
+ branchConditions[node.operator],
1288
1144
  0
1289
1145
  ]);
1290
1146
  nextIndex++;
@@ -1388,16 +1244,14 @@ function evaluate(data, values) {
1388
1244
  */
1389
1245
  function buildEvaluatorFunctionBody(expressions, variableCount) {
1390
1246
  if (expressions.length === 0) throw new Error("No expressions to evaluate");
1391
- const lines = [];
1392
- for (let i = 0; i < variableCount; i++) lines.push(`const $${i} = $values[${i}];`);
1393
- for (let i = 0; i < expressions.length; i++) {
1394
- const exprSource = expressions[i];
1395
- const resultIndex = variableCount + i;
1396
- lines.push(`const $${resultIndex} = ${exprSource};`);
1397
- lines.push(`$values[${resultIndex}] = $${resultIndex};`);
1398
- }
1399
- lines.push(`return $values[$values.length - 1];`);
1400
- return lines.join("\n");
1247
+ return [
1248
+ ...Array.from({ length: variableCount }, (_, i) => `const $${i} = $values[${i}];`),
1249
+ ...expressions.map((expr, i) => {
1250
+ const idx = variableCount + i;
1251
+ return `const $${idx} = ${expr}; $values[${idx}] = $${idx};`;
1252
+ }),
1253
+ `return $values[$values.length - 1];`
1254
+ ].join("\n");
1401
1255
  }
1402
1256
  /**
1403
1257
  * 构造带控制流支持的求值函数体(V2 格式)
@@ -1408,39 +1262,38 @@ function buildEvaluatorFunctionBody(expressions, variableCount) {
1408
1262
  */
1409
1263
  function buildEvaluatorFunctionBodyV2(expressions, variableCount) {
1410
1264
  if (expressions.length === 0) throw new Error("No expressions to evaluate");
1411
- const lines = [];
1412
- for (let i = 0; i < variableCount; i++) lines.push(`const $${i} = $values[${i}];`);
1413
- lines.push(`let $pc = 0;`);
1414
- lines.push(`let $lastValue;`);
1415
- for (let i = 0; i < expressions.length; i++) lines.push(`let $${variableCount + i};`);
1416
- lines.push(`while ($pc < ${expressions.length}) {`);
1417
- lines.push(` switch ($pc) {`);
1418
- for (let i = 0; i < expressions.length; i++) {
1419
- const expr = expressions[i];
1265
+ const lines = [
1266
+ ...Array.from({ length: variableCount }, (_, i) => `const $${i} = $values[${i}];`),
1267
+ "let $pc = 0;",
1268
+ "let $lastValue;",
1269
+ ...expressions.map((_, i) => `let $${variableCount + i};`),
1270
+ `while ($pc < ${expressions.length}) {`,
1271
+ " switch ($pc) {"
1272
+ ];
1273
+ expressions.forEach((expr, i) => {
1420
1274
  const idx = variableCount + i;
1421
1275
  lines.push(` case ${i}: {`);
1422
1276
  if (typeof expr === "string") {
1423
- lines.push(` $${idx} = ${expr};`);
1277
+ lines.push(` $${idx} = $lastValue = ${expr};`);
1424
1278
  lines.push(` $values[${idx}] = $${idx};`);
1425
- lines.push(` $lastValue = $${idx};`);
1426
- lines.push(` $pc++; break;`);
1427
- } else if (expr[0] === "br") {
1428
- const [, condExpr, offset] = expr;
1429
- lines.push(` if (${condExpr}) { $pc += ${offset + 1}; } else { $pc++; }`);
1430
- lines.push(` break;`);
1431
- } else if (expr[0] === "jmp") {
1432
- const [, offset] = expr;
1433
- lines.push(` $pc += ${offset + 1}; break;`);
1434
- } else if (expr[0] === "phi") {
1435
- lines.push(` $${idx} = $lastValue;`);
1436
- lines.push(` $values[${idx}] = $lastValue;`);
1437
- lines.push(` $pc++; break;`);
1279
+ lines.push(" $pc++; break;");
1280
+ } else {
1281
+ const [type] = expr;
1282
+ switch (type) {
1283
+ case "br":
1284
+ lines.push(` if (${expr[1]}) { $pc += ${expr[2] + 1}; } else { $pc++; } break;`);
1285
+ break;
1286
+ case "jmp":
1287
+ lines.push(` $pc += ${expr[1] + 1}; break;`);
1288
+ break;
1289
+ case "phi":
1290
+ lines.push(` $${idx} = $values[${idx}] = $lastValue; $pc++; break;`);
1291
+ break;
1292
+ }
1438
1293
  }
1439
- lines.push(` }`);
1440
- }
1441
- lines.push(` }`);
1442
- lines.push(`}`);
1443
- lines.push(`return $values[$values.length - 1];`);
1294
+ lines.push(" }");
1295
+ });
1296
+ lines.push(" }", "}", "return $values[$values.length - 1];");
1444
1297
  return lines.join("\n");
1445
1298
  }
1446
1299
 
@@ -1550,6 +1403,20 @@ function createLambdaParam(index) {
1550
1403
  */
1551
1404
  function lambda(builder) {
1552
1405
  const paramCount = builder.length;
1406
+ const { params, paramSymbols } = createLambdaParams(paramCount);
1407
+ const { bodyAst, bodyDeps } = extractBodyAstAndDeps(builder(...params));
1408
+ const lambdaProxy = createProxyExpressionWithAST(createArrowFunctionAst(transformParamPlaceholders(bodyAst, paramSymbols), paramCount), filterClosureDeps(bodyDeps, paramSymbols));
1409
+ const existingMeta = getProxyMetadata(lambdaProxy);
1410
+ if (existingMeta) setProxyMetadata(lambdaProxy, {
1411
+ ...existingMeta,
1412
+ type: "expression"
1413
+ });
1414
+ return lambdaProxy;
1415
+ }
1416
+ /**
1417
+ * 创建 lambda 参数和符号映射
1418
+ */
1419
+ function createLambdaParams(paramCount) {
1553
1420
  const params = [];
1554
1421
  const paramSymbols = [];
1555
1422
  for (let i = 0; i < paramCount; i++) {
@@ -1558,19 +1425,34 @@ function lambda(builder) {
1558
1425
  const meta = getProxyMetadata(param);
1559
1426
  if (meta?.rootVariable) paramSymbols.push(meta.rootVariable);
1560
1427
  }
1561
- const bodyExpr = builder(...params);
1562
- let bodyAst;
1563
- let bodyDeps;
1428
+ return {
1429
+ params,
1430
+ paramSymbols
1431
+ };
1432
+ }
1433
+ /**
1434
+ * 从表达式中提取 AST 和依赖
1435
+ */
1436
+ function extractBodyAstAndDeps(bodyExpr) {
1564
1437
  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();
1438
+ if (meta?.ast) return {
1439
+ bodyAst: meta.ast,
1440
+ bodyDeps: meta.dependencies ?? /* @__PURE__ */ new Set()
1441
+ };
1442
+ else {
1443
+ const bodyDeps = /* @__PURE__ */ new Set();
1571
1444
  collectDepsFromArgs([bodyExpr], bodyDeps);
1445
+ return {
1446
+ bodyAst: serializeArgumentToAST(bodyExpr),
1447
+ bodyDeps
1448
+ };
1572
1449
  }
1573
- const transformedBodyAst = transformIdentifiers(bodyAst, (name) => {
1450
+ }
1451
+ /**
1452
+ * 将参数占位符标识符转换为实际参数名
1453
+ */
1454
+ function transformParamPlaceholders(bodyAst, paramSymbols) {
1455
+ return transformIdentifiers(bodyAst, (name) => {
1574
1456
  for (let i = 0; i < paramSymbols.length; i++) {
1575
1457
  const sym = paramSymbols[i];
1576
1458
  if (!sym) continue;
@@ -1578,23 +1460,27 @@ function lambda(builder) {
1578
1460
  }
1579
1461
  return name;
1580
1462
  });
1581
- const arrowFunctionAst = {
1463
+ }
1464
+ /**
1465
+ * 创建箭头函数 AST
1466
+ */
1467
+ function createArrowFunctionAst(bodyAst, paramCount) {
1468
+ return {
1582
1469
  type: "ArrowFunctionExpr",
1583
- params: params.map((_, i) => ({
1470
+ params: Array.from({ length: paramCount }, (_, i) => ({
1584
1471
  type: "Identifier",
1585
1472
  name: `_${i}`
1586
1473
  })),
1587
- body: transformedBodyAst
1474
+ body: bodyAst
1588
1475
  };
1476
+ }
1477
+ /**
1478
+ * 过滤掉 lambda 参数依赖,只保留外部闭包变量
1479
+ */
1480
+ function filterClosureDeps(bodyDeps, paramSymbols) {
1589
1481
  const closureDeps = /* @__PURE__ */ new Set();
1590
1482
  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;
1483
+ return closureDeps;
1598
1484
  }
1599
1485
 
1600
1486
  //#endregion