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,322 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Grid from "../Grid.mjs";
4
- import * as Types from "../Types.mjs";
5
- import * as Vitest from "rescript-vitest/src/Vitest.mjs";
6
- import * as Core__Array from "@rescript/core/src/Core__Array.mjs";
7
-
8
- Vitest.describe("Grid", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
9
- Vitest.describe("fromLines", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
10
- Vitest.test("creates correct dimensions for equal-length lines", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
11
- let lines = [
12
- "abc",
13
- "def",
14
- "ghi"
15
- ];
16
- let grid = Grid.fromLines(lines);
17
- t.expect(grid.width).toBe(3);
18
- t.expect(grid.height).toBe(3);
19
- });
20
- Vitest.test("normalizes uneven line lengths by padding", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
21
- let lines = [
22
- "abc",
23
- "de",
24
- "f"
25
- ];
26
- let grid = Grid.fromLines(lines);
27
- t.expect(grid.width).toBe(3);
28
- t.expect(grid.height).toBe(3);
29
- let line = Grid.getLine(grid, 1);
30
- if (line !== undefined) {
31
- t.expect(line.length).toBe(3);
32
- return t.expect(line[2]).toEqual("Space");
33
- } else {
34
- return t.expect(true).toBe(false);
35
- }
36
- });
37
- Vitest.test("handles empty input", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
38
- let grid = Grid.fromLines([]);
39
- t.expect(grid.width).toBe(0);
40
- t.expect(grid.height).toBe(0);
41
- });
42
- Vitest.test("correctly identifies special characters", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
43
- let lines = [
44
- "+--+",
45
- "| |",
46
- "+==+"
47
- ];
48
- let grid = Grid.fromLines(lines);
49
- t.expect(grid.cornerIndex.length).toBe(4);
50
- t.expect(grid.hLineIndex.length).toBe(2);
51
- t.expect(grid.vLineIndex.length).toBe(2);
52
- t.expect(grid.dividerIndex.length).toBe(2);
53
- });
54
- Vitest.test("builds character indices with correct positions", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
55
- let lines = ["+--+"];
56
- let grid = Grid.fromLines(lines);
57
- t.expect(grid.cornerIndex[0]).toEqual({
58
- row: 0,
59
- col: 0
60
- });
61
- t.expect(grid.cornerIndex[1]).toEqual({
62
- row: 0,
63
- col: 3
64
- });
65
- });
66
- });
67
- Vitest.describe("get", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
68
- let grid = Grid.fromLines([
69
- "+--+",
70
- "| |",
71
- "+--+"
72
- ]);
73
- Vitest.test("returns character at valid position", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
74
- t.expect(Grid.get(grid, Types.Position.make(0, 0))).toEqual("Corner");
75
- t.expect(Grid.get(grid, Types.Position.make(0, 1))).toEqual("HLine");
76
- t.expect(Grid.get(grid, Types.Position.make(1, 0))).toEqual("VLine");
77
- });
78
- Vitest.test("returns None for out of bounds positions", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
79
- t.expect(Grid.get(grid, Types.Position.make(-1, 0))).toBe(undefined);
80
- t.expect(Grid.get(grid, Types.Position.make(0, -1))).toBe(undefined);
81
- t.expect(Grid.get(grid, Types.Position.make(10, 0))).toBe(undefined);
82
- t.expect(Grid.get(grid, Types.Position.make(0, 10))).toBe(undefined);
83
- });
84
- });
85
- Vitest.describe("getLine", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
86
- let grid = Grid.fromLines([
87
- "+--+",
88
- "| |",
89
- "+--+"
90
- ]);
91
- Vitest.test("returns entire line at valid row", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
92
- let line = Grid.getLine(grid, 0);
93
- if (line !== undefined) {
94
- t.expect(line.length).toBe(4);
95
- return t.expect(line[0]).toEqual("Corner");
96
- } else {
97
- return t.expect(true).toBe(false);
98
- }
99
- });
100
- Vitest.test("returns None for out of bounds row", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
101
- t.expect(Grid.getLine(grid, -1)).toBe(undefined);
102
- t.expect(Grid.getLine(grid, 10)).toBe(undefined);
103
- });
104
- });
105
- Vitest.describe("getRange", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
106
- let grid = Grid.fromLines(["+--Name--+"]);
107
- Vitest.test("returns range of characters", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
108
- let range = Grid.getRange(grid, 0, 1, 3);
109
- if (range !== undefined) {
110
- t.expect(range.length).toBe(3);
111
- return t.expect(range[0]).toEqual("HLine");
112
- } else {
113
- return t.expect(true).toBe(false);
114
- }
115
- });
116
- Vitest.test("handles negative start column", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
117
- let range = Grid.getRange(grid, 0, -1, 2);
118
- if (range !== undefined) {
119
- return t.expect(range.length).toBe(3);
120
- } else {
121
- return t.expect(true).toBe(false);
122
- }
123
- });
124
- Vitest.test("returns None for invalid row", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => t.expect(Grid.getRange(grid, -1, 0, 2)).toBe(undefined));
125
- });
126
- Vitest.describe("scanRight", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
127
- let grid = Grid.fromLines(["+----+"]);
128
- Vitest.test("scans right until predicate fails", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
129
- let start = Types.Position.make(0, 0);
130
- let results = Grid.scanRight(grid, start, cell => {
131
- if (typeof cell === "object") {
132
- return false;
133
- }
134
- switch (cell) {
135
- case "Corner" :
136
- case "HLine" :
137
- return true;
138
- default:
139
- return false;
140
- }
141
- });
142
- t.expect(results.length).toBe(6);
143
- });
144
- Vitest.test("stops at grid boundary", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
145
- let start = Types.Position.make(0, 0);
146
- let results = Grid.scanRight(grid, start, _cell => true);
147
- t.expect(results.length).toBe(6);
148
- });
149
- Vitest.test("returns empty array if predicate fails immediately", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
150
- let start = Types.Position.make(0, 0);
151
- let results = Grid.scanRight(grid, start, cell => {
152
- if (typeof cell !== "object") {
153
- return cell === "HLine";
154
- } else {
155
- return false;
156
- }
157
- });
158
- t.expect(results.length).toBe(0);
159
- });
160
- });
161
- Vitest.describe("scanDown", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
162
- let grid = Grid.fromLines([
163
- "+",
164
- "|",
165
- "|",
166
- "+"
167
- ]);
168
- Vitest.test("scans down until predicate fails", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
169
- let start = Types.Position.make(0, 0);
170
- let results = Grid.scanDown(grid, start, cell => {
171
- if (typeof cell === "object") {
172
- return false;
173
- }
174
- switch (cell) {
175
- case "Corner" :
176
- case "VLine" :
177
- return true;
178
- default:
179
- return false;
180
- }
181
- });
182
- t.expect(results.length).toBe(4);
183
- });
184
- Vitest.test("stops at grid boundary", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
185
- let start = Types.Position.make(0, 0);
186
- let results = Grid.scanDown(grid, start, _cell => true);
187
- t.expect(results.length).toBe(4);
188
- });
189
- });
190
- Vitest.describe("scanLeft", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
191
- let grid = Grid.fromLines(["+----+"]);
192
- Vitest.test("scans left until predicate fails", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
193
- let start = Types.Position.make(0, 5);
194
- let results = Grid.scanLeft(grid, start, cell => {
195
- if (typeof cell === "object") {
196
- return false;
197
- }
198
- switch (cell) {
199
- case "Corner" :
200
- case "HLine" :
201
- return true;
202
- default:
203
- return false;
204
- }
205
- });
206
- t.expect(results.length).toBe(6);
207
- });
208
- Vitest.test("stops at grid boundary", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
209
- let start = Types.Position.make(0, 5);
210
- let results = Grid.scanLeft(grid, start, _cell => true);
211
- t.expect(results.length).toBe(6);
212
- });
213
- });
214
- Vitest.describe("scanUp", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
215
- let grid = Grid.fromLines([
216
- "+",
217
- "|",
218
- "|",
219
- "+"
220
- ]);
221
- Vitest.test("scans up until predicate fails", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
222
- let start = Types.Position.make(3, 0);
223
- let results = Grid.scanUp(grid, start, cell => {
224
- if (typeof cell === "object") {
225
- return false;
226
- }
227
- switch (cell) {
228
- case "Corner" :
229
- case "VLine" :
230
- return true;
231
- default:
232
- return false;
233
- }
234
- });
235
- t.expect(results.length).toBe(4);
236
- });
237
- Vitest.test("stops at grid boundary", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
238
- let start = Types.Position.make(3, 0);
239
- let results = Grid.scanUp(grid, start, _cell => true);
240
- t.expect(results.length).toBe(4);
241
- });
242
- });
243
- Vitest.describe("findAll", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
244
- let grid = Grid.fromLines([
245
- "+--+",
246
- "| |",
247
- "+--+"
248
- ]);
249
- Vitest.test("finds all corners using index", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
250
- let corners = Grid.findAll(grid, "Corner");
251
- t.expect(corners.length).toBe(4);
252
- });
253
- Vitest.test("finds all horizontal lines using index", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
254
- let hlines = Grid.findAll(grid, "HLine");
255
- t.expect(hlines.length).toBe(4);
256
- });
257
- Vitest.test("finds all vertical lines using index", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
258
- let vlines = Grid.findAll(grid, "VLine");
259
- t.expect(vlines.length).toBe(2);
260
- });
261
- Vitest.test("finds spaces through scanning", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
262
- let spaces = Grid.findAll(grid, "Space");
263
- t.expect(spaces.length).toBe(2);
264
- });
265
- });
266
- Vitest.describe("findInRange", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
267
- let grid = Grid.fromLines([
268
- "+--+",
269
- "| |",
270
- "+--+",
271
- "| |",
272
- "+--+"
273
- ]);
274
- Vitest.test("finds characters within bounds", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
275
- let corners = Grid.findInRange(grid, "Corner", {
276
- top: 0,
277
- left: 0,
278
- bottom: 3,
279
- right: 4
280
- });
281
- t.expect(corners.length).toBe(4);
282
- });
283
- Vitest.test("excludes characters outside bounds", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
284
- let corners = Grid.findInRange(grid, "Corner", {
285
- top: 1,
286
- left: 1,
287
- bottom: 2,
288
- right: 2
289
- });
290
- t.expect(corners.length).toBe(0);
291
- });
292
- });
293
- Vitest.describe("isValidPosition", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => {
294
- let grid = Grid.fromLines([
295
- "+--+",
296
- "| |",
297
- "+--+"
298
- ]);
299
- Vitest.test("returns true for valid positions", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
300
- t.expect(Grid.isValidPosition(grid, Types.Position.make(0, 0))).toBe(true);
301
- t.expect(Grid.isValidPosition(grid, Types.Position.make(1, 2))).toBe(true);
302
- t.expect(Grid.isValidPosition(grid, Types.Position.make(2, 3))).toBe(true);
303
- });
304
- Vitest.test("returns false for out of bounds positions", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
305
- t.expect(Grid.isValidPosition(grid, Types.Position.make(-1, 0))).toBe(false);
306
- t.expect(Grid.isValidPosition(grid, Types.Position.make(0, -1))).toBe(false);
307
- t.expect(Grid.isValidPosition(grid, Types.Position.make(10, 0))).toBe(false);
308
- t.expect(Grid.isValidPosition(grid, Types.Position.make(0, 10))).toBe(false);
309
- });
310
- });
311
- Vitest.describe("Performance", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, () => Vitest.test("handles large grids efficiently", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
312
- let lines = Core__Array.make(1000, "+----+");
313
- let startTime = Date.now();
314
- let grid = Grid.fromLines(lines);
315
- let endTime = Date.now();
316
- let duration = endTime - startTime;
317
- t.expect(grid.height).toBe(1000);
318
- t.expect(duration).toBeLessThan(10.0);
319
- }));
320
- });
321
-
322
- /* Not a pure module */
@@ -1,319 +0,0 @@
1
- // Grid_test.res
2
- // Unit tests for Grid module
3
-
4
- open Vitest
5
-
6
- describe("Grid", () => {
7
- open Grid
8
-
9
- describe("fromLines", () => {
10
- test("creates correct dimensions for equal-length lines", t => {
11
- let lines = ["abc", "def", "ghi"]
12
- let grid = fromLines(lines)
13
-
14
- t->expect(grid.width)->Expect.toBe(3)
15
- t->expect(grid.height)->Expect.toBe(3)
16
- })
17
-
18
- test("normalizes uneven line lengths by padding", t => {
19
- let lines = ["abc", "de", "f"]
20
- let grid = fromLines(lines)
21
-
22
- t->expect(grid.width)->Expect.toBe(3)
23
- t->expect(grid.height)->Expect.toBe(3)
24
-
25
- // Check that shorter lines are padded with spaces
26
- switch getLine(grid, 1) {
27
- | Some(line) => {
28
- t->expect(Array.length(line))->Expect.toBe(3)
29
- t->expect(Array.get(line, 2))->Expect.toEqual(Some(Types.Space))
30
- }
31
- | None => t->expect(true)->Expect.toBe(false) // fail
32
- }
33
- })
34
-
35
- test("handles empty input", t => {
36
- let grid = fromLines([])
37
- t->expect(grid.width)->Expect.toBe(0)
38
- t->expect(grid.height)->Expect.toBe(0)
39
- })
40
-
41
- test("correctly identifies special characters", t => {
42
- let lines = ["+--+", "| |", "+==+"]
43
- let grid = fromLines(lines)
44
-
45
- t->expect(Array.length(grid.cornerIndex))->Expect.toBe(4)
46
- // HLine (-) only appears on row 0: positions (0,1) and (0,2) = 2
47
- // Divider (=) appears on row 2: positions (2,1) and (2,2) = 2
48
- t->expect(Array.length(grid.hLineIndex))->Expect.toBe(2)
49
- t->expect(Array.length(grid.vLineIndex))->Expect.toBe(2)
50
- t->expect(Array.length(grid.dividerIndex))->Expect.toBe(2)
51
- })
52
-
53
- test("builds character indices with correct positions", t => {
54
- let lines = ["+--+"]
55
- let grid = fromLines(lines)
56
-
57
- // Check corner positions
58
- t->expect(Array.get(grid.cornerIndex, 0))->Expect.toEqual(Some({Types.Position.row: 0, col: 0}))
59
- t->expect(Array.get(grid.cornerIndex, 1))->Expect.toEqual(Some({Types.Position.row: 0, col: 3}))
60
- })
61
- })
62
-
63
- describe("get", () => {
64
- let grid = fromLines(["+--+", "| |", "+--+"])
65
-
66
- test("returns character at valid position", t => {
67
- t->expect(get(grid, Types.Position.make(0, 0)))->Expect.toEqual(Some(Types.Corner))
68
- t->expect(get(grid, Types.Position.make(0, 1)))->Expect.toEqual(Some(Types.HLine))
69
- t->expect(get(grid, Types.Position.make(1, 0)))->Expect.toEqual(Some(Types.VLine))
70
- })
71
-
72
- test("returns None for out of bounds positions", t => {
73
- t->expect(get(grid, Types.Position.make(-1, 0)))->Expect.toBe(None)
74
- t->expect(get(grid, Types.Position.make(0, -1)))->Expect.toBe(None)
75
- t->expect(get(grid, Types.Position.make(10, 0)))->Expect.toBe(None)
76
- t->expect(get(grid, Types.Position.make(0, 10)))->Expect.toBe(None)
77
- })
78
- })
79
-
80
- describe("getLine", () => {
81
- let grid = fromLines(["+--+", "| |", "+--+"])
82
-
83
- test("returns entire line at valid row", t => {
84
- switch getLine(grid, 0) {
85
- | Some(line) => {
86
- t->expect(Array.length(line))->Expect.toBe(4)
87
- t->expect(Array.get(line, 0))->Expect.toEqual(Some(Types.Corner))
88
- }
89
- | None => t->expect(true)->Expect.toBe(false) // fail
90
- }
91
- })
92
-
93
- test("returns None for out of bounds row", t => {
94
- t->expect(getLine(grid, -1))->Expect.toBe(None)
95
- t->expect(getLine(grid, 10))->Expect.toBe(None)
96
- })
97
- })
98
-
99
- describe("getRange", () => {
100
- let grid = fromLines(["+--Name--+"])
101
-
102
- test("returns range of characters", t => {
103
- switch getRange(grid, 0, ~startCol=1, ~endCol=3) {
104
- | Some(range) => {
105
- t->expect(Array.length(range))->Expect.toBe(3)
106
- t->expect(Array.get(range, 0))->Expect.toEqual(Some(Types.HLine))
107
- }
108
- | None => t->expect(true)->Expect.toBe(false) // fail
109
- }
110
- })
111
-
112
- test("handles negative start column", t => {
113
- switch getRange(grid, 0, ~startCol=-1, ~endCol=2) {
114
- | Some(range) => {
115
- t->expect(Array.length(range))->Expect.toBe(3)
116
- }
117
- | None => t->expect(true)->Expect.toBe(false) // fail
118
- }
119
- })
120
-
121
- test("returns None for invalid row", t => {
122
- t->expect(getRange(grid, -1, ~startCol=0, ~endCol=2))->Expect.toBe(None)
123
- })
124
- })
125
-
126
- describe("scanRight", () => {
127
- let grid = fromLines(["+----+"])
128
-
129
- test("scans right until predicate fails", t => {
130
- let start = Types.Position.make(0, 0)
131
- let results = scanRight(grid, start, cell =>
132
- switch cell {
133
- | Types.Corner | Types.HLine => true
134
- | _ => false
135
- }
136
- )
137
-
138
- t->expect(Array.length(results))->Expect.toBe(6)
139
- })
140
-
141
- test("stops at grid boundary", t => {
142
- let start = Types.Position.make(0, 0)
143
- let results = scanRight(grid, start, _cell => true)
144
-
145
- t->expect(Array.length(results))->Expect.toBe(6)
146
- })
147
-
148
- test("returns empty array if predicate fails immediately", t => {
149
- let start = Types.Position.make(0, 0)
150
- let results = scanRight(grid, start, cell =>
151
- switch cell {
152
- | Types.HLine => true
153
- | _ => false
154
- }
155
- )
156
-
157
- t->expect(Array.length(results))->Expect.toBe(0)
158
- })
159
- })
160
-
161
- describe("scanDown", () => {
162
- let grid = fromLines(["+", "|", "|", "+"])
163
-
164
- test("scans down until predicate fails", t => {
165
- let start = Types.Position.make(0, 0)
166
- let results = scanDown(grid, start, cell =>
167
- switch cell {
168
- | Types.Corner | Types.VLine => true
169
- | _ => false
170
- }
171
- )
172
-
173
- t->expect(Array.length(results))->Expect.toBe(4)
174
- })
175
-
176
- test("stops at grid boundary", t => {
177
- let start = Types.Position.make(0, 0)
178
- let results = scanDown(grid, start, _cell => true)
179
-
180
- t->expect(Array.length(results))->Expect.toBe(4)
181
- })
182
- })
183
-
184
- describe("scanLeft", () => {
185
- let grid = fromLines(["+----+"])
186
-
187
- test("scans left until predicate fails", t => {
188
- let start = Types.Position.make(0, 5)
189
- let results = scanLeft(grid, start, cell =>
190
- switch cell {
191
- | Types.Corner | Types.HLine => true
192
- | _ => false
193
- }
194
- )
195
-
196
- t->expect(Array.length(results))->Expect.toBe(6)
197
- })
198
-
199
- test("stops at grid boundary", t => {
200
- let start = Types.Position.make(0, 5)
201
- let results = scanLeft(grid, start, _cell => true)
202
-
203
- t->expect(Array.length(results))->Expect.toBe(6)
204
- })
205
- })
206
-
207
- describe("scanUp", () => {
208
- let grid = fromLines(["+", "|", "|", "+"])
209
-
210
- test("scans up until predicate fails", t => {
211
- let start = Types.Position.make(3, 0)
212
- let results = scanUp(grid, start, cell =>
213
- switch cell {
214
- | Types.Corner | Types.VLine => true
215
- | _ => false
216
- }
217
- )
218
-
219
- t->expect(Array.length(results))->Expect.toBe(4)
220
- })
221
-
222
- test("stops at grid boundary", t => {
223
- let start = Types.Position.make(3, 0)
224
- let results = scanUp(grid, start, _cell => true)
225
-
226
- t->expect(Array.length(results))->Expect.toBe(4)
227
- })
228
- })
229
-
230
- describe("findAll", () => {
231
- let grid = fromLines(["+--+", "| |", "+--+"])
232
-
233
- test("finds all corners using index", t => {
234
- let corners = findAll(grid, Types.Corner)
235
- t->expect(Array.length(corners))->Expect.toBe(4)
236
- })
237
-
238
- test("finds all horizontal lines using index", t => {
239
- let hlines = findAll(grid, Types.HLine)
240
- t->expect(Array.length(hlines))->Expect.toBe(4)
241
- })
242
-
243
- test("finds all vertical lines using index", t => {
244
- let vlines = findAll(grid, Types.VLine)
245
- t->expect(Array.length(vlines))->Expect.toBe(2)
246
- })
247
-
248
- test("finds spaces through scanning", t => {
249
- let spaces = findAll(grid, Types.Space)
250
- t->expect(Array.length(spaces))->Expect.toBe(2)
251
- })
252
- })
253
-
254
- describe("findInRange", () => {
255
- let grid = fromLines(["+--+", "| |", "+--+", "| |", "+--+"])
256
-
257
- test("finds characters within bounds", t => {
258
- // Create bounds that only include first box
259
- let bounds: Types.Bounds.t = {
260
- top: 0,
261
- left: 0,
262
- bottom: 3,
263
- right: 4,
264
- }
265
-
266
- let corners = findInRange(grid, Types.Corner, bounds)
267
- t->expect(Array.length(corners))->Expect.toBe(4)
268
- })
269
-
270
- test("excludes characters outside bounds", t => {
271
- // Create tight bounds that exclude all corners
272
- // Corners are at (0,0), (0,3), (2,0), (2,3), (4,0), (4,3)
273
- // These bounds (row 1-2, col 1-2) don't contain any corners
274
- let bounds: Types.Bounds.t = {
275
- top: 1,
276
- left: 1,
277
- bottom: 2,
278
- right: 2,
279
- }
280
-
281
- let corners = findInRange(grid, Types.Corner, bounds)
282
- t->expect(Array.length(corners))->Expect.toBe(0)
283
- })
284
- })
285
-
286
- describe("isValidPosition", () => {
287
- let grid = fromLines(["+--+", "| |", "+--+"])
288
-
289
- test("returns true for valid positions", t => {
290
- t->expect(isValidPosition(grid, Types.Position.make(0, 0)))->Expect.toBe(true)
291
- t->expect(isValidPosition(grid, Types.Position.make(1, 2)))->Expect.toBe(true)
292
- t->expect(isValidPosition(grid, Types.Position.make(2, 3)))->Expect.toBe(true)
293
- })
294
-
295
- test("returns false for out of bounds positions", t => {
296
- t->expect(isValidPosition(grid, Types.Position.make(-1, 0)))->Expect.toBe(false)
297
- t->expect(isValidPosition(grid, Types.Position.make(0, -1)))->Expect.toBe(false)
298
- t->expect(isValidPosition(grid, Types.Position.make(10, 0)))->Expect.toBe(false)
299
- t->expect(isValidPosition(grid, Types.Position.make(0, 10)))->Expect.toBe(false)
300
- })
301
- })
302
-
303
- describe("Performance", () => {
304
- test("handles large grids efficiently", t => {
305
- // Generate a large grid (1000 lines)
306
- let lines = Array.make(~length=1000, "+----+")
307
-
308
- let startTime = Date.now()
309
- let grid = fromLines(lines)
310
- let endTime = Date.now()
311
-
312
- let duration = endTime -. startTime
313
-
314
- t->expect(grid.height)->Expect.toBe(1000)
315
- // Performance requirement: should be < 10ms
316
- t->expect(duration)->Expect.Float.toBeLessThan(10.0)
317
- })
318
- })
319
- })