@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.cjs CHANGED
@@ -21,147 +21,6 @@ const CATEGORY_COLORS = {
21
21
  literal: "#6B7280"
22
22
  };
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
- // ISO date
39
- /^\d{2}\/\d{2}\/\d{4}/,
40
- // MM/DD/YYYY
41
- /^\d{2}-\d{2}-\d{4}/
42
- // DD-MM-YYYY
43
- ];
44
- return datePatterns.some((pattern) => pattern.test(str));
45
- }
46
- function isSimpleOperand(operand) {
47
- if (operand === null || typeof operand !== "object") {
48
- return true;
49
- }
50
- if (Array.isArray(operand)) {
51
- return operand.length === 0;
52
- }
53
- return false;
54
- }
55
-
56
- const COMPARISON_OPERATORS$1 = ["==", "===", "!=", "!==", ">", ">=", "<", "<="];
57
- const ITERATOR_OPERATORS = ["map", "reduce", "filter", "some", "none", "all"];
58
- const UNARY_OPERATORS$2 = ["!", "!!"];
59
- const ARITHMETIC_BINARY_OPERATORS = ["+", "-", "*", "/", "%"];
60
- function generateExpressionText(value, maxLength = 100) {
61
- function getOperator(val) {
62
- if (isPlainObject(val)) {
63
- const keys = Object.keys(val);
64
- if (keys.length === 1) return keys[0];
65
- }
66
- return null;
67
- }
68
- function needsParens(subVal, parentOp) {
69
- const subOp = getOperator(subVal);
70
- if (!subOp) return false;
71
- if (parentOp === "and" && subOp === "or" || parentOp === "or" && subOp === "and") {
72
- return true;
73
- }
74
- if (COMPARISON_OPERATORS$1.includes(parentOp) && (subOp === "and" || subOp === "or")) {
75
- return true;
76
- }
77
- if ((parentOp === "*" || parentOp === "/") && (subOp === "+" || subOp === "-")) {
78
- return true;
79
- }
80
- return false;
81
- }
82
- function toText(val, _parentOp) {
83
- if (val === null) return "null";
84
- if (typeof val === "boolean") return String(val);
85
- if (typeof val === "number") return String(val);
86
- if (typeof val === "string") return `"${val}"`;
87
- if (Array.isArray(val)) {
88
- if (val.length === 0) return "[]";
89
- const items = val.map((v) => toText(v)).join(", ");
90
- return `[${items}]`;
91
- }
92
- if (isPlainObject(val)) {
93
- const keys = Object.keys(val);
94
- if (keys.length !== 1) return JSON.stringify(val);
95
- const op = keys[0];
96
- const operands = val[op];
97
- if (op === "var") {
98
- const path = Array.isArray(operands) ? operands[0] : operands;
99
- return String(path ?? "");
100
- }
101
- if (op === "val") {
102
- const path = Array.isArray(operands) ? operands[0] : operands;
103
- return `val(${path ?? ""})`;
104
- }
105
- if (op === "exists") {
106
- return `exists(${operands})`;
107
- }
108
- const args = Array.isArray(operands) ? operands : [operands];
109
- const wrapIfNeeded = (subVal) => {
110
- const text2 = toText(subVal);
111
- return needsParens(subVal, op) ? `(${text2})` : text2;
112
- };
113
- if ([...COMPARISON_OPERATORS$1, ...ARITHMETIC_BINARY_OPERATORS].includes(op)) {
114
- if (args.length === 2) {
115
- return `${wrapIfNeeded(args[0])} ${op} ${wrapIfNeeded(args[1])}`;
116
- }
117
- if (args.length > 2) {
118
- return args.map(wrapIfNeeded).join(` ${op} `);
119
- }
120
- }
121
- if (op === "and") {
122
- return args.map(wrapIfNeeded).join(" AND ");
123
- }
124
- if (op === "or") {
125
- return args.map(wrapIfNeeded).join(" OR ");
126
- }
127
- if (UNARY_OPERATORS$2.includes(op)) {
128
- const argText = toText(args[0]);
129
- const subOp = getOperator(args[0]);
130
- if (subOp && (subOp === "and" || subOp === "or" || COMPARISON_OPERATORS$1.includes(subOp))) {
131
- return `${op}(${argText})`;
132
- }
133
- return `${op}${argText}`;
134
- }
135
- if (ITERATOR_OPERATORS.includes(op)) {
136
- const [arr] = args;
137
- return `${op}(${toText(arr)}, ...)`;
138
- }
139
- if (op === "if" || op === "?:") {
140
- const parts = [];
141
- let i = 0;
142
- while (i < args.length) {
143
- if (i + 1 < args.length) {
144
- const prefix = i === 0 ? "if" : "else if";
145
- parts.push(`${prefix} ${toText(args[i])} then ${toText(args[i + 1])}`);
146
- i += 2;
147
- } else {
148
- parts.push(`else ${toText(args[i])}`);
149
- i++;
150
- }
151
- }
152
- return parts.join(" ");
153
- }
154
- return `${op}(${args.map((a) => toText(a)).join(", ")})`;
155
- }
156
- return String(val);
157
- }
158
- const text = toText(value);
159
- if (text.length > maxLength) {
160
- return text.slice(0, maxLength - 3) + "...";
161
- }
162
- return text;
163
- }
164
-
165
24
  const OPERATORS = {
166
25
  // Variable operators
167
26
  var: {
@@ -658,6 +517,162 @@ function getOperatorMeta(operator) {
658
517
  description: `Unknown operator: ${operator}`
659
518
  };
660
519
  }
520
+ function isOperator(key) {
521
+ return key in OPERATORS;
522
+ }
523
+
524
+ function isPlainObject(value) {
525
+ return typeof value === "object" && value !== null && !Array.isArray(value);
526
+ }
527
+ function isJsonLogicExpression(value) {
528
+ if (!isPlainObject(value)) return false;
529
+ const keys = Object.keys(value);
530
+ return keys.length === 1 && isOperator(keys[0]);
531
+ }
532
+ function isDataStructure(value) {
533
+ if (Array.isArray(value)) return value.length > 0;
534
+ if (!isPlainObject(value)) return false;
535
+ const keys = Object.keys(value);
536
+ if (keys.length > 1) return true;
537
+ return keys.length === 1 && !isOperator(keys[0]);
538
+ }
539
+ function getValueType$1(value) {
540
+ if (value === null) return "null";
541
+ if (typeof value === "boolean") return "boolean";
542
+ if (typeof value === "number") return "number";
543
+ if (typeof value === "string") return "string";
544
+ if (Array.isArray(value)) return "array";
545
+ return "string";
546
+ }
547
+ function looksLikeDate(str) {
548
+ const datePatterns = [
549
+ /^\d{4}-\d{2}-\d{2}/,
550
+ // ISO date
551
+ /^\d{2}\/\d{2}\/\d{4}/,
552
+ // MM/DD/YYYY
553
+ /^\d{2}-\d{2}-\d{4}/
554
+ // DD-MM-YYYY
555
+ ];
556
+ return datePatterns.some((pattern) => pattern.test(str));
557
+ }
558
+ function isSimpleOperand(operand) {
559
+ if (operand === null || typeof operand !== "object") {
560
+ return true;
561
+ }
562
+ if (Array.isArray(operand)) {
563
+ return operand.length === 0;
564
+ }
565
+ return false;
566
+ }
567
+
568
+ const COMPARISON_OPERATORS$1 = ["==", "===", "!=", "!==", ">", ">=", "<", "<="];
569
+ const ITERATOR_OPERATORS = ["map", "reduce", "filter", "some", "none", "all"];
570
+ const UNARY_OPERATORS$2 = ["!", "!!"];
571
+ const ARITHMETIC_BINARY_OPERATORS = ["+", "-", "*", "/", "%"];
572
+ function generateExpressionText(value, maxLength = 100) {
573
+ function getOperator(val) {
574
+ if (isPlainObject(val)) {
575
+ const keys = Object.keys(val);
576
+ if (keys.length === 1) return keys[0];
577
+ }
578
+ return null;
579
+ }
580
+ function needsParens(subVal, parentOp) {
581
+ const subOp = getOperator(subVal);
582
+ if (!subOp) return false;
583
+ if (parentOp === "and" && subOp === "or" || parentOp === "or" && subOp === "and") {
584
+ return true;
585
+ }
586
+ if (COMPARISON_OPERATORS$1.includes(parentOp) && (subOp === "and" || subOp === "or")) {
587
+ return true;
588
+ }
589
+ if ((parentOp === "*" || parentOp === "/") && (subOp === "+" || subOp === "-")) {
590
+ return true;
591
+ }
592
+ return false;
593
+ }
594
+ function toText(val, _parentOp) {
595
+ if (val === null) return "null";
596
+ if (typeof val === "boolean") return String(val);
597
+ if (typeof val === "number") return String(val);
598
+ if (typeof val === "string") return `"${val}"`;
599
+ if (Array.isArray(val)) {
600
+ if (val.length === 0) return "[]";
601
+ const items = val.map((v) => toText(v)).join(", ");
602
+ return `[${items}]`;
603
+ }
604
+ if (isPlainObject(val)) {
605
+ const keys = Object.keys(val);
606
+ if (keys.length !== 1) return JSON.stringify(val);
607
+ const op = keys[0];
608
+ const operands = val[op];
609
+ if (op === "var") {
610
+ const path = Array.isArray(operands) ? operands[0] : operands;
611
+ return String(path ?? "");
612
+ }
613
+ if (op === "val") {
614
+ const path = Array.isArray(operands) ? operands[0] : operands;
615
+ return `val(${path ?? ""})`;
616
+ }
617
+ if (op === "exists") {
618
+ return `exists(${operands})`;
619
+ }
620
+ const args = Array.isArray(operands) ? operands : [operands];
621
+ const wrapIfNeeded = (subVal) => {
622
+ const text2 = toText(subVal);
623
+ return needsParens(subVal, op) ? `(${text2})` : text2;
624
+ };
625
+ if ([...COMPARISON_OPERATORS$1, ...ARITHMETIC_BINARY_OPERATORS].includes(op)) {
626
+ if (args.length === 2) {
627
+ return `${wrapIfNeeded(args[0])} ${op} ${wrapIfNeeded(args[1])}`;
628
+ }
629
+ if (args.length > 2) {
630
+ return args.map(wrapIfNeeded).join(` ${op} `);
631
+ }
632
+ }
633
+ if (op === "and") {
634
+ return args.map(wrapIfNeeded).join(" AND ");
635
+ }
636
+ if (op === "or") {
637
+ return args.map(wrapIfNeeded).join(" OR ");
638
+ }
639
+ if (UNARY_OPERATORS$2.includes(op)) {
640
+ const argText = toText(args[0]);
641
+ const subOp = getOperator(args[0]);
642
+ if (subOp && (subOp === "and" || subOp === "or" || COMPARISON_OPERATORS$1.includes(subOp))) {
643
+ return `${op}(${argText})`;
644
+ }
645
+ return `${op}${argText}`;
646
+ }
647
+ if (ITERATOR_OPERATORS.includes(op)) {
648
+ const [arr] = args;
649
+ return `${op}(${toText(arr)}, ...)`;
650
+ }
651
+ if (op === "if" || op === "?:") {
652
+ const parts = [];
653
+ let i = 0;
654
+ while (i < args.length) {
655
+ if (i + 1 < args.length) {
656
+ const prefix = i === 0 ? "if" : "else if";
657
+ parts.push(`${prefix} ${toText(args[i])} then ${toText(args[i + 1])}`);
658
+ i += 2;
659
+ } else {
660
+ parts.push(`else ${toText(args[i])}`);
661
+ i++;
662
+ }
663
+ }
664
+ return parts.join(" ");
665
+ }
666
+ return `${op}(${args.map((a) => toText(a)).join(", ")})`;
667
+ }
668
+ return String(val);
669
+ }
670
+ const text = toText(value);
671
+ if (text.length > maxLength) {
672
+ return text.slice(0, maxLength - 3) + "...";
673
+ }
674
+ return text;
675
+ }
661
676
 
662
677
  const TRUNCATION_LIMITS = {
663
678
  shortLabel: 20,
@@ -829,11 +844,11 @@ const createLucideIcon = (iconName, iconNode) => {
829
844
  */
830
845
 
831
846
 
832
- const __iconNode$v = [
847
+ const __iconNode$w = [
833
848
  ["path", { d: "M4.929 4.929 19.07 19.071", key: "196cmz" }],
834
849
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
835
850
  ];
836
- const Ban = createLucideIcon("ban", __iconNode$v);
851
+ const Ban = createLucideIcon("ban", __iconNode$w);
837
852
 
838
853
  /**
839
854
  * @license lucide-react v0.562.0 - ISC
@@ -843,7 +858,7 @@ const Ban = createLucideIcon("ban", __iconNode$v);
843
858
  */
844
859
 
845
860
 
846
- const __iconNode$u = [
861
+ const __iconNode$v = [
847
862
  [
848
863
  "path",
849
864
  {
@@ -854,7 +869,7 @@ const __iconNode$u = [
854
869
  ["path", { d: "m3.3 7 8.7 5 8.7-5", key: "g66t2b" }],
855
870
  ["path", { d: "M12 22V12", key: "d0xqtd" }]
856
871
  ];
857
- const Box = createLucideIcon("box", __iconNode$u);
872
+ const Box = createLucideIcon("box", __iconNode$v);
858
873
 
859
874
  /**
860
875
  * @license lucide-react v0.562.0 - ISC
@@ -864,7 +879,7 @@ const Box = createLucideIcon("box", __iconNode$u);
864
879
  */
865
880
 
866
881
 
867
- const __iconNode$t = [
882
+ const __iconNode$u = [
868
883
  [
869
884
  "path",
870
885
  {
@@ -896,7 +911,30 @@ const __iconNode$t = [
896
911
  ["path", { d: "m12 8 4.74-2.85", key: "3rx089" }],
897
912
  ["path", { d: "M12 13.5V8", key: "1io7kd" }]
898
913
  ];
899
- const Boxes = createLucideIcon("boxes", __iconNode$t);
914
+ const Boxes = createLucideIcon("boxes", __iconNode$u);
915
+
916
+ /**
917
+ * @license lucide-react v0.562.0 - ISC
918
+ *
919
+ * This source code is licensed under the ISC license.
920
+ * See the LICENSE file in the root directory of this source tree.
921
+ */
922
+
923
+
924
+ const __iconNode$t = [
925
+ [
926
+ "path",
927
+ { 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", key: "ezmyqa" }
928
+ ],
929
+ [
930
+ "path",
931
+ {
932
+ 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",
933
+ key: "e1hn23"
934
+ }
935
+ ]
936
+ ];
937
+ const Braces = createLucideIcon("braces", __iconNode$t);
900
938
 
901
939
  /**
902
940
  * @license lucide-react v0.562.0 - ISC
@@ -1404,7 +1442,8 @@ const ICON_COMPONENTS = {
1404
1442
  "git-commit-horizontal": GitCommitHorizontal,
1405
1443
  "search": Search,
1406
1444
  "divide": Divide,
1407
- "quote": Quote
1445
+ "quote": Quote,
1446
+ "braces": Braces
1408
1447
  };
1409
1448
  function Icon({ name, size = 14, className, style }) {
1410
1449
  const IconComponent = ICON_COMPONENTS[name];
@@ -1905,7 +1944,8 @@ function convertIfElse(ifArgs, context, convertValue) {
1905
1944
  edges: context.edges,
1906
1945
  parentId: parentInfo.parentId,
1907
1946
  argIndex: parentInfo.argIndex,
1908
- branchType: parentInfo.branchType
1947
+ branchType: parentInfo.branchType,
1948
+ preserveStructure: context.preserveStructure
1909
1949
  });
1910
1950
  }
1911
1951
  const cells = [];
@@ -1920,7 +1960,8 @@ function convertIfElse(ifArgs, context, convertValue) {
1920
1960
  nodes: context.nodes,
1921
1961
  edges: context.edges,
1922
1962
  parentId: nodeId,
1923
- argIndex: idx
1963
+ argIndex: idx,
1964
+ preserveStructure: context.preserveStructure
1924
1965
  });
1925
1966
  context.edges.push({
1926
1967
  id: `${nodeId}-cond-${conditionBranchId}`,
@@ -1945,7 +1986,8 @@ function convertIfElse(ifArgs, context, convertValue) {
1945
1986
  edges: context.edges,
1946
1987
  parentId: nodeId,
1947
1988
  argIndex: idx + 1,
1948
- branchType: "yes"
1989
+ branchType: "yes",
1990
+ preserveStructure: context.preserveStructure
1949
1991
  });
1950
1992
  context.edges.push({
1951
1993
  id: `${nodeId}-then-${thenBranchId}`,
@@ -1975,7 +2017,8 @@ function convertIfElse(ifArgs, context, convertValue) {
1975
2017
  edges: context.edges,
1976
2018
  parentId: nodeId,
1977
2019
  argIndex: ifArgs.length - 1,
1978
- branchType: "no"
2020
+ branchType: "no",
2021
+ preserveStructure: context.preserveStructure
1979
2022
  });
1980
2023
  context.edges.push({
1981
2024
  id: `${nodeId}-else-${elseBranchId}`,
@@ -2049,7 +2092,8 @@ function convertToVerticalCell(operator, operandArray, context, convertValue) {
2049
2092
  nodes: context.nodes,
2050
2093
  edges: context.edges,
2051
2094
  parentId: nodeId,
2052
- argIndex: idx
2095
+ argIndex: idx,
2096
+ preserveStructure: context.preserveStructure
2053
2097
  });
2054
2098
  const summary = generateArgSummary(operand);
2055
2099
  summary.label = generateExpressionText(operand, TRUNCATION_LIMITS.expressionText);
@@ -2137,7 +2181,8 @@ function convertOperatorWithChildren(operator, operandArray, value, context, con
2137
2181
  nodes: context.nodes,
2138
2182
  edges: context.edges,
2139
2183
  parentId: nodeId,
2140
- argIndex: idx
2184
+ argIndex: idx,
2185
+ preserveStructure: context.preserveStructure
2141
2186
  });
2142
2187
  childIds.push(childId);
2143
2188
  });
@@ -2172,7 +2217,120 @@ function isUnaryOperator(operator) {
2172
2217
  return UNARY_OPERATORS$1.includes(operator);
2173
2218
  }
2174
2219
 
2220
+ const EXPR_PLACEHOLDER$1 = "{{EXPR}}";
2221
+ const EXPR_PLACEHOLDER_QUOTED$1 = `"${EXPR_PLACEHOLDER$1}"`;
2222
+ function convertStructure(value, context, convertValue) {
2223
+ const parentInfo = getParentInfo(context);
2224
+ const nodeId = v4();
2225
+ const isArray = Array.isArray(value);
2226
+ const elements = [];
2227
+ let expressionIndex = 0;
2228
+ const structureWithPlaceholders = walkAndCollect(
2229
+ value,
2230
+ [],
2231
+ (path, item, key) => {
2232
+ if (isJsonLogicExpression(item)) {
2233
+ const branchId = convertValue(item, {
2234
+ nodes: context.nodes,
2235
+ edges: context.edges,
2236
+ parentId: nodeId,
2237
+ argIndex: expressionIndex,
2238
+ preserveStructure: context.preserveStructure
2239
+ });
2240
+ elements.push({
2241
+ type: "expression",
2242
+ path,
2243
+ key,
2244
+ branchId,
2245
+ startOffset: 0,
2246
+ // Will be calculated after formatting
2247
+ endOffset: 0
2248
+ });
2249
+ expressionIndex++;
2250
+ return EXPR_PLACEHOLDER$1;
2251
+ } else {
2252
+ return item;
2253
+ }
2254
+ }
2255
+ );
2256
+ const formattedJson = JSON.stringify(structureWithPlaceholders, null, 2);
2257
+ let searchPos = 0;
2258
+ for (const element of elements) {
2259
+ if (element.type === "expression") {
2260
+ const placeholderPos = formattedJson.indexOf(EXPR_PLACEHOLDER_QUOTED$1, searchPos);
2261
+ if (placeholderPos !== -1) {
2262
+ element.startOffset = placeholderPos;
2263
+ element.endOffset = placeholderPos + EXPR_PLACEHOLDER_QUOTED$1.length;
2264
+ searchPos = element.endOffset;
2265
+ }
2266
+ }
2267
+ }
2268
+ const expressionText = generateExpressionText(value, 100);
2269
+ const node = {
2270
+ id: nodeId,
2271
+ type: "structure",
2272
+ position: { x: 0, y: 0 },
2273
+ data: {
2274
+ type: "structure",
2275
+ isArray,
2276
+ formattedJson,
2277
+ elements,
2278
+ collapsed: false,
2279
+ expressionText,
2280
+ expression: value,
2281
+ parentId: parentInfo.parentId,
2282
+ argIndex: parentInfo.argIndex,
2283
+ branchType: parentInfo.branchType
2284
+ }
2285
+ };
2286
+ context.nodes.push(node);
2287
+ if (parentInfo.parentId && !parentInfo.branchType) {
2288
+ const edge = createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0);
2289
+ context.edges.push(edge);
2290
+ }
2291
+ let branchIdx = 0;
2292
+ for (const element of elements) {
2293
+ if (element.type === "expression" && element.branchId) {
2294
+ const edge = createBranchEdge(nodeId, element.branchId, branchIdx);
2295
+ context.edges.push(edge);
2296
+ branchIdx++;
2297
+ }
2298
+ }
2299
+ return nodeId;
2300
+ }
2301
+ function walkAndCollect(value, path, onValue) {
2302
+ if (Array.isArray(value)) {
2303
+ return value.map((item, index) => {
2304
+ const itemPath = [...path, String(index)];
2305
+ if (isJsonLogicExpression(item)) {
2306
+ return onValue(itemPath, item);
2307
+ } else if (typeof item === "object" && item !== null) {
2308
+ return walkAndCollect(item, itemPath, onValue);
2309
+ }
2310
+ return item;
2311
+ });
2312
+ }
2313
+ if (typeof value === "object" && value !== null) {
2314
+ const result = {};
2315
+ for (const [key, item] of Object.entries(value)) {
2316
+ const itemPath = [...path, key];
2317
+ if (isJsonLogicExpression(item)) {
2318
+ result[key] = onValue(itemPath, item, key);
2319
+ } else if (typeof item === "object" && item !== null) {
2320
+ result[key] = walkAndCollect(item, itemPath, onValue);
2321
+ } else {
2322
+ result[key] = item;
2323
+ }
2324
+ }
2325
+ return result;
2326
+ }
2327
+ return value;
2328
+ }
2329
+
2175
2330
  function convertValue(value, context) {
2331
+ if (context.preserveStructure && isDataStructure(value)) {
2332
+ return convertStructure(value, context, convertValue);
2333
+ }
2176
2334
  if (!isPlainObject(value)) {
2177
2335
  return convertPrimitive(value, context);
2178
2336
  }
@@ -2202,13 +2360,17 @@ function convertValue(value, context) {
2202
2360
  return convertOperatorWithChildren(operator, operandArray, value, context, convertValue);
2203
2361
  }
2204
2362
 
2205
- function jsonLogicToNodes(expr) {
2363
+ function jsonLogicToNodes(expr, options = {}) {
2206
2364
  if (expr === null || expr === void 0) {
2207
2365
  return { nodes: [], edges: [], rootId: null };
2208
2366
  }
2209
2367
  const nodes = [];
2210
2368
  const edges = [];
2211
- const rootId = convertValue(expr, { nodes, edges });
2369
+ const rootId = convertValue(expr, {
2370
+ nodes,
2371
+ edges,
2372
+ preserveStructure: options.preserveStructure
2373
+ });
2212
2374
  return { nodes, edges, rootId };
2213
2375
  }
2214
2376
 
@@ -2239,14 +2401,20 @@ function buildEvaluationResultsFromTrace(trace) {
2239
2401
  }
2240
2402
  return results;
2241
2403
  }
2242
- function traceToNodes(trace) {
2404
+ function traceToNodes(trace, options = {}) {
2243
2405
  if (!trace.expression_tree) {
2244
2406
  return { nodes: [], edges: [], rootId: null, traceNodeMap: /* @__PURE__ */ new Map() };
2245
2407
  }
2246
2408
  const nodes = [];
2247
2409
  const edges = [];
2248
2410
  const traceNodeMap = /* @__PURE__ */ new Map();
2249
- processExpressionNode(trace.expression_tree, { nodes, edges, traceNodeMap });
2411
+ const rootExpression = options.originalValue ?? JSON.parse(trace.expression_tree.expression);
2412
+ processExpressionNode(trace.expression_tree, {
2413
+ nodes,
2414
+ edges,
2415
+ traceNodeMap,
2416
+ preserveStructure: options.preserveStructure ?? false
2417
+ }, {}, rootExpression);
2250
2418
  return {
2251
2419
  nodes,
2252
2420
  edges,
@@ -2263,11 +2431,11 @@ function mapInlinedChildren(children, parentVisualId, traceNodeMap) {
2263
2431
  }
2264
2432
  }
2265
2433
  }
2266
- function processExpressionNode(exprNode, context, parentInfo = {}) {
2434
+ function processExpressionNode(exprNode, context, parentInfo = {}, originalExpression) {
2267
2435
  const nodeId = traceIdToNodeId(exprNode.id);
2268
- const expression = JSON.parse(exprNode.expression);
2436
+ const expression = originalExpression ?? JSON.parse(exprNode.expression);
2269
2437
  context.traceNodeMap.set(nodeId, nodeId);
2270
- const nodeType = determineNodeType(expression);
2438
+ const nodeType = determineNodeType(expression, context.preserveStructure);
2271
2439
  switch (nodeType) {
2272
2440
  case "literal":
2273
2441
  createLiteralNodeFromTrace(nodeId, expression, exprNode.children, context, parentInfo);
@@ -2284,10 +2452,39 @@ function processExpressionNode(exprNode, context, parentInfo = {}) {
2284
2452
  case "operator":
2285
2453
  createOperatorNodeFromTrace(nodeId, expression, exprNode.children, context, parentInfo);
2286
2454
  break;
2455
+ case "structure":
2456
+ createStructureNodeFromTrace(nodeId, expression, exprNode.children, context, parentInfo);
2457
+ break;
2287
2458
  }
2288
2459
  return nodeId;
2289
2460
  }
2290
- function determineNodeType(expr) {
2461
+ function createFallbackNode(nodeId, value, context, parentInfo) {
2462
+ const nodeType = determineNodeType(value, context.preserveStructure);
2463
+ switch (nodeType) {
2464
+ case "literal":
2465
+ createLiteralNodeFromTrace(nodeId, value, [], context, parentInfo);
2466
+ break;
2467
+ case "variable":
2468
+ createVariableNodeFromTrace(nodeId, value, [], context, parentInfo);
2469
+ break;
2470
+ case "if":
2471
+ createIfElseNodeFromTrace(nodeId, value, [], context, parentInfo);
2472
+ break;
2473
+ case "verticalCell":
2474
+ createVerticalCellNodeFromTrace(nodeId, value, [], context, parentInfo);
2475
+ break;
2476
+ case "operator":
2477
+ createOperatorNodeFromTrace(nodeId, value, [], context, parentInfo);
2478
+ break;
2479
+ case "structure":
2480
+ createStructureNodeFromTrace(nodeId, value, [], context, parentInfo);
2481
+ break;
2482
+ }
2483
+ }
2484
+ function determineNodeType(expr, preserveStructure) {
2485
+ if (preserveStructure && isDataStructure(expr)) {
2486
+ return "structure";
2487
+ }
2291
2488
  if (expr === null || typeof expr !== "object" || Array.isArray(expr)) {
2292
2489
  return "literal";
2293
2490
  }
@@ -2326,6 +2523,9 @@ function createLiteralNodeFromTrace(nodeId, value, children, context, parentInfo
2326
2523
  }
2327
2524
  };
2328
2525
  context.nodes.push(node);
2526
+ if (parentInfo.parentId && !parentInfo.branchType) {
2527
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
2528
+ }
2329
2529
  }
2330
2530
  function createVariableNodeFromTrace(nodeId, expression, children, context, parentInfo) {
2331
2531
  if (children && children.length > 0) {
@@ -2358,6 +2558,9 @@ function createVariableNodeFromTrace(nodeId, expression, children, context, pare
2358
2558
  }
2359
2559
  };
2360
2560
  context.nodes.push(node);
2561
+ if (parentInfo.parentId && !parentInfo.branchType) {
2562
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
2563
+ }
2361
2564
  }
2362
2565
  function createIfElseNodeFromTrace(nodeId, expression, children, context, parentInfo) {
2363
2566
  const obj = expression;
@@ -2382,20 +2585,10 @@ function createIfElseNodeFromTrace(nodeId, expression, children, context, parent
2382
2585
  });
2383
2586
  } else {
2384
2587
  conditionBranchId = `${nodeId}-cond-${idx}`;
2385
- const condNode = {
2386
- id: conditionBranchId,
2387
- type: "literal",
2388
- position: { x: 0, y: 0 },
2389
- data: {
2390
- type: "literal",
2391
- value: condition,
2392
- valueType: getValueType$1(condition),
2393
- expression: condition,
2394
- parentId: nodeId,
2395
- argIndex: idx
2396
- }
2397
- };
2398
- context.nodes.push(condNode);
2588
+ createFallbackNode(conditionBranchId, condition, context, {
2589
+ parentId: nodeId,
2590
+ argIndex: idx
2591
+ });
2399
2592
  }
2400
2593
  context.edges.push(createBranchEdge(nodeId, conditionBranchId, branchIndex));
2401
2594
  const conditionText = generateExpressionText(condition, 40);
@@ -2420,21 +2613,11 @@ function createIfElseNodeFromTrace(nodeId, expression, children, context, parent
2420
2613
  });
2421
2614
  } else {
2422
2615
  thenBranchId = `${nodeId}-then-${idx}`;
2423
- const thenNode = {
2424
- id: thenBranchId,
2425
- type: "literal",
2426
- position: { x: 0, y: 0 },
2427
- data: {
2428
- type: "literal",
2429
- value: thenValue,
2430
- valueType: getValueType$1(thenValue),
2431
- expression: thenValue,
2432
- parentId: nodeId,
2433
- argIndex: idx + 1,
2434
- branchType: "yes"
2435
- }
2436
- };
2437
- context.nodes.push(thenNode);
2616
+ createFallbackNode(thenBranchId, thenValue, context, {
2617
+ parentId: nodeId,
2618
+ argIndex: idx + 1,
2619
+ branchType: "yes"
2620
+ });
2438
2621
  }
2439
2622
  context.edges.push(createBranchEdge(nodeId, thenBranchId, branchIndex));
2440
2623
  const thenText = generateExpressionText(thenValue, 40);
@@ -2464,21 +2647,11 @@ function createIfElseNodeFromTrace(nodeId, expression, children, context, parent
2464
2647
  });
2465
2648
  } else {
2466
2649
  elseBranchId = `${nodeId}-else`;
2467
- const elseNode = {
2468
- id: elseBranchId,
2469
- type: "literal",
2470
- position: { x: 0, y: 0 },
2471
- data: {
2472
- type: "literal",
2473
- value: elseValue,
2474
- valueType: getValueType$1(elseValue),
2475
- expression: elseValue,
2476
- parentId: nodeId,
2477
- argIndex: ifArgs.length - 1,
2478
- branchType: "no"
2479
- }
2480
- };
2481
- context.nodes.push(elseNode);
2650
+ createFallbackNode(elseBranchId, elseValue, context, {
2651
+ parentId: nodeId,
2652
+ argIndex: ifArgs.length - 1,
2653
+ branchType: "no"
2654
+ });
2482
2655
  }
2483
2656
  context.edges.push(createBranchEdge(nodeId, elseBranchId, branchIndex));
2484
2657
  const elseText = generateExpressionText(elseValue, 40);
@@ -2513,6 +2686,9 @@ function createIfElseNodeFromTrace(nodeId, expression, children, context, parent
2513
2686
  }
2514
2687
  };
2515
2688
  context.nodes.push(ifElseNode);
2689
+ if (parentInfo.parentId && !parentInfo.branchType) {
2690
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
2691
+ }
2516
2692
  }
2517
2693
  function findMatchingChild(operand, children, usedIndices) {
2518
2694
  const operandStr = JSON.stringify(operand);
@@ -2573,6 +2749,10 @@ function createVerticalCellNodeFromTrace(nodeId, expression, children, context,
2573
2749
  });
2574
2750
  } else {
2575
2751
  branchId = `${nodeId}-arg-${idx}`;
2752
+ createFallbackNode(branchId, operand, context, {
2753
+ parentId: nodeId,
2754
+ argIndex: idx
2755
+ });
2576
2756
  }
2577
2757
  const summary = generateArgSummary(operand);
2578
2758
  summary.label = generateExpressionText(operand, TRUNCATION_LIMITS.expressionText);
@@ -2608,6 +2788,9 @@ function createVerticalCellNodeFromTrace(nodeId, expression, children, context,
2608
2788
  }
2609
2789
  };
2610
2790
  context.nodes.push(node);
2791
+ if (parentInfo.parentId && !parentInfo.branchType) {
2792
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
2793
+ }
2611
2794
  }
2612
2795
  function createOperatorNodeFromTrace(nodeId, expression, children, context, parentInfo) {
2613
2796
  const obj = expression;
@@ -2648,6 +2831,9 @@ function createOperatorNodeFromTrace(nodeId, expression, children, context, pare
2648
2831
  }
2649
2832
  };
2650
2833
  context.nodes.push(node2);
2834
+ if (parentInfo.parentId && !parentInfo.branchType) {
2835
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
2836
+ }
2651
2837
  return;
2652
2838
  }
2653
2839
  const usedChildIndices = /* @__PURE__ */ new Set();
@@ -2693,6 +2879,121 @@ function createOperatorNodeFromTrace(nodeId, expression, children, context, pare
2693
2879
  }
2694
2880
  };
