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
package/README.md CHANGED
@@ -3,7 +3,11 @@
3
3
  > A library that converts ASCII wireframes into working HTML/UI
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/wyreframe.svg)](https://www.npmjs.com/package/wyreframe)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![npm downloads](https://img.shields.io/npm/dm/wyreframe.svg)](https://www.npmjs.com/package/wyreframe)
7
+ [![codecov](https://codecov.io/gh/wickedev/wyreframe/branch/main/graph/badge.svg)](https://codecov.io/gh/wickedev/wyreframe)
8
+ [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
9
+ [![ReScript](https://img.shields.io/badge/ReScript-12-e6484f.svg)](https://rescript-lang.org/)
10
+ [![Node.js](https://img.shields.io/badge/Node.js-20+-green.svg)](https://nodejs.org/)
7
11
 
8
12
  ```
9
13
  +---------------------------+
@@ -52,6 +56,36 @@ if (result.success) {
52
56
  }
53
57
  ```
54
58
 
59
+ ### ReScript
60
+
61
+ ```rescript
62
+ let ui = `
63
+ @scene: login
64
+
65
+ +---------------------------+
66
+ | 'WYREFRAME' |
67
+ | +---------------------+ |
68
+ | | #email | |
69
+ | +---------------------+ |
70
+ | [ Login ] |
71
+ +---------------------------+
72
+
73
+ #email:
74
+ placeholder: "Enter your email"
75
+
76
+ [Login]:
77
+ @click -> goto(dashboard, slide-left)
78
+ `
79
+
80
+ switch Renderer.createUI(ui, None) {
81
+ | Ok({root, sceneManager, _}) => {
82
+ // Append root to DOM
83
+ sceneManager.goto("login")
84
+ }
85
+ | Error(errors) => Console.error(errors)
86
+ }
87
+ ```
88
+
55
89
  ## Syntax Summary
56
90
 
57
91
  | Syntax | Description | Example |
@@ -66,6 +100,8 @@ if (result.success) {
66
100
 
67
101
  ## API
68
102
 
103
+ ### JavaScript/TypeScript
104
+
69
105
  ```javascript
70
106
  import { parse, render, createUI, createUIOrThrow } from 'wyreframe';
71
107
 
@@ -82,6 +118,22 @@ const result = createUI(text);
82
118
  const { root, sceneManager } = createUIOrThrow(text);
83
119
  ```
84
120
 
121
+ ### ReScript
122
+
123
+ ```rescript
124
+ // Parse only
125
+ let result = Parser.parse(text)
126
+
127
+ // Render only
128
+ let {root, sceneManager} = Renderer.render(ast, None)
129
+
130
+ // Parse + Render (recommended)
131
+ let result = Renderer.createUI(text, None)
132
+
133
+ // Throw on error
134
+ let {root, sceneManager, ast} = Renderer.createUIOrThrow(text, None)
135
+ ```
136
+
85
137
  ### SceneManager
86
138
 
87
139
  ```javascript
@@ -90,6 +142,12 @@ sceneManager.getCurrentScene(); // Get current scene
90
142
  sceneManager.getSceneIds(); // Get all scene IDs
91
143
  ```
92
144
 
145
+ ```rescript
146
+ sceneManager.goto("dashboard") // Navigate to scene
147
+ sceneManager.getCurrentScene() // Get current scene (option<string>)
148
+ sceneManager.getSceneIds() // Get all scene IDs (array<string>)
149
+ ```
150
+
93
151
  ## Interactions
94
152
 
95
153
  ```yaml
@@ -105,9 +163,11 @@ sceneManager.getSceneIds(); // Get all scene IDs
105
163
 
106
164
  ## Documentation
107
165
 
108
- - [Parser Architecture](docs/PARSER_ARCHITECTURE.md)
109
- - [Testing Guide](docs/TESTING.md)
110
- - [Examples](examples/index.html)
166
+ - [API Reference](docs/api.md)
167
+ - [Developer Guide](docs/developer-guide.md)
168
+ - [Examples](docs/examples.md)
169
+ - [Testing Guide](docs/testing.md)
170
+ - [Live Demo](examples/index.html)
111
171
 
112
172
  ## Development
113
173
 
@@ -120,4 +180,4 @@ npm test # Run tests
120
180
 
121
181
  ## License
122
182
 
123
- MIT License
183
+ GPL-3.0 License - see [LICENSE](LICENSE) for details.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wyreframe",
3
- "version": "0.1.0",
3
+ "version": "0.1.5",
4
4
  "description": "ASCII wireframe + interaction DSL to HTML converter with scene transitions",
5
5
  "author": "wickedev",
6
6
  "repository": {
@@ -13,8 +13,8 @@
13
13
  "types": "dist/index.d.ts",
14
14
  "files": [
15
15
  "dist",
16
- "src/parser",
17
- "src/renderer",
16
+ "src",
17
+ "!src/**/__tests__",
18
18
  "README.md"
19
19
  ],
20
20
  "exports": {
@@ -50,14 +50,15 @@
50
50
  "html",
51
51
  "prototype"
52
52
  ],
53
- "license": "MIT",
53
+ "license": "GPL-3.0",
54
54
  "dependencies": {
55
55
  "@rescript/core": "^1.6.1",
56
- "rescript": "12",
57
- "vitest": "^3.2.4"
56
+ "rescript": "12"
58
57
  },
59
58
  "devDependencies": {
59
+ "@vitest/coverage-v8": "^3.1.4",
60
60
  "rescript-vitest": "^2.1.1",
61
- "typescript": "^5.9.3"
61
+ "typescript": "^5.9.3",
62
+ "vitest": "^3.1.4"
62
63
  }
63
64
  }
package/src/index.ts ADDED
@@ -0,0 +1,425 @@
1
+ /**
2
+ * Wyreframe - ASCII Wireframe to HTML/UI Converter
3
+ *
4
+ * This module provides a TypeScript-friendly API wrapper
5
+ * around the ReScript parser implementation.
6
+ */
7
+
8
+ // Note: These imports use relative paths that work when compiled to dist/
9
+ // The ReScript .mjs files remain in src/parser/, so dist/index.js imports ../src/parser/
10
+ // @ts-ignore - ReScript generated module
11
+ import * as Parser from '../src/parser/Parser.mjs';
12
+ // @ts-ignore - ReScript generated module
13
+ import * as Renderer from '../src/renderer/Renderer.mjs';
14
+
15
+ // ============================================================================
16
+ // Type Definitions
17
+ // ============================================================================
18
+
19
+ /** Device type for responsive design */
20
+ export type DeviceType =
21
+ | 'desktop'
22
+ | 'laptop'
23
+ | 'tablet'
24
+ | 'tablet-landscape'
25
+ | 'mobile'
26
+ | 'mobile-landscape';
27
+
28
+ /** Transition effect for scene changes */
29
+ export type TransitionType = 'fade' | 'slide-left' | 'slide-right' | 'zoom';
30
+
31
+ /** Text alignment */
32
+ export type Alignment = 'left' | 'center' | 'right';
33
+
34
+ /** Button variant styles */
35
+ export type ButtonVariant = 'primary' | 'secondary' | 'ghost';
36
+
37
+ /** Action types for interactions */
38
+ export interface GotoAction {
39
+ type: 'goto';
40
+ target: string;
41
+ transition?: TransitionType;
42
+ }
43
+
44
+ export type Action = GotoAction;
45
+
46
+ /** UI Element types */
47
+ export interface BoxElement {
48
+ TAG: 'Box';
49
+ name?: string;
50
+ children: Element[];
51
+ }
52
+
53
+ export interface ButtonElement {
54
+ TAG: 'Button';
55
+ id: string;
56
+ text: string;
57
+ align: Alignment;
58
+ variant?: ButtonVariant;
59
+ actions: Action[];
60
+ }
61
+
62
+ export interface InputElement {
63
+ TAG: 'Input';
64
+ id: string;
65
+ placeholder?: string;
66
+ variant?: string;
67
+ }
68
+
69
+ export interface LinkElement {
70
+ TAG: 'Link';
71
+ id: string;
72
+ text: string;
73
+ align: Alignment;
74
+ actions: Action[];
75
+ }
76
+
77
+ export interface TextElement {
78
+ TAG: 'Text';
79
+ content: string;
80
+ emphasis: boolean;
81
+ align: Alignment;
82
+ }
83
+
84
+ export interface CheckboxElement {
85
+ TAG: 'Checkbox';
86
+ checked: boolean;
87
+ label: string;
88
+ }
89
+
90
+ export interface DividerElement {
91
+ TAG: 'Divider';
92
+ }
93
+
94
+ export interface RowElement {
95
+ TAG: 'Row';
96
+ children: Element[];
97
+ align: Alignment;
98
+ }
99
+
100
+ export interface SectionElement {
101
+ TAG: 'Section';
102
+ name: string;
103
+ children: Element[];
104
+ }
105
+
106
+ export type Element =
107
+ | BoxElement
108
+ | ButtonElement
109
+ | InputElement
110
+ | LinkElement
111
+ | TextElement
112
+ | CheckboxElement
113
+ | DividerElement
114
+ | RowElement
115
+ | SectionElement;
116
+
117
+ /** Scene definition */
118
+ export interface Scene {
119
+ id: string;
120
+ title: string;
121
+ device: DeviceType;
122
+ transition: TransitionType;
123
+ elements: Element[];
124
+ }
125
+
126
+ /** Abstract Syntax Tree */
127
+ export interface AST {
128
+ scenes: Scene[];
129
+ }
130
+
131
+ /** Parse error information */
132
+ export interface ParseError {
133
+ message: string;
134
+ line?: number;
135
+ column?: number;
136
+ source?: string;
137
+ }
138
+
139
+ /** Scene manager for programmatic navigation */
140
+ export interface SceneManager {
141
+ /** Navigate to a scene by ID */
142
+ goto: (sceneId: string) => void;
143
+ /** Get the current scene ID */
144
+ getCurrentScene: () => string | undefined;
145
+ /** Get all available scene IDs */
146
+ getSceneIds: () => string[];
147
+ }
148
+
149
+ /** Render options */
150
+ export interface RenderOptions {
151
+ /** Theme name */
152
+ theme?: string;
153
+ /** Enable interactions (default: true) */
154
+ interactive?: boolean;
155
+ /** Inject default styles (default: true) */
156
+ injectStyles?: boolean;
157
+ /** Additional CSS class for container */
158
+ containerClass?: string;
159
+ }
160
+
161
+ /** Render result */
162
+ export interface RenderResult {
163
+ /** Rendered root element */
164
+ root: HTMLElement;
165
+ /** Scene manager for navigation */
166
+ sceneManager: SceneManager;
167
+ }
168
+
169
+ // ============================================================================
170
+ // Result Types (TypeScript-friendly)
171
+ // ============================================================================
172
+
173
+ export type ParseSuccessResult = {
174
+ success: true;
175
+ ast: AST;
176
+ };
177
+
178
+ export type ParseErrorResult = {
179
+ success: false;
180
+ errors: ParseError[];
181
+ };
182
+
183
+ export type ParseResult = ParseSuccessResult | ParseErrorResult;
184
+
185
+ export type InteractionSuccessResult = {
186
+ success: true;
187
+ interactions: unknown[];
188
+ };
189
+
190
+ export type InteractionErrorResult = {
191
+ success: false;
192
+ errors: ParseError[];
193
+ };
194
+
195
+ export type InteractionResult = InteractionSuccessResult | InteractionErrorResult;
196
+
197
+ export type CreateUISuccessResult = {
198
+ success: true;
199
+ root: HTMLElement;
200
+ sceneManager: SceneManager;
201
+ ast: AST;
202
+ };
203
+
204
+ export type CreateUIErrorResult = {
205
+ success: false;
206
+ errors: ParseError[];
207
+ };
208
+
209
+ export type CreateUIResult = CreateUISuccessResult | CreateUIErrorResult;
210
+
211
+ // ============================================================================
212
+ // Internal ReScript Result Type
213
+ // ============================================================================
214
+
215
+ interface ReScriptOk<T> {
216
+ TAG: 'Ok';
217
+ _0: T;
218
+ }
219
+
220
+ interface ReScriptError<E> {
221
+ TAG: 'Error';
222
+ _0: E;
223
+ }
224
+
225
+ type ReScriptResult<T, E> = ReScriptOk<T> | ReScriptError<E>;
226
+
227
+ // ============================================================================
228
+ // API Functions
229
+ // ============================================================================
230
+
231
+ /**
232
+ * Parse mixed text containing wireframe and interactions.
233
+ *
234
+ * @param text - Text containing ASCII wireframe and/or interaction DSL
235
+ * @returns Parse result with success flag
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * const result = parse(text);
240
+ * if (result.success) {
241
+ * const { root, sceneManager } = render(result.ast);
242
+ * document.body.appendChild(root);
243
+ * } else {
244
+ * console.error(result.errors);
245
+ * }
246
+ * ```
247
+ */
248
+ export function parse(text: string): ParseResult {
249
+ const result = Parser.parse(text) as ReScriptResult<AST, ParseError[]>;
250
+
251
+ if (result.TAG === 'Ok') {
252
+ return { success: true, ast: result._0 };
253
+ } else {
254
+ return { success: false, errors: result._0 };
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Parse text and throw on error.
260
+ * Use this for simpler code when you expect parsing to succeed.
261
+ *
262
+ * @param text - Text containing ASCII wireframe and/or interaction DSL
263
+ * @returns Parsed AST
264
+ * @throws Error if parsing fails
265
+ *
266
+ * @example
267
+ * ```typescript
268
+ * try {
269
+ * const ast = parseOrThrow(text);
270
+ * const { root } = render(ast);
271
+ * document.body.appendChild(root);
272
+ * } catch (error) {
273
+ * console.error('Parse failed:', error.message);
274
+ * }
275
+ * ```
276
+ */
277
+ export function parseOrThrow(text: string): AST {
278
+ const result = parse(text);
279
+
280
+ if (result.success) {
281
+ return result.ast;
282
+ } else {
283
+ const errorMessages = result.errors
284
+ .map((e) => e.message || JSON.stringify(e))
285
+ .join('\n');
286
+ throw new Error(`Parse failed:\n${errorMessages}`);
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Parse only the wireframe structure (no interactions).
292
+ *
293
+ * @param wireframe - ASCII wireframe string
294
+ * @returns Parse result with success flag
295
+ */
296
+ export function parseWireframe(wireframe: string): ParseResult {
297
+ const result = Parser.parseWireframe(wireframe) as ReScriptResult<AST, ParseError[]>;
298
+
299
+ if (result.TAG === 'Ok') {
300
+ return { success: true, ast: result._0 };
301
+ } else {
302
+ return { success: false, errors: result._0 };
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Parse only the interaction DSL.
308
+ *
309
+ * @param dsl - Interaction DSL string
310
+ * @returns Interaction result with success flag
311
+ */
312
+ export function parseInteractions(dsl: string): InteractionResult {
313
+ const result = Parser.parseInteractions(dsl) as ReScriptResult<unknown[], ParseError[]>;
314
+
315
+ if (result.TAG === 'Ok') {
316
+ return { success: true, interactions: result._0 };
317
+ } else {
318
+ return { success: false, errors: result._0 };
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Render AST to DOM elements.
324
+ *
325
+ * @param ast - Parsed AST from parse()
326
+ * @param options - Render options
327
+ * @returns Render result with root element and scene manager
328
+ *
329
+ * @example
330
+ * ```typescript
331
+ * const { root, sceneManager } = render(ast);
332
+ * document.getElementById('app')!.appendChild(root);
333
+ *
334
+ * // Navigate between scenes
335
+ * sceneManager.goto('dashboard');
336
+ * ```
337
+ */
338
+ export function render(ast: AST, options?: RenderOptions): RenderResult {
339
+ // Pass undefined if no options, so ReScript uses its defaults
340
+ const result = Renderer.render(ast, options);
341
+
342
+ return {
343
+ root: result.root,
344
+ sceneManager: {
345
+ goto: result.sceneManager.goto,
346
+ getCurrentScene: result.sceneManager.getCurrentScene,
347
+ getSceneIds: result.sceneManager.getSceneIds,
348
+ },
349
+ };
350
+ }
351
+
352
+ /**
353
+ * Parse and render in one step.
354
+ * Convenience function that combines parse() and render().
355
+ *
356
+ * @param text - Text containing ASCII wireframe and/or interaction DSL
357
+ * @param options - Render options
358
+ * @returns Create UI result with success flag
359
+ *
360
+ * @example
361
+ * ```typescript
362
+ * const result = createUI(text);
363
+ * if (result.success) {
364
+ * document.getElementById('app')!.appendChild(result.root);
365
+ * result.sceneManager.goto('login');
366
+ * }
367
+ * ```
368
+ */
369
+ export function createUI(text: string, options?: RenderOptions): CreateUIResult {
370
+ const parseResult = parse(text);
371
+
372
+ if (!parseResult.success) {
373
+ return parseResult;
374
+ }
375
+
376
+ const { root, sceneManager } = render(parseResult.ast, options);
377
+
378
+ return {
379
+ success: true,
380
+ root,
381
+ sceneManager,
382
+ ast: parseResult.ast,
383
+ };
384
+ }
385
+
386
+ /**
387
+ * Parse and render, throwing on error.
388
+ *
389
+ * @param text - Text containing ASCII wireframe and/or interaction DSL
390
+ * @param options - Render options
391
+ * @returns Render result with root element, scene manager, and AST
392
+ * @throws Error if parsing fails
393
+ *
394
+ * @example
395
+ * ```typescript
396
+ * const { root, sceneManager } = createUIOrThrow(text);
397
+ * document.getElementById('app')!.appendChild(root);
398
+ * ```
399
+ */
400
+ export function createUIOrThrow(
401
+ text: string,
402
+ options?: RenderOptions
403
+ ): RenderResult & { ast: AST } {
404
+ const ast = parseOrThrow(text);
405
+ const { root, sceneManager } = render(ast, options);
406
+
407
+ return { root, sceneManager, ast };
408
+ }
409
+
410
+ // Version info
411
+ export const version: string = Parser.version;
412
+ export const implementation: string = Parser.implementation;
413
+
414
+ // Default export for convenience
415
+ export default {
416
+ parse,
417
+ parseOrThrow,
418
+ parseWireframe,
419
+ parseInteractions,
420
+ render,
421
+ createUI,
422
+ createUIOrThrow,
423
+ version,
424
+ implementation,
425
+ };
@@ -7,6 +7,8 @@ import * as RendererJS from './Renderer.mjs';
7
7
 
8
8
  import type {ast as Types_ast} from '../../src/parser/Core/Types.gen';
9
9
 
10
+ import type {t as ErrorTypes_t} from '../../src/parser/Errors/ErrorTypes.gen';
11
+
10
12
  export abstract class DomBindings_element { protected opaque!: any }; /* simulate opaque types */
11
13
 
12
14
  /** * Configuration for the rendering process. */
@@ -27,6 +29,53 @@ export type sceneManager = {
27
29
  /** * Render result containing the root element and scene manager. */
28
30
  export type renderResult = { readonly root: DomBindings_element; readonly sceneManager: sceneManager };
29
31
 
32
+ /** * Result type for createUI function.
33
+ * Contains either success with rendered elements or error with parse errors. */
34
+ export type createUISuccessResult = {
35
+ readonly root: DomBindings_element;
36
+ readonly sceneManager: sceneManager;
37
+ readonly ast: Types_ast
38
+ };
39
+
40
+ export type createUIResult =
41
+ { TAG: "Ok"; _0: createUISuccessResult }
42
+ | { TAG: "Error"; _0: ErrorTypes_t[] };
43
+
30
44
  export const render: (ast:Types_ast, options:(undefined | renderOptions)) => renderResult = RendererJS.render as any;
31
45
 
32
46
  export const toHTMLString: (_ast:Types_ast, _options:(undefined | renderOptions)) => string = RendererJS.toHTMLString as any;
47
+
48
+ /** * Parse and render wireframe in one step.
49
+ * Combines Parser.parse() and Renderer.render() for convenience.
50
+ *
51
+ * @param text Text containing ASCII wireframe and/or interaction DSL
52
+ * @param options Optional render options
53
+ * @returns Result containing root element, scene manager, and AST, or errors
54
+ *
55
+ * @example
56
+ * ```rescript
57
+ * let result = Renderer.createUI(wireframeText, None)
58
+ * switch result {
59
+ * | Ok({root, sceneManager, ast}) => {
60
+ * // Append root to DOM
61
+ * sceneManager.goto("login")
62
+ * }
63
+ * | Error(errors) => Console.error(errors)
64
+ * }
65
+ * ``` */
66
+ export const createUI: (text:string, options:(undefined | renderOptions)) => createUIResult = RendererJS.createUI as any;
67
+
68
+ /** * Parse and render wireframe, throwing on error.
69
+ * Use this for simpler code when parsing is expected to succeed.
70
+ *
71
+ * @param text Text containing ASCII wireframe and/or interaction DSL
72
+ * @param options Optional render options
73
+ * @returns Rendered root element, scene manager, and AST
74
+ * @raises Js.Exn.Error if parsing fails
75
+ *
76
+ * @example
77
+ * ```rescript
78
+ * let {root, sceneManager, ast} = Renderer.createUIOrThrow(wireframeText, None)
79
+ * // Use root directly - errors will throw exception
80
+ * ``` */
81
+ export const createUIOrThrow: (text:string, options:(undefined | renderOptions)) => createUISuccessResult = RendererJS.createUIOrThrow as any;
@@ -1,6 +1,9 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as Parser from "../parser/Parser.mjs";
3
4
  import * as Core__Option from "@rescript/core/src/Core__Option.mjs";
5
+ import * as ErrorMessages from "../parser/Errors/ErrorMessages.mjs";
6
+ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
4
7
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
5
8
 
6
9
  let DomBindings = {};
@@ -371,6 +374,41 @@ function toHTMLString(_ast, _options) {
371
374
  return "<!-- Static HTML generation not yet implemented -->";
372
375
  }
373
376
 
377
+ function createUI(text, options) {
378
+ let ast = Parser.parse(text);
379
+ if (ast.TAG !== "Ok") {
380
+ return {
381
+ TAG: "Error",
382
+ _0: ast._0
383
+ };
384
+ }
385
+ let ast$1 = ast._0;
386
+ let match = render(ast$1, options);
387
+ return {
388
+ TAG: "Ok",
389
+ _0: {
390
+ root: match.root,
391
+ sceneManager: match.sceneManager,
392
+ ast: ast$1
393
+ }
394
+ };
395
+ }
396
+
397
+ function createUIOrThrow(text, options) {
398
+ let ast = Parser.parse(text);
399
+ if (ast.TAG === "Ok") {
400
+ let ast$1 = ast._0;
401
+ let match = render(ast$1, options);
402
+ return {
403
+ root: match.root,
404
+ sceneManager: match.sceneManager,
405
+ ast: ast$1
406
+ };
407
+ }
408
+ let messages = ast._0.map(err => ErrorMessages.getTitle(err.code)).join("\n");
409
+ return Stdlib_JsError.throwWithMessage("Parse failed:\n" + messages);
410
+ }
411
+
374
412
  export {
375
413
  DomBindings,
376
414
  defaultOptions,
@@ -387,5 +425,7 @@ export {
387
425
  injectStyles,
388
426
  render,
389
427
  toHTMLString,
428
+ createUI,
429
+ createUIOrThrow,
390
430
  }
391
- /* No side effect */
431
+ /* Parser Not a pure module */