wyreframe 0.2.1 → 0.3.0

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.
package/dist/index.d.ts CHANGED
@@ -99,6 +99,8 @@ export interface SceneManager {
99
99
  /** Get all available scene IDs */
100
100
  getSceneIds: () => string[];
101
101
  }
102
+ /** Scene change callback type */
103
+ export type OnSceneChangeCallback = (fromScene: string | undefined, toScene: string) => void;
102
104
  /** Render options */
103
105
  export interface RenderOptions {
104
106
  /** Theme name */
@@ -109,6 +111,13 @@ export interface RenderOptions {
109
111
  injectStyles?: boolean;
110
112
  /** Additional CSS class for container */
111
113
  containerClass?: string;
114
+ /**
115
+ * Callback fired when navigating between scenes.
116
+ * Useful for implementing scene history, analytics, or state synchronization.
117
+ * @param fromScene - The scene ID navigating from (undefined if initial navigation)
118
+ * @param toScene - The scene ID navigating to
119
+ */
120
+ onSceneChange?: OnSceneChangeCallback;
112
121
  }
113
122
  /** Render result */
114
123
  export interface RenderResult {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wyreframe",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "ASCII wireframe + interaction DSL to HTML converter with scene transitions",
5
5
  "author": "wickedev",
6
6
  "repository": {
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Tests for TypeScript API wrapper input validation
3
+ *
4
+ * These tests verify that render() provides helpful error messages
5
+ * when called with incorrect arguments (Issue #1).
6
+ */
7
+
8
+ import { describe, test, expect, vi } from 'vitest';
9
+ import { parse, render, createUI } from './index';
10
+ import type { AST, ParseResult, OnSceneChangeCallback } from './index';
11
+
12
+ describe('render() input validation (Issue #1)', () => {
13
+ const validWireframe = `
14
+ @scene: test
15
+
16
+ +-------+
17
+ | Hello |
18
+ +-------+
19
+ `;
20
+
21
+ test('throws descriptive error when passed successful ParseResult instead of AST', () => {
22
+ const result = parse(validWireframe);
23
+
24
+ // Verify we have a successful parse result
25
+ expect(result.success).toBe(true);
26
+
27
+ // This is the common mistake: passing result instead of result.ast
28
+ expect(() => {
29
+ render(result as unknown as AST);
30
+ }).toThrow('render() expects an AST object, but received a ParseResult');
31
+
32
+ expect(() => {
33
+ render(result as unknown as AST);
34
+ }).toThrow('Did you forget to extract .ast?');
35
+ });
36
+
37
+ test('throws descriptive error when passed failed ParseResult', () => {
38
+ // Invalid wireframe that will fail to parse
39
+ const invalidWireframe = '+--incomplete';
40
+ const result = parse(invalidWireframe);
41
+
42
+ // This should be a failed parse
43
+ expect(result.success).toBe(false);
44
+
45
+ expect(() => {
46
+ render(result as unknown as AST);
47
+ }).toThrow('render() received a failed ParseResult');
48
+
49
+ expect(() => {
50
+ render(result as unknown as AST);
51
+ }).toThrow('Check parse errors before calling render');
52
+ });
53
+
54
+ test('throws descriptive error when passed null or undefined', () => {
55
+ expect(() => {
56
+ render(null as unknown as AST);
57
+ }).toThrow('render() expects an AST object with a scenes array');
58
+
59
+ expect(() => {
60
+ render(undefined as unknown as AST);
61
+ }).toThrow('render() expects an AST object with a scenes array');
62
+ });
63
+
64
+ test('throws descriptive error when passed object without scenes array', () => {
65
+ const invalidAST = { foo: 'bar' };
66
+
67
+ expect(() => {
68
+ render(invalidAST as unknown as AST);
69
+ }).toThrow('render() expects an AST object with a scenes array');
70
+
71
+ expect(() => {
72
+ render(invalidAST as unknown as AST);
73
+ }).toThrow('Did you pass ParseResult instead of ParseResult.ast?');
74
+ });
75
+
76
+ // Note: DOM-dependent tests are skipped in Node.js environment
77
+ // The renderer requires a browser or jsdom environment
78
+ test.skip('works correctly when passed valid AST (requires DOM)', () => {
79
+ const result = parse(validWireframe);
80
+
81
+ expect(result.success).toBe(true);
82
+ if (result.success) {
83
+ // This is the correct usage
84
+ const { root, sceneManager } = render(result.ast);
85
+
86
+ expect(root).toBeDefined();
87
+ expect(root).toBeInstanceOf(HTMLElement);
88
+ expect(sceneManager).toBeDefined();
89
+ expect(sceneManager.getSceneIds()).toContain('test');
90
+ }
91
+ });
92
+ });
93
+
94
+ describe('createUI() convenience function', () => {
95
+ test('handles parse errors gracefully', () => {
96
+ const invalidWireframe = '+--incomplete';
97
+ const result = createUI(invalidWireframe);
98
+
99
+ expect(result.success).toBe(false);
100
+ if (!result.success) {
101
+ expect(result.errors).toBeDefined();
102
+ expect(result.errors.length).toBeGreaterThan(0);
103
+ }
104
+ });
105
+
106
+ // Note: DOM-dependent tests are skipped in Node.js environment
107
+ test.skip('works correctly with valid wireframe (requires DOM)', () => {
108
+ const validWireframe = `
109
+ @scene: test
110
+
111
+ +-------+
112
+ | Hello |
113
+ +-------+
114
+ `;
115
+ const result = createUI(validWireframe);
116
+
117
+ expect(result.success).toBe(true);
118
+ if (result.success) {
119
+ expect(result.root).toBeDefined();
120
+ expect(result.sceneManager).toBeDefined();
121
+ expect(result.ast).toBeDefined();
122
+ }
123
+ });
124
+ });
125
+
126
+ describe('onSceneChange callback (Issue #2)', () => {
127
+ const multiSceneWireframe = `
128
+ @scene: login
129
+
130
+ +---------------+
131
+ | Login Screen |
132
+ +---------------+
133
+
134
+ ---
135
+
136
+ @scene: dashboard
137
+
138
+ +---------------+
139
+ | Dashboard |
140
+ +---------------+
141
+ `;
142
+
143
+ test('OnSceneChangeCallback type is exported', () => {
144
+ // Verify the type is exported by using it
145
+ const callback: OnSceneChangeCallback = (_from, _to) => {};
146
+ expect(typeof callback).toBe('function');
147
+ });
148
+
149
+ // Note: DOM-dependent tests are skipped in Node.js environment
150
+ test.skip('render accepts onSceneChange option without throwing (requires DOM)', () => {
151
+ const result = parse(multiSceneWireframe);
152
+ expect(result.success).toBe(true);
153
+
154
+ if (result.success) {
155
+ const callback = vi.fn();
156
+
157
+ // This should not throw - just verify the API accepts the option
158
+ expect(() => {
159
+ render(result.ast, {
160
+ onSceneChange: callback,
161
+ });
162
+ }).not.toThrow();
163
+ }
164
+ });
165
+
166
+ test.skip('createUI accepts onSceneChange option without throwing (requires DOM)', () => {
167
+ const callback = vi.fn();
168
+
169
+ // Verify the API accepts the option
170
+ expect(() => {
171
+ createUI(multiSceneWireframe, {
172
+ onSceneChange: callback,
173
+ });
174
+ }).not.toThrow();
175
+ });
176
+
177
+ // Note: DOM-dependent tests are skipped in Node.js environment
178
+ test.skip('onSceneChange is called on initial scene load (requires DOM)', () => {
179
+ const result = parse(multiSceneWireframe);
180
+ expect(result.success).toBe(true);
181
+
182
+ if (result.success) {
183
+ const callback = vi.fn();
184
+ render(result.ast, { onSceneChange: callback });
185
+
186
+ // Should be called once for initial scene
187
+ expect(callback).toHaveBeenCalledTimes(1);
188
+ expect(callback).toHaveBeenCalledWith(undefined, 'login');
189
+ }
190
+ });
191
+
192
+ test.skip('onSceneChange is called when navigating between scenes (requires DOM)', () => {
193
+ const result = parse(multiSceneWireframe);
194
+ expect(result.success).toBe(true);
195
+
196
+ if (result.success) {
197
+ const callback = vi.fn();
198
+ const { sceneManager } = render(result.ast, { onSceneChange: callback });
199
+
200
+ // Clear mock after initial call
201
+ callback.mockClear();
202
+
203
+ // Navigate to dashboard
204
+ sceneManager.goto('dashboard');
205
+
206
+ expect(callback).toHaveBeenCalledTimes(1);
207
+ expect(callback).toHaveBeenCalledWith('login', 'dashboard');
208
+ }
209
+ });
210
+
211
+ test.skip('onSceneChange is not called when navigating to the same scene (requires DOM)', () => {
212
+ const result = parse(multiSceneWireframe);
213
+ expect(result.success).toBe(true);
214
+
215
+ if (result.success) {
216
+ const callback = vi.fn();
217
+ const { sceneManager } = render(result.ast, { onSceneChange: callback });
218
+
219
+ // Clear mock after initial call
220
+ callback.mockClear();
221
+
222
+ // Navigate to the same scene
223
+ sceneManager.goto('login');
224
+
225
+ expect(callback).not.toHaveBeenCalled();
226
+ }
227
+ });
228
+
229
+ test.skip('onSceneChange receives correct fromScene and toScene values (requires DOM)', () => {
230
+ const result = parse(multiSceneWireframe);
231
+ expect(result.success).toBe(true);
232
+
233
+ if (result.success) {
234
+ const navigationHistory: Array<{ from: string | undefined; to: string }> = [];
235
+ const callback: OnSceneChangeCallback = (from, to) => {
236
+ navigationHistory.push({ from, to });
237
+ };
238
+
239
+ const { sceneManager } = render(result.ast, { onSceneChange: callback });
240
+
241
+ // Navigate through scenes
242
+ sceneManager.goto('dashboard');
243
+ sceneManager.goto('login');
244
+
245
+ expect(navigationHistory).toEqual([
246
+ { from: undefined, to: 'login' }, // Initial
247
+ { from: 'login', to: 'dashboard' },
248
+ { from: 'dashboard', to: 'login' },
249
+ ]);
250
+ }
251
+ });
252
+ });
package/src/index.ts CHANGED
@@ -146,6 +146,9 @@ export interface SceneManager {
146
146
  getSceneIds: () => string[];
147
147
  }
148
148
 
149
+ /** Scene change callback type */
150
+ export type OnSceneChangeCallback = (fromScene: string | undefined, toScene: string) => void;
151
+
149
152
  /** Render options */
150
153
  export interface RenderOptions {
151
154
  /** Theme name */
@@ -156,6 +159,13 @@ export interface RenderOptions {
156
159
  injectStyles?: boolean;
157
160
  /** Additional CSS class for container */
158
161
  containerClass?: string;
162
+ /**
163
+ * Callback fired when navigating between scenes.
164
+ * Useful for implementing scene history, analytics, or state synchronization.
165
+ * @param fromScene - The scene ID navigating from (undefined if initial navigation)
166
+ * @param toScene - The scene ID navigating to
167
+ */
168
+ onSceneChange?: OnSceneChangeCallback;
159
169
  }
160
170
 
161
171
  /** Render result */
@@ -178,15 +178,12 @@ function adjustCodeLineOffset(code, offset) {
178
178
  }
179
179
 
180
180
  function adjustLineOffset(error, offset) {
181
- if (offset === 0) {
182
- return error;
183
- } else {
184
- return {
185
- code: adjustCodeLineOffset(error.code, offset),
186
- severity: error.severity,
187
- context: error.context
188
- };
189
- }
181
+ let totalOffset = offset + 1 | 0;
182
+ return {
183
+ code: adjustCodeLineOffset(error.code, totalOffset),
184
+ severity: error.severity,
185
+ context: error.context
186
+ };
190
187
  }
191
188
 
192
189
  export {
@@ -217,18 +217,21 @@ let adjustCodeLineOffset = (code: errorCode, offset: int): errorCode => {
217
217
  * Adjust the line offset in an error's position.
218
218
  * Creates a new error with the position adjusted by the given offset.
219
219
  *
220
+ * This function always adds +1 to convert from 0-indexed grid rows
221
+ * to 1-indexed file line numbers, plus any offset for stripped directive lines.
222
+ *
220
223
  * @param error - The error to adjust
221
- * @param offset - The number of lines to add to the row
222
- * @returns A new error with adjusted position
224
+ * @param offset - The number of directive lines stripped before grid processing
225
+ * @returns A new error with 1-indexed line position
223
226
  */
224
227
  let adjustLineOffset = (error: t, offset: int): t => {
225
- if offset === 0 {
226
- error
227
- } else {
228
- {
229
- code: adjustCodeLineOffset(error.code, offset),
230
- severity: error.severity,
231
- context: error.context,
232
- }
228
+ // Always add 1 to convert from 0-indexed to 1-indexed line numbers
229
+ // offset accounts for stripped directive lines (e.g., @scene: login)
230
+ // +1 converts from 0-indexed grid rows to 1-indexed file lines
231
+ let totalOffset = offset + 1
232
+ {
233
+ code: adjustCodeLineOffset(error.code, totalOffset),
234
+ severity: error.severity,
235
+ context: error.context,
233
236
  }
234
237
  }
@@ -11,12 +11,19 @@ import type {t as ErrorTypes_t} from '../../src/parser/Errors/ErrorTypes.gen';
11
11
 
12
12
  export abstract class DomBindings_element { protected opaque!: any }; /* simulate opaque types */
13
13
 
14
+ /** * Scene change callback type.
15
+ * Called when navigating between scenes.
16
+ * @param fromScene The scene ID navigating from (None if initial)
17
+ * @param toScene The scene ID navigating to */
18
+ export type onSceneChangeCallback = (_1:(undefined | string), _2:string) => void;
19
+
14
20
  /** * Configuration for the rendering process. */
15
21
  export type renderOptions = {
16
22
  readonly theme: (undefined | string);
17
23
  readonly interactive: boolean;
18
24
  readonly injectStyles: boolean;
19
- readonly containerClass: (undefined | string)
25
+ readonly containerClass: (undefined | string);
26
+ readonly onSceneChange: (undefined | onSceneChangeCallback)
20
27
  };
21
28
 
22
29
  /** * Scene management interface returned by render function. */
@@ -12,7 +12,8 @@ let defaultOptions = {
12
12
  theme: undefined,
13
13
  interactive: true,
14
14
  injectStyles: true,
15
- containerClass: undefined
15
+ containerClass: undefined,
16
+ onSceneChange: undefined
16
17
  };
17
18
 
18
19
  let defaultStyles = `
@@ -280,7 +281,7 @@ function renderScene(scene, onAction) {
280
281
  return sceneEl;
281
282
  }
282
283
 
283
- function createSceneManager(scenes) {
284
+ function createSceneManager(scenes, onSceneChange) {
284
285
  let currentScene = {
285
286
  contents: undefined
286
287
  };
@@ -290,10 +291,11 @@ function createSceneManager(scenes) {
290
291
  let forwardStack = {
291
292
  contents: []
292
293
  };
293
- let switchToScene = id => {
294
- let currentId = currentScene.contents;
295
- if (currentId !== undefined) {
296
- let el = scenes.get(currentId);
294
+ let switchToScene = (id, notifyOpt) => {
295
+ let notify = notifyOpt !== undefined ? notifyOpt : true;
296
+ let previousScene = currentScene.contents;
297
+ if (previousScene !== undefined) {
298
+ let el = scenes.get(previousScene);
297
299
  if (el !== undefined) {
298
300
  Primitive_option.valFromOption(el).classList.remove("active");
299
301
  }
@@ -302,7 +304,15 @@ function createSceneManager(scenes) {
302
304
  if (el$1 !== undefined) {
303
305
  Primitive_option.valFromOption(el$1).classList.add("active");
304
306
  currentScene.contents = id;
305
- return;
307
+ if (notify && (previousScene === undefined || previousScene !== id)) {
308
+ if (onSceneChange !== undefined) {
309
+ return onSceneChange(previousScene, id);
310
+ } else {
311
+ return;
312
+ }
313
+ } else {
314
+ return;
315
+ }
306
316
  }
307
317
  };
308
318
  let goto = id => {
@@ -311,7 +321,7 @@ function createSceneManager(scenes) {
311
321
  historyStack.contents = historyStack.contents.concat([currentId]);
312
322
  forwardStack.contents = [];
313
323
  }
314
- switchToScene(id);
324
+ switchToScene(id, undefined);
315
325
  };
316
326
  let back = () => {
317
327
  let history = historyStack.contents;
@@ -328,7 +338,7 @@ function createSceneManager(scenes) {
328
338
  forwardStack.contents = forwardStack.contents.concat([currentId]);
329
339
  }
330
340
  historyStack.contents = history.slice(0, len - 1 | 0);
331
- switchToScene(prevId);
341
+ switchToScene(prevId, undefined);
332
342
  };
333
343
  let forward = () => {
334
344
  let fwdStack = forwardStack.contents;
@@ -345,7 +355,7 @@ function createSceneManager(scenes) {
345
355
  historyStack.contents = historyStack.contents.concat([currentId]);
346
356
  }
347
357
  forwardStack.contents = fwdStack.slice(0, len - 1 | 0);
348
- switchToScene(nextId);
358
+ switchToScene(nextId, undefined);
349
359
  };
350
360
  let refresh = () => {
351
361
  let id = currentScene.contents;
@@ -451,7 +461,7 @@ function render(ast, options) {
451
461
  app.appendChild(sceneEl);
452
462
  sceneMap.set(scene.id, sceneEl);
453
463
  });
454
- let manager = createSceneManager(sceneMap);
464
+ let manager = createSceneManager(sceneMap, opts.onSceneChange);
455
465
  gotoRef.contents = manager.goto;
456
466
  backRef.contents = manager.back;
457
467
  forwardRef.contents = manager.forward;
@@ -48,6 +48,14 @@ module DomBindings = {
48
48
  // Render Options
49
49
  // ============================================================================
50
50
 
51
+ /**
52
+ * Scene change callback type.
53
+ * Called when navigating between scenes.
54
+ * @param fromScene The scene ID navigating from (None if initial)
55
+ * @param toScene The scene ID navigating to
56
+ */
57
+ type onSceneChangeCallback = (option<string>, string) => unit
58
+
51
59
  /**
52
60
  * Configuration for the rendering process.
53
61
  */
@@ -56,6 +64,7 @@ type renderOptions = {
56
64
  interactive: bool,
57
65
  injectStyles: bool,
58
66
  containerClass: option<string>,
67
+ onSceneChange: option<onSceneChangeCallback>,
59
68
  }
60
69
 
61
70
  /**
@@ -66,6 +75,7 @@ let defaultOptions: renderOptions = {
66
75
  interactive: true,
67
76
  injectStyles: true,
68
77
  containerClass: None,
78
+ onSceneChange: None,
69
79
  }
70
80
 
71
81
  // ============================================================================
@@ -418,14 +428,27 @@ let renderScene = (scene: scene, ~onAction: option<actionHandler>=?): DomBinding
418
428
  // Scene Manager Implementation
419
429
  // ============================================================================
420
430
 
421
- let createSceneManager = (scenes: Map.t<string, DomBindings.element>): sceneManager => {
431
+ let createSceneManager = (
432
+ scenes: Map.t<string, DomBindings.element>,
433
+ ~onSceneChange: option<onSceneChangeCallback>=?,
434
+ ): sceneManager => {
422
435
  let currentScene = ref(None)
423
436
  let historyStack: ref<array<string>> = ref([])
424
437
  let forwardStack: ref<array<string>> = ref([])
425
438
 
439
+ // Helper to call onSceneChange callback if provided
440
+ let notifySceneChange = (fromScene: option<string>, toScene: string): unit => {
441
+ switch onSceneChange {
442
+ | Some(callback) => callback(fromScene, toScene)
443
+ | None => ()
444
+ }
445
+ }
446
+
426
447
  // Internal function to switch scenes without affecting history
427
- let switchToScene = (id: string): unit => {
428
- switch currentScene.contents {
448
+ let switchToScene = (id: string, ~notify: bool=true): unit => {
449
+ let previousScene = currentScene.contents
450
+
451
+ switch previousScene {
429
452
  | Some(currentId) => {
430
453
  switch scenes->Map.get(currentId) {
431
454
  | Some(el) => el->DomBindings.classList->DomBindings.remove("active")
@@ -439,6 +462,13 @@ let createSceneManager = (scenes: Map.t<string, DomBindings.element>): sceneMana
439
462
  | Some(el) => {
440
463
  el->DomBindings.classList->DomBindings.add("active")
441
464
  currentScene := Some(id)
465
+ // Notify callback if enabled and scene actually changed
466
+ if notify {
467
+ switch previousScene {
468
+ | Some(prevId) if prevId == id => () // Same scene, no notification
469
+ | _ => notifySceneChange(previousScene, id)
470
+ }
471
+ }
442
472
  }
443
473
  | None => ()
444
474
  }
@@ -634,7 +664,7 @@ let render = (ast: ast, options: option<renderOptions>): renderResult => {
634
664
  sceneMap->Map.set(scene.id, sceneEl)
635
665
  })
636
666
 
637
- let manager = createSceneManager(sceneMap)
667
+ let manager = createSceneManager(sceneMap, ~onSceneChange=?opts.onSceneChange)
638
668
 
639
669
  // Now that sceneManager is created, set the refs
640
670
  gotoRef := Some(manager.goto)