2695
2881
  context.nodes.push(node);
2882
+ if (parentInfo.parentId && !parentInfo.branchType) {
2883
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
2884
+ }
2885
+ }
2886
+ const EXPR_PLACEHOLDER = "{{EXPR}}";
2887
+ const EXPR_PLACEHOLDER_QUOTED = `"${EXPR_PLACEHOLDER}"`;
2888
+ function createStructureNodeFromTrace(nodeId, expression, children, context, parentInfo) {
2889
+ const isArray = Array.isArray(expression);
2890
+ const elements = [];
2891
+ const usedChildIndices = /* @__PURE__ */ new Set();
2892
+ let expressionIndex = 0;
2893
+ const structureWithPlaceholders = walkAndCollectFromTrace(
2894
+ expression,
2895
+ [],
2896
+ (path, item, key) => {
2897
+ if (isJsonLogicExpression(item)) {
2898
+ const match = findMatchingChild(item, children, usedChildIndices);
2899
+ let branchId;
2900
+ if (match) {
2901
+ usedChildIndices.add(match.index);
2902
+ branchId = processExpressionNode(match.child, context, {
2903
+ parentId: nodeId,
2904
+ argIndex: expressionIndex
2905
+ });
2906
+ } else {
2907
+ branchId = `${nodeId}-expr-${expressionIndex}`;
2908
+ createFallbackNode(branchId, item, context, {
2909
+ parentId: nodeId,
2910
+ argIndex: expressionIndex,
2911
+ branchType: "branch"
2912
+ // Prevents edge creation in fallback
2913
+ });
2914
+ }
2915
+ elements.push({
2916
+ type: "expression",
2917
+ path,
2918
+ key,
2919
+ branchId,
2920
+ startOffset: 0,
2921
+ endOffset: 0
2922
+ });
2923
+ expressionIndex++;
2924
+ return EXPR_PLACEHOLDER;
2925
+ }
2926
+ return item;
2927
+ });
2928
+ const formattedJson = JSON.stringify(structureWithPlaceholders, null, 2);
2929
+ let searchPos = 0;
2930
+ for (const element of elements) {
2931
+ if (element.type === "expression") {
2932
+ const placeholderPos = formattedJson.indexOf(EXPR_PLACEHOLDER_QUOTED, searchPos);
2933
+ if (placeholderPos !== -1) {
2934
+ element.startOffset = placeholderPos;
2935
+ element.endOffset = placeholderPos + EXPR_PLACEHOLDER_QUOTED.length;
2936
+ searchPos = element.endOffset;
2937
+ }
2938
+ }
2939
+ }
2940
+ const expressionText = generateExpressionText(expression, 100);
2941
+ const node = {
2942
+ id: nodeId,
2943
+ type: "structure",
2944
+ position: { x: 0, y: 0 },
2945
+ data: {
2946
+ type: "structure",
2947
+ isArray,
2948
+ formattedJson,
2949
+ elements,
2950
+ collapsed: false,
2951
+ expressionText,
2952
+ expression,
2953
+ parentId: parentInfo.parentId,
2954
+ argIndex: parentInfo.argIndex,
2955
+ branchType: parentInfo.branchType
2956
+ }
2957
+ };
2958
+ context.nodes.push(node);
2959
+ if (parentInfo.parentId && !parentInfo.branchType) {
2960
+ context.edges.push(createArgEdge(parentInfo.parentId, nodeId, parentInfo.argIndex ?? 0));
2961
+ }
2962
+ let branchIdx = 0;
2963
+ for (const element of elements) {
2964
+ if (element.type === "expression" && element.branchId) {
2965
+ context.edges.push(createBranchEdge(nodeId, element.branchId, branchIdx));
2966
+ branchIdx++;
2967
+ }
2968
+ }
2969
+ }
2970
+ function walkAndCollectFromTrace(value, path, onValue, context) {
2971
+ if (Array.isArray(value)) {
2972
+ return value.map((item, index) => {
2973
+ const itemPath = [...path, String(index)];
2974
+ if (isJsonLogicExpression(item)) {
2975
+ return onValue(itemPath, item);
2976
+ } else if (typeof item === "object" && item !== null) {
2977
+ return walkAndCollectFromTrace(item, itemPath, onValue);
2978
+ }
2979
+ return item;
2980
+ });
2981
+ }
2982
+ if (typeof value === "object" && value !== null) {
2983
+ const result = {};
2984
+ for (const [key, item] of Object.entries(value)) {
2985
+ const itemPath = [...path, key];
2986
+ if (isJsonLogicExpression(item)) {
2987
+ result[key] = onValue(itemPath, item, key);
2988
+ } else if (typeof item === "object" && item !== null) {
2989
+ result[key] = walkAndCollectFromTrace(item, itemPath, onValue);
2990
+ } else {
2991
+ result[key] = item;
2992
+ }
2993
+ }
2994
+ return result;
2995
+ }
2996
+ return value;
2696
2997
  }
