wyreframe 0.1.0 → 0.1.5

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.
Files changed (58) hide show
  1. package/LICENSE +692 -0
  2. package/README.md +65 -5
  3. package/package.json +8 -7
  4. package/src/index.ts +425 -0
  5. package/src/renderer/Renderer.gen.tsx +49 -0
  6. package/src/renderer/Renderer.mjs +41 -1
  7. package/src/renderer/Renderer.res +78 -0
  8. package/src/parser/Core/__tests__/Bounds_test.mjs +0 -326
  9. package/src/parser/Core/__tests__/Bounds_test.res +0 -412
  10. package/src/parser/Core/__tests__/Grid_test.mjs +0 -322
  11. package/src/parser/Core/__tests__/Grid_test.res +0 -319
  12. package/src/parser/Core/__tests__/Types_test.mjs +0 -614
  13. package/src/parser/Core/__tests__/Types_test.res +0 -650
  14. package/src/parser/Detector/__tests__/BoxTracer_test.mjs +0 -70
  15. package/src/parser/Detector/__tests__/BoxTracer_test.res +0 -92
  16. package/src/parser/Detector/__tests__/HierarchyBuilder_test.mjs +0 -489
  17. package/src/parser/Detector/__tests__/HierarchyBuilder_test.res +0 -849
  18. package/src/parser/Detector/__tests__/ShapeDetector_test.mjs +0 -377
  19. package/src/parser/Detector/__tests__/ShapeDetector_test.res +0 -563
  20. package/src/parser/Interactions/__tests__/InteractionMerger_test.mjs +0 -576
  21. package/src/parser/Interactions/__tests__/InteractionMerger_test.res +0 -646
  22. package/src/parser/Scanner/__tests__/Grid_manual.mjs +0 -214
  23. package/src/parser/Scanner/__tests__/Grid_manual.res +0 -141
  24. package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.mjs +0 -189
  25. package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.res +0 -257
  26. package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.mjs +0 -202
  27. package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.res +0 -250
  28. package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.mjs +0 -293
  29. package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.res +0 -134
  30. package/src/parser/Semantic/Elements/__tests__/InputParser_test.mjs +0 -253
  31. package/src/parser/Semantic/Elements/__tests__/InputParser_test.res +0 -304
  32. package/src/parser/Semantic/Elements/__tests__/LinkParser_test.mjs +0 -289
  33. package/src/parser/Semantic/Elements/__tests__/LinkParser_test.res +0 -402
  34. package/src/parser/Semantic/Elements/__tests__/TextParser_test.mjs +0 -149
  35. package/src/parser/Semantic/Elements/__tests__/TextParser_test.res +0 -167
  36. package/src/parser/Semantic/__tests__/ASTBuilder_test.mjs +0 -187
  37. package/src/parser/Semantic/__tests__/ASTBuilder_test.res +0 -192
  38. package/src/parser/Semantic/__tests__/ParserRegistry_test.mjs +0 -154
  39. package/src/parser/Semantic/__tests__/ParserRegistry_test.res +0 -191
  40. package/src/parser/Semantic/__tests__/SemanticParser_integration_test.mjs +0 -768
  41. package/src/parser/Semantic/__tests__/SemanticParser_integration_test.res +0 -1069
  42. package/src/parser/Semantic/__tests__/SemanticParser_manual.mjs +0 -1329
  43. package/src/parser/Semantic/__tests__/SemanticParser_manual.res +0 -544
  44. package/src/parser/__tests__/GridScanner_integration.test.mjs +0 -632
  45. package/src/parser/__tests__/GridScanner_integration.test.res +0 -816
  46. package/src/parser/__tests__/Performance.test.mjs +0 -244
  47. package/src/parser/__tests__/Performance.test.res +0 -371
  48. package/src/parser/__tests__/PerformanceFixtures.mjs +0 -200
  49. package/src/parser/__tests__/PerformanceFixtures.res +0 -284
  50. package/src/parser/__tests__/WyreframeParser_integration.test.mjs +0 -770
  51. package/src/parser/__tests__/WyreframeParser_integration.test.res +0 -1008
  52. package/src/parser/__tests__/fixtures/alignment-test.txt +0 -9
  53. package/src/parser/__tests__/fixtures/all-elements.txt +0 -16
  54. package/src/parser/__tests__/fixtures/login-scene.txt +0 -17
  55. package/src/parser/__tests__/fixtures/multi-scene.txt +0 -25
  56. package/src/parser/__tests__/fixtures/nested-boxes.txt +0 -15
  57. package/src/parser/__tests__/fixtures/simple-box.txt +0 -5
  58. package/src/parser/__tests__/fixtures/with-dividers.txt +0 -14
