@goplasmatic/datalogic-ui 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -21,172 +21,6 @@ let __tla = (async () => {
21
21
  error: "#F43F5E",
22
22
  literal: "#6B7280"
23
23
  };
24
- function isPlainObject(value) {
25
- return typeof value === "object" && value !== null && !Array.isArray(value);
26
- }
27
- function getValueType$1(value) {
28
- if (value === null) return "null";
29
- if (typeof value === "boolean") return "boolean";
30
- if (typeof value === "number") return "number";
31
- if (typeof value === "string") return "string";
32
- if (Array.isArray(value)) return "array";
33
- return "string";
34
- }
35
- function looksLikeDate(str) {
36
- const datePatterns = [
37
- /^\d{4}-\d{2}-\d{2}/,
38
- /^\d{2}\/\d{2}\/\d{4}/,
39
- /^\d{2}-\d{2}-\d{4}/
40
- ];
41
- return datePatterns.some((pattern) => pattern.test(str));
42
- }
43
- function isSimpleOperand(operand) {
44
- if (operand === null || typeof operand !== "object") {
45
- return true;
46
- }
47
- if (Array.isArray(operand)) {
48
- return operand.length === 0;
49
- }
50
- return false;
51
- }
52
- const COMPARISON_OPERATORS$1 = [
53
- "==",
54
- "===",
55
- "!=",
56
- "!==",
57
- ">",
58
- ">=",
59
- "<",
60
- "<="
61
- ];
62
- const ITERATOR_OPERATORS = [
63
- "map",
64
- "reduce",
65
- "filter",
66
- "some",
67
- "none",
68
- "all"
69
- ];
70
- const UNARY_OPERATORS$2 = [
71
- "!",
72
- "!!"
73
- ];
74
- const ARITHMETIC_BINARY_OPERATORS = [
75
- "+",
76
- "-",
77
- "*",
78
- "/",
79
- "%"
80
- ];
81
- function generateExpressionText(value, maxLength = 100) {
82
- function getOperator(val) {
83
- if (isPlainObject(val)) {
84
- const keys = Object.keys(val);
85
- if (keys.length === 1) return keys[0];
86
- }
87
- return null;
88
- }
89
- function needsParens(subVal, parentOp) {
90
- const subOp = getOperator(subVal);
91
- if (!subOp) return false;
92
- if (parentOp === "and" && subOp === "or" || parentOp === "or" && subOp === "and") {
93
- return true;
94
- }
95
- if (COMPARISON_OPERATORS$1.includes(parentOp) && (subOp === "and" || subOp === "or")) {
96
- return true;
97
- }
98
- if ((parentOp === "*" || parentOp === "/") && (subOp === "+" || subOp === "-")) {
99
- return true;
100
- }
101
- return false;
102
- }
103
- function toText(val, _parentOp) {
104
- if (val === null) return "null";
105
- if (typeof val === "boolean") return String(val);
106
- if (typeof val === "number") return String(val);
107
- if (typeof val === "string") return `"${val}"`;
108
- if (Array.isArray(val)) {
109
- if (val.length === 0) return "[]";
110
- const items = val.map((v) => toText(v)).join(", ");
111
- return `[${items}]`;
112
- }
113
- if (isPlainObject(val)) {
114
- const keys = Object.keys(val);
115
- if (keys.length !== 1) return JSON.stringify(val);
116
- const op = keys[0];
117
- const operands = val[op];
118
- if (op === "var") {
119
- const path = Array.isArray(operands) ? operands[0] : operands;
120
- return String(path ?? "");
121
- }
122
- if (op === "val") {
123
- const path = Array.isArray(operands) ? operands[0] : operands;
124
- return `val(${path ?? ""})`;
125
- }
126
- if (op === "exists") {
127
- return `exists(${operands})`;
128
- }
129
- const args = Array.isArray(operands) ? operands : [
130
- operands
131
- ];
132
- const wrapIfNeeded = (subVal) => {
133
- const text2 = toText(subVal);
134
- return needsParens(subVal, op) ? `(${text2})` : text2;
135
- };
136
- if ([
137
- ...COMPARISON_OPERATORS$1,
138
- ...ARITHMETIC_BINARY_OPERATORS
139
- ].includes(op)) {
140
- if (args.length === 2) {
141
- return `${wrapIfNeeded(args[0])} ${op} ${wrapIfNeeded(args[1])}`;
142
- }
143
- if (args.length > 2) {
144
- return args.map(wrapIfNeeded).join(` ${op} `);
145
- }
146
- }
147
- if (op === "and") {
148
- return args.map(wrapIfNeeded).join(" AND ");
149
- }
150
- if (op === "or") {
151
- return args.map(wrapIfNeeded).join(" OR ");
152
- }
153
- if (UNARY_OPERATORS$2.includes(op)) {
154
- const argText = toText(args[0]);
155
- const subOp = getOperator(args[0]);
156
- if (subOp && (subOp === "and" || subOp === "or" || COMPARISON_OPERATORS$1.includes(subOp))) {
157
- return `${op}(${argText})`;
158
- }
159
- return `${op}${argText}`;
160
- }
161
- if (ITERATOR_OPERATORS.includes(op)) {
162
- const [arr] = args;
163
- return `${op}(${toText(arr)}, ...)`;
164
- }
165
- if (op === "if" || op === "?:") {
166
- const parts = [];
167
- let i = 0;
168
- while (i < args.length) {
169
- if (i + 1 < args.length) {
170
- const prefix = i === 0 ? "if" : "else if";
171
- parts.push(`${prefix} ${toText(args[i])} then ${toText(args[i + 1])}`);
172
- i += 2;
173
- } else {
174
- parts.push(`else ${toText(args[i])}`);
175
- i++;
176
- }
177
- }
178
- return parts.join(" ");
179
- }
180
- return `${op}(${args.map((a) => toText(a)).join(", ")})`;
181
- }
182
- return String(val);
183
- }
184
- const text = toText(value);
185
- if (text.length > maxLength) {
186
- return text.slice(0, maxLength - 3) + "...";
187
- }
188
- return text;
189
- }
190
24
  OPERATORS = {
191
25
  var: {
192
26
  name: "var",
@@ -801,14 +635,195 @@ let __tla = (async () => {
801
635
  "message"
802
636
  ]
803
637
  }
804
- };
805
- function getOperatorMeta(operator) {
806
- return OPERATORS[operator] || {
807
- name: operator,
808
- category: "literal",
809
- label: operator,
810
- description: `Unknown operator: ${operator}`
811
- };
638
+ };
639
+ function getOperatorMeta(operator) {
640
+ return OPERATORS[operator] || {
641
+ name: operator,
642
+ category: "literal",
643
+ label: operator,
644
+ description: `Unknown operator: ${operator}`
645
+ };
646
+ }
647
+ function isOperator(key) {
648
+ return key in OPERATORS;
649
+ }
650
+ function isPlainObject(value) {
651
+ return typeof value === "object" && value !== null && !Array.isArray(value);
652
+ }
653
+ function isJsonLogicExpression(value) {
654
+ if (!isPlainObject(value)) return false;
655
+ const keys = Object.keys(value);
656
+ return keys.length === 1 && isOperator(keys[0]);
657
+ }
658
+ function isDataStructure(value) {
659
+ if (Array.isArray(value)) return value.length > 0;
660
+ if (!isPlainObject(value)) return false;
661
+ const keys = Object.keys(value);
662
+ if (keys.length > 1) return true;
663
+ return keys.length === 1 && !isOperator(keys[0]);
664
+ }
665
+ function getValueType$1(value) {
666
+ if (value === null) return "null";
667
+ if (typeof value === "boolean") return "boolean";
668
+ if (typeof value === "number") return "number";
669
+ if (typeof value === "string") return "string";
670
+ if (Array.isArray(value)) return "array";
671
+ return "string";
672
+ }
673
+ function looksLikeDate(str) {
674
+ const datePatterns = [
675
+ /^\d{4}-\d{2}-\d{2}/,
676
+ /^\d{2}\/\d{2}\/\d{4}/,
677
+ /^\d{2}-\d{2}-\d{4}/
678
+ ];
679
+ return datePatterns.some((pattern) => pattern.test(str));
680
+ }
681
+ function isSimpleOperand(operand) {
682
+ if (operand === null || typeof operand !== "object") {
683
+ return true;
684
+ }
685
+ if (Array.isArray(operand)) {
686
+ return operand.length === 0;
687
+ }
688
+ return false;
689
+ }
690
+ const COMPARISON_OPERATORS$1 = [
691
+ "==",
692
+ "===",
693
+ "!=",
694
+ "!==",
695
+ ">",
696
+ ">=",
697
+ "<",
698
+ "<="
699
+ ];
700
+ const ITERATOR_OPERATORS = [
701
+ "map",
702
+ "reduce",
703
+ "filter",
704
+ "some",
705
+ "none",
706
+ "all"
707
+ ];
708
+ const UNARY_OPERATORS$2 = [
709
+ "!",
710
+ "!!"
711
+ ];
712
+ const ARITHMETIC_BINARY_OPERATORS = [
713
+ "+",
714
+ "-",
715
+ "*",
716
+ "/",
717
+ "%"
718
+ ];
719
+ function generateExpressionText(value, maxLength = 100) {
720
+ function getOperator(val) {
721
+ if (isPlainObject(val)) {
722
+ const keys = Object.keys(val);
723
+ if (keys.length === 1) return keys[0];
724
+ }
725
+ return null;
726
+ }
727
+ function needsParens(subVal, parentOp) {
728
+ const subOp = getOperator(subVal);
729
+ if (!subOp) return false;
730
+ if (parentOp === "and" && subOp === "or" || parentOp === "or" && subOp === "and") {
731
+ return true;
732
+ }
733
+ if (COMPARISON_OPERATORS$1.includes(parentOp) && (subOp === "and" || subOp === "or")) {
734
+ return true;
735
+ }
736
+ if ((parentOp === "*" || parentOp === "/") && (subOp === "+" || subOp === "-")) {
737
+ return true;
738
+ }
739
+ return false;
740
+ }
741
+ function toText(val, _parentOp) {
742
+ if (val === null) return "null";
743
+ if (typeof val === "boolean") return String(val);
744
+ if (typeof val === "number") return String(val);
745
+ if (typeof val === "string") return `"${val}"`;
746
+ if (Array.isArray(val)) {
747
+ if (val.length === 0) return "[]";
748
+ const items = val.map((v) => toText(v)).join(", ");
749
+ return `[${items}]`;
750
+ }
751
+ if (isPlainObject(val)) {
752
+ const keys = Object.keys(val);
753
+ if (keys.length !== 1) return JSON.stringify(val);
754
+ const op = keys[0];
755
+ const operands = val[op];
756
+ if (op === "var") {
757
+ const path = Array.isArray(operands) ? operands[0] : operands;
758
+ return String(path ?? "");
759
+ }
760
+ if (op === "val") {
761
+ const path = Array.isArray(operands) ? operands[0] : operands;
762
+ return `val(${path ?? ""})`;
763
+ }
764
+ if (op === "exists") {
765
+ return `exists(${operands})`;
766
+ }
767
+ const args = Array.isArray(operands) ? operands : [
768
+ operands
769
+ ];
770
+ const wrapIfNeeded = (subVal) => {
771
+ const text2 = toText(subVal);
772
+ return needsParens(subVal, op) ? `(${text2})` : text2;
773
+ };
774
+ if ([
775
+ ...COMPARISON_OPERATORS$1,
776
+ ...ARITHMETIC_BINARY_OPERATORS
777
+ ].includes(op)) {
778
+ if (args.length === 2) {
779
+ return `${wrapIfNeeded(args[0])} ${op} ${wrapIfNeeded(args[1])}`;
780
+ }
781
+ if (args.length > 2) {
782
+ return args.map(wrapIfNeeded).join(` ${op} `);
783
+ }
784
+ }
785
+ if (op === "and") {
786
+ return args.map(wrapIfNeeded).join(" AND ");
787
+ }
788
+ if (op === "or") {
789
+ return args.map(wrapIfNeeded).join(" OR ");
790
+ }
791
+ if (UNARY_OPERATORS$2.includes(op)) {
792
+ const argText = toText(args[0]);
793
+ const subOp = getOperator(args[0]);
794
+ if (subOp && (subOp === "and" || subOp === "or" || COMPARISON_OPERATORS$1.includes(subOp))) {
795
+ return `${op}(${argText})`;
796
+ }
797
+ return `${op}${argText}`;
798
+ }
799
+ if (ITERATOR_OPERATORS.includes(op)) {
800
+ const [arr] = args;
801
+ return `${op}(${toText(arr)}, ...)`;
802
+ }
803
+ if (op === "if" || op === "?:") {
804
+ const parts = [];
805
+ let i = 0;
806
+ while (i < args.length) {
807
+ if (i + 1 < args.length) {
808
+ const prefix = i === 0 ? "if" : "else if";
809
+ parts.push(`${prefix} ${toText(args[i])} then ${toText(args[i + 1])}`);
810
+ i += 2;
811
+ } else {
812
+ parts.push(`else ${toText(args[i])}`);
813
+ i++;
814
+ }
815
+ }
816
+ return parts.join(" ");
817
+ }
818
+ return `${op}(${args.map((a) => toText(a)).join(", ")})`;
819
+ }
820
+ return String(val);
821
+ }
822
+ const text = toText(value);
823
+ if (text.length > maxLength) {
824
+ return text.slice(0, maxLength - 3) + "...";
825
+ }
826
+ return text;
812
827
  }
813
828
  const TRUNCATION_LIMITS = {
814
829
  shortLabel: 20,
@@ -904,7 +919,7 @@ let __tla = (async () => {
904
919
  Component.displayName = toPascalCase(iconName);
905
920
  return Component;
906
921
  };
907
- const __iconNode$v = [
922
+ const __iconNode$w = [
908
923
  [
909
924
  "path",
910
925
  {
@@ -922,8 +937,8 @@ let __tla = (async () => {
922
937
  }
923
938
  ]
924
939
  ];
925
- const Ban = createLucideIcon("ban", __iconNode$v);
926
- const __iconNode$u = [
940
+ const Ban = createLucideIcon("ban", __iconNode$w);
941
+ const __iconNode$v = [
927
942
  [
928
943
  "path",
929
944
  {
@@ -946,8 +961,8 @@ let __tla = (async () => {
946
961
  }
947
962
  ]
948
963
  ];
949
- const Box = createLucideIcon("box", __iconNode$u);
950
- const __iconNode$t = [
964
+ const Box = createLucideIcon("box", __iconNode$v);
965
+ const __iconNode$u = [
951
966
  [
952
967
  "path",
953
968
  {
@@ -1033,7 +1048,24 @@ let __tla = (async () => {
1033
1048
  }
1034
1049
  ]
1035
1050
  ];
1036
- const Boxes = createLucideIcon("boxes", __iconNode$t);
1051
+ const Boxes = createLucideIcon("boxes", __iconNode$u);
1052
+ const __iconNode$t = [
1053
+ [
1054
+ "path",
1055
+ {
1056
+ d: "M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1",
1057
+ key: "ezmyqa"
1058
+ }
1059
+ ],
1060
+ [
1061
+ "path",
1062
+ {
1063
+ d: "M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1",
1064
+ key: "e1hn23"
1065
+ }
1066
+ ]
1067
+ ];
1068
+ const Braces = createLucideIcon("braces", __iconNode$t);
1037
1069
  const __iconNode$s = [
1038
1070
  [
1039
1071
  "path",
@@ -1945,7 +1977,8 @@ let __tla = (async () => {
1945
1977
  "git-commit-horizontal": GitCommitHorizontal,
1946
1978
  "search": Search,
1947
1979
  "divide": Divide,
1948
- "quote": Quote
1980
+ "quote": Quote,
1981
+ "braces": Braces
1949
1982
  };
1950
1983
  function Icon({ name, size = 14, className, style }) {
1951
1984
  const IconComponent = ICON_COMPONENTS[name];
@@ -2516,7 +2549,8 @@ let __tla = (async () => {
2516
2549
  edges: context.edges,
2517
2550
  parentId: parentInfo.parentId,
2518
2551
  argIndex: parentInfo.argIndex,
2519
- branchType: parentInfo.branchType
2552
+ branchType: parentInfo.branchType,
2553
+ preserveStructure: context.preserveStructure
2520
2554
  });
2521
2555
  }
2522
2556
  const cells = [];
@@ -2531,7 +2565,8 @@ let __tla = (async () => {
2531
2565
  nodes: context.nodes,
2532
2566
  edges: context.edges,
2533
2567
  parentId: nodeId,
2534
- argIndex: idx
2568
+ argIndex: idx,
2569
+ preserveStructure: context.preserveStructure
2535
2570
  });
2536
2571
  context.edges.push({
2537
2572
  id: `${nodeId}-cond-${conditionBranchId}`,
@@ -2556,7 +2591,8 @@ let __tla = (async () => {
2556
2591
  edges: context.edges,
2557
2592
  parentId: nodeId,
2558
2593
  argIndex: idx + 1,
2559
- branchType: "yes"
2594
+ branchType: "yes",
2595
+ preserveStructure: context.preserveStructure
2560
2596
  });
2561
2597
  context.edges.push({
2562
2598
  id: `${nodeId}-then-${thenBranchId}`,
@@ -2586,7 +2622,8 @@ let __tla = (async () => {
2586
2622
  edges: context.edges,
2587
2623
  parentId: nodeId,
2588
2624
  argIndex: ifArgs.length - 1,
2589
- branchType: "no"
2625
+ branchType: "no",
2626
+ preserveStructure: context.preserveStructure
2590
2627
  });
2591
2628
  context.edges.push({
2592
2629
  id: `${nodeId}-else-${elseBranchId}`,
@@ -2665,7 +2702,8 @@ let __tla = (async () => {
2665
2702
  nodes: context.nodes,
2666
2703
  edges: context.edges,
2667
2704
  parentId: nodeId,
2668
- argIndex: idx
2705
+ argIndex: idx,
2706
+ preserveStructure: context.preserveStructure
2669
2707
  });
2670
2708
  const summary = generateArgSummary(operand);
2671
2709
  summary.label = generateExpressionText(operand, TRUNCATION_LIMITS.expressionText);
@@ -2755,7 +2793,8 @@ let __tla = (async () => {
2755
2793
  nodes: context.nodes,
2756
2794
  edges: context.edges,
2757
2795
  parentId: nodeId,
2758
- argIndex: idx
2796
+ argIndex: idx,
2797
+ preserveStructure: context.preserveStructure
2759
2798
  });
2760
2799
  childIds.push(childId);
2761
2800
  });
@@ -2790,7 +2829,123 @@ let __tla = (async () => {
2790
2829
  function isUnaryOperator(operator) {
2791
2830
  return UNARY_OPERATORS$1.includes(operator);
2792
2831
  }
2832
+ const EXPR_PLACEHOLDER$1 = "{{EXPR}}";
2833
+ const EXPR_PLACEHOLDER_QUOTED$1 = `"${EXPR_PLACEHOLDER$1}"`;
2834
+ function convertStructure(value, context, convertValue2) {
2835
+ const parentInfo = getParentInfo(context);
2836
+ const nodeId = v4();
2837
+ const isArray = Array.isArray(value);
2838
+ const elements = [];
2839
+ let expressionIndex = 0;
2840
+ const structureWithPlaceholders = walkAndCollect(value, [], (path, item, key) => {
2841
+ if (isJsonLogicExpression(item)) {
2842
+ const branchId = convertValue2(item, {
2843
+ nodes: context.nodes,
2844
+ edges: context.edges,
2845
+ parentId: nodeId,
2846
+ argIndex: expressionIndex,
2847
+ preserveStructure: context.preserveStructure
2848
+ });
2849
+ elements.push({
2850
+ type: "expression",
2851
+ path,
2852
+ key,
2853
+ branchId,
2854
+ startOffset: 0,
2855
+ endOffset: 0
2856
+ });
2857
+ expressionIndex++;
2858
+ return EXPR_PLACEHOLDER$1;
2859
+ } else {
2860
+ return item;
2861
+ }
2862
+ });
2863
+ const formattedJson = JSON.stringify(structureWithPlaceholders, null, 2);
2864
+ let searchPos = 0;
2865
+ for (const element of elements) {
2866
+ if (element.type === "expression") {
2867
+ const placeholderPos = formattedJson.indexOf(EXPR_PLACEHOLDER_QUOTED$1, searchPos);
2868
+ if (placeholderPos !== -1) {
2869
+ element.startOffset = placeholderPos;
2870
+ element.endOffset = placeholderPos + EXPR_PLACEHOLDER_QUOTED$1.length;
2871
+ searchPos = element.endOffset;
2872
+ }
2873
+ }
2874
+ }
2875
+ const expressionText = generateExpressionText(value, 100);
2876
+ const node = {
2877
+ id: nodeId,
2878
+ type: "structure",
2879
+ position: {
2880
+ x: 0,
2881
+ y: 0
2882
+ },
2883
+ data: {
2884
+ type: "structure",
2885
+ isArray,
2886
+ formattedJson,
2887
+ elements,
2888
+ collapsed: false,
2889
+ expressionText,
2890
+ expression: value,
2891
+ parentId: parentInfo.parentId,
2892
+ argIndex: parentInfo.argIndex,
2893
+ branchType: parentInfo.branchType
2894
+ }
2895
+ };
2896
+ context.nodes.push(node);
2897
+ if (parentInfo.parentId && !parentInfo.branchType) {
2898
+ const edge = createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0);
2899
+ context.edges.push(edge);
2900
+ }
2901
+ let branchIdx = 0;
2902
+ for (const element of elements) {
2903
+ if (element.type === "expression" && element.branchId) {
2904
+ const edge = createBranchEdge(nodeId, element.branchId, branchIdx);
2905
+ context.edges.push(edge);
2906
+ branchIdx++;
2907
+ }
2908
+ }
2909
+ return nodeId;
2910
+ }
2911
+ function walkAndCollect(value, path, onValue) {
2912
+ if (Array.isArray(value)) {
2913
+ return value.map((item, index) => {
2914
+ const itemPath = [
2915
+ ...path,
2916
+ String(index)
2917
+ ];
2918
+ if (isJsonLogicExpression(item)) {
2919
+ return onValue(itemPath, item);
2920
+ } else if (typeof item === "object" && item !== null) {
2921
+ return walkAndCollect(item, itemPath, onValue);
2922
+ }
2923
+ return item;
2924
+ });
2925
+ }
2926
+ if (typeof value === "object" && value !== null) {
2927
+ const result = {};
2928
+ for (const [key, item] of Object.entries(value)) {
2929
+ const itemPath = [
2930
+ ...path,
2931
+ key
2932
+ ];
2933
+ if (isJsonLogicExpression(item)) {
2934
+ result[key] = onValue(itemPath, item, key);
2935
+ } else if (typeof item === "object" && item !== null) {
2936
+ result[key] = walkAndCollect(item, itemPath, onValue);
2937
+ } else {
2938
+ result[key] = item;
2939
+ }
2940
+ }
2941
+ return result;
2942
+ }
2943
+ return value;
2944
+ }
2793
2945
  function convertValue(value, context) {
2946
+ if (context.preserveStructure && isDataStructure(value)) {
2947
+ return convertStructure(value, context, convertValue);
2948
+ }
2794
2949
  if (!isPlainObject(value)) {
2795
2950
  return convertPrimitive(value, context);
2796
2951
  }
@@ -2823,7 +2978,7 @@ let __tla = (async () => {
2823
2978
  }
2824
2979
  return convertOperatorWithChildren(operator, operandArray, value, context, convertValue);
2825
2980
  }
2826
- jsonLogicToNodes = function(expr) {
2981
+ jsonLogicToNodes = function(expr, options = {}) {
2827
2982
  if (expr === null || expr === void 0) {
2828
2983
  return {
2829
2984
  nodes: [],
@@ -2835,7 +2990,8 @@ let __tla = (async () => {
2835
2990
  const edges = [];
2836
2991
  const rootId = convertValue(expr, {
2837
2992
  nodes,
2838
- edges
2993
+ edges,
2994
+ preserveStructure: options.preserveStructure
2839
2995
  });
2840
2996
  return {
2841
2997
  nodes,
@@ -2870,7 +3026,7 @@ let __tla = (async () => {
2870
3026
  }
2871
3027
  return results;
2872
3028
  }
2873
- function traceToNodes(trace) {
3029
+ function traceToNodes(trace, options = {}) {
2874
3030
  if (!trace.expression_tree) {
2875
3031
  return {
2876
3032
  nodes: [],
@@ -2882,11 +3038,13 @@ let __tla = (async () => {
2882
3038
  const nodes = [];
2883
3039
  const edges = [];
2884
3040
  const traceNodeMap = /* @__PURE__ */ new Map();
3041
+ const rootExpression = options.originalValue ?? JSON.parse(trace.expression_tree.expression);
2885
3042
  processExpressionNode(trace.expression_tree, {
2886
3043
  nodes,
2887
3044
  edges,
2888
- traceNodeMap
2889
- });
3045
+ traceNodeMap,
3046
+ preserveStructure: options.preserveStructure ?? false
3047
+ }, {}, rootExpression);
2890
3048
  return {
2891
3049
  nodes,
2892
3050
  edges,
@@ -2903,11 +3061,11 @@ let __tla = (async () => {
2903
3061
  }
2904
3062
  }
2905
3063
  }
2906
- function processExpressionNode(exprNode, context, parentInfo = {}) {
3064
+ function processExpressionNode(exprNode, context, parentInfo = {}, originalExpression) {
2907
3065
  const nodeId = traceIdToNodeId(exprNode.id);
2908
- const expression = JSON.parse(exprNode.expression);
3066
+ const expression = originalExpression ?? JSON.parse(exprNode.expression);
2909
3067
  context.traceNodeMap.set(nodeId, nodeId);
2910
- const nodeType = determineNodeType(expression);
3068
+ const nodeType = determineNodeType(expression, context.preserveStructure);
2911
3069
  switch (nodeType) {
2912
3070
  case "literal":
2913
3071
  createLiteralNodeFromTrace(nodeId, expression, exprNode.children, context, parentInfo);
@@ -2924,10 +3082,39 @@ let __tla = (async () => {
2924
3082
  case "operator":
2925
3083
  createOperatorNodeFromTrace(nodeId, expression, exprNode.children, context, parentInfo);
2926
3084
  break;
3085
+ case "structure":
3086
+ createStructureNodeFromTrace(nodeId, expression, exprNode.children, context, parentInfo);
3087
+ break;
2927
3088
  }
2928
3089
  return nodeId;
2929
3090
  }
2930
- function determineNodeType(expr) {
3091
+ function createFallbackNode(nodeId, value, context, parentInfo) {
3092
+ const nodeType = determineNodeType(value, context.preserveStructure);
3093
+ switch (nodeType) {
3094
+ case "literal":
3095
+ createLiteralNodeFromTrace(nodeId, value, [], context, parentInfo);
3096
+ break;
3097
+ case "variable":
3098
+ createVariableNodeFromTrace(nodeId, value, [], context, parentInfo);
3099
+ break;
3100
+ case "if":
3101
+ createIfElseNodeFromTrace(nodeId, value, [], context, parentInfo);
3102
+ break;
3103
+ case "verticalCell":
3104
+ createVerticalCellNodeFromTrace(nodeId, value, [], context, parentInfo);
3105
+ break;
3106
+ case "operator":
3107
+ createOperatorNodeFromTrace(nodeId, value, [], context, parentInfo);
3108
+ break;
3109
+ case "structure":
3110
+ createStructureNodeFromTrace(nodeId, value, [], context, parentInfo);
3111
+ break;
3112
+ }
3113
+ }
3114
+ function determineNodeType(expr, preserveStructure) {
3115
+ if (preserveStructure && isDataStructure(expr)) {
3116
+ return "structure";
3117
+ }
2931
3118
  if (expr === null || typeof expr !== "object" || Array.isArray(expr)) {
2932
3119
  return "literal";
2933
3120
  }
@@ -2975,6 +3162,9 @@ let __tla = (async () => {
2975
3162
  }
2976
3163
  };
2977
3164
  context.nodes.push(node);
3165
+ if (parentInfo.parentId && !parentInfo.branchType) {
3166
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
3167
+ }
2978
3168
  }
2979
3169
  function createVariableNodeFromTrace(nodeId, expression, children, context, parentInfo) {
2980
3170
  if (children && children.length > 0) {
@@ -3010,6 +3200,9 @@ let __tla = (async () => {
3010
3200
  }
3011
3201
  };
3012
3202
  context.nodes.push(node);
3203
+ if (parentInfo.parentId && !parentInfo.branchType) {
3204
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
3205
+ }
3013
3206
  }
3014
3207
  function createIfElseNodeFromTrace(nodeId, expression, children, context, parentInfo) {
3015
3208
  const obj = expression;
@@ -3034,23 +3227,10 @@ let __tla = (async () => {
3034
3227
  });
3035
3228
  } else {
3036
3229
  conditionBranchId = `${nodeId}-cond-${idx}`;
3037
- const condNode = {
3038
- id: conditionBranchId,
3039
- type: "literal",
3040
- position: {
3041
- x: 0,
3042
- y: 0
3043
- },
3044
- data: {
3045
- type: "literal",
3046
- value: condition,
3047
- valueType: getValueType$1(condition),
3048
- expression: condition,
3049
- parentId: nodeId,
3050
- argIndex: idx
3051
- }
3052
- };
3053
- context.nodes.push(condNode);
3230
+ createFallbackNode(conditionBranchId, condition, context, {
3231
+ parentId: nodeId,
3232
+ argIndex: idx
3233
+ });
3054
3234
  }
3055
3235
  context.edges.push(createBranchEdge(nodeId, conditionBranchId, branchIndex));
3056
3236
  const conditionText = generateExpressionText(condition, 40);
@@ -3075,24 +3255,11 @@ let __tla = (async () => {
3075
3255
  });
3076
3256
  } else {
3077
3257
  thenBranchId = `${nodeId}-then-${idx}`;
3078
- const thenNode = {
3079
- id: thenBranchId,
3080
- type: "literal",
3081
- position: {
3082
- x: 0,
3083
- y: 0
3084
- },
3085
- data: {
3086
- type: "literal",
3087
- value: thenValue,
3088
- valueType: getValueType$1(thenValue),
3089
- expression: thenValue,
3090
- parentId: nodeId,
3091
- argIndex: idx + 1,
3092
- branchType: "yes"
3093
- }
3094
- };
3095
- context.nodes.push(thenNode);
3258
+ createFallbackNode(thenBranchId, thenValue, context, {
3259
+ parentId: nodeId,
3260
+ argIndex: idx + 1,
3261
+ branchType: "yes"
3262
+ });
3096
3263
  }
3097
3264
  context.edges.push(createBranchEdge(nodeId, thenBranchId, branchIndex));
3098
3265
  const thenText = generateExpressionText(thenValue, 40);
@@ -3122,24 +3289,11 @@ let __tla = (async () => {
3122
3289
  });
3123
3290
  } else {
3124
3291
  elseBranchId = `${nodeId}-else`;
3125
- const elseNode = {
3126
- id: elseBranchId,
3127
- type: "literal",
3128
- position: {
3129
- x: 0,
3130
- y: 0
3131
- },
3132
- data: {
3133
- type: "literal",
3134
- value: elseValue,
3135
- valueType: getValueType$1(elseValue),
3136
- expression: elseValue,
3137
- parentId: nodeId,
3138
- argIndex: ifArgs.length - 1,
3139
- branchType: "no"
3140
- }
3141
- };
3142
- context.nodes.push(elseNode);
3292
+ createFallbackNode(elseBranchId, elseValue, context, {
3293
+ parentId: nodeId,
3294
+ argIndex: ifArgs.length - 1,
3295
+ branchType: "no"
3296
+ });
3143
3297
  }
3144
3298
  context.edges.push(createBranchEdge(nodeId, elseBranchId, branchIndex));
3145
3299
  const elseText = generateExpressionText(elseValue, 40);
@@ -3177,6 +3331,9 @@ let __tla = (async () => {
3177
3331
  }
3178
3332
  };
3179
3333
  context.nodes.push(ifElseNode);
3334
+ if (parentInfo.parentId && !parentInfo.branchType) {
3335
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
3336
+ }
3180
3337
  }
3181
3338
  function findMatchingChild(operand, children, usedIndices) {
3182
3339
  const operandStr = JSON.stringify(operand);
@@ -3245,6 +3402,10 @@ let __tla = (async () => {
3245
3402
  });
3246
3403
  } else {
3247
3404
  branchId = `${nodeId}-arg-${idx}`;
3405
+ createFallbackNode(branchId, operand, context, {
3406
+ parentId: nodeId,
3407
+ argIndex: idx
3408
+ });
3248
3409
  }
3249
3410
  const summary = generateArgSummary(operand);
3250
3411
  summary.label = generateExpressionText(operand, TRUNCATION_LIMITS.expressionText);
@@ -3283,6 +3444,9 @@ let __tla = (async () => {
3283
3444
  }
3284
3445
  };
3285
3446
  context.nodes.push(node);
3447
+ if (parentInfo.parentId && !parentInfo.branchType) {
3448
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
3449
+ }
3286
3450
  }
3287
3451
  function createOperatorNodeFromTrace(nodeId, expression, children, context, parentInfo) {
3288
3452
  const obj = expression;
@@ -3328,6 +3492,9 @@ let __tla = (async () => {
3328
3492
  }
3329
3493
  };
3330
3494
  context.nodes.push(node2);
3495
+ if (parentInfo.parentId && !parentInfo.branchType) {
3496
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
3497
+ }
3331
3498
  return;
3332
3499
  }
3333
3500
  const usedChildIndices = /* @__PURE__ */ new Set();
@@ -3336,37 +3503,113 @@ let __tla = (async () => {
3336
3503
  const match = findMatchingChild(operand, children, usedChildIndices);
3337
3504
  if (match) {
3338
3505
  usedChildIndices.add(match.index);
3339
- const childId = processExpressionNode(match.child, context, {
3506
+ const childId = processExpressionNode(match.child, context, {
3507
+ parentId: nodeId,
3508
+ argIndex: idx
3509
+ });
3510
+ childIds.push(childId);
3511
+ }
3512
+ } else {
3513
+ const match = findMatchingChild(operand, children, usedChildIndices);
3514
+ if (match) {
3515
+ usedChildIndices.add(match.index);
3516
+ const traceId = traceIdToNodeId(match.child.id);
3517
+ context.traceNodeMap.set(traceId, nodeId);
3518
+ if (match.child.children && match.child.children.length > 0) {
3519
+ mapInlinedChildren(match.child.children, nodeId, context.traceNodeMap);
3520
+ }
3521
+ }
3522
+ }
3523
+ });
3524
+ const node = {
3525
+ id: nodeId,
3526
+ type: "operator",
3527
+ position: {
3528
+ x: 0,
3529
+ y: 0
3530
+ },
3531
+ data: {
3532
+ type: "operator",
3533
+ operator,
3534
+ category: meta.category,
3535
+ label: meta.label,
3536
+ childIds,
3537
+ collapsed: false,
3538
+ expressionText,
3539
+ expression,
3540
+ parentId: parentInfo.parentId,
3541
+ argIndex: parentInfo.argIndex,
3542
+ branchType: parentInfo.branchType
3543
+ }
3544
+ };
3545
+ context.nodes.push(node);
3546
+ if (parentInfo.parentId && !parentInfo.branchType) {
3547
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
3548
+ }
3549
+ }
3550
+ const EXPR_PLACEHOLDER = "{{EXPR}}";
3551
+ const EXPR_PLACEHOLDER_QUOTED = `"${EXPR_PLACEHOLDER}"`;
3552
+ function createStructureNodeFromTrace(nodeId, expression, children, context, parentInfo) {
3553
+ const isArray = Array.isArray(expression);
3554
+ const elements = [];
3555
+ const usedChildIndices = /* @__PURE__ */ new Set();
3556
+ let expressionIndex = 0;
3557
+ const structureWithPlaceholders = walkAndCollectFromTrace(expression, [], (path, item, key) => {
3558
+ if (isJsonLogicExpression(item)) {
3559
+ const match = findMatchingChild(item, children, usedChildIndices);
3560
+ let branchId;
3561
+ if (match) {
3562
+ usedChildIndices.add(match.index);
3563
+ branchId = processExpressionNode(match.child, context, {
3340
3564
  parentId: nodeId,
3341
- argIndex: idx
3565
+ argIndex: expressionIndex
3566
+ });
3567
+ } else {
3568
+ branchId = `${nodeId}-expr-${expressionIndex}`;
3569
+ createFallbackNode(branchId, item, context, {
3570
+ parentId: nodeId,
3571
+ argIndex: expressionIndex,
3572
+ branchType: "branch"
3342
3573
  });
3343
- childIds.push(childId);
3344
- }
3345
- } else {
3346
- const match = findMatchingChild(operand, children, usedChildIndices);
3347
- if (match) {
3348
- usedChildIndices.add(match.index);
3349
- const traceId = traceIdToNodeId(match.child.id);
3350
- context.traceNodeMap.set(traceId, nodeId);
3351
- if (match.child.children && match.child.children.length > 0) {
3352
- mapInlinedChildren(match.child.children, nodeId, context.traceNodeMap);
3353
- }
3354
3574
  }
3575
+ elements.push({
3576
+ type: "expression",
3577
+ path,
3578
+ key,
3579
+ branchId,
3580
+ startOffset: 0,
3581
+ endOffset: 0
3582
+ });
3583
+ expressionIndex++;
3584
+ return EXPR_PLACEHOLDER;
3355
3585
  }
3586
+ return item;
3356
3587
  });
3588
+ const formattedJson = JSON.stringify(structureWithPlaceholders, null, 2);
3589
+ let searchPos = 0;
3590
+ for (const element of elements) {
3591
+ if (element.type === "expression") {
3592
+ const placeholderPos = formattedJson.indexOf(EXPR_PLACEHOLDER_QUOTED, searchPos);
3593
+ if (placeholderPos !== -1) {
3594
+ element.startOffset = placeholderPos;
3595
+ element.endOffset = placeholderPos + EXPR_PLACEHOLDER_QUOTED.length;
3596
+ searchPos = element.endOffset;
3597
+ }
3598
+ }
3599
+ }
3600
+ const expressionText = generateExpressionText(expression, 100);
3357
3601
  const node = {
3358
3602
  id: nodeId,
3359
- type: "operator",
3603
+ type: "structure",
3360
3604
  position: {
3361
3605
  x: 0,
3362
3606
  y: 0
3363
3607
  },
3364
3608
  data: {
3365
- type: "operator",
3366
- operator,
3367
- category: meta.category,
3368
- label: meta.label,
3369
- childIds,
3609
+ type: "structure",
3610
+ isArray,
3611
+ formattedJson,
3612
+ elements,
3370
3613
  collapsed: false,
3371
3614
  expressionText,
3372
3615
  expression,
@@ -3376,6 +3619,50 @@ let __tla = (async () => {
3376
3619
  }
3377
3620
  };
3378
3621
  context.nodes.push(node);
3622
+ if (parentInfo.parentId && !parentInfo.branchType) {
3623
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
3624
+ }
3625
+ let branchIdx = 0;
3626
+ for (const element of elements) {
3627
+ if (element.type === "expression" && element.branchId) {
3628
+ context.edges.push(createBranchEdge(nodeId, element.branchId, branchIdx));
3629
+ branchIdx++;
3630
+ }
3631
+ }
3632
+ }
3633
+ function walkAndCollectFromTrace(value, path, onValue, context) {
3634
+ if (Array.isArray(value)) {
3635
+ return value.map((item, index) => {
3636
+ const itemPath = [
3637
+ ...path,
3638
+ String(index)
3639
+ ];
3640
+ if (isJsonLogicExpression(item)) {
3641
+ return onValue(itemPath, item);
3642
+ } else if (typeof item === "object" && item !== null) {
3643
+ return walkAndCollectFromTrace(item, itemPath, onValue);
3644
+ }
3645
+ return item;
3646
+ });
3647
+ }
3648
+ if (typeof value === "object" && value !== null) {
3649
+ const result = {};
3650
+ for (const [key, item] of Object.entries(value)) {
3651
+ const itemPath = [
3652
+ ...path,
3653
+ key
3654
+ ];
3655
+ if (isJsonLogicExpression(item)) {
3656
+ result[key] = onValue(itemPath, item, key);
3657
+ } else if (typeof item === "object" && item !== null) {
3658
+ result[key] = walkAndCollectFromTrace(item, itemPath, onValue);
3659
+ } else {
3660
+ result[key] = item;
3661
+ }
3662
+ }
3663
+ return result;
3664
+ }
3665
+ return value;
3379
3666
  }
3380
3667
  function getDefaultExportFromCjs(x) {
3381
3668
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
@@ -6900,6 +7187,9 @@ let __tla = (async () => {
6900
7187
  function isVerticalCellNode(node) {
6901
7188
  return node.data.type === "verticalCell";
6902
7189
  }
7190
+ function isStructureNode(node) {
7191
+ return node.data.type === "structure";
7192
+ }
6903
7193
  function estimateTextWidth(text, isMonospace = false) {
6904
7194
  const charWidth = isMonospace ? TEXT_METRICS.charWidthMono : TEXT_METRICS.charWidthRegular;
6905
7195
  return text.length * charWidth;
@@ -6938,12 +7228,31 @@ let __tla = (async () => {
6938
7228
  maxCellWidth = Math.max(maxCellWidth, estimateTextWidth(vcData.expressionText, true));
6939
7229
  }
6940
7230
  contentWidth = maxCellWidth;
7231
+ } else if (isStructureNode(node)) {
7232
+ const structData = node.data;
7233
+ if (structData.collapsed && structData.expressionText) {
7234
+ contentWidth = estimateTextWidth(structData.expressionText, true);
7235
+ } else {
7236
+ const lines = structData.formattedJson.split("\n");
7237
+ let maxLineWidth = 0;
7238
+ for (const line of lines) {
7239
+ const lineWidth = estimateTextWidth(line, true);
7240
+ maxLineWidth = Math.max(maxLineWidth, lineWidth);
7241
+ }
7242
+ contentWidth = maxLineWidth;
7243
+ }
6941
7244
  } else {
6942
7245
  contentWidth = FIXED_WIDTHS.fallbackNode;
6943
7246
  }
6944
7247
  const totalWidth = contentWidth + NODE_PADDING.contentPadding;
6945
7248
  return Math.max(NODE_DIMENSIONS.minWidth, Math.min(NODE_DIMENSIONS.maxWidth, totalWidth));
6946
7249
  }
7250
+ const STRUCTURE_DIMENSIONS = {
7251
+ headerHeight: 32,
7252
+ lineHeight: 18,
7253
+ bodyPadding: 16,
7254
+ collapsedBodyHeight: 30
7255
+ };
6947
7256
  function getNodeDimensions(node) {
6948
7257
  const width = calculateNodeWidth(node);
6949
7258
  if (isVerticalCellNode(node)) {
@@ -6960,6 +7269,20 @@ let __tla = (async () => {
6960
7269
  height: VERTICAL_CELL_DIMENSIONS.headerHeight + cellCount * VERTICAL_CELL_DIMENSIONS.rowHeight
6961
7270
  };
6962
7271
  }
7272
+ if (isStructureNode(node)) {
7273
+ const structData = node.data;
7274
+ if (structData.collapsed) {
7275
+ return {
7276
+ width,
7277
+ height: STRUCTURE_DIMENSIONS.headerHeight + STRUCTURE_DIMENSIONS.collapsedBodyHeight
7278
+ };
7279
+ }
7280
+ const lineCount = structData.formattedJson.split("\n").length;
7281
+ return {
7282
+ width,
7283
+ height: STRUCTURE_DIMENSIONS.headerHeight + STRUCTURE_DIMENSIONS.bodyPadding + lineCount * STRUCTURE_DIMENSIONS.lineHeight
7284
+ };
7285
+ }
6963
7286
  return {
6964
7287
  width,
6965
7288
  height: NODE_DIMENSIONS.defaultHeight
@@ -6983,7 +7306,7 @@ let __tla = (async () => {
6983
7306
  height
6984
7307
  });
6985
7308
  });
6986
- const edgesToUse = edges || buildEdgesFromNodes(nodes);
7309
+ const edgesToUse = edges || buildEdgesFromNodes$1(nodes);
6987
7310
  const nodeIdSet = new Set(nodes.map((n) => n.id));
6988
7311
  const sourceEdgeCount = /* @__PURE__ */ new Map();
6989
7312
  edgesToUse.forEach((edge) => {
@@ -7016,7 +7339,7 @@ let __tla = (async () => {
7016
7339
  return node;
7017
7340
  });
7018
7341
  };
7019
- function buildEdgesFromNodes(nodes) {
7342
+ function buildEdgesFromNodes$1(nodes) {
7020
7343
  const edges = [];
7021
7344
  nodes.forEach((node) => {
7022
7345
  if (isOperatorNode(node)) {
@@ -7037,38 +7360,34 @@ let __tla = (async () => {
7037
7360
  const vcData = node.data;
7038
7361
  if (!vcData.collapsed) {
7039
7362
  const collapsedIndices = vcData.collapsedCellIndices || [];
7040
- let branchIndex = 0;
7041
7363
  vcData.cells.forEach((cell) => {
7042
7364
  if (collapsedIndices.includes(cell.index)) return;
7043
- if (cell.branchId) {
7044
- edges.push({
7045
- id: `${node.id}-branch-${cell.branchId}`,
7046
- source: node.id,
7047
- target: cell.branchId,
7048
- sourceHandle: `branch-${branchIndex}`,
7049
- targetHandle: "left"
7050
- });
7051
- branchIndex++;
7052
- }
7053
7365
  if (cell.conditionBranchId) {
7054
7366
  edges.push({
7055
7367
  id: `${node.id}-cond-${cell.conditionBranchId}`,
7056
7368
  source: node.id,
7057
7369
  target: cell.conditionBranchId,
7058
- sourceHandle: `branch-${branchIndex}`,
7370
+ sourceHandle: `branch-${cell.index}-cond`,
7059
7371
  targetHandle: "left"
7060
7372
  });
7061
- branchIndex++;
7062
7373
  }
7063
7374
  if (cell.thenBranchId) {
7064
7375
  edges.push({
7065
7376
  id: `${node.id}-then-${cell.thenBranchId}`,
7066
7377
  source: node.id,
7067
7378
  target: cell.thenBranchId,
7068
- sourceHandle: `branch-${branchIndex}`,
7379
+ sourceHandle: `branch-${cell.index}-then`,
7380
+ targetHandle: "left"
7381
+ });
7382
+ }
7383
+ if (cell.branchId && !cell.conditionBranchId && !cell.thenBranchId) {
7384
+ edges.push({
7385
+ id: `${node.id}-branch-${cell.branchId}`,
7386
+ source: node.id,
7387
+ target: cell.branchId,
7388
+ sourceHandle: `branch-${cell.index}`,
7069
7389
  targetHandle: "left"
7070
7390
  });
7071
- branchIndex++;
7072
7391
  }
7073
7392
  });
7074
7393
  }
@@ -7092,7 +7411,7 @@ let __tla = (async () => {
7092
7411
  const emptyResults$1 = /* @__PURE__ */ new Map();
7093
7412
  const emptySteps = [];
7094
7413
  const emptyTraceNodeMap = /* @__PURE__ */ new Map();
7095
- function useLogicEditor({ value, evaluateWithTrace, data }) {
7414
+ function useLogicEditor({ value, evaluateWithTrace, data, preserveStructure = false }) {
7096
7415
  const [nodes, setNodes] = useState([]);
7097
7416
  const [edges, setEdges] = useState([]);
7098
7417
  const [error, setError] = useState(null);
@@ -7103,11 +7422,12 @@ let __tla = (async () => {
7103
7422
  const [lastExternalValue, setLastExternalValue] = useState("");
7104
7423
  const [lastData, setLastData] = useState("");
7105
7424
  const [lastHadTrace, setLastHadTrace] = useState(false);
7425
+ const [lastPreserveStructure, setLastPreserveStructure] = useState(false);
7106
7426
  useEffect(() => {
7107
7427
  const valueStr = JSON.stringify(value);
7108
7428
  const dataStr = JSON.stringify(data);
7109
7429
  const hasTrace = !!evaluateWithTrace;
7110
- if (valueStr === lastExternalValue && dataStr === lastData && hasTrace === lastHadTrace) {
7430
+ if (valueStr === lastExternalValue && dataStr === lastData && hasTrace === lastHadTrace && preserveStructure === lastPreserveStructure) {
7111
7431
  return;
7112
7432
  }
7113
7433
  try {
@@ -7122,12 +7442,16 @@ let __tla = (async () => {
7122
7442
  setLastExternalValue(valueStr);
7123
7443
  setLastData(dataStr);
7124
7444
  setLastHadTrace(hasTrace);
7445
+ setLastPreserveStructure(preserveStructure);
7125
7446
  return;
7126
7447
  }
7127
7448
  if (evaluateWithTrace && value) {
7128
7449
  try {
7129
7450
  const trace = evaluateWithTrace(value, data ?? {});
7130
- const { nodes: newNodes2, edges: newEdges2, traceNodeMap: newTraceNodeMap } = traceToNodes(trace);
7451
+ const { nodes: newNodes2, edges: newEdges2, traceNodeMap: newTraceNodeMap } = traceToNodes(trace, {
7452
+ preserveStructure,
7453
+ originalValue: value
7454
+ });
7131
7455
  const layoutedNodes2 = applyTreeLayout(newNodes2, newEdges2);
7132
7456
  const traceResults = buildEvaluationResultsFromTrace(trace);
7133
7457
  setNodes(layoutedNodes2);
@@ -7140,12 +7464,15 @@ let __tla = (async () => {
7140
7464
  setLastExternalValue(valueStr);
7141
7465
  setLastData(dataStr);
7142
7466
  setLastHadTrace(hasTrace);
7467
+ setLastPreserveStructure(preserveStructure);
7143
7468
  return;
7144
7469
  } catch (traceErr) {
7145
7470
  console.warn("Trace conversion failed, falling back to JS:", traceErr);
7146
7471
  }
7147
7472
  }
7148
- const { nodes: newNodes, edges: newEdges } = jsonLogicToNodes(value);
7473
+ const { nodes: newNodes, edges: newEdges } = jsonLogicToNodes(value, {
7474
+ preserveStructure
7475
+ });
7149
7476
  const layoutedNodes = applyTreeLayout(newNodes, newEdges);
7150
7477
  setNodes(layoutedNodes);
7151
7478
  setEdges(newEdges);
@@ -7167,13 +7494,16 @@ let __tla = (async () => {
7167
7494
  setLastExternalValue(valueStr);
7168
7495
  setLastData(dataStr);
7169
7496
  setLastHadTrace(hasTrace);
7497
+ setLastPreserveStructure(preserveStructure);
7170
7498
  }, [
7171
7499
  value,
7172
7500
  data,
7173
7501
  evaluateWithTrace,
7502
+ preserveStructure,
7174
7503
  lastExternalValue,
7175
7504
  lastData,
7176
- lastHadTrace
7505
+ lastHadTrace,
7506
+ lastPreserveStructure
7177
7507
  ]);
7178
7508
  return useMemo(() => ({
7179
7509
  nodes,
@@ -7564,7 +7894,8 @@ let __tla = (async () => {
7564
7894
  enabled
7565
7895
  ]);
7566
7896
  }
7567
- function useWasmEvaluator() {
7897
+ function useWasmEvaluator(options = {}) {
7898
+ const { preserveStructure = false } = options;
7568
7899
  const [ready, setReady] = useState(false);
7569
7900
  const [loading, setLoading] = useState(true);
7570
7901
  const [error, setError] = useState(null);
@@ -7575,7 +7906,7 @@ let __tla = (async () => {
7575
7906
  try {
7576
7907
  setLoading(true);
7577
7908
  setError(null);
7578
- const wasm = await import("./datalogic_wasm-r9jsW6oT.js");
7909
+ const wasm = await import("./datalogic_wasm-Cl34E6jc.js");
7579
7910
  await wasm.default();
7580
7911
  if (!cancelled) {
7581
7912
  moduleRef.current = {
@@ -7605,12 +7936,14 @@ let __tla = (async () => {
7605
7936
  try {
7606
7937
  const logicStr = JSON.stringify(logic);
7607
7938
  const dataStr = JSON.stringify(data);
7608
- const resultStr = moduleRef.current.evaluate(logicStr, dataStr);
7939
+ const resultStr = moduleRef.current.evaluate(logicStr, dataStr, preserveStructure);
7609
7940
  return JSON.parse(resultStr);
7610
7941
  } catch (err) {
7611
7942
  throw new Error(err instanceof Error ? err.message : "Evaluation failed");
7612
7943
  }
7613
- }, []);
7944
+ }, [
7945
+ preserveStructure
7946
+ ]);
7614
7947
  const evaluateWithTrace = useCallback((logic, data) => {
7615
7948
  if (!moduleRef.current) {
7616
7949
  throw new Error("WASM module not initialized");
@@ -7621,12 +7954,14 @@ let __tla = (async () => {
7621
7954
  try {
7622
7955
  const logicStr = JSON.stringify(logic);
7623
7956
  const dataStr = JSON.stringify(data);
7624
- const resultStr = moduleRef.current.evaluate_with_trace(logicStr, dataStr);
7957
+ const resultStr = moduleRef.current.evaluate_with_trace(logicStr, dataStr, preserveStructure);
7625
7958
  return JSON.parse(resultStr);
7626
7959
  } catch (err) {
7627
7960
  throw new Error(err instanceof Error ? err.message : "Trace evaluation failed");
7628
7961
  }
7629
- }, []);
7962
+ }, [
7963
+ preserveStructure
7964
+ ]);
7630
7965
  return {
7631
7966
  ready,
7632
7967
  loading,
@@ -8188,13 +8523,14 @@ let __tla = (async () => {
8188
8523
  ]
8189
8524
  });
8190
8525
  });
8191
- const CellHandles = memo(function CellHandles2({ cell, branchIndex, color }) {
8526
+ const CellHandles = memo(function CellHandles2({ cell, color }) {
8527
+ const cellIndex = cell.index;
8192
8528
  return jsxs(Fragment, {
8193
8529
  children: [
8194
8530
  cell.conditionBranchId && jsx(Handle, {
8195
8531
  type: "source",
8196
8532
  position: Position.Right,
8197
- id: `branch-${branchIndex}`,
8533
+ id: `branch-${cellIndex}-cond`,
8198
8534
  className: "cell-handle condition-handle",
8199
8535
  style: {
8200
8536
  background: color,
@@ -8204,7 +8540,7 @@ let __tla = (async () => {
8204
8540
  cell.thenBranchId && jsx(Handle, {
8205
8541
  type: "source",
8206
8542
  position: Position.Right,
8207
- id: `branch-${branchIndex + (cell.conditionBranchId ? 1 : 0)}`,
8543
+ id: `branch-${cellIndex}-then`,
8208
8544
  className: "cell-handle then-handle",
8209
8545
  style: {
8210
8546
  background: "#22C55E",
@@ -8214,7 +8550,7 @@ let __tla = (async () => {
8214
8550
  cell.branchId && !cell.conditionBranchId && !cell.thenBranchId && jsx(Handle, {
8215
8551
  type: "source",
8216
8552
  position: Position.Right,
8217
- id: `branch-${branchIndex}`,
8553
+ id: `branch-${cellIndex}`,
8218
8554
  className: "cell-handle",
8219
8555
  style: {
8220
8556
  background: color,
@@ -8224,25 +8560,12 @@ let __tla = (async () => {
8224
8560
  ]
8225
8561
  });
8226
8562
  });
8227
- function calculateBranchIndex(cells, currentIndex) {
8228
- let branchIdx = 0;
8229
- for (let i = 0; i < currentIndex; i++) {
8230
- const prevCell = cells.find((c) => c.index === i);
8231
- if (prevCell) {
8232
- if (prevCell.conditionBranchId) branchIdx++;
8233
- if (prevCell.thenBranchId) branchIdx++;
8234
- if (prevCell.branchId) branchIdx++;
8235
- }
8236
- }
8237
- return branchIdx;
8238
- }
8239
- const CellRow = memo(function CellRow2({ cell, cells, collapsedIndices, color, onToggleCollapse }) {
8563
+ const CellRow = memo(function CellRow2({ cell, collapsedIndices, color, onToggleCollapse }) {
8240
8564
  var _a;
8241
8565
  const isCellCollapsed = collapsedIndices.includes(cell.index);
8242
8566
  const isIfThenCell = cell.conditionBranchId || cell.thenBranchId;
8243
8567
  const hasAnyBranch = cell.type === "branch" || isIfThenCell;
8244
8568
  const isExpanded = hasAnyBranch && !isCellCollapsed;
8245
- const branchIndex = calculateBranchIndex(cells, cell.index);
8246
8569
  const handleToggle = useCallback((e) => {
8247
8570
  onToggleCollapse(cell.index, e);
8248
8571
  }, [
@@ -8277,7 +8600,6 @@ let __tla = (async () => {
8277
8600
  }),
8278
8601
  isExpanded && jsx(CellHandles, {
8279
8602
  cell,
8280
- branchIndex,
8281
8603
  color: isThenRow ? BRANCH_COLORS.yes : color
8282
8604
  })
8283
8605
  ]
@@ -8366,7 +8688,6 @@ let __tla = (async () => {
8366
8688
  className: "vertical-cell-body",
8367
8689
  children: data.cells.map((cell) => jsx(CellRow, {
8368
8690
  cell,
8369
- cells: data.cells,
8370
8691
  collapsedIndices,
8371
8692
  color,
8372
8693
  onToggleCollapse: toggleCellCollapse
@@ -8375,11 +8696,232 @@ let __tla = (async () => {
8375
8696
  ]
8376
8697
  });
8377
8698
  });
8699
+ const STRUCTURE_COLOR = "#64748B";
8700
+ const LINE_HEIGHT = 18;
8701
+ const HEADER_HEIGHT = 32;
8702
+ const BODY_PADDING = 8;
8703
+ const StructureNode = memo(function StructureNode2({ id, data, selected }) {
8704
+ const debugClassName = useDebugClassName(id);
8705
+ const toggleNodeCollapse = useNodeCollapse(id);
8706
+ const isCollapsed = data.collapsed ?? false;
8707
+ const expressionElements = useMemo(() => data.elements.filter((e) => e.type === "expression"), [
8708
+ data.elements
8709
+ ]);
8710
+ const hasExpressions = expressionElements.length > 0;
8711
+ const expressionLineNumbers = useMemo(() => {
8712
+ return expressionElements.map((element) => {
8713
+ const textBefore = data.formattedJson.slice(0, element.startOffset);
8714
+ const lineNumber = textBefore.split("\n").length;
8715
+ return lineNumber;
8716
+ });
8717
+ }, [
8718
+ expressionElements,
8719
+ data.formattedJson
8720
+ ]);
8721
+ return jsxs("div", {
8722
+ className: `structure-node ${selected ? "selected" : ""} ${isCollapsed ? "collapsed" : ""} ${debugClassName}`,
8723
+ style: {
8724
+ borderColor: STRUCTURE_COLOR,
8725
+ backgroundColor: `${STRUCTURE_COLOR}10`
8726
+ },
8727
+ children: [
8728
+ jsx(NodeDebugBubble, {
8729
+ nodeId: id,
8730
+ position: "top"
8731
+ }),
8732
+ jsx(NodeInputHandles, {
8733
+ nodeId: id,
8734
+ color: STRUCTURE_COLOR
8735
+ }),
8736
+ jsxs("div", {
8737
+ className: "structure-node-header",
8738
+ style: {
8739
+ backgroundColor: STRUCTURE_COLOR
8740
+ },
8741
+ children: [
8742
+ jsx("span", {
8743
+ className: "structure-node-icon",
8744
+ children: jsx(Icon, {
8745
+ name: data.isArray ? "list" : "braces",
8746
+ size: 14
8747
+ })
8748
+ }),
8749
+ jsx("span", {
8750
+ className: "structure-node-label",
8751
+ children: data.isArray ? "Array" : "Object"
8752
+ }),
8753
+ hasExpressions && jsx(CollapseToggleButton, {
8754
+ isCollapsed,
8755
+ onClick: toggleNodeCollapse
8756
+ })
8757
+ ]
8758
+ }),
8759
+ isCollapsed ? jsx("div", {
8760
+ className: "structure-node-body collapsed-body",
8761
+ children: jsx("div", {
8762
+ className: "expression-text",
8763
+ children: jsx(ExpressionSyntax, {
8764
+ text: data.expressionText || "..."
8765
+ })
8766
+ })
8767
+ }) : jsx("div", {
8768
+ className: "structure-node-body",
8769
+ children: jsx(FormattedJson, {
8770
+ json: data.formattedJson,
8771
+ elements: data.elements
8772
+ })
8773
+ }),
8774
+ !isCollapsed && expressionElements.map((_element, idx) => {
8775
+ const lineNumber = expressionLineNumbers[idx];
8776
+ const topPosition = HEADER_HEIGHT + BODY_PADDING + (lineNumber - 1) * LINE_HEIGHT + LINE_HEIGHT / 2;
8777
+ return jsx(Handle, {
8778
+ type: "source",
8779
+ position: Position.Right,
8780
+ id: `branch-${idx}`,
8781
+ className: "structure-branch-handle",
8782
+ style: {
8783
+ background: "#3B82F6",
8784
+ top: `${topPosition}px`,
8785
+ right: "-4px"
8786
+ }
8787
+ }, `branch-${idx}`);
8788
+ })
8789
+ ]
8790
+ });
8791
+ });
8792
+ function FormattedJson({ json: json2, elements }) {
8793
+ const expressionElements = elements.filter((e) => e.type === "expression").sort((a, b) => a.startOffset - b.startOffset);
8794
+ if (expressionElements.length === 0) {
8795
+ return jsx(JsonSyntax, {
8796
+ text: json2
8797
+ });
8798
+ }
8799
+ const parts = [];
8800
+ let lastEnd = 0;
8801
+ let markerIndex = 0;
8802
+ for (const element of expressionElements) {
8803
+ if (element.startOffset > lastEnd) {
8804
+ const textBefore = json2.slice(lastEnd, element.startOffset);
8805
+ parts.push(jsx(JsonSyntax, {
8806
+ text: textBefore
8807
+ }, `text-${lastEnd}`));
8808
+ }
8809
+ parts.push(jsx("span", {
8810
+ className: "structure-expression-marker",
8811
+ children: element.key || `[${markerIndex}]`
8812
+ }, `marker-${markerIndex}`));
8813
+ lastEnd = element.endOffset;
8814
+ markerIndex++;
8815
+ }
8816
+ if (lastEnd < json2.length) {
8817
+ parts.push(jsx(JsonSyntax, {
8818
+ text: json2.slice(lastEnd)
8819
+ }, `text-${lastEnd}`));
8820
+ }
8821
+ return jsx(Fragment, {
8822
+ children: parts
8823
+ });
8824
+ }
8825
+ function JsonSyntax({ text }) {
8826
+ const highlighted = highlightJson(text);
8827
+ return jsx(Fragment, {
8828
+ children: highlighted
8829
+ });
8830
+ }
8831
+ function highlightJson(text) {
8832
+ const result = [];
8833
+ let i = 0;
8834
+ while (i < text.length) {
8835
+ const char = text[i];
8836
+ if (/\s/.test(char)) {
8837
+ let whitespace = "";
8838
+ while (i < text.length && /\s/.test(text[i])) {
8839
+ whitespace += text[i];
8840
+ i++;
8841
+ }
8842
+ result.push(whitespace);
8843
+ continue;
8844
+ }
8845
+ if (char === '"') {
8846
+ let str = '"';
8847
+ i++;
8848
+ while (i < text.length && text[i] !== '"') {
8849
+ if (text[i] === "\\" && i + 1 < text.length) {
8850
+ str += text[i] + text[i + 1];
8851
+ i += 2;
8852
+ } else {
8853
+ str += text[i];
8854
+ i++;
8855
+ }
8856
+ }
8857
+ if (i < text.length) {
8858
+ str += '"';
8859
+ i++;
8860
+ }
8861
+ let j = i;
8862
+ while (j < text.length && /\s/.test(text[j])) j++;
8863
+ const isKey = text[j] === ":";
8864
+ result.push(jsx("span", {
8865
+ className: isKey ? "json-syntax-key" : "json-syntax-string",
8866
+ children: str
8867
+ }, `str-${i}`));
8868
+ continue;
8869
+ }
8870
+ if (/[-\d]/.test(char)) {
8871
+ let num = "";
8872
+ while (i < text.length && /[-\d.eE+]/.test(text[i])) {
8873
+ num += text[i];
8874
+ i++;
8875
+ }
8876
+ result.push(jsx("span", {
8877
+ className: "json-syntax-number",
8878
+ children: num
8879
+ }, `num-${i}`));
8880
+ continue;
8881
+ }
8882
+ if (text.slice(i, i + 4) === "true") {
8883
+ result.push(jsx("span", {
8884
+ className: "json-syntax-boolean-true",
8885
+ children: "true"
8886
+ }, `bool-${i}`));
8887
+ i += 4;
8888
+ continue;
8889
+ }
8890
+ if (text.slice(i, i + 5) === "false") {
8891
+ result.push(jsx("span", {
8892
+ className: "json-syntax-boolean-false",
8893
+ children: "false"
8894
+ }, `bool-${i}`));
8895
+ i += 5;
8896
+ continue;
8897
+ }
8898
+ if (text.slice(i, i + 4) === "null") {
8899
+ result.push(jsx("span", {
8900
+ className: "json-syntax-null",
8901
+ children: "null"
8902
+ }, `null-${i}`));
8903
+ i += 4;
8904
+ continue;
8905
+ }
8906
+ if (/[{}[\]:,]/.test(char)) {
8907
+ result.push(jsx("span", {
8908
+ className: "json-syntax-punctuation",
8909
+ children: char
8910
+ }, `punct-${i}`));
8911
+ i++;
8912
+ continue;
8913
+ }
8914
+ result.push(char);
8915
+ i++;
8916
+ }
8917
+ return result;
8918
+ }
8378
8919
  const nodeTypes = {
8379
8920
  operator: OperatorNode,
8380
8921
  variable: VariableNode,
8381
8922
  literal: LiteralNode,
8382
- verticalCell: VerticalCellNode
8923
+ verticalCell: VerticalCellNode,
8924
+ structure: StructureNode
8383
8925
  };
8384
8926
  function collectCellBranchIds(cell, target) {
8385
8927
  if (cell.branchId) target.add(cell.branchId);
@@ -8443,6 +8985,79 @@ let __tla = (async () => {
8443
8985
  });
8444
8986
  return hiddenIds;
8445
8987
  }
8988
+ function buildEdgesFromNodes(nodes) {
8989
+ const edges = [];
8990
+ nodes.forEach((node) => {
8991
+ if (node.type === "operator") {
8992
+ const opData = node.data;
8993
+ if (!opData.collapsed) {
8994
+ opData.childIds.forEach((childId, idx) => {
8995
+ edges.push({
8996
+ id: `${node.id}-${childId}`,
8997
+ source: node.id,
8998
+ target: childId,
8999
+ sourceHandle: `arg-${idx}`,
9000
+ targetHandle: "left"
9001
+ });
9002
+ });
9003
+ }
9004
+ }
9005
+ if (node.type === "verticalCell") {
9006
+ const vcData = node.data;
9007
+ if (!vcData.collapsed) {
9008
+ const collapsedIndices = vcData.collapsedCellIndices || [];
9009
+ vcData.cells.forEach((cell) => {
9010
+ if (collapsedIndices.includes(cell.index)) return;
9011
+ if (cell.conditionBranchId) {
9012
+ edges.push({
9013
+ id: `${node.id}-cond-${cell.conditionBranchId}`,
9014
+ source: node.id,
9015
+ target: cell.conditionBranchId,
9016
+ sourceHandle: `branch-${cell.index}-cond`,
9017
+ targetHandle: "left"
9018
+ });
9019
+ }
9020
+ if (cell.thenBranchId) {
9021
+ edges.push({
9022
+ id: `${node.id}-then-${cell.thenBranchId}`,
9023
+ source: node.id,
9024
+ target: cell.thenBranchId,
9025
+ sourceHandle: `branch-${cell.index}-then`,
9026
+ targetHandle: "left"
9027
+ });
9028
+ }
9029
+ if (cell.branchId && !cell.conditionBranchId && !cell.thenBranchId) {
9030
+ edges.push({
9031
+ id: `${node.id}-branch-${cell.branchId}`,
9032
+ source: node.id,
9033
+ target: cell.branchId,
9034
+ sourceHandle: `branch-${cell.index}`,
9035
+ targetHandle: "left"
9036
+ });
9037
+ }
9038
+ });
9039
+ }
9040
+ }
9041
+ if (node.type === "structure") {
9042
+ const structData = node.data;
9043
+ if (!structData.collapsed && structData.elements) {
9044
+ const expressionElements = structData.elements.filter((el) => el.type === "expression" && el.branchId);
9045
+ expressionElements.forEach((element, idx) => {
9046
+ if (element.branchId) {
9047
+ edges.push({
9048
+ id: `${node.id}-expr-${element.branchId}`,
9049
+ source: node.id,
9050
+ target: element.branchId,
9051
+ sourceHandle: `expr-${idx}`,
9052
+ targetHandle: "left"
9053
+ });
9054
+ }
9055
+ });
9056
+ }
9057
+ }
9058
+ });
9059
+ return edges;
9060
+ }
8446
9061
  function DebuggerControls() {
8447
9062
  const { state, play, pause, reset, stepForward, stepBackward, goToStep, setSpeed } = useDebuggerContext();
8448
9063
  const { steps, currentStepIndex, playbackState, playbackSpeed } = state;
@@ -8639,15 +9254,12 @@ let __tla = (async () => {
8639
9254
  function DataLogicEditorInner({ initialNodes, initialEdges, readOnly, evaluationResults, theme, showDebugger }) {
8640
9255
  const bgColor = theme === "dark" ? "#404040" : "#cccccc";
8641
9256
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
8642
- const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
9257
+ const [, , onEdgesChange] = useEdgesState(initialEdges);
8643
9258
  useEffect(() => {
8644
9259
  setNodes(initialNodes);
8645
- setEdges(initialEdges);
8646
9260
  }, [
8647
9261
  initialNodes,
8648
- initialEdges,
8649
- setNodes,
8650
- setEdges
9262
+ setNodes
8651
9263
  ]);
8652
9264
  const hiddenNodeIds = useMemo(() => getHiddenNodeIds(nodes), [
8653
9265
  nodes
@@ -8659,8 +9271,11 @@ let __tla = (async () => {
8659
9271
  nodes,
8660
9272
  hiddenNodeIds
8661
9273
  ]);
8662
- const visibleEdges = useMemo(() => edges.filter((edge) => nodeIds.has(edge.source) && nodeIds.has(edge.target) && !hiddenNodeIds.has(edge.source) && !hiddenNodeIds.has(edge.target)), [
8663
- edges,
9274
+ const currentEdges = useMemo(() => buildEdgesFromNodes(nodes), [
9275
+ nodes
9276
+ ]);
9277
+ const visibleEdges = useMemo(() => currentEdges.filter((edge) => nodeIds.has(edge.source) && nodeIds.has(edge.target) && !hiddenNodeIds.has(edge.source) && !hiddenNodeIds.has(edge.target)), [
9278
+ currentEdges,
8664
9279
  nodeIds,
8665
9280
  hiddenNodeIds
8666
9281
  ]);
@@ -8719,20 +9334,24 @@ let __tla = (async () => {
8719
9334
  })
8720
9335
  });
8721
9336
  }
8722
- DataLogicEditor = function({ value, onChange: _onChange, data, mode = "visualize", theme: themeProp, className = "" }) {
9337
+ DataLogicEditor = function({ value, onChange: _onChange, data, mode = "visualize", theme: themeProp, className = "", preserveStructure = false }) {
9338
+ var _a;
8723
9339
  if (mode === "edit") {
8724
9340
  console.warn("[DataLogicEditor] Edit mode is not yet implemented. Component will render in read-only mode with debug evaluation if data is provided.");
8725
9341
  }
8726
9342
  const systemTheme = useSystemTheme();
8727
9343
  const resolvedTheme = themeProp ?? systemTheme;
8728
- const { ready: wasmReady, evaluate, evaluateWithTrace } = useWasmEvaluator();
9344
+ const { ready: wasmReady, evaluate, evaluateWithTrace } = useWasmEvaluator({
9345
+ preserveStructure
9346
+ });
8729
9347
  const debugEnabled = mode === "debug" && data !== void 0;
8730
9348
  const editor = useLogicEditor({
8731
9349
  value,
8732
9350
  evaluateWithTrace: debugEnabled && wasmReady ? evaluateWithTrace : void 0,
8733
- data: debugEnabled ? data : void 0
9351
+ data: debugEnabled ? data : void 0,
9352
+ preserveStructure
8734
9353
  });
8735
- const expressionKey = editor.nodes.length > 0 ? editor.nodes[0].id : "empty";
9354
+ const expressionKey = `${editor.nodes.length}-${editor.edges.length}-${((_a = editor.nodes[0]) == null ? void 0 : _a.id) ?? "empty"}`;
8736
9355
  const fallbackResults = useDebugEvaluation({
8737
9356
  nodes: editor.nodes,
8738
9357
  data,
@@ -8760,7 +9379,7 @@ let __tla = (async () => {
8760
9379
  });
8761
9380
  }
8762
9381
  const showDebugger = debugEnabled && editor.usingTraceMode && editor.steps.length > 0;
8763
- const readOnly = mode !== "edit";
9382
+ const readOnly = false;
8764
9383
  const editorInner = jsx(DataLogicEditorInner, {
8765
9384
  initialNodes: editor.nodes,
8766
9385
  initialEdges: editor.edges,