waygraph 0.12.23 → 0.12.24
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/cli.js +35 -36
- package/dist/engine.d.ts +9 -9
- package/dist/highlights.d.ts +90 -21
- package/dist/highlights.js +199 -52
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/types.d.ts +22 -10
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -207,6 +207,7 @@ import { tmpdir } from "node:os";
|
|
|
207
207
|
import {
|
|
208
208
|
resolveHighlightSlots,
|
|
209
209
|
resolveSlides,
|
|
210
|
+
runStubPhase,
|
|
210
211
|
resolveFixtureDwellMs,
|
|
211
212
|
resolveSlideDwellMs,
|
|
212
213
|
formatHighlightCaption,
|
|
@@ -1246,8 +1247,11 @@ async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
1246
1247
|
size: h.size,
|
|
1247
1248
|
weight: h.weight,
|
|
1248
1249
|
});
|
|
1249
|
-
if (h.todos && h.todos.length) {
|
|
1250
|
-
const rows =
|
|
1250
|
+
if ((opts && opts.todos && opts.todos.length) || (h.todos && h.todos.length)) {
|
|
1251
|
+
const rows =
|
|
1252
|
+
opts && opts.todos && opts.todos.length
|
|
1253
|
+
? opts.todos
|
|
1254
|
+
: normalizeTodos(h.todos, h.todoIndex);
|
|
1251
1255
|
await page
|
|
1252
1256
|
.evaluate((todos) => {
|
|
1253
1257
|
const ul = document.getElementById("wg-todos");
|
|
@@ -2525,9 +2529,11 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2525
2529
|
!!r.wasFastForward;
|
|
2526
2530
|
const fixtures = r.highlightFixtures;
|
|
2527
2531
|
const flowStyle = r.highlightStyle;
|
|
2528
|
-
|
|
2532
|
+
const stubBeforePhase = await runStubPhase(r.block, "stubBefore", { fixtures });
|
|
2533
|
+
stubBeforeRef.current = stubBeforePhase.highlights.map((h) =>
|
|
2529
2534
|
applyHighlightStyleDefaults(h, flowStyle),
|
|
2530
2535
|
);
|
|
2536
|
+
const stubBeforeTodos = stubBeforePhase.todos || [];
|
|
2531
2537
|
const isNavBlock = r.block.__waygraphKind === "nav";
|
|
2532
2538
|
const autoNow = await currentAutoplay();
|
|
2533
2539
|
// Auto-next: tuck stepper on NavBlocks so the page transition fills the frame.
|
|
@@ -2573,12 +2579,7 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2573
2579
|
episodeTitle: r.episodeTitle,
|
|
2574
2580
|
stepperMode,
|
|
2575
2581
|
forceCollapsed,
|
|
2576
|
-
todos:
|
|
2577
|
-
for (const h of stubBeforeRef.current || []) {
|
|
2578
|
-
if (h.todos && h.todos.length) return normalizeTodos(h.todos, h.todoIndex);
|
|
2579
|
-
}
|
|
2580
|
-
return [];
|
|
2581
|
-
})(),
|
|
2582
|
+
todos: stubBeforeTodos,
|
|
2582
2583
|
...paceSpeak,
|
|
2583
2584
|
});
|
|
2584
2585
|
const edits = await gate();
|
|
@@ -2638,9 +2639,11 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2638
2639
|
}
|
|
2639
2640
|
})
|
|
2640
2641
|
.catch(() => {});
|
|
2641
|
-
const
|
|
2642
|
+
const errPhase = await runStubPhase(r.block, "stubOnError", {
|
|
2642
2643
|
fixtures: fixturesOnError,
|
|
2643
|
-
|
|
2644
|
+
error: err,
|
|
2645
|
+
});
|
|
2646
|
+
const errHighlights = errPhase.highlights.map((h) => {
|
|
2644
2647
|
const styled = applyHighlightStyleDefaults(h, r.highlightStyle);
|
|
2645
2648
|
return {
|
|
2646
2649
|
selector: styled.selector,
|
|
@@ -2650,14 +2653,13 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2650
2653
|
tone: styled.tone,
|
|
2651
2654
|
size: styled.size,
|
|
2652
2655
|
weight: styled.weight,
|
|
2653
|
-
todos: styled.todos,
|
|
2654
|
-
todoIndex: styled.todoIndex,
|
|
2655
2656
|
zoom: styled.zoom,
|
|
2656
2657
|
};
|
|
2657
2658
|
});
|
|
2658
2659
|
await cycleHighlightRings(page, errHighlights, !!pacing.gatesFast, {
|
|
2659
2660
|
defaultHoldMs: 2000,
|
|
2660
2661
|
pace: pacing.demoPace,
|
|
2662
|
+
todos: errPhase.todos,
|
|
2661
2663
|
});
|
|
2662
2664
|
}
|
|
2663
2665
|
// A thrown act()/observe()/a failed verify Trait used to just crash
|
|
@@ -2723,24 +2725,26 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2723
2725
|
});
|
|
2724
2726
|
}
|
|
2725
2727
|
let highlights;
|
|
2728
|
+
let stubAfterTodos = [];
|
|
2726
2729
|
if (hasAuthoredStubAfter(r.block, result, fixturesAfter)) {
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2730
|
+
const afterPhase = await runStubPhase(r.block, "stubAfter", {
|
|
2731
|
+
out: result,
|
|
2732
|
+
fixtures: fixturesAfter,
|
|
2733
|
+
});
|
|
2734
|
+
stubAfterTodos = afterPhase.todos || [];
|
|
2735
|
+
highlights = afterPhase.highlights.map((h) => {
|
|
2736
|
+
const styled = applyHighlightStyleDefaults(h, r.highlightStyle);
|
|
2737
|
+
return {
|
|
2738
|
+
selector: styled.selector,
|
|
2739
|
+
label: formatHighlightCaption(styled),
|
|
2740
|
+
duration: styled.duration,
|
|
2741
|
+
fastMode: styled.fastMode,
|
|
2742
|
+
tone: styled.tone,
|
|
2743
|
+
size: styled.size,
|
|
2744
|
+
weight: styled.weight,
|
|
2745
|
+
zoom: styled.zoom,
|
|
2746
|
+
};
|
|
2747
|
+
});
|
|
2744
2748
|
} else {
|
|
2745
2749
|
highlights = extractVerifyHighlights(r.block, result.__state).map((h) =>
|
|
2746
2750
|
applyHighlightStyleDefaults(h, r.highlightStyle),
|
|
@@ -2765,12 +2769,7 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
2765
2769
|
episodeNumber: r.episodeNumber,
|
|
2766
2770
|
episodeTitle: r.episodeTitle,
|
|
2767
2771
|
stepperMode,
|
|
2768
|
-
todos:
|
|
2769
|
-
for (const h of highlights || []) {
|
|
2770
|
-
if (h.todos && h.todos.length) return normalizeTodos(h.todos, h.todoIndex);
|
|
2771
|
-
}
|
|
2772
|
-
return [];
|
|
2773
|
-
})(),
|
|
2772
|
+
todos: stubAfterTodos,
|
|
2774
2773
|
// After a nav under auto-next, stay compact until the next action block expands.
|
|
2775
2774
|
forceCollapsed: !!process.env.WAYGRAPH_VIDEO || ((await currentAutoplay()) && isNavBlock),
|
|
2776
2775
|
});
|
package/dist/engine.d.ts
CHANGED
|
@@ -603,9 +603,9 @@ export type NavBlockOptions<Out extends Checkpoint<string>> = {
|
|
|
603
603
|
checkpoint: Out["__state"];
|
|
604
604
|
requires?: readonly MemKey<any>[];
|
|
605
605
|
verify?: Trait[] | ((out: Out) => Trait[]);
|
|
606
|
-
stubBefore?: import("./highlights.js").
|
|
607
|
-
stubAfter?: import("./highlights.js").
|
|
608
|
-
stubOnError?: import("./highlights.js").
|
|
606
|
+
stubBefore?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
|
|
607
|
+
stubAfter?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
|
|
608
|
+
stubOnError?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
|
|
609
609
|
/** @deprecated Prefer stubAfter. */
|
|
610
610
|
highlights?: readonly WaygraphHighlight[] | ((out: Out) => readonly WaygraphHighlight[]);
|
|
611
611
|
/**
|
|
@@ -667,9 +667,9 @@ export type NavClickBlockOptions<Out extends Checkpoint<string>> = {
|
|
|
667
667
|
click: string | ((mem: MemPage) => string);
|
|
668
668
|
requires?: readonly MemKey<any>[];
|
|
669
669
|
verify?: Trait[] | ((out: Out) => Trait[]);
|
|
670
|
-
stubBefore?: import("./highlights.js").
|
|
671
|
-
stubAfter?: import("./highlights.js").
|
|
672
|
-
stubOnError?: import("./highlights.js").
|
|
670
|
+
stubBefore?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
|
|
671
|
+
stubAfter?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
|
|
672
|
+
stubOnError?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
|
|
673
673
|
/** @deprecated Prefer stubAfter. */
|
|
674
674
|
highlights?: readonly WaygraphHighlight[] | ((out: Out) => readonly WaygraphHighlight[]);
|
|
675
675
|
instanceOptions?: Block<Checkpoint<string>, Out>["instanceOptions"];
|
|
@@ -699,9 +699,9 @@ export type PageBlockOptions<Out extends Checkpoint<string>> = {
|
|
|
699
699
|
/** Checkpoint tag for this screen (hub). */
|
|
700
700
|
checkpoint: Out["__state"];
|
|
701
701
|
verify?: Trait[] | ((out: Out) => Trait[]);
|
|
702
|
-
stubBefore?: import("./highlights.js").
|
|
703
|
-
stubAfter?: import("./highlights.js").
|
|
704
|
-
stubOnError?: import("./highlights.js").
|
|
702
|
+
stubBefore?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
|
|
703
|
+
stubAfter?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
|
|
704
|
+
stubOnError?: import("./highlights.js").HighlightStubPhaseOrFn<Out>;
|
|
705
705
|
/** @deprecated Prefer stubAfter. */
|
|
706
706
|
highlights?: readonly WaygraphHighlight[] | ((out: Out) => readonly WaygraphHighlight[]);
|
|
707
707
|
requires?: readonly MemKey<any>[];
|
package/dist/highlights.d.ts
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Block stubBefore / stubAfter / stubOnError + flow highlightFixtures + demo slides.
|
|
3
3
|
* Demo narration only - never affects runGraph pass/fail.
|
|
4
4
|
*
|
|
5
|
+
* Stubs are **open block lifecycles** - prefer `stubBefore(ctx) { ... }`, not a
|
|
6
|
+
* closed slot object. Inside the fn authors set fixtures (todos, zoom) and rings.
|
|
7
|
+
* Object maps remain a shorthand for highlight-only slots.
|
|
8
|
+
*
|
|
5
9
|
* Lifecycle (stubs) ≠ yap slides: stubs are fill/after/error rings tied to the block;
|
|
6
10
|
* slides are multi-step captions with Next between them (long-process explain).
|
|
7
11
|
*
|
|
@@ -26,7 +30,7 @@ export type FixtureDurationFields = {
|
|
|
26
30
|
};
|
|
27
31
|
/**
|
|
28
32
|
* One checklist row for episode planning (demo panel).
|
|
29
|
-
*
|
|
33
|
+
* Set via {@link StubCtx.todos} / {@link StubCtx.todoIndex} inside the lifecycle.
|
|
30
34
|
*/
|
|
31
35
|
export type WaygraphTodoItem = {
|
|
32
36
|
text: string;
|
|
@@ -36,6 +40,14 @@ export type WaygraphTodoItem = {
|
|
|
36
40
|
current?: boolean;
|
|
37
41
|
};
|
|
38
42
|
export type WaygraphTodoInput = string | WaygraphTodoItem;
|
|
43
|
+
/** Episode-level fixtures authored inside stubBefore/After/OnError(ctx). */
|
|
44
|
+
export type StubPhaseFixtures = {
|
|
45
|
+
todos?: readonly WaygraphTodoInput[];
|
|
46
|
+
/** Which todo is current (0-based). Rows before = done, after = pending. */
|
|
47
|
+
todoIndex?: number;
|
|
48
|
+
/** Default zoom for rings that omit their own zoom. */
|
|
49
|
+
zoom?: number;
|
|
50
|
+
};
|
|
39
51
|
/** One named highlight slot on a block (selector + caption). */
|
|
40
52
|
export interface WaygraphHighlightStub extends FixtureDurationFields {
|
|
41
53
|
selector: string;
|
|
@@ -63,26 +75,71 @@ export interface WaygraphHighlightStub extends FixtureDurationFields {
|
|
|
63
75
|
*/
|
|
64
76
|
weight?: HighlightWeight;
|
|
65
77
|
/**
|
|
66
|
-
*
|
|
67
|
-
* (stubBefore / stubAfter / stubOnError). Strings or `{ text, done?, current? }`.
|
|
68
|
-
*/
|
|
69
|
-
todos?: readonly WaygraphTodoInput[];
|
|
70
|
-
/**
|
|
71
|
-
* Which todo is current (0-based). Rows before = done, after = pending.
|
|
72
|
-
* Authored `done`/`current` on an item still win when set.
|
|
73
|
-
* Bump in a stub phase function for sequential plans.
|
|
74
|
-
*/
|
|
75
|
-
todoIndex?: number;
|
|
76
|
-
/**
|
|
77
|
-
* Magnify the target element while this ring is shown (e.g. `1.35`).
|
|
78
|
+
* Magnify this target while its ring is shown (e.g. `1.35`).
|
|
78
79
|
* Cleared when the ring hides / next highlight starts. `1` or omit = off.
|
|
80
|
+
* Episode default: {@link StubCtx.zoom}.
|
|
79
81
|
*/
|
|
80
82
|
zoom?: number;
|
|
81
83
|
}
|
|
82
84
|
/** Flow fixture patch: label required; selector optional (inherits from stub). */
|
|
83
|
-
export type WaygraphHighlightFixture = Partial<Pick<WaygraphHighlightStub, "selector">> & Required<Pick<WaygraphHighlightStub, "label">> & Pick<WaygraphHighlightStub, "detail" | "tag" | "tone" | "size" | "weight" | "
|
|
85
|
+
export type WaygraphHighlightFixture = Partial<Pick<WaygraphHighlightStub, "selector">> & Required<Pick<WaygraphHighlightStub, "label">> & Pick<WaygraphHighlightStub, "detail" | "tag" | "tone" | "size" | "weight" | "zoom"> & FixtureDurationFields;
|
|
84
86
|
export type HighlightStubPhase = Record<string, WaygraphHighlightStub>;
|
|
85
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Open stub lifecycle context. Authors set rings + episode fixtures freely —
|
|
89
|
+
* not restricted to returning a closed slot object.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* stubBefore: (ctx) => {
|
|
93
|
+
* ctx.todos(["Enter email", "Enter password", "Click Sign in"]);
|
|
94
|
+
* ctx.todoIndex(0);
|
|
95
|
+
* ctx.zoom(1.35);
|
|
96
|
+
* ctx.highlights({
|
|
97
|
+
* email: { selector: "#email", label: "Email" },
|
|
98
|
+
* submit: { selector: "#login-button", label: "Sign in" },
|
|
99
|
+
* });
|
|
100
|
+
* }
|
|
101
|
+
* // Sequential plan: bump todoIndex in a later phase / later block's stubBefore
|
|
102
|
+
* stubAfter: (ctx) => {
|
|
103
|
+
* ctx.todos(["Enter email", "Enter password", "Click Sign in"]);
|
|
104
|
+
* ctx.todoIndex(2);
|
|
105
|
+
* ctx.ring("inventory", { selector: ".inventory_list", label: "Landed" });
|
|
106
|
+
* }
|
|
107
|
+
*/
|
|
108
|
+
export type StubCtx<Out extends Checkpoint<string> = Checkpoint<string>> = {
|
|
109
|
+
/** Present after resolve (stubAfter). Undefined for stubBefore. */
|
|
110
|
+
readonly out: Out | undefined;
|
|
111
|
+
/** Present on stubOnError when the step threw. */
|
|
112
|
+
readonly error: unknown | undefined;
|
|
113
|
+
/** Replace named highlight rings for this phase. */
|
|
114
|
+
highlights(slots: HighlightStubPhase): void;
|
|
115
|
+
/** Set / overwrite one named ring. */
|
|
116
|
+
ring(id: string, stub: WaygraphHighlightStub): void;
|
|
117
|
+
/** Episode checklist (demo panel). */
|
|
118
|
+
todos(items: readonly WaygraphTodoInput[]): void;
|
|
119
|
+
/** Current checklist index (bump for sequential plans). */
|
|
120
|
+
todoIndex(n: number): void;
|
|
121
|
+
/** Default zoom for rings without their own zoom. */
|
|
122
|
+
zoom(n: number): void;
|
|
123
|
+
/** Batch-set rings + episode fixtures. */
|
|
124
|
+
set(partial: {
|
|
125
|
+
highlights?: HighlightStubPhase;
|
|
126
|
+
} & StubPhaseFixtures): void;
|
|
127
|
+
};
|
|
128
|
+
export type StubLifecycleFn<Out extends Checkpoint<string>> = (ctx: StubCtx<Out>) => void | HighlightStubPhase | Promise<void | HighlightStubPhase>;
|
|
129
|
+
/**
|
|
130
|
+
* Block stub authoring:
|
|
131
|
+
* - **preferred:** open lifecycle `stubBefore(ctx) { ctx.todos(...); ctx.ring(...) }`
|
|
132
|
+
* - **shorthand:** static slot map `{ email: { selector, label } }`
|
|
133
|
+
* - **legacy:** `(out) => slotMap` still accepted (treated as highlights only)
|
|
134
|
+
*/
|
|
135
|
+
export type HighlightStubPhaseOrFn<Out extends Checkpoint<string>> = HighlightStubPhase | StubLifecycleFn<Out> | ((out: Out) => HighlightStubPhase);
|
|
136
|
+
/** Result of running a stub phase (rings + episode fixtures). */
|
|
137
|
+
export type StubPhaseResult = {
|
|
138
|
+
highlights: ResolvedHighlight[];
|
|
139
|
+
todos: WaygraphTodoItem[];
|
|
140
|
+
todoIndex?: number;
|
|
141
|
+
zoom?: number;
|
|
142
|
+
};
|
|
86
143
|
/**
|
|
87
144
|
* One yap/slide in a multi-step demo caption sequence.
|
|
88
145
|
* Not block lifecycle - demo pauses (Next / auto-next) between slides.
|
|
@@ -223,9 +280,21 @@ export type ResolvedHighlight = WaygraphHighlightStub;
|
|
|
223
280
|
*/
|
|
224
281
|
export declare function normalizeTodos(todos: readonly WaygraphTodoInput[] | undefined, todoIndex?: number): WaygraphTodoItem[];
|
|
225
282
|
/**
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
283
|
+
* Run an open stub lifecycle (preferred) or resolve a static slot map.
|
|
284
|
+
* Returns rings + episode fixtures (todos / todoIndex / zoom).
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* const before = await runStubPhase(block, "stubBefore", { fixtures });
|
|
288
|
+
* // before.todos, before.highlights
|
|
289
|
+
*/
|
|
290
|
+
export declare function runStubPhase(block: Block<any, any>, phase: HighlightStubPhaseName, opts?: {
|
|
291
|
+
out?: Checkpoint<string>;
|
|
292
|
+
error?: unknown;
|
|
293
|
+
fixtures?: HighlightFixtureMap;
|
|
294
|
+
}): Promise<StubPhaseResult>;
|
|
295
|
+
/**
|
|
296
|
+
* Sync resolve of highlight slots. Prefer {@link runStubPhase} for open
|
|
297
|
+
* async lifecycles + episode fixtures (todos/zoom).
|
|
229
298
|
*/
|
|
230
299
|
export declare function resolveHighlightSlots(block: Block<any, any>, phase: HighlightStubPhaseName, opts?: {
|
|
231
300
|
out?: Checkpoint<string>;
|
|
@@ -248,12 +317,12 @@ export declare function formatHighlightCaption(h: {
|
|
|
248
317
|
tone?: HighlightTone | string;
|
|
249
318
|
}): string;
|
|
250
319
|
/**
|
|
251
|
-
* True when the block authored
|
|
252
|
-
*
|
|
320
|
+
* True when the block authored stubAfter (lifecycle fn, slots, fixtures, or legacy highlights).
|
|
321
|
+
* When true, demo should not use verify-trait fallback.
|
|
253
322
|
*/
|
|
254
323
|
export declare function hasAuthoredStubAfter(block: Block<any, any>, out?: Checkpoint<string>, fixtures?: HighlightFixtureMap): boolean;
|
|
255
324
|
/**
|
|
256
|
-
* True when stubOnError
|
|
325
|
+
* True when stubOnError is authored (lifecycle fn and/or rings).
|
|
257
326
|
* Demo fail path only - success never consults this.
|
|
258
327
|
*/
|
|
259
328
|
export declare function hasAuthoredStubOnError(block: Block<any, any>, fixtures?: HighlightFixtureMap): boolean;
|
package/dist/highlights.js
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Block stubBefore / stubAfter / stubOnError + flow highlightFixtures + demo slides.
|
|
3
3
|
* Demo narration only - never affects runGraph pass/fail.
|
|
4
4
|
*
|
|
5
|
+
* Stubs are **open block lifecycles** - prefer `stubBefore(ctx) { ... }`, not a
|
|
6
|
+
* closed slot object. Inside the fn authors set fixtures (todos, zoom) and rings.
|
|
7
|
+
* Object maps remain a shorthand for highlight-only slots.
|
|
8
|
+
*
|
|
5
9
|
* Lifecycle (stubs) ≠ yap slides: stubs are fill/after/error rings tied to the block;
|
|
6
10
|
* slides are multi-step captions with Next between them (long-process explain).
|
|
7
11
|
*
|
|
@@ -314,25 +318,18 @@ export function normalizeTodos(todos, todoIndex) {
|
|
|
314
318
|
return item;
|
|
315
319
|
});
|
|
316
320
|
}
|
|
317
|
-
function
|
|
318
|
-
const out = {};
|
|
319
|
-
const todos = patch?.todos !== undefined ? patch.todos : base?.todos;
|
|
320
|
-
const todoIndex = patch?.todoIndex !== undefined ? patch.todoIndex : base?.todoIndex;
|
|
321
|
+
function pickZoom(base, patch) {
|
|
321
322
|
const zoom = patch?.zoom !== undefined ? patch.zoom : base?.zoom;
|
|
322
|
-
if (todos !== undefined)
|
|
323
|
-
out.todos = todos;
|
|
324
|
-
if (todoIndex !== undefined)
|
|
325
|
-
out.todoIndex = todoIndex;
|
|
326
323
|
if (zoom !== undefined && Number.isFinite(zoom) && zoom > 0)
|
|
327
|
-
|
|
328
|
-
return
|
|
324
|
+
return { zoom };
|
|
325
|
+
return {};
|
|
329
326
|
}
|
|
330
327
|
function mergeSlot(base, patch) {
|
|
331
328
|
if (!base && !patch)
|
|
332
329
|
return null;
|
|
333
330
|
const dwell = pickDurationFields(base, patch);
|
|
334
331
|
const style = pickStyleFields(base, patch);
|
|
335
|
-
const
|
|
332
|
+
const zoom = pickZoom(base, patch);
|
|
336
333
|
if (!base && patch) {
|
|
337
334
|
if (!patch.selector)
|
|
338
335
|
return null;
|
|
@@ -343,7 +340,7 @@ function mergeSlot(base, patch) {
|
|
|
343
340
|
...(patch.tag ? { tag: patch.tag } : {}),
|
|
344
341
|
...style,
|
|
345
342
|
...dwell,
|
|
346
|
-
...
|
|
343
|
+
...zoom,
|
|
347
344
|
};
|
|
348
345
|
}
|
|
349
346
|
if (base && !patch) {
|
|
@@ -352,7 +349,7 @@ function mergeSlot(base, patch) {
|
|
|
352
349
|
...(base.tone ? { tone: normalizeHighlightTone(base.tone) } : {}),
|
|
353
350
|
...(base.size ? { size: normalizeHighlightSize(base.size) } : {}),
|
|
354
351
|
...(base.weight ? { weight: normalizeHighlightWeight(base.weight) } : {}),
|
|
355
|
-
...
|
|
352
|
+
...pickZoom(base, undefined),
|
|
356
353
|
};
|
|
357
354
|
}
|
|
358
355
|
return {
|
|
@@ -366,9 +363,78 @@ function mergeSlot(base, patch) {
|
|
|
366
363
|
...(patch.tag !== undefined ? { tag: patch.tag } : base.tag ? { tag: base.tag } : {}),
|
|
367
364
|
...style,
|
|
368
365
|
...dwell,
|
|
369
|
-
...
|
|
366
|
+
...zoom,
|
|
370
367
|
};
|
|
371
368
|
}
|
|
369
|
+
function createStubCtx(bag, opts) {
|
|
370
|
+
return {
|
|
371
|
+
out: opts.out,
|
|
372
|
+
error: opts.error,
|
|
373
|
+
highlights(slots) {
|
|
374
|
+
bag.highlights = { ...(slots || {}) };
|
|
375
|
+
},
|
|
376
|
+
ring(id, stub) {
|
|
377
|
+
bag.highlights = { ...bag.highlights, [id]: stub };
|
|
378
|
+
},
|
|
379
|
+
todos(items) {
|
|
380
|
+
bag.todos = items;
|
|
381
|
+
},
|
|
382
|
+
todoIndex(n) {
|
|
383
|
+
bag.todoIndex = n;
|
|
384
|
+
},
|
|
385
|
+
zoom(n) {
|
|
386
|
+
if (Number.isFinite(n) && n > 0)
|
|
387
|
+
bag.zoom = n;
|
|
388
|
+
},
|
|
389
|
+
set(partial) {
|
|
390
|
+
if (partial.highlights)
|
|
391
|
+
bag.highlights = { ...partial.highlights };
|
|
392
|
+
if (partial.todos !== undefined)
|
|
393
|
+
bag.todos = partial.todos;
|
|
394
|
+
if (partial.todoIndex !== undefined)
|
|
395
|
+
bag.todoIndex = partial.todoIndex;
|
|
396
|
+
if (partial.zoom !== undefined && Number.isFinite(partial.zoom) && partial.zoom > 0) {
|
|
397
|
+
bag.zoom = partial.zoom;
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
/** Lift legacy per-slot todos (0.12.23) onto the phase bag once. */
|
|
403
|
+
function liftLegacySlotTodos(bag) {
|
|
404
|
+
if (bag.todos && bag.todos.length)
|
|
405
|
+
return;
|
|
406
|
+
for (const stub of Object.values(bag.highlights)) {
|
|
407
|
+
const legacy = stub;
|
|
408
|
+
if (legacy.todos && legacy.todos.length) {
|
|
409
|
+
bag.todos = legacy.todos;
|
|
410
|
+
if (legacy.todoIndex !== undefined)
|
|
411
|
+
bag.todoIndex = legacy.todoIndex;
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
function applyDefaultZoom(slots, defaultZoom) {
|
|
417
|
+
if (defaultZoom === undefined || !(defaultZoom > 0))
|
|
418
|
+
return slots;
|
|
419
|
+
return slots.map((h) => (h.zoom !== undefined && h.zoom > 0 ? h : { ...h, zoom: defaultZoom }));
|
|
420
|
+
}
|
|
421
|
+
function mergePhaseMaps(phaseMap, fixturePhase) {
|
|
422
|
+
const slotIds = new Set([...Object.keys(phaseMap), ...Object.keys(fixturePhase || {})]);
|
|
423
|
+
const ordered = [...slotIds].sort((a, b) => {
|
|
424
|
+
const na = Number(a);
|
|
425
|
+
const nb = Number(b);
|
|
426
|
+
if (!Number.isNaN(na) && !Number.isNaN(nb))
|
|
427
|
+
return na - nb;
|
|
428
|
+
return a.localeCompare(b);
|
|
429
|
+
});
|
|
430
|
+
const resolved = [];
|
|
431
|
+
for (const id of ordered) {
|
|
432
|
+
const merged = mergeSlot(phaseMap[id], fixturePhase?.[id]);
|
|
433
|
+
if (merged)
|
|
434
|
+
resolved.push(merged);
|
|
435
|
+
}
|
|
436
|
+
return resolved;
|
|
437
|
+
}
|
|
372
438
|
function phaseFromLegacyHighlights(highlights) {
|
|
373
439
|
const out = {};
|
|
374
440
|
if (!highlights)
|
|
@@ -384,58 +450,121 @@ function phaseFromLegacyHighlights(highlights) {
|
|
|
384
450
|
});
|
|
385
451
|
return out;
|
|
386
452
|
}
|
|
453
|
+
function readStubRaw(block, phase) {
|
|
454
|
+
const instr = block.instruction;
|
|
455
|
+
if (phase === "stubBefore")
|
|
456
|
+
return instr.stubBefore;
|
|
457
|
+
if (phase === "stubAfter")
|
|
458
|
+
return instr.stubAfter;
|
|
459
|
+
return instr.stubOnError;
|
|
460
|
+
}
|
|
461
|
+
function applyLegacyHighlightsShim(block, phase, phaseMap, out) {
|
|
462
|
+
if (phase !== "stubAfter" || Object.keys(phaseMap).length > 0)
|
|
463
|
+
return phaseMap;
|
|
464
|
+
const instr = block.instruction;
|
|
465
|
+
if (!instr.highlights)
|
|
466
|
+
return phaseMap;
|
|
467
|
+
let legacy = instr.highlights;
|
|
468
|
+
if (typeof legacy === "function") {
|
|
469
|
+
try {
|
|
470
|
+
legacy = legacy(out ?? { __state: "" });
|
|
471
|
+
}
|
|
472
|
+
catch {
|
|
473
|
+
legacy = [];
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return phaseFromLegacyHighlights(Array.isArray(legacy) ? legacy : []);
|
|
477
|
+
}
|
|
387
478
|
/**
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
479
|
+
* Run an open stub lifecycle (preferred) or resolve a static slot map.
|
|
480
|
+
* Returns rings + episode fixtures (todos / todoIndex / zoom).
|
|
481
|
+
*
|
|
482
|
+
* @example
|
|
483
|
+
* const before = await runStubPhase(block, "stubBefore", { fixtures });
|
|
484
|
+
* // before.todos, before.highlights
|
|
391
485
|
*/
|
|
392
|
-
export function
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
?
|
|
396
|
-
:
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
let phaseMap = {};
|
|
486
|
+
export async function runStubPhase(block, phase, opts) {
|
|
487
|
+
const bag = { highlights: {} };
|
|
488
|
+
const ctx = createStubCtx(bag, {
|
|
489
|
+
...(opts?.out !== undefined ? { out: opts.out } : {}),
|
|
490
|
+
...(opts?.error !== undefined ? { error: opts.error } : {}),
|
|
491
|
+
});
|
|
492
|
+
const raw = readStubRaw(block, phase);
|
|
400
493
|
if (typeof raw === "function") {
|
|
401
494
|
try {
|
|
402
|
-
|
|
495
|
+
const ret = await raw(ctx);
|
|
496
|
+
if (isStubPhase(ret)) {
|
|
497
|
+
bag.highlights = { ...bag.highlights, ...ret };
|
|
498
|
+
}
|
|
403
499
|
}
|
|
404
500
|
catch {
|
|
405
|
-
|
|
501
|
+
/* best-effort */
|
|
502
|
+
}
|
|
503
|
+
// Compat: legacy `(out) => map` that expected Checkpoint (__state on arg)
|
|
504
|
+
if (Object.keys(bag.highlights).length === 0 && !bag.todos) {
|
|
505
|
+
try {
|
|
506
|
+
const legacyOut = (opts?.out ?? { __state: "" });
|
|
507
|
+
const ret2 = raw(legacyOut);
|
|
508
|
+
if (isStubPhase(ret2))
|
|
509
|
+
bag.highlights = { ...ret2 };
|
|
510
|
+
}
|
|
511
|
+
catch {
|
|
512
|
+
/* ignore */
|
|
513
|
+
}
|
|
406
514
|
}
|
|
407
515
|
}
|
|
408
516
|
else if (isStubPhase(raw)) {
|
|
409
|
-
|
|
517
|
+
bag.highlights = { ...raw };
|
|
410
518
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
519
|
+
bag.highlights = applyLegacyHighlightsShim(block, phase, bag.highlights, opts?.out);
|
|
520
|
+
liftLegacySlotTodos(bag);
|
|
521
|
+
const fixturePhase = opts?.fixtures?.[block.name]?.[phase];
|
|
522
|
+
let highlights = mergePhaseMaps(bag.highlights, fixturePhase);
|
|
523
|
+
highlights = applyDefaultZoom(highlights, bag.zoom);
|
|
524
|
+
const todos = normalizeTodos(bag.todos, bag.todoIndex);
|
|
525
|
+
return {
|
|
526
|
+
highlights,
|
|
527
|
+
todos,
|
|
528
|
+
...(bag.todoIndex !== undefined ? { todoIndex: bag.todoIndex } : {}),
|
|
529
|
+
...(bag.zoom !== undefined ? { zoom: bag.zoom } : {}),
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Sync resolve of highlight slots. Prefer {@link runStubPhase} for open
|
|
534
|
+
* async lifecycles + episode fixtures (todos/zoom).
|
|
535
|
+
*/
|
|
536
|
+
export function resolveHighlightSlots(block, phase, opts) {
|
|
537
|
+
const bag = { highlights: {} };
|
|
538
|
+
const raw = readStubRaw(block, phase);
|
|
539
|
+
if (typeof raw === "function") {
|
|
540
|
+
try {
|
|
541
|
+
const ctx = createStubCtx(bag, {
|
|
542
|
+
...(opts?.out !== undefined ? { out: opts.out } : {}),
|
|
543
|
+
});
|
|
544
|
+
const ret = raw(ctx);
|
|
545
|
+
if (isStubPhase(ret)) {
|
|
546
|
+
bag.highlights = { ...bag.highlights, ...ret };
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
catch {
|
|
414
550
|
try {
|
|
415
|
-
|
|
551
|
+
const legacyOut = (opts?.out ?? { __state: "" });
|
|
552
|
+
const ret2 = raw(legacyOut);
|
|
553
|
+
if (isStubPhase(ret2))
|
|
554
|
+
bag.highlights = { ...ret2 };
|
|
416
555
|
}
|
|
417
556
|
catch {
|
|
418
|
-
|
|
557
|
+
bag.highlights = {};
|
|
419
558
|
}
|
|
420
559
|
}
|
|
421
|
-
phaseMap = phaseFromLegacyHighlights(Array.isArray(legacy) ? legacy : []);
|
|
422
560
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const ordered = [...slotIds].sort((a, b) => {
|
|
426
|
-
const na = Number(a);
|
|
427
|
-
const nb = Number(b);
|
|
428
|
-
if (!Number.isNaN(na) && !Number.isNaN(nb))
|
|
429
|
-
return na - nb;
|
|
430
|
-
return a.localeCompare(b);
|
|
431
|
-
});
|
|
432
|
-
const resolved = [];
|
|
433
|
-
for (const id of ordered) {
|
|
434
|
-
const merged = mergeSlot(phaseMap[id], fixturePhase?.[id]);
|
|
435
|
-
if (merged)
|
|
436
|
-
resolved.push(merged);
|
|
561
|
+
else if (isStubPhase(raw)) {
|
|
562
|
+
bag.highlights = { ...raw };
|
|
437
563
|
}
|
|
438
|
-
|
|
564
|
+
bag.highlights = applyLegacyHighlightsShim(block, phase, bag.highlights, opts?.out);
|
|
565
|
+
liftLegacySlotTodos(bag);
|
|
566
|
+
const fixturePhase = opts?.fixtures?.[block.name]?.[phase];
|
|
567
|
+
return applyDefaultZoom(mergePhaseMaps(bag.highlights, fixturePhase), bag.zoom);
|
|
439
568
|
}
|
|
440
569
|
/**
|
|
441
570
|
* Resolve multi-step yap slides: flow fixture `slides` wins when present,
|
|
@@ -470,21 +599,39 @@ export function formatHighlightCaption(h) {
|
|
|
470
599
|
return `${icon}${tag}${primary} - ${h.detail}`;
|
|
471
600
|
return `${icon}${tag}${primary}`;
|
|
472
601
|
}
|
|
602
|
+
function stubPhaseLooksAuthored(block, phase, fixtures) {
|
|
603
|
+
const raw = readStubRaw(block, phase);
|
|
604
|
+
if (typeof raw === "function")
|
|
605
|
+
return true;
|
|
606
|
+
if (isStubPhase(raw) && Object.keys(raw).length > 0)
|
|
607
|
+
return true;
|
|
608
|
+
const fx = fixtures?.[block.name]?.[phase];
|
|
609
|
+
if (fx && Object.keys(fx).length > 0)
|
|
610
|
+
return true;
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
473
613
|
/**
|
|
474
|
-
* True when the block authored
|
|
475
|
-
*
|
|
614
|
+
* True when the block authored stubAfter (lifecycle fn, slots, fixtures, or legacy highlights).
|
|
615
|
+
* When true, demo should not use verify-trait fallback.
|
|
476
616
|
*/
|
|
477
617
|
export function hasAuthoredStubAfter(block, out, fixtures) {
|
|
618
|
+
if (stubPhaseLooksAuthored(block, "stubAfter", fixtures))
|
|
619
|
+
return true;
|
|
620
|
+
const instr = block.instruction;
|
|
621
|
+
if (instr.highlights)
|
|
622
|
+
return true;
|
|
478
623
|
return resolveHighlightSlots(block, "stubAfter", {
|
|
479
624
|
...(out !== undefined ? { out } : {}),
|
|
480
625
|
...(fixtures !== undefined ? { fixtures } : {}),
|
|
481
626
|
}).length > 0;
|
|
482
627
|
}
|
|
483
628
|
/**
|
|
484
|
-
* True when stubOnError
|
|
629
|
+
* True when stubOnError is authored (lifecycle fn and/or rings).
|
|
485
630
|
* Demo fail path only - success never consults this.
|
|
486
631
|
*/
|
|
487
632
|
export function hasAuthoredStubOnError(block, fixtures) {
|
|
633
|
+
if (stubPhaseLooksAuthored(block, "stubOnError", fixtures))
|
|
634
|
+
return true;
|
|
488
635
|
return (resolveHighlightSlots(block, "stubOnError", {
|
|
489
636
|
...(fixtures !== undefined ? { fixtures } : {}),
|
|
490
637
|
}).length > 0);
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export { connect, checkpoint } from "./types.js";
|
|
|
3
3
|
export { MemKey, MemPage, key, keyGroup } from "./mem-page.js";
|
|
4
4
|
export { Trait, urlMatches, textEquals, visible } from "./trait.js";
|
|
5
5
|
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, chainFlow, } from "./engine.js";
|
|
6
|
-
export { resolveHighlightSlots, resolveSlides, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, demoPaceScale, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, demoPaceGateMs, formatDemoPaceBadge, formatDemoPaceLabel, normalizeTodos, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, } from "./highlights.js";
|
|
7
|
-
export type { WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, WaygraphTodoItem, WaygraphTodoInput, FixtureDurationFields, HighlightStubPhase, HighlightStubPhaseName, HighlightFixtureMap, ResolvedHighlight, WaygraphHighlight, HighlightTone, HighlightSize, HighlightWeight, HighlightStyleDefaults, DemoPace, DemoPaceName, } from "./highlights.js";
|
|
6
|
+
export { resolveHighlightSlots, resolveSlides, runStubPhase, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, demoPaceScale, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, demoPaceGateMs, formatDemoPaceBadge, formatDemoPaceLabel, normalizeTodos, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, } from "./highlights.js";
|
|
7
|
+
export type { WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, WaygraphTodoItem, WaygraphTodoInput, FixtureDurationFields, HighlightStubPhase, HighlightStubPhaseName, HighlightFixtureMap, ResolvedHighlight, WaygraphHighlight, HighlightTone, HighlightSize, HighlightWeight, HighlightStyleDefaults, DemoPace, DemoPaceName, StubCtx, StubLifecycleFn, StubPhaseResult, StubPhaseFixtures, } from "./highlights.js";
|
|
8
8
|
export type { Flow, EngineConfig, ComposedBlock, FastForwardComposedBlock, RunGraphOptions, BlockInfo, NavBlock, NavBlockOptions, NavClickBlock, NavClickBlockOptions, MethodBlock, ActionBlock, PageBlock, PageBlockOptions, PageMethodEntry, EffectBlock, MemEffectBlock, MemNavBlock, } from "./engine.js";
|
|
9
9
|
export type { ActionPage } from "./types.js";
|
|
10
10
|
export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ export { connect, checkpoint } from "./types.js";
|
|
|
2
2
|
export { MemKey, MemPage, key, keyGroup } from "./mem-page.js";
|
|
3
3
|
export { Trait, urlMatches, textEquals, visible } from "./trait.js";
|
|
4
4
|
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, chainFlow, } from "./engine.js";
|
|
5
|
-
export { resolveHighlightSlots, resolveSlides, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, demoPaceScale, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, demoPaceGateMs, formatDemoPaceBadge, formatDemoPaceLabel, normalizeTodos, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, } from "./highlights.js";
|
|
5
|
+
export { resolveHighlightSlots, resolveSlides, runStubPhase, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, demoPaceScale, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, demoPaceGateMs, formatDemoPaceBadge, formatDemoPaceLabel, normalizeTodos, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, } from "./highlights.js";
|
|
6
6
|
export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
|
|
7
7
|
export { isFileSelectToken, parseBlocksSelect, matchBlocksSelect, globToRegExp, } from "./blocks-select.js";
|
|
8
8
|
export { EdgeLeaseCoordinator } from "./traverse-lease.js";
|
package/dist/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Page } from "@playwright/test";
|
|
|
2
2
|
import type { MemPage, MemKey } from "./mem-page.js";
|
|
3
3
|
import type { Trait } from "./trait.js";
|
|
4
4
|
import type { HighlightStubPhaseOrFn, WaygraphHighlight, WaygraphSlidesOrFn } from "./highlights.js";
|
|
5
|
-
export type { WaygraphHighlight, WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, HighlightStubPhase, HighlightStubPhaseOrFn, HighlightFixtureMap, ResolvedHighlight, } from "./highlights.js";
|
|
5
|
+
export type { WaygraphHighlight, WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, HighlightStubPhase, HighlightStubPhaseOrFn, HighlightFixtureMap, ResolvedHighlight, StubCtx, StubLifecycleFn, StubPhaseResult, StubPhaseFixtures, WaygraphTodoItem, WaygraphTodoInput, } from "./highlights.js";
|
|
6
6
|
/**
|
|
7
7
|
* A Checkpoint is identified solely by its string tag - a phantom marker with no
|
|
8
8
|
* embedded data. Two Checkpoints with the same tag are the same state everywhere.
|
|
@@ -90,22 +90,34 @@ export interface Instruction<In extends Checkpoint<string>, Out extends Checkpoi
|
|
|
90
90
|
*/
|
|
91
91
|
verify?: Trait[] | ((out: Out) => Trait[]);
|
|
92
92
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
93
|
+
* Open block lifecycle **before / during** `act` (demo rings + fixtures).
|
|
94
|
+
* Prefer `stubBefore(ctx) { ctx.todos(...); ctx.ring(...) }` — not a closed
|
|
95
|
+
* slot object. Object map `{ email: { selector, label } }` remains a shorthand.
|
|
96
|
+
* Flow {@link HighlightFixtureMap} still overrides ring labels.
|
|
97
|
+
* @example stubBefore: (ctx) => {
|
|
98
|
+
* ctx.todos(["Email", "Password", "Submit"]);
|
|
99
|
+
* ctx.todoIndex(0);
|
|
100
|
+
* ctx.highlights({ email: { selector: "#email", label: "Email" } });
|
|
101
|
+
* }
|
|
96
102
|
*/
|
|
97
103
|
stubBefore?: HighlightStubPhaseOrFn<Out>;
|
|
98
104
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
105
|
+
* Open block lifecycle **after** resolve (step panel rings + fixtures).
|
|
106
|
+
* Prefer `stubAfter(ctx) { ... }`. Object map shorthand still works.
|
|
107
|
+
* Prefer this over legacy {@link Instruction.highlights}.
|
|
108
|
+
* @example stubAfter: (ctx) => {
|
|
109
|
+
* ctx.todoIndex(2);
|
|
110
|
+
* ctx.ring("badge", { selector: ".cart", label: "Cart updated" });
|
|
111
|
+
* }
|
|
102
112
|
*/
|
|
103
113
|
stubAfter?: HighlightStubPhaseOrFn<Out>;
|
|
104
114
|
/**
|
|
105
|
-
*
|
|
115
|
+
* Open block lifecycle when a **step throws** (failed verify / act error) -
|
|
106
116
|
* before the error panel. Success-only {@link Instruction.stubAfter} never runs
|
|
107
|
-
* here
|
|
108
|
-
* @example stubOnError:
|
|
117
|
+
* here. Prefer `stubOnError(ctx) { ... }`.
|
|
118
|
+
* @example stubOnError: (ctx) => {
|
|
119
|
+
* ctx.ring("card", { selector: ".alt-1", label: "Card at failure", tag: "BUG" });
|
|
120
|
+
* }
|
|
109
121
|
*/
|
|
110
122
|
stubOnError?: HighlightStubPhaseOrFn<Out>;
|
|
111
123
|
/**
|