@@ -1,70 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Grid from "../../Core/Grid.mjs";
4
- import * as Types from "../../Core/Types.mjs";
5
- import * as Vitest from "rescript-vitest/src/Vitest.mjs";
6
- import * as BoxTracer from "../BoxTracer.mjs";
7
-
8
- Vitest.describe("BoxTracer - Width Validation", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
9
- Vitest.test("should detect mismatched width between top and bottom edges", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
10
- let input = [
11
- "+-----+",
12
- "| |",
13
- "+-------+"
14
- ];
15
- let grid = Grid.fromLines(input);
16
- let topLeft = Types.Position.make(0, 0);
17
- let result = BoxTracer.traceBox(grid, topLeft);
18
- if (result.TAG === "Ok") {
19
- return t.expect(true).toBe(false);
20
- }
21
- let match = result._0.code;
22
- if (match.TAG !== "MismatchedWidth") {
23
- return t.expect(true).toBe(false);
24
- }
25
- let pos = match.topLeft;
26
- t.expect(match.topWidth).toBe(6);
27
- t.expect(match.bottomWidth).toBe(8);
28
- t.expect(pos.row).toBe(0);
29
- t.expect(pos.col).toBe(0);
30
- });
31
- Vitest.test("should successfully trace box with matching widths", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
32
- let input = [
33
- "+-----+",
34
- "| |",
35
- "+-----+"
36
- ];
37
- let grid = Grid.fromLines(input);
38
- let topLeft = Types.Position.make(0, 0);
39
- let result = BoxTracer.traceBox(grid, topLeft);
40
- if (result.TAG === "Ok") {
41
- let box = result._0;
42
- t.expect(box.bounds.top).toBe(0);
43
- t.expect(box.bounds.left).toBe(0);
44
- t.expect(box.bounds.bottom).toBe(2);
45
- t.expect(box.bounds.right).toBe(6);
46
- return t.expect(box.name).toBe(undefined);
47
- }
48
- console.log(result._0);
49
- t.expect(true).toBe(false);
50
- });
51
- Vitest.test("should extract box name and validate width", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
52
- let input = [
53
- "+--Login--+",
54
- "| |",
55
- "+--Login--+"
56
- ];
57
- let grid = Grid.fromLines(input);
58
- let topLeft = Types.Position.make(0, 0);
59
- let result = BoxTracer.traceBox(grid, topLeft);
60
- if (result.TAG !== "Ok") {
61
- return t.expect(true).toBe(false);
62
- }
63
- let box = result._0;
64
- t.expect(box.name).toBe("Login");
65
- t.expect(Types.Bounds.width(box.bounds)).toBe(10);
66
- t.expect(Types.Bounds.height(box.bounds)).toBe(2);
67
- });
68
- });
69
-
70
- /* Not a pure module */
@@ -1,92 +0,0 @@
1
- // BoxTracer_test.res
2
- // Unit tests for BoxTracer width validation and box tracing
3
-
4
- open Vitest
5
-
6
- describe("BoxTracer - Width Validation", () => {
7
- test("should detect mismatched width between top and bottom edges", t => {
8
- // Create a malformed box with different top and bottom widths
9
- let input = [
10
- "+-----+", // Top: 7 chars wide (5 dashes + 2 corners)
11
- "| |",
12
- "+-------+", // Bottom: 9 chars wide (7 dashes + 2 corners) - MISMATCH!
13
- ]
14
-
15
- let grid = Grid.fromLines(input)
16
- let topLeft = Types.Position.make(0, 0)
17
-
18
- let result = BoxTracer.traceBox(grid, topLeft)
19
-
20
- switch result {
21
- | Error(err) => {
22
- // Verify we get a MismatchedWidth error
23
- switch err.code {
24
- | ErrorTypes.MismatchedWidth({topWidth, bottomWidth, topLeft: pos}) => {
25
- t->expect(topWidth)->Expect.toBe(6) // 0 to 6 = 6 chars
26
- t->expect(bottomWidth)->Expect.toBe(8) // 0 to 8 = 8 chars
27
- t->expect(pos.row)->Expect.toBe(0)
28
- t->expect(pos.col)->Expect.toBe(0)
29
- }
30
- | _ => t->expect(true)->Expect.toBe(false) // fail: Expected MismatchedWidth error
31
- }
32
- }
33
- | Ok(_) => t->expect(true)->Expect.toBe(false) // fail: Expected error for mismatched width, but got Ok
34
- }
35
- })
36
-
37
- test("should successfully trace box with matching widths", t => {
38
- // Create a well-formed box with matching top and bottom widths
39
- let input = [
40
- "+-----+",
41
- "| |",
42
- "+-----+", // Same width as top
43
- ]
44
-
45
- let grid = Grid.fromLines(input)
46
- let topLeft = Types.Position.make(0, 0)
47
-
48
- let result = BoxTracer.traceBox(grid, topLeft)
49
-
50
- switch result {
51
- | Ok(box) => {
52
- // Verify box bounds are correct
53
- t->expect(box.bounds.top)->Expect.toBe(0)
54
- t->expect(box.bounds.left)->Expect.toBe(0)
55
- t->expect(box.bounds.bottom)->Expect.toBe(2)
56
- t->expect(box.bounds.right)->Expect.toBe(6)
57
-
58
- // Verify no name (unnamed box)
59
- t->expect(box.name)->Expect.toBe(None)
60
- }
61
- | Error(err) => {
62
- Console.log(err)
63
- t->expect(true)->Expect.toBe(false) // fail: Expected successful box trace for matching widths
64
- }
65
- }
66
- })
67
-
68
- test("should extract box name and validate width", t => {
69
- let input = [
70
- "+--Login--+",
71
- "| |",
72
- "+--Login--+",
73
- ]
74
-
75
- let grid = Grid.fromLines(input)
76
- let topLeft = Types.Position.make(0, 0)
77
-
78
- let result = BoxTracer.traceBox(grid, topLeft)
79
-
80
- switch result {
81
- | Ok(box) => {
82
- // Verify box name extraction
83
- t->expect(box.name)->Expect.toBe(Some("Login"))
84
-
85
- // Verify bounds
86
- t->expect(Types.Bounds.width(box.bounds))->Expect.toBe(10)
87
- t->expect(Types.Bounds.height(box.bounds))->Expect.toBe(2)
88
- }
89
- | Error(_) => t->expect(true)->Expect.toBe(false) // fail: Expected successful trace for named box
90
- }
91
- })
92
- })
@@ -1,489 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Types from "../../Core/Types.mjs";
4
- import * as Vitest from "rescript-vitest/src/Vitest.mjs";
5
- import * as HierarchyBuilder from "../HierarchyBuilder.mjs";
6
-
7
- Vitest.describe("HierarchyBuilder - Containment Detection", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
8
- Vitest.test("contains returns true when outer completely contains inner", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
9
- let outer = Types.Bounds.make(0, 0, 10, 10);
10
- let inner = Types.Bounds.make(2, 2, 8, 8);
11
- t.expect(HierarchyBuilder.contains(outer, inner)).toBe(true);
12
- });
13
- Vitest.test("contains returns false when boxes are equal", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
14
- let bounds = Types.Bounds.make(0, 0, 10, 10);
15
- t.expect(HierarchyBuilder.contains(bounds, bounds)).toBe(false);
16
- });
17
- Vitest.test("contains returns false when boxes are disjoint", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
18
- let box1 = Types.Bounds.make(0, 0, 5, 5);
19
- let box2 = Types.Bounds.make(10, 10, 15, 15);
20
- t.expect(HierarchyBuilder.contains(box1, box2)).toBe(false);
21
- });
22
- Vitest.test("contains returns false when boxes partially overlap", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
23
- let box1 = Types.Bounds.make(0, 0, 10, 10);
24
- let box2 = Types.Bounds.make(5, 5, 15, 15);
25
- t.expect(HierarchyBuilder.contains(box1, box2)).toBe(false);
26
- });
27
- Vitest.test("contains returns false when inner touches outer's edge", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
28
- let outer = Types.Bounds.make(0, 0, 10, 10);
29
- let inner = Types.Bounds.make(0, 0, 5, 5);
30
- t.expect(HierarchyBuilder.contains(outer, inner)).toBe(false);
31
- });
32
- });
33
-
34
- Vitest.describe("HierarchyBuilder - findParent", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
35
- Vitest.test("findParent returns None for root box (no container)", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
36
- let box = HierarchyBuilder.makeBox("Root", Types.Bounds.make(0, 0, 10, 10));
37
- let candidates = [box];
38
- t.expect(HierarchyBuilder.findParent(box, candidates)).toEqual(undefined);
39
- });
40
- Vitest.test("findParent returns immediate parent (smallest containing box)", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
41
- let grandparent = HierarchyBuilder.makeBox("Grandparent", Types.Bounds.make(0, 0, 20, 20));
42
- let parent = HierarchyBuilder.makeBox("Parent", Types.Bounds.make(2, 2, 18, 18));
43
- let child = HierarchyBuilder.makeBox("Child", Types.Bounds.make(4, 4, 16, 16));
44
- let candidates = [
45
- grandparent,
46
- parent,
47
- child
48
- ];
49
- t.expect(HierarchyBuilder.findParent(child, candidates)).toEqual(parent);
50
- });
51
- Vitest.test("findParent ignores boxes that don't contain the target", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
52
- let box1 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(0, 0, 5, 5));
53
- let box2 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(10, 10, 15, 15));
54
- let candidates = [
55
- box1,
56
- box2
57
- ];
58
- t.expect(HierarchyBuilder.findParent(box2, candidates)).toEqual(undefined);
59
- });
60
- });
61
-
62
- Vitest.describe("HierarchyBuilder - buildHierarchy - 2-level nesting", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
63
- Vitest.test("builds hierarchy with one root and one child", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
64
- let parent = HierarchyBuilder.makeBox("Parent", Types.Bounds.make(0, 0, 10, 10));
65
- let child = HierarchyBuilder.makeBox("Child", Types.Bounds.make(2, 2, 8, 8));
66
- let boxes = [
67
- parent,
68
- child
69
- ];
70
- let result = HierarchyBuilder.buildHierarchy(boxes);
71
- if (result.TAG !== "Ok") {
72
- return t.expect(true).toBe(false);
73
- }
74
- let roots = result._0;
75
- t.expect(roots.length).toBe(1);
76
- let root = roots[0];
77
- if (root === undefined) {
78
- return t.expect(true).toBe(false);
79
- }
80
- t.expect(root.name).toEqual("Parent");
81
- t.expect(root.children.length).toBe(1);
82
- let childBox = root.children[0];
83
- if (childBox !== undefined) {
84
- return t.expect(childBox.name).toEqual("Child");
85
- } else {
86
- return t.expect(true).toBe(false);
87
- }
88
- });
89
- Vitest.test("builds hierarchy with one root and multiple children", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
90
- let parent = HierarchyBuilder.makeBox("Parent", Types.Bounds.make(0, 0, 20, 20));
91
- let child1 = HierarchyBuilder.makeBox("Child1", Types.Bounds.make(2, 2, 8, 8));
92
- let child2 = HierarchyBuilder.makeBox("Child2", Types.Bounds.make(12, 12, 18, 18));
93
- let boxes = [
94
- parent,
95
- child1,
96
- child2
97
- ];
98
- let result = HierarchyBuilder.buildHierarchy(boxes);
99
- if (result.TAG !== "Ok") {
100
- return t.expect(true).toBe(false);
101
- }
102
- let roots = result._0;
103
- t.expect(roots.length).toBe(1);
104
- let root = roots[0];
105
- if (root !== undefined) {
106
- t.expect(root.name).toEqual("Parent");
107
- return t.expect(root.children.length).toBe(2);
108
- } else {
109
- return t.expect(true).toBe(false);
110
- }
111
- });
112
- });
113
-
114
- Vitest.describe("HierarchyBuilder - buildHierarchy - 3-level nesting", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
115
- Vitest.test("builds hierarchy with 3 levels: root -> child -> grandchild", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
116
- let root = HierarchyBuilder.makeBox("Root", Types.Bounds.make(0, 0, 30, 30));
117
- let child = HierarchyBuilder.makeBox("Child", Types.Bounds.make(5, 5, 25, 25));
118
- let grandchild = HierarchyBuilder.makeBox("Grandchild", Types.Bounds.make(10, 10, 20, 20));
119
- let boxes = [
120
- root,
121
- child,
122
- grandchild
123
- ];
124
- let result = HierarchyBuilder.buildHierarchy(boxes);
125
- if (result.TAG !== "Ok") {
126
- return t.expect(true).toBe(false);
127
- }
128
- let roots = result._0;
129
- t.expect(roots.length).toBe(1);
130
- let rootBox = roots[0];
131
- if (rootBox === undefined) {
132
- return t.expect(true).toBe(false);
133
- }
134
- t.expect(rootBox.name).toEqual("Root");
135
- t.expect(rootBox.children.length).toBe(1);
136
- let childBox = rootBox.children[0];
137
- if (childBox === undefined) {
138
- return t.expect(true).toBe(false);
139
- }
140
- t.expect(childBox.name).toEqual("Child");
141
- t.expect(childBox.children.length).toBe(1);
142
- let grandchildBox = childBox.children[0];
143
- if (grandchildBox !== undefined) {
144
- return t.expect(grandchildBox.name).toEqual("Grandchild");
145
- } else {
146
- return t.expect(true).toBe(false);
147
- }
148
- });
149
- Vitest.test("getDepth correctly calculates depth for 3-level hierarchy", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
150
- let root = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(0, 0, 30, 30));
151
- let child = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(5, 5, 25, 25));
152
- let grandchild = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(10, 10, 20, 20));
153
- let allBoxes = [
154
- root,
155
- child,
156
- grandchild
157
- ];
158
- t.expect(HierarchyBuilder.getDepth(root, allBoxes)).toBe(0);
159
- t.expect(HierarchyBuilder.getDepth(child, allBoxes)).toBe(1);
160
- t.expect(HierarchyBuilder.getDepth(grandchild, allBoxes)).toBe(2);
161
- });
162
- });
163
-
164
- Vitest.describe("HierarchyBuilder - buildHierarchy - 4-level nesting", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
165
- Vitest.test("builds hierarchy with 4 levels: root -> child -> grandchild -> great-grandchild", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
166
- let root = HierarchyBuilder.makeBox("Root", Types.Bounds.make(0, 0, 40, 40));
167
- let child = HierarchyBuilder.makeBox("Child", Types.Bounds.make(5, 5, 35, 35));
168
- let grandchild = HierarchyBuilder.makeBox("Grandchild", Types.Bounds.make(10, 10, 30, 30));
169
- let greatGrandchild = HierarchyBuilder.makeBox("GreatGrandchild", Types.Bounds.make(15, 15, 25, 25));
170
- let boxes = [
171
- root,
172
- child,
173
- grandchild,
174
- greatGrandchild
175
- ];
176
- let result = HierarchyBuilder.buildHierarchy(boxes);
177
- if (result.TAG !== "Ok") {
178
- return t.expect(true).toBe(false);
179
- }
180
- let roots = result._0;
181
- t.expect(roots.length).toBe(1);
182
- let rootBox = roots[0];
183
- if (rootBox === undefined) {
184
- return t.expect(true).toBe(false);
185
- }
186
- t.expect(rootBox.name).toEqual("Root");
187
- t.expect(rootBox.children.length).toBe(1);
188
- let childBox = rootBox.children[0];
189
- if (childBox === undefined) {
190
- return t.expect(true).toBe(false);
191
- }
192
- t.expect(childBox.name).toEqual("Child");
193
- t.expect(childBox.children.length).toBe(1);
194
- let grandchildBox = childBox.children[0];
195
- if (grandchildBox === undefined) {
196
- return t.expect(true).toBe(false);
197
- }
198
- t.expect(grandchildBox.name).toEqual("Grandchild");
199
- t.expect(grandchildBox.children.length).toBe(1);
200
- let greatGrandchildBox = grandchildBox.children[0];
201
- if (greatGrandchildBox !== undefined) {
202
- return t.expect(greatGrandchildBox.name).toEqual("GreatGrandchild");
203
- } else {
204
- return t.expect(true).toBe(false);
205
- }
206
- });
207
- Vitest.test("getDepth correctly calculates depth for 4-level hierarchy", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
208
- let root = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(0, 0, 40, 40));
209
- let child = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(5, 5, 35, 35));
210
- let grandchild = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(10, 10, 30, 30));
211
- let greatGrandchild = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(15, 15, 25, 25));
212
- let allBoxes = [
213
- root,
214
- child,
215
- grandchild,
216
- greatGrandchild
217
- ];
218
- t.expect(HierarchyBuilder.getDepth(root, allBoxes)).toBe(0);
219
- t.expect(HierarchyBuilder.getDepth(child, allBoxes)).toBe(1);
220
- t.expect(HierarchyBuilder.getDepth(grandchild, allBoxes)).toBe(2);
221
- t.expect(HierarchyBuilder.getDepth(greatGrandchild, allBoxes)).toBe(3);
222
- });
223
- });
224
-
225
- Vitest.describe("HierarchyBuilder - buildHierarchy - Multiple roots", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => Vitest.test("handles multiple root boxes with children", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
226
- let root1 = HierarchyBuilder.makeBox("Root1", Types.Bounds.make(0, 0, 10, 10));
227
- let root1Child = HierarchyBuilder.makeBox("Root1Child", Types.Bounds.make(2, 2, 8, 8));
228
- let root2 = HierarchyBuilder.makeBox("Root2", Types.Bounds.make(20, 20, 30, 30));
229
- let root2Child = HierarchyBuilder.makeBox("Root2Child", Types.Bounds.make(22, 22, 28, 28));
230
- let boxes = [
231
- root1,
232
- root1Child,
233
- root2,
234
- root2Child
235
- ];
236
- let result = HierarchyBuilder.buildHierarchy(boxes);
237
- if (result.TAG !== "Ok") {
238
- return t.expect(true).toBe(false);
239
- }
240
- let roots = result._0;
241
- t.expect(roots.length).toBe(2);
242
- roots.forEach(root => t.expect(root.children.length).toBe(1));
243
- }));
244
-
245
- Vitest.describe("HierarchyBuilder - buildHierarchy - Error cases", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
246
- Vitest.test("detects overlapping boxes (invalid partial overlap)", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
247
- let box1 = HierarchyBuilder.makeBox("Box1", Types.Bounds.make(0, 0, 10, 10));
248
- let box2 = HierarchyBuilder.makeBox("Box2", Types.Bounds.make(5, 5, 15, 15));
249
- let boxes = [
250
- box1,
251
- box2
252
- ];
253
- let result = HierarchyBuilder.buildHierarchy(boxes);
254
- if (result.TAG === "Ok") {
255
- return t.expect(true).toBe(false);
256
- }
257
- let match = result._0;
258
- if (typeof match !== "object") {
259
- return t.expect(true).toBe(false);
260
- }
261
- let b2 = match.box2;
262
- let b1 = match.box1;
263
- t.expect(b1 === box1 || b1 === box2).toBe(true);
264
- t.expect(b2 === box1 || b2 === box2).toBe(true);
265
- t.expect(b1 !== b2).toBe(true);
266
- });
267
- Vitest.test("allows disjoint boxes (no overlap)", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
268
- let box1 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(0, 0, 5, 5));
269
- let box2 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(10, 10, 15, 15));
270
- let boxes = [
271
- box1,
272
- box2
273
- ];
274
- let result = HierarchyBuilder.buildHierarchy(boxes);
275
- if (result.TAG === "Ok") {
276
- return t.expect(result._0.length).toBe(2);
277
- } else {
278
- return t.expect(true).toBe(false);
279
- }
280
- });
281
- Vitest.test("allows nested boxes (one contains the other)", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
282
- let outer = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(0, 0, 10, 10));
283
- let inner = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(2, 2, 8, 8));
284
- let boxes = [
285
- outer,
286
- inner
287
- ];
288
- let result = HierarchyBuilder.buildHierarchy(boxes);
289
- if (result.TAG !== "Ok") {
290
- return t.expect(true).toBe(false);
291
- }
292
- let roots = result._0;
293
- t.expect(roots.length).toBe(1);
294
- let root = roots[0];
295
- if (root !== undefined) {
296
- return t.expect(root.children.length).toBe(1);
297
- } else {
298
- return t.expect(true).toBe(false);
299
- }
300
- });
301
- });
302
-
303
- Vitest.describe("HierarchyBuilder - Deep Nesting Detection", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
304
- Vitest.describe("collectDeepNestingWarnings", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
305
- Vitest.test("should not warn for boxes at or below threshold (depth 0-4)", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
306
- let root = HierarchyBuilder.makeBox("Root", Types.Bounds.make(0, 0, 10, 10));
307
- let warnings0 = HierarchyBuilder.collectDeepNestingWarnings(root, 0, 4);
308
- t.expect(warnings0.length).toBe(0);
309
- let warnings4 = HierarchyBuilder.collectDeepNestingWarnings(root, 4, 4);
310
- t.expect(warnings4.length).toBe(0);
311
- });
312
- Vitest.test("should warn when depth exceeds threshold of 4", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
313
- let deepBox = HierarchyBuilder.makeBox("DeepBox", Types.Bounds.make(5, 5, 8, 8));
314
- let warnings = HierarchyBuilder.collectDeepNestingWarnings(deepBox, 5, 4);
315
- t.expect(warnings.length).toBe(1);
316
- let warning = warnings[0];
317
- t.expect(warning.severity).toEqual("Warning");
318
- let match = warning.code;
319
- if (match.TAG !== "DeepNesting") {
320
- return t.expect(true).toBe(false);
321
- }
322
- let position = match.position;
323
- t.expect(match.depth).toBe(5);
324
- t.expect(position.row).toBe(5);
325
- t.expect(position.col).toBe(5);
326
- });
327
- Vitest.test("should collect warnings from all children recursively", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
328
- let parent = HierarchyBuilder.makeBox("Parent", Types.Bounds.make(0, 0, 20, 20));
329
- let child1 = HierarchyBuilder.makeBox("Child1", Types.Bounds.make(2, 2, 8, 8));
330
- let child2 = HierarchyBuilder.makeBox("Child2", Types.Bounds.make(12, 12, 18, 18));
331
- parent.children.push(child1);
332
- parent.children.push(child2);
333
- let warnings = HierarchyBuilder.collectDeepNestingWarnings(parent, 4, 4);
334
- t.expect(warnings.length).toBe(2);
335
- });
336
- Vitest.test("should handle custom threshold", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
337
- let box = HierarchyBuilder.makeBox("Box", Types.Bounds.make(0, 0, 5, 5));
338
- let warnings = HierarchyBuilder.collectDeepNestingWarnings(box, 3, 2);
339
- t.expect(warnings.length).toBe(1);
340
- let warnings2 = HierarchyBuilder.collectDeepNestingWarnings(box, 3, 5);
341
- t.expect(warnings2.length).toBe(0);
342
- });
343
- });
344
- Vitest.describe("detectDeepNesting", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
345
- Vitest.test("should detect deep nesting in complete hierarchy", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
346
- let root = HierarchyBuilder.makeBox("Root", Types.Bounds.make(0, 0, 50, 50));
347
- let level1 = HierarchyBuilder.makeBox("Level1", Types.Bounds.make(2, 2, 48, 48));
348
- let level2 = HierarchyBuilder.makeBox("Level2", Types.Bounds.make(4, 4, 46, 46));
349
- let level3 = HierarchyBuilder.makeBox("Level3", Types.Bounds.make(6, 6, 44, 44));
350
- let level4 = HierarchyBuilder.makeBox("Level4", Types.Bounds.make(8, 8, 42, 42));
351
- let level5 = HierarchyBuilder.makeBox("Level5", Types.Bounds.make(10, 10, 40, 40));
352
- root.children.push(level1);
353
- level1.children.push(level2);
354
- level2.children.push(level3);
355
- level3.children.push(level4);
356
- level4.children.push(level5);
357
- let warnings = HierarchyBuilder.detectDeepNesting([root], 4);
358
- t.expect(warnings.length).toBe(1);
359
- let warning = warnings[0];
360
- if (warning === undefined) {
361
- return t.expect(true).toBe(false);
362
- }
363
- let match = warning.code;
364
- if (match.TAG !== "DeepNesting") {
365
- return t.expect(true).toBe(false);
366
- }
367
- let position = match.position;
368
- t.expect(match.depth).toBe(5);
369
- t.expect(position.row).toBe(10);
370
- t.expect(position.col).toBe(10);
371
- });
372
- Vitest.test("should detect multiple deep boxes in different branches", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
373
- let root = HierarchyBuilder.makeBox("Root", Types.Bounds.make(0, 0, 100, 100));
374
- let b1_l1 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(2, 2, 48, 48));
375
- let b1_l2 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(4, 4, 46, 46));
376
- let b1_l3 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(6, 6, 44, 44));
377
- let b1_l4 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(8, 8, 42, 42));
378
- let b1_l5 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(10, 10, 40, 40));
379
- let b2_l1 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(52, 52, 98, 98));
380
- let b2_l2 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(54, 54, 96, 96));
381
- let b2_l3 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(56, 56, 94, 94));
382
- let b2_l4 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(58, 58, 92, 92));
383
- let b2_l5 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(60, 60, 90, 90));
384
- let b2_l6 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(62, 62, 88, 88));
385
- root.children.push(b1_l1);
386
- root.children.push(b2_l1);
387
- b1_l1.children.push(b1_l2);
388
- b1_l2.children.push(b1_l3);
389
- b1_l3.children.push(b1_l4);
390
- b1_l4.children.push(b1_l5);
391
- b2_l1.children.push(b2_l2);
392
- b2_l2.children.push(b2_l3);
393
- b2_l3.children.push(b2_l4);
394
- b2_l4.children.push(b2_l5);
395
- b2_l5.children.push(b2_l6);
396
- let warnings = HierarchyBuilder.detectDeepNesting([root], 4);
397
- t.expect(warnings.length).toBe(3);
398
- });
399
- Vitest.test("should handle multiple root boxes", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
400
- let root1 = HierarchyBuilder.makeBox("Root1", Types.Bounds.make(0, 0, 30, 30));
401
- let root1_child = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(2, 2, 28, 28));
402
- let root2 = HierarchyBuilder.makeBox("Root2", Types.Bounds.make(40, 40, 90, 90));
403
- let root2_l1 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(42, 42, 88, 88));
404
- let root2_l2 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(44, 44, 86, 86));
405
- let root2_l3 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(46, 46, 84, 84));
406
- let root2_l4 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(48, 48, 82, 82));
407
- let root2_l5 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(50, 50, 80, 80));
408
- root1.children.push(root1_child);
409
- root2.children.push(root2_l1);
410
- root2_l1.children.push(root2_l2);
411
- root2_l2.children.push(root2_l3);
412
- root2_l3.children.push(root2_l4);
413
- root2_l4.children.push(root2_l5);
414
- let warnings = HierarchyBuilder.detectDeepNesting([
415
- root1,
416
- root2
417
- ], 4);
418
- t.expect(warnings.length).toBe(1);
419
- });
420
- Vitest.test("should return empty array when no deep nesting", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
421
- let root = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(0, 0, 30, 30));
422
- let child1 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(2, 2, 14, 14));
423
- let child2 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(16, 16, 28, 28));
424
- root.children.push(child1);
425
- root.children.push(child2);
426
- let warnings = HierarchyBuilder.detectDeepNesting([root], 4);
427
- t.expect(warnings.length).toBe(0);
428
- });
429
- });
430
- Vitest.describe("getMaxDepth", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
431
- Vitest.test("should return 0 for empty array", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
432
- let maxDepth = HierarchyBuilder.getMaxDepth([]);
433
- t.expect(maxDepth).toBe(0);
434
- });
435
- Vitest.test("should return 0 for single root box with no children", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
436
- let root = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(0, 0, 10, 10));
437
- let maxDepth = HierarchyBuilder.getMaxDepth([root]);
438
- t.expect(maxDepth).toBe(0);
439
- });
440
- Vitest.test("should calculate max depth for single branch", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
441
- let root = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(0, 0, 30, 30));
442
- let level1 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(2, 2, 28, 28));
443
- let level2 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(4, 4, 26, 26));
444
- root.children.push(level1);
445
- level1.children.push(level2);
446
- let maxDepth = HierarchyBuilder.getMaxDepth([root]);
447
- t.expect(maxDepth).toBe(2);
448
- });
449
- Vitest.test("should find max depth across multiple branches", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
450
- let root = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(0, 0, 100, 100));
451
- let b1_l1 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(2, 2, 20, 20));
452
- let b1_l2 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(4, 4, 18, 18));
453
- let b2_l1 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(30, 30, 98, 98));
454
- let b2_l2 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(32, 32, 96, 96));
455
- let b2_l3 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(34, 34, 94, 94));
456
- let b2_l4 = HierarchyBuilder.makeBox(undefined, Types.Bounds.make(36, 36, 92, 92));
457
- root.children.push(b1_l1);
458
- root.children.push(b2_l1);
459
- b1_l1.children.push(b1_l2);
460
- b2_l1.children.push(b2_l2);
461
- b2_l2.children.push(b2_l3);
462
- b2_l3.children.push(b2_l4);
463
- let maxDepth = HierarchyBuilder.getMaxDepth([root]);
464
- t.expect(maxDepth).toBe(4);
465
- });
466
- });
467
- Vitest.describe("Integration with buildHierarchy", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => Vitest.test("should detect deep nesting after building hierarchy from flat array", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
468
- let boxes = [
469
- HierarchyBuilder.makeBox("Root", Types.Bounds.make(0, 0, 50, 50)),
470
- HierarchyBuilder.makeBox("L1", Types.Bounds.make(2, 2, 48, 48)),
471
- HierarchyBuilder.makeBox("L2", Types.Bounds.make(4, 4, 46, 46)),
472
- HierarchyBuilder.makeBox("L3", Types.Bounds.make(6, 6, 44, 44)),
473
- HierarchyBuilder.makeBox("L4", Types.Bounds.make(8, 8, 42, 42)),
474
- HierarchyBuilder.makeBox("L5", Types.Bounds.make(10, 10, 40, 40))
475
- ];
476
- let result = HierarchyBuilder.buildHierarchy(boxes);
477
- if (result.TAG !== "Ok") {
478
- return t.expect(true).toBe(false);
479
- }
480
- let roots = result._0;
481
- t.expect(roots.length).toBe(1);
482
- let warnings = HierarchyBuilder.detectDeepNesting(roots, 4);
483
- t.expect(warnings.length).toBe(1);
484
- let maxDepth = HierarchyBuilder.getMaxDepth(roots);
485
- t.expect(maxDepth).toBe(5);
486
- }));
487
- });
488
-
489
- /* Not a pure module */