2697
2998
 
2698
2999
  function getDefaultExportFromCjs (x) {
@@ -7456,6 +7757,9 @@ function isLiteralNode(node) {
7456
7757
  function isVerticalCellNode(node) {
7457
7758
  return node.data.type === "verticalCell";
7458
7759
  }
7760
+ function isStructureNode(node) {
7761
+ return node.data.type === "structure";
7762
+ }
7459
7763
 
7460
7764
  function estimateTextWidth(text, isMonospace = false) {
7461
7765
  const charWidth = isMonospace ? TEXT_METRICS.charWidthMono : TEXT_METRICS.charWidthRegular;
@@ -7494,12 +7798,32 @@ function calculateNodeWidth(node) {
7494
7798
  maxCellWidth = Math.max(maxCellWidth, estimateTextWidth(vcData.expressionText, true));
7495
7799
  }
7496
7800
  contentWidth = maxCellWidth;
7801
+ } else if (isStructureNode(node)) {
7802
+ const structData = node.data;
7803
+ if (structData.collapsed && structData.expressionText) {
7804
+ contentWidth = estimateTextWidth(structData.expressionText, true);
7805
+ } else {
7806
+ const lines = structData.formattedJson.split("\n");
7807
+ let maxLineWidth = 0;
7808
+ for (const line of lines) {
7809
+ const lineWidth = estimateTextWidth(line, true);
7810
+ maxLineWidth = Math.max(maxLineWidth, lineWidth);
7811
+ }
7812
+ contentWidth = maxLineWidth;
7813
+ }
7497
7814
  } else {
7498
7815
  contentWidth = FIXED_WIDTHS.fallbackNode;
7499
7816
  }
7500
7817
  const totalWidth = contentWidth + NODE_PADDING.contentPadding;
7501
7818
  return Math.max(NODE_DIMENSIONS.minWidth, Math.min(NODE_DIMENSIONS.maxWidth, totalWidth));
7502
7819
  }
7820
+ const STRUCTURE_DIMENSIONS = {
7821
+ headerHeight: 32,
7822
+ lineHeight: 18,
7823
+ bodyPadding: 16,
7824
+ // 8px top + 8px bottom
7825
+ collapsedBodyHeight: 30
7826
+ };
7503
7827
  function getNodeDimensions(node) {
7504
7828
  const width = calculateNodeWidth(node);
7505
7829
  if (isVerticalCellNode(node)) {
@@ -7516,6 +7840,20 @@ function getNodeDimensions(node) {
7516
7840
  height: VERTICAL_CELL_DIMENSIONS.headerHeight + cellCount * VERTICAL_CELL_DIMENSIONS.rowHeight
7517
7841
  };
7518
7842
  }
7843
+ if (isStructureNode(node)) {
7844
+ const structData = node.data;
7845
+ if (structData.collapsed) {
7846
+ return {
7847
+ width,
7848
+ height: STRUCTURE_DIMENSIONS.headerHeight + STRUCTURE_DIMENSIONS.collapsedBodyHeight
7849
+ };
7850
+ }
7851
+ const lineCount = structData.formattedJson.split("\n").length;
7852
+ return {
7853
+ width,
7854
+ height: STRUCTURE_DIMENSIONS.headerHeight + STRUCTURE_DIMENSIONS.bodyPadding + lineCount * STRUCTURE_DIMENSIONS.lineHeight
7855
+ };
7856
+ }
7519
7857
  return { width, height: NODE_DIMENSIONS.defaultHeight };
7520
7858
  }
7521
7859
  function applyTreeLayout(nodes, edges) {
@@ -7533,7 +7871,7 @@ function applyTreeLayout(nodes, edges) {
7533
7871
  const { width, height } = getNodeDimensions(node);
7534
7872
  g.setNode(node.id, { width, height });
7535
7873
  });
7536
- const edgesToUse = edges || buildEdgesFromNodes(nodes);
7874
+ const edgesToUse = edges || buildEdgesFromNodes$1(nodes);
7537
7875
  const nodeIdSet = new Set(nodes.map((n) => n.id));
7538
7876
  const sourceEdgeCount = /* @__PURE__ */ new Map();
7539
7877
  edgesToUse.forEach((edge) => {
@@ -7566,7 +7904,7 @@ function applyTreeLayout(nodes, edges) {
7566
7904
  return node;
7567
7905
  });
7568
7906
  }
7569
- function buildEdgesFromNodes(nodes) {
7907
+ function buildEdgesFromNodes$1(nodes) {
7570
7908
  const edges = [];
7571
7909
  nodes.forEach((node) => {
7572
7910
  if (isOperatorNode(node)) {
@@ -7587,38 +7925,34 @@ function buildEdgesFromNodes(nodes) {
7587
7925
  const vcData = node.data;
7588
7926
  if (!vcData.collapsed) {
7589
7927
  const collapsedIndices = vcData.collapsedCellIndices || [];
7590
- let branchIndex = 0;
7591
7928
  vcData.cells.forEach((cell) => {
7592
7929
  if (collapsedIndices.includes(cell.index)) return;
7593
- if (cell.branchId) {
7594
- edges.push({
7595
- id: `${node.id}-branch-${cell.branchId}`,
7596
- source: node.id,
7597
- target: cell.branchId,
7598
- sourceHandle: `branch-${branchIndex}`,
7599
- targetHandle: "left"
7600
- });
7601
- branchIndex++;
7602
- }
7603
7930
  if (cell.conditionBranchId) {
7604
7931
  edges.push({
7605
7932
  id: `${node.id}-cond-${cell.conditionBranchId}`,
7606
7933
  source: node.id,
7607
7934
  target: cell.conditionBranchId,
7608
- sourceHandle: `branch-${branchIndex}`,
7935
+ sourceHandle: `branch-${cell.index}-cond`,
7609
7936
  targetHandle: "left"
7610
7937
  });
7611
- branchIndex++;
7612
7938
  }
7613
7939
  if (cell.thenBranchId) {
7614
7940
  edges.push({
7615
7941
  id: `${node.id}-then-${cell.thenBranchId}`,
7616
7942
  source: node.id,
7617
7943
  target: cell.thenBranchId,
7618
- sourceHandle: `branch-${branchIndex}`,
7944
+ sourceHandle: `branch-${cell.index}-then`,
7945
+ targetHandle: "left"
7946
+ });
7947
+ }
7948
+ if (cell.branchId && !cell.conditionBranchId && !cell.thenBranchId) {
7949
+ edges.push({
7950
+ id: `${node.id}-branch-${cell.branchId}`,
7951
+ source: node.id,
7952
+ target: cell.branchId,
7953
+ sourceHandle: `branch-${cell.index}`,
7619
7954
  targetHandle: "left"
7620
7955
  });
7621
- branchIndex++;
7622
7956
  }
7623
7957
  });
7624
7958
  }
@@ -7646,7 +7980,8 @@ const emptyTraceNodeMap = /* @__PURE__ */ new Map();
7646
7980
  function useLogicEditor({
7647
7981
  value,
7648
7982
  evaluateWithTrace,
7649
- data
7983
+ data,
7984
+ preserveStructure = false
7650
7985
  }) {
7651
7986
  const [nodes, setNodes] = react.useState([]);
7652
7987
  const [edges, setEdges] = react.useState([]);
@@ -7658,11 +7993,12 @@ function useLogicEditor({
7658
7993
  const [lastExternalValue, setLastExternalValue] = react.useState("");
7659
7994
  const [lastData, setLastData] = react.useState("");
7660
7995
  const [lastHadTrace, setLastHadTrace] = react.useState(false);
7996
+ const [lastPreserveStructure, setLastPreserveStructure] = react.useState(false);
7661
7997
  react.useEffect(() => {
7662
7998
  const valueStr = JSON.stringify(value);
7663
7999
  const dataStr = JSON.stringify(data);
7664
8000
  const hasTrace = !!evaluateWithTrace;
7665
- if (valueStr === lastExternalValue && dataStr === lastData && hasTrace === lastHadTrace) {
8001
+ if (valueStr === lastExternalValue && dataStr === lastData && hasTrace === lastHadTrace && preserveStructure === lastPreserveStructure) {
7666
8002
  return;
7667
8003
  }
7668
8004
  try {
@@ -7677,12 +8013,13 @@ function useLogicEditor({
7677
8013
  setLastExternalValue(valueStr);
7678
8014
  setLastData(dataStr);
7679
8015
  setLastHadTrace(hasTrace);
8016
+ setLastPreserveStructure(preserveStructure);
7680
8017
  return;
7681
8018
  }
7682
8019
  if (evaluateWithTrace && value) {
7683
8020
  try {
7684
8021
  const trace = evaluateWithTrace(value, data ?? {});
7685
- const { nodes: newNodes2, edges: newEdges2, traceNodeMap: newTraceNodeMap } = traceToNodes(trace);
8022
+ const { nodes: newNodes2, edges: newEdges2, traceNodeMap: newTraceNodeMap } = traceToNodes(trace, { preserveStructure, originalValue: value });
7686
8023
  const layoutedNodes2 = applyTreeLayout(newNodes2, newEdges2);
7687
8024
  const traceResults = buildEvaluationResultsFromTrace(trace);
7688
8025
  setNodes(layoutedNodes2);
@@ -7695,12 +8032,13 @@ function useLogicEditor({
7695
8032
  setLastExternalValue(valueStr);
7696
8033
  setLastData(dataStr);
7697
8034
  setLastHadTrace(hasTrace);
8035
+ setLastPreserveStructure(preserveStructure);
7698
8036
  return;
7699
8037
  } catch (traceErr) {
7700
8038
  console.warn("Trace conversion failed, falling back to JS:", traceErr);
7701
8039
  }
7702
8040
  }
7703
- const { nodes: newNodes, edges: newEdges } = jsonLogicToNodes(value);
8041
+ const { nodes: newNodes, edges: newEdges } = jsonLogicToNodes(value, { preserveStructure });
7704
8042
  const layoutedNodes = applyTreeLayout(newNodes, newEdges);
7705
8043
  setNodes(layoutedNodes);
7706
8044
  setEdges(newEdges);
@@ -7722,7 +8060,8 @@ function useLogicEditor({
7722
8060
  setLastExternalValue(valueStr);
7723
8061
  setLastData(dataStr);
7724
8062
  setLastHadTrace(hasTrace);
7725
- }, [value, data, evaluateWithTrace, lastExternalValue, lastData, lastHadTrace]);
8063
+ setLastPreserveStructure(preserveStructure);
8064
+ }, [value, data, evaluateWithTrace, preserveStructure, lastExternalValue, lastData, lastHadTrace, lastPreserveStructure]);
7726
8065
  return react.useMemo(
7727
8066
  () => ({
7728
8067
  nodes,
@@ -8041,7 +8380,8 @@ function useDebugEvaluation({
8041
8380
  }, [nodes, data, evaluate, enabled]);
8042
8381
  }
8043
8382
 
8044
- function useWasmEvaluator() {
8383
+ function useWasmEvaluator(options = {}) {
8384
+ const { preserveStructure = false } = options;
8045
8385
  const [ready, setReady] = react.useState(false);
8046
8386
  const [loading, setLoading] = react.useState(true);
8047
8387
  const [error, setError] = react.useState(null);
@@ -8052,7 +8392,7 @@ function useWasmEvaluator() {
8052
8392
  try {
8053
8393
  setLoading(true);
8054
8394
  setError(null);
8055
- const wasm = await Promise.resolve().then(() => require('./datalogic_wasm-vS4KZjmk.cjs'));
8395
+ const wasm = await Promise.resolve().then(() => require('./datalogic_wasm-BN8H01AG.cjs'));
8056
8396
  await wasm.default();
8057
8397
  if (!cancelled) {
8058
8398
  moduleRef.current = {
@@ -8082,12 +8422,12 @@ function useWasmEvaluator() {
8082
8422
  try {
8083
8423
  const logicStr = JSON.stringify(logic);
8084
8424
  const dataStr = JSON.stringify(data);
8085
- const resultStr = moduleRef.current.evaluate(logicStr, dataStr);
8425
+ const resultStr = moduleRef.current.evaluate(logicStr, dataStr, preserveStructure);
8086
8426
  return JSON.parse(resultStr);
8087
8427
  } catch (err) {
8088
8428
  throw new Error(err instanceof Error ? err.message : "Evaluation failed");
8089
8429
  }
8090
- }, []);
8430
+ }, [preserveStructure]);
8091
8431
  const evaluateWithTrace = react.useCallback((logic, data) => {
8092
8432
  if (!moduleRef.current) {
8093
8433
  throw new Error("WASM module not initialized");
@@ -8098,12 +8438,12 @@ function useWasmEvaluator() {
8098
8438
  try {
8099
8439
  const logicStr = JSON.stringify(logic);
8100
8440
  const dataStr = JSON.stringify(data);
8101
- const resultStr = moduleRef.current.evaluate_with_trace(logicStr, dataStr);
8441
+ const resultStr = moduleRef.current.evaluate_with_trace(logicStr, dataStr, preserveStructure);
8102
8442
  return JSON.parse(resultStr);
8103
8443
  } catch (err) {
8104
8444
  throw new Error(err instanceof Error ? err.message : "Trace evaluation failed");
8105
8445
  }
8106
- }, []);
8446
+ }, [preserveStructure]);
8107
8447
  return {
8108
8448
  ready,
8109
8449
  loading,
@@ -8493,16 +8833,16 @@ const LiteralNode = react.memo(function LiteralNode2({
8493
8833
 
8494
8834
  const CellHandles = react.memo(function CellHandles2({
8495
8835
  cell,
8496
- branchIndex,
8497
8836
  color
8498
8837
  }) {
8838
+ const cellIndex = cell.index;
8499
8839
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8500
8840
  cell.conditionBranchId && /* @__PURE__ */ jsxRuntime.jsx(
8501
8841
  react$1.Handle,
8502
8842
  {
8503
8843
  type: "source",
8504
8844
  position: react$1.Position.Right,
8505
- id: `branch-${branchIndex}`,
8845
+ id: `branch-${cellIndex}-cond`,
8506
8846
  className: "cell-handle condition-handle",
8507
8847
  style: { background: color, top: `${HANDLE_POSITIONS.conditionTop}px` }
8508
8848
  }
@@ -8512,7 +8852,7 @@ const CellHandles = react.memo(function CellHandles2({
8512
8852
  {
8513
8853
  type: "source",
8514
8854
  position: react$1.Position.Right,
8515
- id: `branch-${branchIndex + (cell.conditionBranchId ? 1 : 0)}`,
8855
+ id: `branch-${cellIndex}-then`,
8516
8856
  className: "cell-handle then-handle",
8517
8857
  style: { background: "#22C55E", top: `${HANDLE_POSITIONS.thenTop}px` }
8518
8858
  }
@@ -8522,7 +8862,7 @@ const CellHandles = react.memo(function CellHandles2({
8522
8862
  {
8523
8863
  type: "source",
8524
8864
  position: react$1.Position.Right,
8525
- id: `branch-${branchIndex}`,
8865
+ id: `branch-${cellIndex}`,
8526
8866
  className: "cell-handle",
8527
8867
  style: { background: color, top: `${HANDLE_POSITIONS.centeredTop}px` }
8528
8868
  }
@@ -8530,21 +8870,8 @@ const CellHandles = react.memo(function CellHandles2({
8530
8870
  ] });
8531
8871
  });
8532
8872
 
8533
- function calculateBranchIndex(cells, currentIndex) {
8534
- let branchIdx = 0;
8535
- for (let i = 0; i < currentIndex; i++) {
8536
- const prevCell = cells.find((c) => c.index === i);
8537
- if (prevCell) {
8538
- if (prevCell.conditionBranchId) branchIdx++;
8539
- if (prevCell.thenBranchId) branchIdx++;
8540
- if (prevCell.branchId) branchIdx++;
8541
- }
8542
- }
8543
- return branchIdx;
8544
- }
8545
8873
  const CellRow = react.memo(function CellRow2({
8546
8874
  cell,
8547
- cells,
8548
8875
  collapsedIndices,
8549
8876
  color,
8550
8877
  onToggleCollapse
@@ -8553,7 +8880,6 @@ const CellRow = react.memo(function CellRow2({
8553
8880
  const isIfThenCell = cell.conditionBranchId || cell.thenBranchId;
8554
8881
  const hasAnyBranch = cell.type === "branch" || isIfThenCell;
8555
8882
  const isExpanded = hasAnyBranch && !isCellCollapsed;
8556
- const branchIndex = calculateBranchIndex(cells, cell.index);
8557
8883
  const handleToggle = react.useCallback(
8558
8884
  (e) => {
8559
8885
  onToggleCollapse(cell.index, e);
@@ -8573,7 +8899,7 @@ const CellRow = react.memo(function CellRow2({
8573
8899
  variant: "cell"
8574
8900
  }
8575
8901
  ),
8576
- isExpanded && /* @__PURE__ */ jsxRuntime.jsx(CellHandles, { cell, branchIndex, color: isThenRow ? BRANCH_COLORS.yes : color })
8902
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx(CellHandles, { cell, color: isThenRow ? BRANCH_COLORS.yes : color })
8577
8903
  ] });
8578
8904
  });
8579
8905
 
@@ -8633,7 +8959,6 @@ const VerticalCellNode = react.memo(function VerticalCellNode2({
8633
8959
  CellRow,
8634
8960
  {
8635
8961
  cell,
8636
- cells: data.cells,
8637
8962
  collapsedIndices,
8638
8963
  color,
8639
8964
  onToggleCollapse: toggleCellCollapse
@@ -8645,11 +8970,197 @@ const VerticalCellNode = react.memo(function VerticalCellNode2({
8645
8970
  );
8646
8971
  });
8647
8972
 
8973
+ const STRUCTURE_COLOR = "#64748B";
8974
+ const LINE_HEIGHT = 18;
8975
+ const HEADER_HEIGHT = 32;
8976
+ const BODY_PADDING = 8;
8977
+ const StructureNode = react.memo(function StructureNode2({
8978
+ id,
8979
+ data,
8980
+ selected
8981
+ }) {
8982
+ const debugClassName = useDebugClassName(id);
8983
+ const toggleNodeCollapse = useNodeCollapse(id);
8984
+ const isCollapsed = data.collapsed ?? false;
8985
+ const expressionElements = react.useMemo(
8986
+ () => data.elements.filter((e) => e.type === "expression"),
8987
+ [data.elements]
8988
+ );
8989
+ const hasExpressions = expressionElements.length > 0;
8990
+ const expressionLineNumbers = react.useMemo(() => {
8991
+ return expressionElements.map((element) => {
8992
+ const textBefore = data.formattedJson.slice(0, element.startOffset);
8993
+ const lineNumber = textBefore.split("\n").length;
8994
+ return lineNumber;
8995
+ });
8996
+ }, [expressionElements, data.formattedJson]);
8997
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8998
+ "div",
8999
+ {
9000
+ className: `structure-node ${selected ? "selected" : ""} ${isCollapsed ? "collapsed" : ""} ${debugClassName}`,
9001
+ style: {
9002
+ borderColor: STRUCTURE_COLOR,
9003
+ backgroundColor: `${STRUCTURE_COLOR}10`
9004
+ },
9005
+ children: [
9006
+ /* @__PURE__ */ jsxRuntime.jsx(NodeDebugBubble, { nodeId: id, position: "top" }),
9007
+ /* @__PURE__ */ jsxRuntime.jsx(NodeInputHandles, { nodeId: id, color: STRUCTURE_COLOR }),
9008
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "structure-node-header", style: { backgroundColor: STRUCTURE_COLOR }, children: [
9009
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "structure-node-icon", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: data.isArray ? "list" : "braces", size: 14 }) }),
9010
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "structure-node-label", children: data.isArray ? "Array" : "Object" }),
9011
+ hasExpressions && /* @__PURE__ */ jsxRuntime.jsx(CollapseToggleButton, { isCollapsed, onClick: toggleNodeCollapse })
9012
+ ] }),
9013
+ isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "structure-node-body collapsed-body", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "expression-text", children: /* @__PURE__ */ jsxRuntime.jsx(ExpressionSyntax, { text: data.expressionText || "..." }) }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "structure-node-body", children: /* @__PURE__ */ jsxRuntime.jsx(
9014
+ FormattedJson,
9015
+ {
9016
+ json: data.formattedJson,
9017
+ elements: data.elements
9018
+ }
9019
+ ) }),
9020
+ !isCollapsed && expressionElements.map((_element, idx) => {
9021
+ const lineNumber = expressionLineNumbers[idx];
9022
+ const topPosition = HEADER_HEIGHT + BODY_PADDING + (lineNumber - 1) * LINE_HEIGHT + LINE_HEIGHT / 2;
9023
+ return /* @__PURE__ */ jsxRuntime.jsx(
9024
+ react$1.Handle,
9025
+ {
9026
+ type: "source",
9027
+ position: react$1.Position.Right,
9028
+ id: `branch-${idx}`,
9029
+ className: "structure-branch-handle",
9030
+ style: {
9031
+ background: "#3B82F6",
9032
+ top: `${topPosition}px`,
9033
+ right: "-4px"
9034
+ }
9035
+ },
9036
+ `branch-${idx}`
9037
+ );
9038
+ })
9039
+ ]
9040
+ }
9041
+ );
9042
+ });
9043
+ function FormattedJson({ json, elements }) {
9044
+ const expressionElements = elements.filter((e) => e.type === "expression").sort((a, b) => a.startOffset - b.startOffset);
9045
+ if (expressionElements.length === 0) {
9046
+ return /* @__PURE__ */ jsxRuntime.jsx(JsonSyntax, { text: json });
9047
+ }
9048
+ const parts = [];
9049
+ let lastEnd = 0;
9050
+ let markerIndex = 0;
9051
+ for (const element of expressionElements) {
9052
+ if (element.startOffset > lastEnd) {
9053
+ const textBefore = json.slice(lastEnd, element.startOffset);
9054
+ parts.push(
9055
+ /* @__PURE__ */ jsxRuntime.jsx(JsonSyntax, { text: textBefore }, `text-${lastEnd}`)
9056
+ );
9057
+ }
9058
+ parts.push(
9059
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "structure-expression-marker", children: element.key || `[${markerIndex}]` }, `marker-${markerIndex}`)
9060
+ );
9061
+ lastEnd = element.endOffset;
9062
+ markerIndex++;
9063
+ }
9064
+ if (lastEnd < json.length) {
9065
+ parts.push(
9066
+ /* @__PURE__ */ jsxRuntime.jsx(JsonSyntax, { text: json.slice(lastEnd) }, `text-${lastEnd}`)
9067
+ );
9068
+ }
9069
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: parts });
9070
+ }
9071
+ function JsonSyntax({ text }) {
9072
+ const highlighted = highlightJson(text);
9073
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: highlighted });
9074
+ }
9075
+ function highlightJson(text) {
9076
+ const result = [];
9077
+ let i = 0;
9078
+ while (i < text.length) {
9079
+ const char = text[i];
9080
+ if (/\s/.test(char)) {
9081
+ let whitespace = "";
9082
+ while (i < text.length && /\s/.test(text[i])) {
9083
+ whitespace += text[i];
9084
+ i++;
9085
+ }
9086
+ result.push(whitespace);
9087
+ continue;
9088
+ }
9089
+ if (char === '"') {
9090
+ let str = '"';
9091
+ i++;
9092
+ while (i < text.length && text[i] !== '"') {
9093
+ if (text[i] === "\\" && i + 1 < text.length) {
9094
+ str += text[i] + text[i + 1];
9095
+ i += 2;
9096
+ } else {
9097
+ str += text[i];
9098
+ i++;
9099
+ }
9100
+ }
9101
+ if (i < text.length) {
9102
+ str += '"';
9103
+ i++;
9104
+ }
9105
+ let j = i;
9106
+ while (j < text.length && /\s/.test(text[j])) j++;
9107
+ const isKey = text[j] === ":";
9108
+ result.push(
9109
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: isKey ? "json-syntax-key" : "json-syntax-string", children: str }, `str-${i}`)
9110
+ );
9111
+ continue;
9112
+ }
9113
+ if (/[-\d]/.test(char)) {
9114
+ let num = "";
9115
+ while (i < text.length && /[-\d.eE+]/.test(text[i])) {
9116
+ num += text[i];
9117
+ i++;
9118
+ }
9119
+ result.push(
9120
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "json-syntax-number", children: num }, `num-${i}`)
9121
+ );
9122
+ continue;
9123
+ }
9124
+ if (text.slice(i, i + 4) === "true") {
9125
+ result.push(
9126
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "json-syntax-boolean-true", children: "true" }, `bool-${i}`)
9127
+ );
9128
+ i += 4;
9129
+ continue;
9130
+ }
9131
+ if (text.slice(i, i + 5) === "false") {
9132
+ result.push(
9133
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "json-syntax-boolean-false", children: "false" }, `bool-${i}`)
9134
+ );
9135
+ i += 5;
9136
+ continue;
9137
+ }
9138
+ if (text.slice(i, i + 4) === "null") {
9139
+ result.push(
9140
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "json-syntax-null", children: "null" }, `null-${i}`)
9141
+ );
9142
+ i += 4;
9143
+ continue;
9144
+ }
9145
+ if (/[{}[\]:,]/.test(char)) {
9146
+ result.push(
9147
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "json-syntax-punctuation", children: char }, `punct-${i}`)
9148
+ );
9149
+ i++;
9150
+ continue;
9151
+ }
9152
+ result.push(char);
9153
+ i++;
9154
+ }
9155
+ return result;
9156
+ }
9157
+
8648
9158
  const nodeTypes = {
8649
9159
  operator: OperatorNode,
8650
9160
  variable: VariableNode,
8651
9161
  literal: LiteralNode,
8652
- verticalCell: VerticalCellNode
9162
+ verticalCell: VerticalCellNode,
9163
+ structure: StructureNode
8653
9164
  };
8654
9165
 
8655
9166
  function collectCellBranchIds(cell, target) {
@@ -8715,6 +9226,82 @@ function getHiddenNodeIds(nodes) {
8715
9226
  return hiddenIds;
8716
9227
  }
8717
9228
 
9229
+ function buildEdgesFromNodes(nodes) {
9230
+ const edges = [];
9231
+ nodes.forEach((node) => {
9232
+ if (node.type === "operator") {
9233
+ const opData = node.data;
9234
+ if (!opData.collapsed) {
9235
+ opData.childIds.forEach((childId, idx) => {
9236
+ edges.push({
9237
+ id: `${node.id}-${childId}`,
9238
+ source: node.id,
9239
+ target: childId,
9240
+ sourceHandle: `arg-${idx}`,
9241
+ targetHandle: "left"
9242
+ });
9243
+ });
9244
+ }
9245
+ }
9246
+ if (node.type === "verticalCell") {
9247
+ const vcData = node.data;
9248
+ if (!vcData.collapsed) {
9249
+ const collapsedIndices = vcData.collapsedCellIndices || [];
9250
+ vcData.cells.forEach((cell) => {
9251
+ if (collapsedIndices.includes(cell.index)) return;
9252
+ if (cell.conditionBranchId) {
9253
+ edges.push({
9254
+ id: `${node.id}-cond-${cell.conditionBranchId}`,
9255
+ source: node.id,
9256
+ target: cell.conditionBranchId,
9257
+ sourceHandle: `branch-${cell.index}-cond`,
9258
+ targetHandle: "left"
9259
+ });
9260
+ }
9261
+ if (cell.thenBranchId) {
9262
+ edges.push({
9263
+ id: `${node.id}-then-${cell.thenBranchId}`,
9264
+ source: node.id,
9265
+ target: cell.thenBranchId,
9266
+ sourceHandle: `branch-${cell.index}-then`,
9267
+ targetHandle: "left"
9268
+ });
9269
+ }
9270
+ if (cell.branchId && !cell.conditionBranchId && !cell.thenBranchId) {
9271
+ edges.push({
9272
+ id: `${node.id}-branch-${cell.branchId}`,
9273
+ source: node.id,
9274
+ target: cell.branchId,
9275
+ sourceHandle: `branch-${cell.index}`,
9276
+ targetHandle: "left"
9277
+ });
9278
+ }
9279
+ });
9280
+ }
9281
+ }
9282
+ if (node.type === "structure") {
9283
+ const structData = node.data;
9284
+ if (!structData.collapsed && structData.elements) {
9285
+ const expressionElements = structData.elements.filter(
9286
+ (el) => el.type === "expression" && el.branchId
9287
+ );
9288
+ expressionElements.forEach((element, idx) => {
9289
+ if (element.branchId) {
9290
+ edges.push({
9291
+ id: `${node.id}-expr-${element.branchId}`,
9292
+ source: node.id,
9293
+ target: element.branchId,
9294
+ sourceHandle: `expr-${idx}`,
9295
+ targetHandle: "left"
9296
+ });
9297
+ }
9298
+ });
9299
+ }
9300
+ }
9301
+ });
9302
+ return edges;
9303
+ }
9304
+
8718
9305
  function DebuggerControls() {
8719
9306
  const {
8720
9307
  state,
@@ -8888,22 +9475,22 @@ function DataLogicEditorInner({
8888
9475
  }) {
8889
9476
  const bgColor = theme === "dark" ? "#404040" : "#cccccc";
8890
9477
  const [nodes, setNodes, onNodesChange] = react$1.useNodesState(initialNodes);
8891
- const [edges, setEdges, onEdgesChange] = react$1.useEdgesState(initialEdges);
9478
+ const [, , onEdgesChange] = react$1.useEdgesState(initialEdges);
8892
9479
  react.useEffect(() => {
8893
9480
  setNodes(initialNodes);
8894
- setEdges(initialEdges);
8895
- }, [initialNodes, initialEdges, setNodes, setEdges]);
9481
+ }, [initialNodes, setNodes]);
8896
9482
  const hiddenNodeIds = react.useMemo(() => getHiddenNodeIds(nodes), [nodes]);
8897
9483
  const nodeIds = react.useMemo(() => new Set(nodes.map((n) => n.id)), [nodes]);
8898
9484
  const visibleNodes = react.useMemo(
8899
9485
  () => nodes.filter((node) => !hiddenNodeIds.has(node.id)),
8900
9486
  [nodes, hiddenNodeIds]
8901
9487
  );
9488
+ const currentEdges = react.useMemo(() => buildEdgesFromNodes(nodes), [nodes]);
8902
9489
  const visibleEdges = react.useMemo(
8903
- () => edges.filter(
9490
+ () => currentEdges.filter(
8904
9491
  (edge) => nodeIds.has(edge.source) && nodeIds.has(edge.target) && !hiddenNodeIds.has(edge.source) && !hiddenNodeIds.has(edge.target)
8905
9492
  ),
8906
- [edges, nodeIds, hiddenNodeIds]
9493
+ [currentEdges, nodeIds, hiddenNodeIds]
8907
9494
  );
8908
9495
  return /* @__PURE__ */ jsxRuntime.jsx(EvaluationContext.Provider, { value: evaluationResults, children: /* @__PURE__ */ jsxRuntime.jsxs(ConnectedHandlesProvider, { edges: visibleEdges, children: [
8909
9496
  /* @__PURE__ */ jsxRuntime.jsx(react$1.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(
@@ -8942,7 +9529,8 @@ function DataLogicEditor({
8942
9529
  data,
8943
9530
  mode = "visualize",
8944
9531
  theme: themeProp,
8945
- className = ""
9532
+ className = "",
9533
+ preserveStructure = false
8946
9534
  }) {
8947
9535
  if (mode === "edit") {
8948
9536
  console.warn("[DataLogicEditor] Edit mode is not yet implemented. Component will render in read-only mode with debug evaluation if data is provided.");
@@ -8953,14 +9541,15 @@ function DataLogicEditor({
8953
9541
  ready: wasmReady,
8954
9542
  evaluate,
8955
9543
  evaluateWithTrace
8956
- } = useWasmEvaluator();
9544
+ } = useWasmEvaluator({ preserveStructure });
8957
9545
  const debugEnabled = mode === "debug" && data !== void 0;
8958
9546
  const editor = useLogicEditor({
8959
9547
  value,
8960
9548
  evaluateWithTrace: debugEnabled && wasmReady ? evaluateWithTrace : void 0,
8961
- data: debugEnabled ? data : void 0
9549
+ data: debugEnabled ? data : void 0,
9550
+ preserveStructure
8962
9551
  });
8963
- const expressionKey = editor.nodes.length > 0 ? editor.nodes[0].id : "empty";
9552
+ const expressionKey = `${editor.nodes.length}-${editor.edges.length}-${editor.nodes[0]?.id ?? "empty"}`;
8964
9553
  const fallbackResults = useDebugEvaluation({
8965
9554
  nodes: editor.nodes,
8966
9555
  data,
@@ -8975,7 +9564,7 @@ function DataLogicEditor({
8975
9564
  ] }) });
8976
9565
  }
8977
9566
  const showDebugger = debugEnabled && editor.usingTraceMode && editor.steps.length > 0;
8978
- const readOnly = mode !== "edit";
9567
+ const readOnly = false;
8979
9568
  const editorInner = /* @__PURE__ */ jsxRuntime.jsx(
8980
9569
  DataLogicEditorInner,
8981
9570
  {