wyreframe 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.
Files changed (59) 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/test/Expect.mjs +9 -0
  9. package/src/parser/Core/__tests__/Bounds_test.mjs +0 -326
  10. package/src/parser/Core/__tests__/Bounds_test.res +0 -412
  11. package/src/parser/Core/__tests__/Grid_test.mjs +0 -322
  12. package/src/parser/Core/__tests__/Grid_test.res +0 -319
  13. package/src/parser/Core/__tests__/Types_test.mjs +0 -614
  14. package/src/parser/Core/__tests__/Types_test.res +0 -650
  15. package/src/parser/Detector/__tests__/BoxTracer_test.mjs +0 -70
  16. package/src/parser/Detector/__tests__/BoxTracer_test.res +0 -92
  17. package/src/parser/Detector/__tests__/HierarchyBuilder_test.mjs +0 -489
  18. package/src/parser/Detector/__tests__/HierarchyBuilder_test.res +0 -849
  19. package/src/parser/Detector/__tests__/ShapeDetector_test.mjs +0 -377
  20. package/src/parser/Detector/__tests__/ShapeDetector_test.res +0 -563
  21. package/src/parser/Interactions/__tests__/InteractionMerger_test.mjs +0 -576
  22. package/src/parser/Interactions/__tests__/InteractionMerger_test.res +0 -646
  23. package/src/parser/Scanner/__tests__/Grid_manual.mjs +0 -214
  24. package/src/parser/Scanner/__tests__/Grid_manual.res +0 -141
  25. package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.mjs +0 -189
  26. package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.res +0 -257
  27. package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.mjs +0 -202
  28. package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.res +0 -250
  29. package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.mjs +0 -293
  30. package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.res +0 -134
  31. package/src/parser/Semantic/Elements/__tests__/InputParser_test.mjs +0 -253
  32. package/src/parser/Semantic/Elements/__tests__/InputParser_test.res +0 -304
  33. package/src/parser/Semantic/Elements/__tests__/LinkParser_test.mjs +0 -289
  34. package/src/parser/Semantic/Elements/__tests__/LinkParser_test.res +0 -402
  35. package/src/parser/Semantic/Elements/__tests__/TextParser_test.mjs +0 -149
  36. package/src/parser/Semantic/Elements/__tests__/TextParser_test.res +0 -167
  37. package/src/parser/Semantic/__tests__/ASTBuilder_test.mjs +0 -187
  38. package/src/parser/Semantic/__tests__/ASTBuilder_test.res +0 -192
  39. package/src/parser/Semantic/__tests__/ParserRegistry_test.mjs +0 -154
  40. package/src/parser/Semantic/__tests__/ParserRegistry_test.res +0 -191
  41. package/src/parser/Semantic/__tests__/SemanticParser_integration_test.mjs +0 -768
  42. package/src/parser/Semantic/__tests__/SemanticParser_integration_test.res +0 -1069
  43. package/src/parser/Semantic/__tests__/SemanticParser_manual.mjs +0 -1329
  44. package/src/parser/Semantic/__tests__/SemanticParser_manual.res +0 -544
  45. package/src/parser/__tests__/GridScanner_integration.test.mjs +0 -632
  46. package/src/parser/__tests__/GridScanner_integration.test.res +0 -816
  47. package/src/parser/__tests__/Performance.test.mjs +0 -244
  48. package/src/parser/__tests__/Performance.test.res +0 -371
  49. package/src/parser/__tests__/PerformanceFixtures.mjs +0 -200
  50. package/src/parser/__tests__/PerformanceFixtures.res +0 -284
  51. package/src/parser/__tests__/WyreframeParser_integration.test.mjs +0 -770
  52. package/src/parser/__tests__/WyreframeParser_integration.test.res +0 -1008
  53. package/src/parser/__tests__/fixtures/alignment-test.txt +0 -9
  54. package/src/parser/__tests__/fixtures/all-elements.txt +0 -16
  55. package/src/parser/__tests__/fixtures/login-scene.txt +0 -17
  56. package/src/parser/__tests__/fixtures/multi-scene.txt +0 -25
  57. package/src/parser/__tests__/fixtures/nested-boxes.txt +0 -15
  58. package/src/parser/__tests__/fixtures/simple-box.txt +0 -5
  59. 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
- })