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,770 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Parser from "../Parser.mjs";
4
- import * as Vitest from "rescript-vitest/src/Vitest.mjs";
5
- import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
6
-
7
- function collectAllElements(elements) {
8
- return elements.flatMap(el => {
9
- if (el.TAG === "Box") {
10
- return [el].concat(collectAllElements(el.children));
11
- } else {
12
- return [el];
13
- }
14
- });
15
- }
16
-
17
- function findElement(elements, predicate) {
18
- let allElements = collectAllElements(elements);
19
- return Belt_Array.getBy(allElements, predicate);
20
- }
21
-
22
- function hasElement(elements, predicate) {
23
- let allElements = collectAllElements(elements);
24
- return Belt_Array.some(allElements, predicate);
25
- }
26
-
27
- function countElements(elements, predicate) {
28
- let allElements = collectAllElements(elements);
29
- return Belt_Array.reduce(allElements, 0, (count, el) => {
30
- if (predicate(el)) {
31
- return count + 1 | 0;
32
- } else {
33
- return count;
34
- }
35
- });
36
- }
37
-
38
- Vitest.describe("E2E-01: Parse Simple Login Scene", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => Vitest.test("parses complete login scene with all element types", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
39
- let result = Parser.parse(`
40
- @scene: login
41
- @title: Login Page
42
- @transition: fade
43
-
44
- +--Login----------------+
45
- | |
46
- | * Welcome Back |
47
- | |
48
- | Email: |
49
- | #email |
50
- | |
51
- | Password: |
52
- | #password |
53
- | |
54
- | [x] Remember me |
55
- | |
56
- | [ Login ] |
57
- | |
58
- | "Forgot password?" |
59
- | |
60
- +-----------------------+
61
- `);
62
- if (result.TAG === "Ok") {
63
- let ast = result._0;
64
- t.expect(ast.scenes.length).toBe(1);
65
- let scene = ast.scenes[0];
66
- t.expect(scene.id).toBe("login");
67
- t.expect(scene.title).toBe("Login Page");
68
- t.expect(scene.transition).toBe("fade");
69
- let emphasisFound = hasElement(scene.elements, el => {
70
- if (el.TAG === "Text" && el.emphasis) {
71
- return el.content.includes("Welcome Back");
72
- } else {
73
- return false;
74
- }
75
- });
76
- t.expect(emphasisFound).toBe(true);
77
- let emailInput = findElement(scene.elements, el => {
78
- if (el.TAG === "Input") {
79
- return el.id === "email";
80
- } else {
81
- return false;
82
- }
83
- });
84
- t.expect(emailInput).not.toBe(undefined);
85
- let passwordInput = findElement(scene.elements, el => {
86
- if (el.TAG === "Input") {
87
- return el.id === "password";
88
- } else {
89
- return false;
90
- }
91
- });
92
- t.expect(passwordInput).not.toBe(undefined);
93
- let checkbox = findElement(scene.elements, el => {
94
- if (el.TAG === "Checkbox" && el.checked) {
95
- return el.label.includes("Remember me");
96
- } else {
97
- return false;
98
- }
99
- });
100
- t.expect(checkbox).not.toBe(undefined);
101
- let button = findElement(scene.elements, el => {
102
- if (el.TAG !== "Button") {
103
- return false;
104
- }
105
- if (el.text !== "Login") {
106
- return false;
107
- }
108
- switch (el.align) {
109
- case "Center" :
110
- return true;
111
- case "Left" :
112
- case "Right" :
113
- return false;
114
- }
115
- });
116
- t.expect(button).not.toBe(undefined);
117
- let link = findElement(scene.elements, el => {
118
- if (el.TAG === "Link") {
119
- return el.text.includes("Forgot password");
120
- } else {
121
- return false;
122
- }
123
- });
124
- return t.expect(link).not.toBe(undefined);
125
- }
126
- console.error("Parse errors:", result._0);
127
- t.expect(true).toBe(false);
128
- }));
129
-
130
- Vitest.describe("E2E-02: Parse Multi-Scene Wireframe", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => Vitest.test("parses multiple scenes with correct transitions", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
131
- let result = Parser.parse(`
132
- @scene: home
133
- @title: Home Screen
134
- @transition: slide-right
135
-
136
- +--Home---------------+
137
- | |
138
- | "Go to Settings" |
139
- | |
140
- +---------------------+
141
-
142
- ---
143
-
144
- @scene: settings
145
- @title: Settings
146
- @transition: slide-left
147
-
148
- +--Settings----------+
149
- | |
150
- | [x] Notifications |
151
- | [ ] Dark Mode |
152
- | |
153
- | [ Save ] |
154
- | |
155
- +--------------------+
156
- `);
157
- if (result.TAG === "Ok") {
158
- let ast = result._0;
159
- t.expect(ast.scenes.length).toBe(2);
160
- let homeScene = ast.scenes[0];
161
- t.expect(homeScene.id).toBe("home");
162
- t.expect(homeScene.title).toBe("Home Screen");
163
- t.expect(homeScene.transition).toBe("slide-right");
164
- let settingsScene = ast.scenes[1];
165
- t.expect(settingsScene.id).toBe("settings");
166
- t.expect(settingsScene.title).toBe("Settings");
167
- t.expect(settingsScene.transition).toBe("slide-left");
168
- let notificationsCheckbox = findElement(settingsScene.elements, el => {
169
- if (el.TAG === "Checkbox" && el.checked) {
170
- return el.label.includes("Notifications");
171
- } else {
172
- return false;
173
- }
174
- });
175
- t.expect(notificationsCheckbox).not.toBe(undefined);
176
- let darkModeCheckbox = findElement(settingsScene.elements, el => {
177
- if (el.TAG === "Checkbox" && !el.checked) {
178
- return el.label.includes("Dark Mode");
179
- } else {
180
- return false;
181
- }
182
- });
183
- t.expect(darkModeCheckbox).not.toBe(undefined);
184
- let saveButton = findElement(settingsScene.elements, el => {
185
- if (el.TAG === "Button") {
186
- return el.text === "Save";
187
- } else {
188
- return false;
189
- }
190
- });
191
- return t.expect(saveButton).not.toBe(undefined);
192
- }
193
- console.error("Parse errors:", result._0);
194
- t.expect(true).toBe(false);
195
- }));
196
-
197
- Vitest.describe("E2E-03: Parse Deeply Nested Boxes", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => Vitest.test("parses 3-level nested boxes with correct hierarchy", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
198
- let result = Parser.parse(`
199
- @scene: nested-test
200
-
201
- +--Level1-(Outer)------------------+
202
- | |
203
- | +--Level2-(Middle)-----------+ |
204
- | | | |
205
- | | +--Level3-(Inner)------+ | |
206
- | | | | | |
207
- | | | [ Action Button ] | | |
208
- | | | | | |
209
- | | +----------------------+ | |
210
- | | | |
211
- | +----------------------------+ |
212
- | |
213
- +----------------------------------+
214
- `);
215
- if (result.TAG === "Ok") {
216
- let scene = result._0.scenes[0];
217
- let rootBox = Belt_Array.getBy(scene.elements, el => {
218
- if (el.TAG !== "Box") {
219
- return false;
220
- }
221
- let boxName = el.name;
222
- if (boxName !== undefined) {
223
- return boxName.includes("Level1");
224
- } else {
225
- return false;
226
- }
227
- });
228
- t.expect(rootBox).not.toBe(undefined);
229
- if (rootBox !== undefined && rootBox.TAG === "Box") {
230
- let boxName = rootBox.name;
231
- if (boxName !== undefined) {
232
- let children = rootBox.children;
233
- t.expect(boxName.includes("Outer")).toBe(true);
234
- t.expect(children.length).toBeGreaterThan(0);
235
- let level2Box = Belt_Array.getBy(children, el => {
236
- if (el.TAG !== "Box") {
237
- return false;
238
- }
239
- let name = el.name;
240
- if (name !== undefined) {
241
- return name.includes("Level2");
242
- } else {
243
- return false;
244
- }
245
- });
246
- t.expect(level2Box).not.toBe(undefined);
247
- if (level2Box === undefined) {
248
- return t.expect(true).toBe(false);
249
- }
250
- if (level2Box.TAG !== "Box") {
251
- return t.expect(true).toBe(false);
252
- }
253
- let level3Box = Belt_Array.getBy(level2Box.children, el => {
254
- if (el.TAG !== "Box") {
255
- return false;
256
- }
257
- let name = el.name;
258
- if (name !== undefined) {
259
- return name.includes("Level3");
260
- } else {
261
- return false;
262
- }
263
- });
264
- t.expect(level3Box).not.toBe(undefined);
265
- if (level3Box === undefined) {
266
- return t.expect(true).toBe(false);
267
- }
268
- if (level3Box.TAG !== "Box") {
269
- return t.expect(true).toBe(false);
270
- }
271
- let button = Belt_Array.getBy(level3Box.children, el => {
272
- if (el.TAG === "Button") {
273
- return el.text.includes("Action Button");
274
- } else {
275
- return false;
276
- }
277
- });
278
- return t.expect(button).not.toBe(undefined);
279
- }
280
- }
281
- return t.expect(true).toBe(false);
282
- }
283
- console.error("Parse errors:", result._0);
284
- t.expect(true).toBe(false);
285
- }));
286
-
287
- Vitest.describe("E2E-04: Parse Wireframe with Dividers", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => Vitest.test("recognizes dividers as section separators", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
288
- let result = Parser.parse(`
289
- @scene: profile
290
-
291
- +--UserProfile---------+
292
- | |
293
- | * John Doe |
294
- | john@example.com |
295
- | |
296
- +======================+
297
- | |
298
- | Settings |
299
- | [x] Email Updates |
300
- | [ ] SMS Alerts |
301
- | |
302
- +======================+
303
- | |
304
- | [ Save Profile ] |
305
- | |
306
- +----------------------+
307
- `);
308
- if (result.TAG === "Ok") {
309
- let scene = result._0.scenes[0];
310
- let profileBox = Belt_Array.getBy(scene.elements, el => {
311
- if (el.TAG !== "Box") {
312
- return false;
313
- }
314
- let boxName = el.name;
315
- if (boxName !== undefined) {
316
- return boxName.includes("UserProfile");
317
- } else {
318
- return false;
319
- }
320
- });
321
- t.expect(profileBox).not.toBe(undefined);
322
- let dividerCount = countElements(scene.elements, el => el.TAG === "Divider");
323
- t.expect(dividerCount).toBeGreaterThan(0);
324
- let emphasisFound = hasElement(scene.elements, el => {
325
- if (el.TAG === "Text") {
326
- return el.emphasis;
327
- } else {
328
- return false;
329
- }
330
- });
331
- t.expect(emphasisFound).toBe(true);
332
- let checkboxesFound = hasElement(scene.elements, el => el.TAG === "Checkbox");
333
- t.expect(checkboxesFound).toBe(true);
334
- let buttonFound = hasElement(scene.elements, el => {
335
- if (el.TAG === "Button") {
336
- return el.text.includes("Save Profile");
337
- } else {
338
- return false;
339
- }
340
- });
341
- return t.expect(buttonFound).toBe(true);
342
- }
343
- console.error("Parse errors:", result._0);
344
- t.expect(true).toBe(false);
345
- }));
346
-
347
- Vitest.describe("E2E-05: Parse Wireframe with Interactions", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => Vitest.test("merges interaction DSL with wireframe AST", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
348
- let result = Parser.parse(`
349
- @scene: login
350
-
351
- +--Login---------+
352
- | |
353
- | #username |
354
- | #password |
355
- | |
356
- | [ Submit ] |
357
- | |
358
- +----------------+
359
- ` + "\n" + `
360
- @scene: login
361
-
362
- #username:
363
- placeholder: "Enter username"
364
- required: true
365
-
366
- #password:
367
- type: "password"
368
- placeholder: "Enter password"
369
-
370
- [ Submit ]:
371
- variant: "primary"
372
- @click -> validate(username, password)
373
- @click -> goto(dashboard, fade)
374
- `);
375
- if (result.TAG === "Ok") {
376
- let scene = result._0.scenes[0];
377
- let usernameInput = findElement(scene.elements, el => {
378
- if (el.TAG === "Input") {
379
- return el.id === "username";
380
- } else {
381
- return false;
382
- }
383
- });
384
- t.expect(usernameInput).not.toBe(undefined);
385
- let passwordInput = findElement(scene.elements, el => {
386
- if (el.TAG === "Input") {
387
- return el.id === "password";
388
- } else {
389
- return false;
390
- }
391
- });
392
- t.expect(passwordInput).not.toBe(undefined);
393
- let submitButton = findElement(scene.elements, el => {
394
- if (el.TAG === "Button" && el.text === "Submit") {
395
- return el.actions.length !== 0;
396
- } else {
397
- return false;
398
- }
399
- });
400
- return t.expect(submitButton).not.toBe(undefined);
401
- }
402
- console.error("Parse errors:", result._0);
403
- t.expect(true).toBe(false);
404
- }));
405
-
406
- Vitest.describe("E2E-06: Detect Structural Errors", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => Vitest.test("detects unclosed box errors", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
407
- let result = Parser.parse(`
408
- @scene: error-test
409
-
410
- +--Unclosed Box---+
411
- | |
412
- | Content here |
413
- +--
414
- `);
415
- if (result.TAG === "Ok") {
416
- return t.expect(true).toBe(false);
417
- }
418
- let errors = result._0;
419
- t.expect(errors.length).toBeGreaterThan(0);
420
- let hasUncloseError = Belt_Array.some(errors, error => {
421
- let match = error.code;
422
- return match.TAG === "UncloseBox";
423
- });
424
- t.expect(hasUncloseError).toBe(true);
425
- }));
426
-
427
- Vitest.describe("E2E-07: Detect Width Mismatch Errors", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => Vitest.test("detects mismatched top and bottom widths", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
428
- let result = Parser.parse(`
429
- @scene: error-test
430
-
431
- +--ShortTop--+
432
- | |
433
- +--------------+
434
- `);
435
- if (result.TAG === "Ok") {
436
- return t.expect(true).toBe(false);
437
- }
438
- let errors = result._0;
439
- t.expect(errors.length).toBeGreaterThan(0);
440
- let hasMismatchError = Belt_Array.some(errors, error => {
441
- let match = error.code;
442
- if (match.TAG !== "MismatchedWidth") {
443
- return false;
444
- }
445
- t.expect(match.topWidth).not.toBe(match.bottomWidth);
446
- return true;
447
- });
448
- t.expect(hasMismatchError).toBe(true);
449
- }));
450
-
451
- Vitest.describe("E2E-08: Detect Overlapping Boxes", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, _t => Vitest.test("detects overlapping non-nested boxes - feature not implemented", undefined, undefined, undefined, undefined, undefined, true, undefined, undefined, undefined, t => {
452
- let result = Parser.parse(`
453
- @scene: error-test
454
-
455
- +--Box1-------+
456
- | |
457
- | +--Box2----+---+
458
- | | | |
459
- +--|----------+ |
460
- | |
461
- +--------------+
462
- `);
463
- if (result.TAG === "Ok") {
464
- return t.expect(true).toBe(false);
465
- }
466
- let errors = result._0;
467
- t.expect(errors.length).toBeGreaterThan(0);
468
- let hasOverlapError = Belt_Array.some(errors, error => {
469
- let match = error.code;
470
- return match.TAG === "OverlappingBoxes";
471
- });
472
- t.expect(hasOverlapError).toBe(true);
473
- }));
474
-
475
- Vitest.describe("E2E-09: Generate Warnings for Deep Nesting", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => Vitest.test("generates warning for nesting depth > 4", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
476
- let result = Parser.parse(`
477
- @scene: warning-test
478
-
479
- +--L1------------------+
480
- | +--L2-------------+ |
481
- | | +--L3--------+ | |
482
- | | | +--L4----+ | | |
483
- | | | | +--L5-+ | | | |
484
- | | | | | | | | | |
485
- | | | | +-----+ | | | |
486
- | | | +---------+ | | |
487
- | | +-------------+ | |
488
- | +-----------------+ |
489
- +-----------------------+
490
- `);
491
- if (result.TAG === "Ok") {
492
- return t.expect(result._0.scenes.length).toBe(1);
493
- }
494
- let errors = result._0;
495
- let hasDeepNestingWarning = Belt_Array.some(errors, error => {
496
- let match = error.code;
497
- if (match.TAG !== "DeepNesting") {
498
- return false;
499
- }
500
- t.expect(match.depth).toBeGreaterThan(4);
501
- return true;
502
- });
503
- if (hasDeepNestingWarning) {
504
- return;
505
- } else {
506
- console.error("Parse errors:", errors);
507
- return t.expect(true).toBe(false);
508
- }
509
- }));
510
-
511
- Vitest.describe("E2E-10: Parse Complete Registration Flow", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => Vitest.test("parses realistic registration scene", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
512
- let result = Parser.parse(`
513
- @scene: register
514
- @title: Create Account
515
- @transition: fade
516
-
517
- +--CreateAccount--------------------+
518
- | |
519
- | * Join our community |
520
- | |
521
- | First Name: |
522
- | #firstName |
523
- | |
524
- | Last Name: |
525
- | #lastName |
526
- | |
527
- | Email Address: |
528
- | #email |
529
- | |
530
- | Password: |
531
- | #password |
532
- | |
533
- | Confirm Password: |
534
- | #confirmPassword |
535
- | |
536
- | [x] I agree to Terms of Service |
537
- | [x] Subscribe to newsletter |
538
- | |
539
- | [ Create Account ] |
540
- | |
541
- | "Already have an account?" |
542
- | |
543
- +-----------------------------------+
544
- `);
545
- if (result.TAG === "Ok") {
546
- let scene = result._0.scenes[0];
547
- t.expect(scene.id).toBe("register");
548
- t.expect(scene.title).toBe("Create Account");
549
- let inputCount = countElements(scene.elements, el => el.TAG === "Input");
550
- t.expect(inputCount).toBe(5);
551
- let checkboxCount = countElements(scene.elements, el => {
552
- if (el.TAG === "Checkbox") {
553
- return el.checked;
554
- } else {
555
- return false;
556
- }
557
- });
558
- t.expect(checkboxCount).toBe(2);
559
- let centerButton = findElement(scene.elements, el => {
560
- if (el.TAG !== "Button") {
561
- return false;
562
- }
563
- switch (el.align) {
564
- case "Center" :
565
- return el.text.includes("Create Account");
566
- case "Left" :
567
- case "Right" :
568
- return false;
569
- }
570
- });
571
- t.expect(centerButton).not.toBe(undefined);
572
- let linkFound = hasElement(scene.elements, el => el.TAG === "Link");
573
- t.expect(linkFound).toBe(true);
574
- let emphasisFound = hasElement(scene.elements, el => {
575
- if (el.TAG === "Text") {
576
- return el.emphasis;
577
- } else {
578
- return false;
579
- }
580
- });
581
- return t.expect(emphasisFound).toBe(true);
582
- }
583
- console.error("Parse errors:", result._0);
584
- t.expect(true).toBe(false);
585
- }));
586
-
587
- Vitest.describe("E2E-11: Parse Dashboard with Multiple Components", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => Vitest.test("parses complex dashboard layout", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
588
- let result = Parser.parse(`
589
- @scene: dashboard
590
- @title: Dashboard
591
-
592
- +--Dashboard------------------------+
593
- | |
594
- | +--Header---------------------+ |
595
- | | * Dashboard | |
596
- | | "Logout" | |
597
- | +-----------------------------+ |
598
- | |
599
- | +--Stats----------------------+ |
600
- | | | |
601
- | | Users: 1,234 | |
602
- | | Revenue: $45,678 | |
603
- | | | |
604
- | +-----------------------------+ |
605
- | |
606
- | +--Actions--------------------+ |
607
- | | | |
608
- | | [ Add User ] | |
609
- | | [ Generate Report ] | |
610
- | | | |
611
- | +-----------------------------+ |
612
- | |
613
- +-----------------------------------+
614
- `);
615
- if (result.TAG === "Ok") {
616
- let scene = result._0.scenes[0];
617
- let dashboardBox = Belt_Array.getBy(scene.elements, el => {
618
- if (el.TAG !== "Box") {
619
- return false;
620
- }
621
- let boxName = el.name;
622
- if (boxName !== undefined) {
623
- return boxName.includes("Dashboard");
624
- } else {
625
- return false;
626
- }
627
- });
628
- t.expect(dashboardBox).not.toBe(undefined);
629
- if (dashboardBox === undefined) {
630
- return t.expect(true).toBe(false);
631
- }
632
- if (dashboardBox.TAG !== "Box") {
633
- return t.expect(true).toBe(false);
634
- }
635
- let children = dashboardBox.children;
636
- let boxCount = Belt_Array.reduce(children, 0, (count, el) => {
637
- if (el.TAG === "Box") {
638
- return count + 1 | 0;
639
- } else {
640
- return count;
641
- }
642
- });
643
- t.expect(boxCount).toBe(3);
644
- let headerBox = Belt_Array.getBy(children, el => {
645
- if (el.TAG !== "Box") {
646
- return false;
647
- }
648
- let name = el.name;
649
- if (name !== undefined) {
650
- return name.includes("Header");
651
- } else {
652
- return false;
653
- }
654
- });
655
- t.expect(headerBox).not.toBe(undefined);
656
- let actionsBox = Belt_Array.getBy(children, el => {
657
- if (el.TAG !== "Box") {
658
- return false;
659
- }
660
- let name = el.name;
661
- if (name === undefined) {
662
- return false;
663
- }
664
- if (!name.includes("Actions")) {
665
- return false;
666
- }
667
- let buttonCount = Belt_Array.reduce(el.children, 0, (count, child) => {
668
- if (child.TAG === "Button") {
669
- return count + 1 | 0;
670
- } else {
671
- return count;
672
- }
673
- });
674
- return buttonCount >= 2;
675
- });
676
- return t.expect(actionsBox).not.toBe(undefined);
677
- }
678
- console.error("Parse errors:", result._0);
679
- t.expect(true).toBe(false);
680
- }));
681
-
682
- Vitest.describe("E2E-12: Handle Mixed Valid and Invalid Boxes", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
683
- Vitest.test("continues parsing after errors and collects all issues", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
684
- let result = Parser.parse(`
685
- @scene: mixed
686
-
687
- +--Good Box 1-----+
688
- | |
689
- | [ Button 1 ] |
690
- | |
691
- +-----------------+
692
-
693
- +--Bad Box 1------+
694
- | |
695
- +-------
696
-
697
- +--Good Box 2-----+
698
- | |
699
- | [ Button 2 ] |
700
- | |
701
- +-----------------+
702
-
703
- +--Bad Box 2+
704
- | |
705
- +-------------+
706
- `);
707
- if (result.TAG === "Ok") {
708
- return t.expect(true).toBe(false);
709
- }
710
- let errors = result._0;
711
- t.expect(errors.length).toBeGreaterThan(1);
712
- let hasUncloseError = Belt_Array.some(errors, error => {
713
- let match = error.code;
714
- return match.TAG === "UncloseBox";
715
- });
716
- let hasMismatchError = Belt_Array.some(errors, error => {
717
- let match = error.code;
718
- return match.TAG === "MismatchedWidth";
719
- });
720
- t.expect(hasUncloseError || hasMismatchError).toBe(true);
721
- });
722
- Vitest.test("successfully parses valid boxes even when errors exist", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, t => {
723
- let result = Parser.parse(`
724
- @scene: mixed
725
-
726
- +--Good Box 1-----+
727
- | |
728
- | [ Button 1 ] |
729
- | |
730
- +-----------------+
731
-
732
- +--Bad Box-------+
733
- | |
734
- +-----
735
-
736
- +--Good Box 2-----+
737
- | |
738
- | [ Button 2 ] |
739
- | |
740
- +-----------------+
741
- `);
742
- if (result.TAG === "Ok") {
743
- return;
744
- }
745
- let errors = result._0;
746
- t.expect(errors.length).toBeGreaterThan(0);
747
- let hasStructuralError = Belt_Array.some(errors, error => {
748
- let match = error.code;
749
- switch (match.TAG) {
750
- case "UncloseBox" :
751
- case "MismatchedWidth" :
752
- return true;
753
- default:
754
- return false;
755
- }
756
- });
757
- t.expect(hasStructuralError).toBe(true);
758
- });
759
- });
760
-
761
- let pass;
762
-
763
- export {
764
- pass,
765
- collectAllElements,
766
- findElement,
767
- hasElement,
768
- countElements,
769
- }
770
- /* Not a pure module */