@pygmalionjs/pygmalion 0.5.17 → 0.5.19
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-lib/{FrozenRoutePreview-CZOpvN6z.js → FrozenRoutePreview-C3TjaTBK.js} +1783 -1639
- package/dist-lib/pygmalion.js +7005 -6861
- package/dist-lib/style.css +1 -1
- package/dist-lib/testing.js +1 -1
- package/dist-lib/types/canvas/ShadowRoutePreview.d.ts +6 -0
- package/dist-lib/types/editor/captureSupply.d.ts +107 -0
- package/dist-lib/types/editor/designImport.d.ts +19 -0
- package/dist-lib/types/editor/documentStability.d.ts +35 -0
- package/dist-lib/types/editor/flowSessionScheduler.d.ts +6 -0
- package/dist-lib/types/editor/flowSessions.d.ts +33 -1
- package/dist-lib/types/editor/interactiveStates.d.ts +27 -0
- package/dist-lib/types/editor/mountScheduler.d.ts +31 -0
- package/dist-lib/types/editor/previewBootstrap.d.ts +55 -3
- package/dist-lib/types/editor/projectBootGate.d.ts +10 -0
- package/dist-lib/types/editor/routePreview.d.ts +28 -7
- package/dist-lib/types/editor/store.d.ts +6 -0
- package/dist-lib/types/editor/storyboardJourney.d.ts +37 -0
- package/dist-lib/types/lib.d.ts +21 -1
- package/dist-lib/types/shell/LayerTree.d.ts +6 -3
- package/dist-lib/types/shell/StoryboardGraphPanel.d.ts +1 -9
- package/node/dev-mirror.mjs +11 -0
- package/node/preview-artifact-plugin.mjs +237 -40
- package/node/storyboard-capture-runtime.mjs +97 -9
- package/node/vite.mjs +4 -0
- package/package.json +1 -1
- package/dist-lib/types/canvas/StoryboardConnections.d.ts +0 -31
- package/dist-lib/types/shell/AssetsPanel.d.ts +0 -3
|
@@ -704,6 +704,11 @@ export function storyboardDocumentStabilitySignature(volatileSelectors = []) {
|
|
|
704
704
|
selectorKey,
|
|
705
705
|
observer: null,
|
|
706
706
|
revision: 0,
|
|
707
|
+
// What kept changing, by element, so a screen that never settles can say
|
|
708
|
+
// which part of it would not stop — the alternative is a capture that
|
|
709
|
+
// reports "unstable" and a person guessing which widget to declare
|
|
710
|
+
// volatile. Bounded: a screen has a handful of movers, not thousands.
|
|
711
|
+
churn: new Map(),
|
|
707
712
|
};
|
|
708
713
|
// A screen can hold something that never stops changing — an elapsed clock, a
|
|
709
714
|
// level meter, a marquee. Counting those makes the document look unstable
|
|
@@ -719,6 +724,35 @@ export function storyboardDocumentStabilitySignature(volatileSelectors = []) {
|
|
|
719
724
|
return false;
|
|
720
725
|
}
|
|
721
726
|
};
|
|
727
|
+
const describe = (node) => {
|
|
728
|
+
const element =
|
|
729
|
+
node && node.nodeType === 1 ? node : (node && node.parentElement) || null;
|
|
730
|
+
if (!element) return '(text)';
|
|
731
|
+
const tag = String(element.tagName || '').toLowerCase();
|
|
732
|
+
const id = element.id ? `#${element.id}` : '';
|
|
733
|
+
const classes = String(element.getAttribute?.('class') ?? '')
|
|
734
|
+
.split(/\s+/)
|
|
735
|
+
.filter(Boolean)
|
|
736
|
+
.slice(0, 2)
|
|
737
|
+
.map((name) => `.${name}`)
|
|
738
|
+
.join('');
|
|
739
|
+
const testId = element.getAttribute?.('data-testid');
|
|
740
|
+
return `${tag}${id}${classes}${testId ? `[data-testid=${testId}]` : ''}`;
|
|
741
|
+
};
|
|
742
|
+
const countChurn = (records) => {
|
|
743
|
+
for (const record of records) {
|
|
744
|
+
if (isVolatile(record.target)) continue;
|
|
745
|
+
const key = describe(record.target);
|
|
746
|
+
const known = tracker.churn.get(key);
|
|
747
|
+
if (known != null) {
|
|
748
|
+
tracker.churn.set(key, known + 1);
|
|
749
|
+
} else if (tracker.churn.size < 64) {
|
|
750
|
+
tracker.churn.set(key, 1);
|
|
751
|
+
} else {
|
|
752
|
+
tracker.churn.set('(other)', (tracker.churn.get('(other)') ?? 0) + 1);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
};
|
|
722
756
|
if (
|
|
723
757
|
document.documentElement &&
|
|
724
758
|
typeof runtime.MutationObserver === 'function'
|
|
@@ -728,6 +762,7 @@ export function storyboardDocumentStabilitySignature(volatileSelectors = []) {
|
|
|
728
762
|
if (batch.length > 0 && batch.every((record) => isVolatile(record.target))) {
|
|
729
763
|
return;
|
|
730
764
|
}
|
|
765
|
+
countChurn(batch);
|
|
731
766
|
tracker.revision += 1;
|
|
732
767
|
});
|
|
733
768
|
tracker.observer.observe(document.documentElement, {
|
|
@@ -782,6 +817,47 @@ export function storyboardDocumentStabilitySignature(volatileSelectors = []) {
|
|
|
782
817
|
});
|
|
783
818
|
}
|
|
784
819
|
|
|
820
|
+
/**
|
|
821
|
+
* What kept the document from settling, most active first.
|
|
822
|
+
*
|
|
823
|
+
* Runs inside the page: the stability tracker keeps a bounded count of
|
|
824
|
+
* mutation targets that were not declared volatile, and this reads it back so
|
|
825
|
+
* a failed wait can name the mover instead of only saying "unstable".
|
|
826
|
+
*/
|
|
827
|
+
export function storyboardDocumentChurnReport(limit = 6) {
|
|
828
|
+
const tracker = window['__PYGMALION_STORYBOARD_STABILITY__'];
|
|
829
|
+
const churn = tracker?.churn;
|
|
830
|
+
if (!churn || typeof churn.entries !== 'function') return [];
|
|
831
|
+
return [...churn.entries()]
|
|
832
|
+
.sort((left, right) => right[1] - left[1])
|
|
833
|
+
.slice(0, Math.max(0, limit))
|
|
834
|
+
.map(([target, count]) => ({ target, count }));
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/** One line naming what a screen kept changing, for a stability failure. */
|
|
838
|
+
export function formatStoryboardChurn(report) {
|
|
839
|
+
if (!Array.isArray(report) || report.length === 0) return '';
|
|
840
|
+
const parts = report
|
|
841
|
+
.filter((entry) => entry && typeof entry.target === 'string')
|
|
842
|
+
.map((entry) => `${entry.target} ×${Number(entry.count) || 0}`);
|
|
843
|
+
return parts.length ? ` Still changing: ${parts.join(', ')}.` : '';
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
async function describeStoryboardChurn(page) {
|
|
847
|
+
try {
|
|
848
|
+
const report = await page.evaluate(storyboardDocumentChurnReport, 6);
|
|
849
|
+
return formatStoryboardChurn(report);
|
|
850
|
+
} catch {
|
|
851
|
+
return '';
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function unstableDocumentError(churn) {
|
|
856
|
+
return new Error(
|
|
857
|
+
`The rendered document did not reach a stable DOM and overlay state.${churn}`,
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
|
|
785
861
|
export async function waitForStableStoryboardDocument(
|
|
786
862
|
page,
|
|
787
863
|
{
|
|
@@ -1148,17 +1224,23 @@ async function collectStableEvidence(
|
|
|
1148
1224
|
screenshotOptions,
|
|
1149
1225
|
screenshotScale = STORYBOARD_CAPTURE_SCREENSHOT_SCALE,
|
|
1150
1226
|
stability = {},
|
|
1227
|
+
// The stabilize stage already froze the page and saw it hold still. Waiting
|
|
1228
|
+
// again here measured as the single largest cost of a capture (two rounds
|
|
1229
|
+
// of the same wait, ~40% of the whole), and a document that was still a
|
|
1230
|
+
// moment ago is not made stiller by asking twice.
|
|
1231
|
+
frozenStyleApplied = false,
|
|
1232
|
+
alreadyStable = false,
|
|
1151
1233
|
},
|
|
1152
1234
|
) {
|
|
1153
1235
|
const evidence = {};
|
|
1154
1236
|
const errors = [];
|
|
1155
1237
|
try {
|
|
1156
|
-
await page.addStyleTag({ content: FROZEN_STYLE });
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1238
|
+
if (!frozenStyleApplied) await page.addStyleTag({ content: FROZEN_STYLE });
|
|
1239
|
+
if (!alreadyStable) {
|
|
1240
|
+
const stable = await waitForStableStoryboardDocument(page, stability);
|
|
1241
|
+
if (!stable) {
|
|
1242
|
+
throw unstableDocumentError(await describeStoryboardChurn(page));
|
|
1243
|
+
}
|
|
1162
1244
|
}
|
|
1163
1245
|
} catch (error) {
|
|
1164
1246
|
errors.push(new StoryboardCaptureStageError('stabilize', error));
|
|
@@ -1306,6 +1388,10 @@ export async function captureStoryboardCase({
|
|
|
1306
1388
|
let primaryError = null;
|
|
1307
1389
|
let evidence = {};
|
|
1308
1390
|
const evidenceErrors = [];
|
|
1391
|
+
// Set by the stabilize stage; evidence collection reuses both instead of
|
|
1392
|
+
// freezing and waiting a second time.
|
|
1393
|
+
let frozenStyleApplied = Boolean(session?.frozen);
|
|
1394
|
+
let stabilized = false;
|
|
1309
1395
|
try {
|
|
1310
1396
|
throwIfAborted(signal);
|
|
1311
1397
|
if (!warm) {
|
|
@@ -1394,12 +1480,12 @@ export async function captureStoryboardCase({
|
|
|
1394
1480
|
await page.addStyleTag({ content: FROZEN_STYLE });
|
|
1395
1481
|
if (session) session.frozen = true;
|
|
1396
1482
|
}
|
|
1483
|
+
frozenStyleApplied = true;
|
|
1397
1484
|
const stable = await waitForStableStoryboardDocument(page, stability);
|
|
1398
1485
|
if (!stable) {
|
|
1399
|
-
throw
|
|
1400
|
-
'The rendered document did not reach a stable DOM and overlay state.',
|
|
1401
|
-
);
|
|
1486
|
+
throw unstableDocumentError(await describeStoryboardChurn(page));
|
|
1402
1487
|
}
|
|
1488
|
+
stabilized = true;
|
|
1403
1489
|
});
|
|
1404
1490
|
await atCaptureStage('assertion', async () => {
|
|
1405
1491
|
await assertFinalStoryboardState(page, screenCase.assertions ?? []);
|
|
@@ -1420,6 +1506,8 @@ export async function captureStoryboardCase({
|
|
|
1420
1506
|
screenshotOptions,
|
|
1421
1507
|
screenshotScale: resolveScreenshotScale(contextOptions),
|
|
1422
1508
|
stability,
|
|
1509
|
+
frozenStyleApplied,
|
|
1510
|
+
alreadyStable: stabilized,
|
|
1423
1511
|
});
|
|
1424
1512
|
evidence = collected.evidence;
|
|
1425
1513
|
evidenceErrors.push(...collected.errors);
|
package/node/vite.mjs
CHANGED
|
@@ -258,6 +258,10 @@ export function createPygmalionVitePlugins(config) {
|
|
|
258
258
|
endpoint: project.preview.artifactEndpoint,
|
|
259
259
|
generateArtifact,
|
|
260
260
|
acquireLease: (label) => devMirror?.acquireLease(label) ?? null,
|
|
261
|
+
requestRuntime: () => devMirror?.requestRuntime?.(),
|
|
262
|
+
// No mirror plugin means no checkout to prepare, so generation is
|
|
263
|
+
// always allowed to proceed as it did before.
|
|
264
|
+
runtimePrepared: () => devMirror?.runtimePrepared?.() ?? true,
|
|
261
265
|
}),
|
|
262
266
|
);
|
|
263
267
|
}
|
package/package.json
CHANGED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { StoryboardGraphViewModel } from '../editor/storyboardGraphView';
|
|
2
|
-
export interface StoryboardFrameGeometry {
|
|
3
|
-
frameId: string;
|
|
4
|
-
x: number;
|
|
5
|
-
y: number;
|
|
6
|
-
width: number;
|
|
7
|
-
height: number;
|
|
8
|
-
}
|
|
9
|
-
export interface StoryboardConnectionPath {
|
|
10
|
-
id: string;
|
|
11
|
-
sourceFrameId: string;
|
|
12
|
-
targetFrameId: string;
|
|
13
|
-
path: string;
|
|
14
|
-
}
|
|
15
|
-
export type StoryboardConnectionMode = 'story' | 'focus' | 'overview';
|
|
16
|
-
export interface StoryboardConnectionPathOptions {
|
|
17
|
-
mode?: StoryboardConnectionMode;
|
|
18
|
-
activeFrameId?: string | null;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Projects graph transitions into world-space paths. The calculation is kept
|
|
22
|
-
* independent from camera pan and zoom because the SVG lives inside the same
|
|
23
|
-
* transformed canvas layer as the frames.
|
|
24
|
-
*/
|
|
25
|
-
export declare function createStoryboardConnectionPaths(model: StoryboardGraphViewModel, frames: readonly StoryboardFrameGeometry[], options?: StoryboardConnectionPathOptions): StoryboardConnectionPath[];
|
|
26
|
-
export declare function StoryboardConnections({ model, frames, mode, activeFrameId, }: {
|
|
27
|
-
model: StoryboardGraphViewModel;
|
|
28
|
-
frames: readonly StoryboardFrameGeometry[];
|
|
29
|
-
mode?: StoryboardConnectionMode;
|
|
30
|
-
activeFrameId?: string | null;
|
|
31
|
-
}): import("react").JSX.Element | null;
|