@juxtapose/core 0.2.0 → 0.5.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/agent/handoff.d.ts +8 -1
- package/dist/agent/handoff.js +75 -7
- package/dist/agent/handoff.js.map +1 -1
- package/dist/analysis/affected.d.ts +58 -0
- package/dist/analysis/affected.js +134 -22
- package/dist/analysis/affected.js.map +1 -1
- package/dist/analysis/cause.d.ts +32 -0
- package/dist/analysis/cause.js +187 -0
- package/dist/analysis/cause.js.map +1 -0
- package/dist/baseline/approve.d.ts +24 -0
- package/dist/baseline/approve.js +54 -0
- package/dist/baseline/approve.js.map +1 -0
- package/dist/baseline/git-store.d.ts +4 -0
- package/dist/baseline/git-store.js +22 -0
- package/dist/baseline/git-store.js.map +1 -1
- package/dist/browser/acquire.d.ts +11 -0
- package/dist/browser/acquire.js +15 -0
- package/dist/browser/acquire.js.map +1 -0
- package/dist/browser/browser.d.ts +53 -0
- package/dist/browser/browser.js +122 -0
- package/dist/browser/browser.js.map +1 -0
- package/dist/browser/cdp.d.ts +81 -0
- package/dist/browser/cdp.js +230 -0
- package/dist/browser/cdp.js.map +1 -0
- package/dist/browser/index.d.ts +9 -0
- package/dist/browser/index.js +10 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/install.d.ts +33 -0
- package/dist/browser/install.js +167 -0
- package/dist/browser/install.js.map +1 -0
- package/dist/browser/launch.d.ts +37 -0
- package/dist/browser/launch.js +265 -0
- package/dist/browser/launch.js.map +1 -0
- package/dist/browser/page.d.ts +125 -0
- package/dist/browser/page.js +564 -0
- package/dist/browser/page.js.map +1 -0
- package/dist/browser/pins.d.ts +12 -0
- package/dist/browser/pins.js +57 -0
- package/dist/browser/pins.js.map +1 -0
- package/dist/browser/resolve.d.ts +25 -0
- package/dist/browser/resolve.js +115 -0
- package/dist/browser/resolve.js.map +1 -0
- package/dist/browser/selectors.d.ts +10 -0
- package/dist/browser/selectors.js +60 -0
- package/dist/browser/selectors.js.map +1 -0
- package/dist/browser/transport.d.ts +39 -0
- package/dist/browser/transport.js +99 -0
- package/dist/browser/transport.js.map +1 -0
- package/dist/browser/zip.d.ts +27 -0
- package/dist/browser/zip.js +241 -0
- package/dist/browser/zip.js.map +1 -0
- package/dist/capture/capture.d.ts +7 -1
- package/dist/capture/capture.js +27 -3
- package/dist/capture/capture.js.map +1 -1
- package/dist/capture/env.d.ts +8 -0
- package/dist/capture/env.js +38 -0
- package/dist/capture/env.js.map +1 -0
- package/dist/capture/launch.d.ts +19 -1
- package/dist/capture/launch.js +91 -1
- package/dist/capture/launch.js.map +1 -1
- package/dist/capture/pool.d.ts +1 -1
- package/dist/capture/pool.js +41 -8
- package/dist/capture/pool.js.map +1 -1
- package/dist/capture/settle.d.ts +1 -1
- package/dist/capture/settle.js +2 -0
- package/dist/capture/settle.js.map +1 -1
- package/dist/capture/snap.d.ts +43 -0
- package/dist/capture/snap.js +103 -0
- package/dist/capture/snap.js.map +1 -0
- package/dist/capture/structure.d.ts +77 -0
- package/dist/capture/structure.js +498 -0
- package/dist/capture/structure.js.map +1 -0
- package/dist/diff/compare.d.ts +19 -0
- package/dist/diff/compare.js +19 -0
- package/dist/diff/compare.js.map +1 -0
- package/dist/diff/crops.d.ts +26 -0
- package/dist/diff/crops.js +92 -0
- package/dist/diff/crops.js.map +1 -0
- package/dist/diff/structural/classify.d.ts +29 -0
- package/dist/diff/structural/classify.js +113 -0
- package/dist/diff/structural/classify.js.map +1 -0
- package/dist/diff/structural/coverage.d.ts +11 -0
- package/dist/diff/structural/coverage.js +37 -0
- package/dist/diff/structural/coverage.js.map +1 -0
- package/dist/diff/structural/deltas.d.ts +29 -0
- package/dist/diff/structural/deltas.js +218 -0
- package/dist/diff/structural/deltas.js.map +1 -0
- package/dist/diff/structural/disambiguate.d.ts +3 -0
- package/dist/diff/structural/disambiguate.js +89 -0
- package/dist/diff/structural/disambiguate.js.map +1 -0
- package/dist/diff/structural/label.d.ts +15 -0
- package/dist/diff/structural/label.js +64 -0
- package/dist/diff/structural/label.js.map +1 -0
- package/dist/diff/structural/match.d.ts +13 -0
- package/dist/diff/structural/match.js +135 -0
- package/dist/diff/structural/match.js.map +1 -0
- package/dist/diff/structural/shift.d.ts +2 -0
- package/dist/diff/structural/shift.js +144 -0
- package/dist/diff/structural/shift.js.map +1 -0
- package/dist/diff/structural/summary.d.ts +31 -0
- package/dist/diff/structural/summary.js +420 -0
- package/dist/diff/structural/summary.js.map +1 -0
- package/dist/diff/structural.d.ts +40 -0
- package/dist/diff/structural.js +219 -0
- package/dist/diff/structural.js.map +1 -0
- package/dist/index.d.ts +34 -12
- package/dist/index.js +55 -11
- package/dist/index.js.map +1 -1
- package/dist/platform.d.ts +1 -1
- package/dist/platforms/urls.d.ts +3 -0
- package/dist/platforms/urls.js +89 -0
- package/dist/platforms/urls.js.map +1 -0
- package/dist/report/comment.d.ts +2 -1
- package/dist/report/comment.js +305 -57
- package/dist/report/comment.js.map +1 -1
- package/dist/report/format.d.ts +20 -0
- package/dist/report/format.js +32 -0
- package/dist/report/format.js.map +1 -0
- package/dist/report/github.d.ts +12 -0
- package/dist/report/github.js +21 -0
- package/dist/report/github.js.map +1 -1
- package/dist/report/html.d.ts +12 -0
- package/dist/report/html.js +202 -0
- package/dist/report/html.js.map +1 -0
- package/dist/run/groups.d.ts +2 -0
- package/dist/run/groups.js +45 -0
- package/dist/run/groups.js.map +1 -0
- package/dist/run/phases.d.ts +19 -0
- package/dist/run/phases.js +50 -0
- package/dist/run/phases.js.map +1 -0
- package/dist/run/run.d.ts +10 -2
- package/dist/run/run.js +97 -9
- package/dist/run/run.js.map +1 -1
- package/dist/shell-quote.d.ts +2 -0
- package/dist/shell-quote.js +10 -0
- package/dist/shell-quote.js.map +1 -0
- package/dist/types.d.ts +234 -3
- package/dist/url-platform.d.ts +2 -2
- package/dist/url-platform.js +2 -2
- package/dist/url-platform.js.map +1 -1
- package/package.json +14 -10
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snap.js","sourceRoot":"","sources":["../../src/capture/snap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { Page } from '../browser/page.js';
|
|
2
|
+
import type { StructureSnapshot, Viewport } from '../types.js';
|
|
3
|
+
/** Styles recorded per element. `display`/`visibility` are deliberately absent:
|
|
4
|
+
* display:none elements have no layout entry at all, and visibility is read
|
|
5
|
+
* only to filter (see `visibilityIdx` in normalizeStructure). */
|
|
6
|
+
export declare const STRUCTURE_PROPS: readonly string[];
|
|
7
|
+
/** Inherited properties are stored only where they differ from the parent. */
|
|
8
|
+
export declare const INHERITED_PROPS: ReadonlySet<string>;
|
|
9
|
+
/** Computed-style initial values for non-inherited properties. A value equal
|
|
10
|
+
* to its initial value is not stored. Border colors are special-cased: they
|
|
11
|
+
* default to currentColor, so they are stored only when that side's width is
|
|
12
|
+
* non-zero. */
|
|
13
|
+
export declare const INITIAL_VALUES: Readonly<Record<string, string>>;
|
|
14
|
+
export declare const MASK_ATTR = "data-jux-masked";
|
|
15
|
+
export declare const MAX_ELEMENTS = 5000;
|
|
16
|
+
/** The subset of a CDP DOMSnapshot.captureSnapshot response we read. */
|
|
17
|
+
export interface CdpSnapshot {
|
|
18
|
+
documents: Array<{
|
|
19
|
+
contentHeight?: number;
|
|
20
|
+
nodes: {
|
|
21
|
+
parentIndex: number[];
|
|
22
|
+
nodeType: number[];
|
|
23
|
+
nodeName: number[];
|
|
24
|
+
nodeValue: number[];
|
|
25
|
+
attributes: number[][];
|
|
26
|
+
/** Rare-string data: parallel arrays of node index → string index.
|
|
27
|
+
* Verified on Chromium 151: pseudo-elements appear as element nodes
|
|
28
|
+
* named `::before`/`::after` with pseudoType set; an <input>'s typed
|
|
29
|
+
* value is in inputValue, not in an attribute. */
|
|
30
|
+
pseudoType?: {
|
|
31
|
+
index: number[];
|
|
32
|
+
value: number[];
|
|
33
|
+
};
|
|
34
|
+
inputValue?: {
|
|
35
|
+
index: number[];
|
|
36
|
+
value: number[];
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
layout: {
|
|
40
|
+
nodeIndex: number[];
|
|
41
|
+
styles: number[][];
|
|
42
|
+
bounds: number[][];
|
|
43
|
+
paintOrders?: number[];
|
|
44
|
+
};
|
|
45
|
+
}>;
|
|
46
|
+
strings: string[];
|
|
47
|
+
}
|
|
48
|
+
export declare const round: (n: number) => number;
|
|
49
|
+
/**
|
|
50
|
+
* Turn a raw CDP snapshot into a StructureSnapshot.
|
|
51
|
+
*
|
|
52
|
+
* Only the top document is read: iframe content is a separate document and is
|
|
53
|
+
* represented by the <iframe> element's own rect. Open shadow content is part
|
|
54
|
+
* of the host document's node list and is included.
|
|
55
|
+
*/
|
|
56
|
+
export declare function normalizeStructure(raw: CdpSnapshot, viewport: Viewport): StructureSnapshot;
|
|
57
|
+
/** The full value of `prop` for element `index`, reconstructing what the
|
|
58
|
+
* compact storage omitted. */
|
|
59
|
+
export declare function effectiveStyle(s: StructureSnapshot, index: number, prop: string): string;
|
|
60
|
+
export declare function encodeStructure(s: StructureSnapshot): Buffer;
|
|
61
|
+
export declare function decodeStructure(b: Buffer): StructureSnapshot;
|
|
62
|
+
/**
|
|
63
|
+
* Snapshot the page's structure. Never throws: a missing structure costs the
|
|
64
|
+
* agent some explanation, a thrown error would cost the story its capture.
|
|
65
|
+
*
|
|
66
|
+
* Mask selectors are resolved with the same CSS-over-open-shadow-roots query
|
|
67
|
+
* the screenshot masks with; Playwright-only syntax is rejected in
|
|
68
|
+
* captureStory before anything runs. Matches get MASK_ATTR so the normalizer
|
|
69
|
+
* collapses their subtree. A plain document.querySelectorAll would miss
|
|
70
|
+
* matches inside shadow roots and leak masked content into the sidecar.
|
|
71
|
+
*
|
|
72
|
+
* Fail closed: if marking fails, or any match lost its mark by the time the
|
|
73
|
+
* snapshot returns (the page mutated in between), return undefined. Setting an
|
|
74
|
+
* attribute does not affect paint unless a stylesheet targets it, which
|
|
75
|
+
* nothing ships with.
|
|
76
|
+
*/
|
|
77
|
+
export declare function captureStructure(page: Page, viewport: Viewport, mask: readonly string[]): Promise<StructureSnapshot | undefined>;
|
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
// Structure snapshot: the visible DOM and its computed styles, captured in the
|
|
2
|
+
// same frame as the screenshot.
|
|
3
|
+
//
|
|
4
|
+
// Why: pixels say WHERE something changed; this says WHAT — which element,
|
|
5
|
+
// which property, old → new — so an agent can decide without reading an image
|
|
6
|
+
// (spec: docs/specs/2026-10-12-sp0-structural-diff-agent-surface-design.md).
|
|
7
|
+
// It explains a failure; it never decides one. The pixel hash still does.
|
|
8
|
+
//
|
|
9
|
+
// Everything here is a pure function of the CDP response so it can be tested
|
|
10
|
+
// against real Chromium output committed as a fixture.
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { gunzipSync, gzipSync } from 'node:zlib';
|
|
13
|
+
import { queryAllExpression } from '../browser/selectors.js';
|
|
14
|
+
/** Styles recorded per element. `display`/`visibility` are deliberately absent:
|
|
15
|
+
* display:none elements have no layout entry at all, and visibility is read
|
|
16
|
+
* only to filter (see `visibilityIdx` in normalizeStructure). */
|
|
17
|
+
export const STRUCTURE_PROPS = [
|
|
18
|
+
'color',
|
|
19
|
+
'background-color',
|
|
20
|
+
'background-image',
|
|
21
|
+
'font-family',
|
|
22
|
+
'font-size',
|
|
23
|
+
'font-weight',
|
|
24
|
+
'font-style',
|
|
25
|
+
'line-height',
|
|
26
|
+
'letter-spacing',
|
|
27
|
+
'text-align',
|
|
28
|
+
'text-decoration-line',
|
|
29
|
+
'text-transform',
|
|
30
|
+
'padding-top',
|
|
31
|
+
'padding-right',
|
|
32
|
+
'padding-bottom',
|
|
33
|
+
'padding-left',
|
|
34
|
+
'margin-top',
|
|
35
|
+
'margin-right',
|
|
36
|
+
'margin-bottom',
|
|
37
|
+
'margin-left',
|
|
38
|
+
'border-top-width',
|
|
39
|
+
'border-right-width',
|
|
40
|
+
'border-bottom-width',
|
|
41
|
+
'border-left-width',
|
|
42
|
+
'border-top-color',
|
|
43
|
+
'border-right-color',
|
|
44
|
+
'border-bottom-color',
|
|
45
|
+
'border-left-color',
|
|
46
|
+
'border-top-left-radius',
|
|
47
|
+
'border-top-right-radius',
|
|
48
|
+
'border-bottom-right-radius',
|
|
49
|
+
'border-bottom-left-radius',
|
|
50
|
+
'opacity',
|
|
51
|
+
'transform',
|
|
52
|
+
'box-shadow',
|
|
53
|
+
'gap',
|
|
54
|
+
'z-index',
|
|
55
|
+
// SVG paint is computed style, not an attribute: without these an icon
|
|
56
|
+
// recolour is unexplained pixels.
|
|
57
|
+
'fill',
|
|
58
|
+
'stroke',
|
|
59
|
+
'stroke-width',
|
|
60
|
+
// A pseudo-element's visible text lives here, not in a text node: without it
|
|
61
|
+
// a CSS icon swap (`content: "★"` → `"☆"`) is unexplained pixels.
|
|
62
|
+
'content',
|
|
63
|
+
];
|
|
64
|
+
/** Inherited properties are stored only where they differ from the parent. */
|
|
65
|
+
export const INHERITED_PROPS = new Set([
|
|
66
|
+
'color',
|
|
67
|
+
'font-family',
|
|
68
|
+
'font-size',
|
|
69
|
+
'font-weight',
|
|
70
|
+
'font-style',
|
|
71
|
+
'line-height',
|
|
72
|
+
'letter-spacing',
|
|
73
|
+
'text-align',
|
|
74
|
+
'text-transform',
|
|
75
|
+
'fill',
|
|
76
|
+
'stroke',
|
|
77
|
+
'stroke-width',
|
|
78
|
+
]);
|
|
79
|
+
/** Computed-style initial values for non-inherited properties. A value equal
|
|
80
|
+
* to its initial value is not stored. Border colors are special-cased: they
|
|
81
|
+
* default to currentColor, so they are stored only when that side's width is
|
|
82
|
+
* non-zero. */
|
|
83
|
+
export const INITIAL_VALUES = {
|
|
84
|
+
'background-color': 'rgba(0, 0, 0, 0)',
|
|
85
|
+
'background-image': 'none',
|
|
86
|
+
'text-decoration-line': 'none',
|
|
87
|
+
'padding-top': '0px',
|
|
88
|
+
'padding-right': '0px',
|
|
89
|
+
'padding-bottom': '0px',
|
|
90
|
+
'padding-left': '0px',
|
|
91
|
+
'margin-top': '0px',
|
|
92
|
+
'margin-right': '0px',
|
|
93
|
+
'margin-bottom': '0px',
|
|
94
|
+
'margin-left': '0px',
|
|
95
|
+
'border-top-width': '0px',
|
|
96
|
+
'border-right-width': '0px',
|
|
97
|
+
'border-bottom-width': '0px',
|
|
98
|
+
'border-left-width': '0px',
|
|
99
|
+
'border-top-left-radius': '0px',
|
|
100
|
+
'border-top-right-radius': '0px',
|
|
101
|
+
'border-bottom-right-radius': '0px',
|
|
102
|
+
'border-bottom-left-radius': '0px',
|
|
103
|
+
opacity: '1',
|
|
104
|
+
transform: 'none',
|
|
105
|
+
'box-shadow': 'none',
|
|
106
|
+
gap: 'normal',
|
|
107
|
+
'z-index': 'auto',
|
|
108
|
+
content: 'normal',
|
|
109
|
+
};
|
|
110
|
+
/** Root defaults for inherited props when no kept ancestor exists. */
|
|
111
|
+
const ROOT_INHERITED = {
|
|
112
|
+
color: 'rgb(0, 0, 0)',
|
|
113
|
+
'font-style': 'normal',
|
|
114
|
+
'font-weight': '400',
|
|
115
|
+
'letter-spacing': 'normal',
|
|
116
|
+
'text-align': 'start',
|
|
117
|
+
'text-transform': 'none',
|
|
118
|
+
// SVG paint defaults (CSS initial values, as Chromium computes them)
|
|
119
|
+
fill: 'rgb(0, 0, 0)',
|
|
120
|
+
stroke: 'none',
|
|
121
|
+
'stroke-width': '1px',
|
|
122
|
+
};
|
|
123
|
+
export const MASK_ATTR = 'data-jux-masked';
|
|
124
|
+
export const MAX_ELEMENTS = 5000;
|
|
125
|
+
const ELEMENT_NODE = 1;
|
|
126
|
+
const TEXT_NODE = 3;
|
|
127
|
+
const IMPLICIT_ROLES = {
|
|
128
|
+
button: 'button',
|
|
129
|
+
h1: 'heading',
|
|
130
|
+
h2: 'heading',
|
|
131
|
+
h3: 'heading',
|
|
132
|
+
h4: 'heading',
|
|
133
|
+
h5: 'heading',
|
|
134
|
+
h6: 'heading',
|
|
135
|
+
img: 'img',
|
|
136
|
+
select: 'combobox',
|
|
137
|
+
textarea: 'textbox',
|
|
138
|
+
nav: 'navigation',
|
|
139
|
+
main: 'main',
|
|
140
|
+
header: 'banner',
|
|
141
|
+
footer: 'contentinfo',
|
|
142
|
+
ul: 'list',
|
|
143
|
+
ol: 'list',
|
|
144
|
+
li: 'listitem',
|
|
145
|
+
table: 'table',
|
|
146
|
+
dialog: 'dialog',
|
|
147
|
+
iframe: 'document',
|
|
148
|
+
};
|
|
149
|
+
export const round = (n) => Math.round(n * 100) / 100;
|
|
150
|
+
/**
|
|
151
|
+
* Turn a raw CDP snapshot into a StructureSnapshot.
|
|
152
|
+
*
|
|
153
|
+
* Only the top document is read: iframe content is a separate document and is
|
|
154
|
+
* represented by the <iframe> element's own rect. Open shadow content is part
|
|
155
|
+
* of the host document's node list and is included.
|
|
156
|
+
*/
|
|
157
|
+
export function normalizeStructure(raw, viewport) {
|
|
158
|
+
const doc = raw.documents[0];
|
|
159
|
+
const str = (i) => i === undefined || i < 0 ? undefined : raw.strings[i];
|
|
160
|
+
const { nodes, layout } = doc;
|
|
161
|
+
const styleIdx = STRUCTURE_PROPS.map((_, i) => i);
|
|
162
|
+
// `visibility` is requested after STRUCTURE_PROPS and used only to filter.
|
|
163
|
+
const visibilityIdx = STRUCTURE_PROPS.length;
|
|
164
|
+
// node index -> layout row. A node can have several rows (a pseudo-element
|
|
165
|
+
// gets one for its box and one per text fragment); the FIRST is the box.
|
|
166
|
+
const layoutOf = new Map();
|
|
167
|
+
layout.nodeIndex.forEach((n, row) => {
|
|
168
|
+
if (!layoutOf.has(n))
|
|
169
|
+
layoutOf.set(n, row);
|
|
170
|
+
});
|
|
171
|
+
const contentIdx = STRUCTURE_PROPS.indexOf('content');
|
|
172
|
+
const rare = (r) => {
|
|
173
|
+
const m = new Map();
|
|
174
|
+
r?.index.forEach((n, k) => m.set(n, str(r.value[k]) ?? ''));
|
|
175
|
+
return m;
|
|
176
|
+
};
|
|
177
|
+
const inputValue = rare(nodes.inputValue);
|
|
178
|
+
// children lists and own text, in document order
|
|
179
|
+
const children = new Map();
|
|
180
|
+
const ownText = new Map();
|
|
181
|
+
for (let i = 0; i < nodes.nodeType.length; i++) {
|
|
182
|
+
const p = nodes.parentIndex[i];
|
|
183
|
+
if (p < 0)
|
|
184
|
+
continue;
|
|
185
|
+
if (nodes.nodeType[i] === TEXT_NODE) {
|
|
186
|
+
const t = str(nodes.nodeValue[i]) ?? '';
|
|
187
|
+
ownText.set(p, (ownText.get(p) ?? '') + t);
|
|
188
|
+
}
|
|
189
|
+
else if (nodes.nodeType[i] === ELEMENT_NODE) {
|
|
190
|
+
const list = children.get(p) ?? [];
|
|
191
|
+
list.push(i);
|
|
192
|
+
children.set(p, list);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const attrs = (i) => {
|
|
196
|
+
const out = {};
|
|
197
|
+
const a = nodes.attributes[i] ?? [];
|
|
198
|
+
for (let k = 0; k + 1 < a.length; k += 2)
|
|
199
|
+
out[str(a[k])] = str(a[k + 1]) ?? '';
|
|
200
|
+
return out;
|
|
201
|
+
};
|
|
202
|
+
const elements = [];
|
|
203
|
+
let total = 0;
|
|
204
|
+
// effective inherited values per kept element, for compact storage
|
|
205
|
+
const effective = [];
|
|
206
|
+
const visit = (i, parentPath, keptParent) => {
|
|
207
|
+
const tag = (str(nodes.nodeName[i]) ?? '').toLowerCase();
|
|
208
|
+
if (tag === 'head' || tag === 'script' || tag === 'style')
|
|
209
|
+
return;
|
|
210
|
+
const a = attrs(i);
|
|
211
|
+
const siblings = children.get(nodes.parentIndex[i]) ?? [];
|
|
212
|
+
const sameTag = siblings.filter((s) => (str(nodes.nodeName[s]) ?? '').toLowerCase() === tag);
|
|
213
|
+
const step = a.id !== undefined
|
|
214
|
+
? `${tag}#${a.id}`
|
|
215
|
+
: a['data-testid'] !== undefined
|
|
216
|
+
? `${tag}[data-testid="${a['data-testid']}"]`
|
|
217
|
+
: `${tag}:nth-of-type(${sameTag.indexOf(i) + 1})`;
|
|
218
|
+
const path = parentPath ? `${parentPath}>${step}` : step;
|
|
219
|
+
const row = layoutOf.get(i);
|
|
220
|
+
// Mask first, before any check that can descend: a visibility:hidden mask
|
|
221
|
+
// target with a visibility:visible child used to take the hidden branch
|
|
222
|
+
// below and record the child's text, while the screenshot mask covered it.
|
|
223
|
+
if (a[MASK_ATTR] !== undefined) {
|
|
224
|
+
if (row === undefined)
|
|
225
|
+
return; // no box: nothing to stand in for
|
|
226
|
+
total++;
|
|
227
|
+
if (elements.length < MAX_ELEMENTS) {
|
|
228
|
+
const [x, y, w, h] = layout.bounds[row];
|
|
229
|
+
elements.push({
|
|
230
|
+
path,
|
|
231
|
+
parent: keptParent,
|
|
232
|
+
tag: 'masked',
|
|
233
|
+
rect: { x: round(x), y: round(y), w: round(w), h: round(h) },
|
|
234
|
+
paintOrder: layout.paintOrders?.[row] ?? 0,
|
|
235
|
+
styles: {},
|
|
236
|
+
});
|
|
237
|
+
effective.push(keptParent === null ? { ...ROOT_INHERITED } : effective[keptParent]);
|
|
238
|
+
}
|
|
239
|
+
return; // never descend into a masked subtree
|
|
240
|
+
}
|
|
241
|
+
if (row === undefined)
|
|
242
|
+
return; // display:none (or no box): drop the subtree
|
|
243
|
+
const values = layout.styles[row].map((s) => urlsToFileNames(str(s) ?? ''));
|
|
244
|
+
if (values[visibilityIdx] === 'hidden' || values[visibilityIdx] === 'collapse') {
|
|
245
|
+
// hidden boxes can still contain visible descendants (visibility: visible)
|
|
246
|
+
for (const c of children.get(i) ?? [])
|
|
247
|
+
visit(c, path, keptParent);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const [x, y, w, h] = layout.bounds[row];
|
|
251
|
+
const rect = { x: round(x), y: round(y), w: round(w), h: round(h) };
|
|
252
|
+
const offscreen = rect.x + rect.w <= 0 ||
|
|
253
|
+
rect.y + rect.h <= 0 ||
|
|
254
|
+
rect.x >= viewport.width ||
|
|
255
|
+
rect.y >= viewport.height;
|
|
256
|
+
const empty = rect.w <= 0 || rect.h <= 0;
|
|
257
|
+
const keep = !offscreen && !empty && tag !== 'html' && tag !== 'body';
|
|
258
|
+
let me = keptParent;
|
|
259
|
+
if (keep) {
|
|
260
|
+
total++;
|
|
261
|
+
if (elements.length < MAX_ELEMENTS) {
|
|
262
|
+
const inherited = keptParent === null ? ROOT_INHERITED : effective[keptParent];
|
|
263
|
+
const styles = {};
|
|
264
|
+
const eff = { ...inherited };
|
|
265
|
+
for (const k of styleIdx) {
|
|
266
|
+
const prop = STRUCTURE_PROPS[k];
|
|
267
|
+
const v = values[k];
|
|
268
|
+
if (INHERITED_PROPS.has(prop)) {
|
|
269
|
+
eff[prop] = v;
|
|
270
|
+
if (inherited[prop] !== v)
|
|
271
|
+
styles[prop] = v;
|
|
272
|
+
}
|
|
273
|
+
else if (prop.startsWith('border-') && prop.endsWith('-color')) {
|
|
274
|
+
const side = prop.split('-')[1];
|
|
275
|
+
const width = values[STRUCTURE_PROPS.indexOf(`border-${side}-width`)];
|
|
276
|
+
if (width !== '0px')
|
|
277
|
+
styles[prop] = v;
|
|
278
|
+
}
|
|
279
|
+
else if (INITIAL_VALUES[prop] !== v) {
|
|
280
|
+
styles[prop] = v;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// `content` is meaningful only on a pseudo-element, where it IS the
|
|
284
|
+
// text; on a normal element it is always `normal`, so drop it there.
|
|
285
|
+
const isPseudo = tag.startsWith('::');
|
|
286
|
+
if (!isPseudo)
|
|
287
|
+
delete styles.content;
|
|
288
|
+
const pseudoText = isPseudo ? parseContent(values[contentIdx]) : '';
|
|
289
|
+
// Sidecars are committed to git: never record a secret field's value.
|
|
290
|
+
const secret = tag === 'input' && isSecretInput(a);
|
|
291
|
+
const typed = secret ? undefined : inputValue.get(i);
|
|
292
|
+
const text = collapse(pseudoText || typed || ownText.get(i) || '');
|
|
293
|
+
const role = a.role ?? implicitRole(tag, a);
|
|
294
|
+
const name = (a['aria-label'] ?? a.alt ?? a.title ?? text) || undefined;
|
|
295
|
+
const el = {
|
|
296
|
+
path,
|
|
297
|
+
parent: keptParent,
|
|
298
|
+
tag,
|
|
299
|
+
rect,
|
|
300
|
+
paintOrder: layout.paintOrders?.[row] ?? 0,
|
|
301
|
+
styles,
|
|
302
|
+
};
|
|
303
|
+
if (a.id !== undefined)
|
|
304
|
+
el.id = a.id;
|
|
305
|
+
if (a['data-testid'] !== undefined)
|
|
306
|
+
el.testId = a['data-testid'];
|
|
307
|
+
const classes = (a.class ?? '').split(/\s+/).filter(Boolean);
|
|
308
|
+
if (classes.length)
|
|
309
|
+
el.classes = classes;
|
|
310
|
+
if (role)
|
|
311
|
+
el.role = role;
|
|
312
|
+
if (name)
|
|
313
|
+
el.name = name.slice(0, 80);
|
|
314
|
+
if (text)
|
|
315
|
+
el.text = text.slice(0, 200);
|
|
316
|
+
if (a.src !== undefined)
|
|
317
|
+
el.src = fileName(a.src);
|
|
318
|
+
elements.push(el);
|
|
319
|
+
effective.push(eff);
|
|
320
|
+
me = elements.length - 1;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
for (const c of children.get(i) ?? [])
|
|
324
|
+
visit(c, path, me);
|
|
325
|
+
};
|
|
326
|
+
// node 0 is #document; start from its element children (<html>)
|
|
327
|
+
for (const c of children.get(0) ?? [])
|
|
328
|
+
visit(c, '', null);
|
|
329
|
+
const snapshot = {
|
|
330
|
+
schema: 'juxtapose.structure/v1',
|
|
331
|
+
viewport,
|
|
332
|
+
structureHash: hashElements(elements),
|
|
333
|
+
contentHeight: round(doc.contentHeight ?? viewport.height),
|
|
334
|
+
elements,
|
|
335
|
+
};
|
|
336
|
+
if (total > elements.length)
|
|
337
|
+
snapshot.truncated = { kept: elements.length, total };
|
|
338
|
+
return snapshot;
|
|
339
|
+
}
|
|
340
|
+
/** Autofill tokens that name a secret: a typed OTP, password or card number
|
|
341
|
+
* in a `type=text` field is as sensitive as one in `type=password`. */
|
|
342
|
+
const SECRET_AUTOCOMPLETE = new Set([
|
|
343
|
+
'one-time-code',
|
|
344
|
+
'current-password',
|
|
345
|
+
'new-password',
|
|
346
|
+
]);
|
|
347
|
+
function isSecretInput(a) {
|
|
348
|
+
if (['password', 'hidden'].includes((a.type ?? '').toLowerCase()))
|
|
349
|
+
return true;
|
|
350
|
+
return (a.autocomplete ?? '')
|
|
351
|
+
.toLowerCase()
|
|
352
|
+
.split(/\s+/)
|
|
353
|
+
.some((t) => SECRET_AUTOCOMPLETE.has(t) || t.startsWith('cc-'));
|
|
354
|
+
}
|
|
355
|
+
function implicitRole(tag, a) {
|
|
356
|
+
if (tag === 'a')
|
|
357
|
+
return a.href !== undefined ? 'link' : undefined;
|
|
358
|
+
if (tag === 'input') {
|
|
359
|
+
const t = (a.type ?? 'text').toLowerCase();
|
|
360
|
+
return t === 'checkbox' || t === 'radio'
|
|
361
|
+
? t
|
|
362
|
+
: t === 'button' || t === 'submit'
|
|
363
|
+
? 'button'
|
|
364
|
+
: 'textbox';
|
|
365
|
+
}
|
|
366
|
+
return IMPLICIT_ROLES[tag];
|
|
367
|
+
}
|
|
368
|
+
/** The filename of a URL: no origin, path, query or hash. The origin changes
|
|
369
|
+
* every run (`jux run` serves on port 0) and between machines, so recording
|
|
370
|
+
* it would make the same page hash differently each time. */
|
|
371
|
+
function fileName(u) {
|
|
372
|
+
// A data: URI's "filename" is a slice of its payload: opaque, and as long as
|
|
373
|
+
// the payload happens to be between slashes.
|
|
374
|
+
if (/^data:/i.test(u.trim()))
|
|
375
|
+
return 'data:';
|
|
376
|
+
return u.split(/[?#]/)[0].split('/').pop() ?? '';
|
|
377
|
+
}
|
|
378
|
+
/** Computed values serialize url() tokens absolute: probe2 recorded
|
|
379
|
+
* `url("http://127.0.0.1:41001/bg.png")` vs `...:41002/bg.png` for one page
|
|
380
|
+
* on two ports, and two different structureHashes. Keep only the filename. */
|
|
381
|
+
function urlsToFileNames(v) {
|
|
382
|
+
if (!v.includes('url('))
|
|
383
|
+
return v;
|
|
384
|
+
return v.replace(/url\((?:"((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)'|([^)]*))\)/g, (_m, dq, sq, bare) => `url(${JSON.stringify(fileName((dq ?? sq ?? bare ?? '').trim()))})`);
|
|
385
|
+
}
|
|
386
|
+
const collapse = (s) => s.replace(/\s+/g, ' ').trim();
|
|
387
|
+
/** Computed `content` is a CSS string like `"★"` (quoted), `none`, `normal`,
|
|
388
|
+
* or something like `counter(x)`. Return the visible literal text when there
|
|
389
|
+
* is one; otherwise the raw value, so a change is still detected. */
|
|
390
|
+
function parseContent(v) {
|
|
391
|
+
if (!v || v === 'none' || v === 'normal')
|
|
392
|
+
return '';
|
|
393
|
+
const m = /^"(.*)"$/.exec(v);
|
|
394
|
+
return m ? m[1] : v;
|
|
395
|
+
}
|
|
396
|
+
/** The full value of `prop` for element `index`, reconstructing what the
|
|
397
|
+
* compact storage omitted. */
|
|
398
|
+
export function effectiveStyle(s, index, prop) {
|
|
399
|
+
const el = s.elements[index];
|
|
400
|
+
if (el.styles[prop] !== undefined)
|
|
401
|
+
return el.styles[prop];
|
|
402
|
+
if (INHERITED_PROPS.has(prop)) {
|
|
403
|
+
return el.parent === null
|
|
404
|
+
? (ROOT_INHERITED[prop] ?? '')
|
|
405
|
+
: effectiveStyle(s, el.parent, prop);
|
|
406
|
+
}
|
|
407
|
+
if (prop.startsWith('border-') && prop.endsWith('-color')) {
|
|
408
|
+
return effectiveStyle(s, index, 'color'); // currentColor
|
|
409
|
+
}
|
|
410
|
+
return INITIAL_VALUES[prop] ?? '';
|
|
411
|
+
}
|
|
412
|
+
/** Canonical JSON: object keys sorted at every level, so hashing is stable. */
|
|
413
|
+
function canonical(v) {
|
|
414
|
+
if (Array.isArray(v))
|
|
415
|
+
return `[${v.map(canonical).join(',')}]`;
|
|
416
|
+
if (v && typeof v === 'object') {
|
|
417
|
+
const o = v;
|
|
418
|
+
return `{${Object.keys(o)
|
|
419
|
+
.sort()
|
|
420
|
+
.filter((k) => o[k] !== undefined)
|
|
421
|
+
.map((k) => `${JSON.stringify(k)}:${canonical(o[k])}`)
|
|
422
|
+
.join(',')}}`;
|
|
423
|
+
}
|
|
424
|
+
return JSON.stringify(v);
|
|
425
|
+
}
|
|
426
|
+
function hashElements(elements) {
|
|
427
|
+
return createHash('sha256').update(canonical(elements)).digest('hex');
|
|
428
|
+
}
|
|
429
|
+
export function encodeStructure(s) {
|
|
430
|
+
return gzipSync(Buffer.from(JSON.stringify(s)));
|
|
431
|
+
}
|
|
432
|
+
export function decodeStructure(b) {
|
|
433
|
+
return JSON.parse(gunzipSync(b).toString('utf8'));
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Snapshot the page's structure. Never throws: a missing structure costs the
|
|
437
|
+
* agent some explanation, a thrown error would cost the story its capture.
|
|
438
|
+
*
|
|
439
|
+
* Mask selectors are resolved with the same CSS-over-open-shadow-roots query
|
|
440
|
+
* the screenshot masks with; Playwright-only syntax is rejected in
|
|
441
|
+
* captureStory before anything runs. Matches get MASK_ATTR so the normalizer
|
|
442
|
+
* collapses their subtree. A plain document.querySelectorAll would miss
|
|
443
|
+
* matches inside shadow roots and leak masked content into the sidecar.
|
|
444
|
+
*
|
|
445
|
+
* Fail closed: if marking fails, or any match lost its mark by the time the
|
|
446
|
+
* snapshot returns (the page mutated in between), return undefined. Setting an
|
|
447
|
+
* attribute does not affect paint unless a stylesheet targets it, which
|
|
448
|
+
* nothing ships with.
|
|
449
|
+
*/
|
|
450
|
+
export async function captureStructure(page, viewport, mask) {
|
|
451
|
+
const mark = (sel) => page.evaluate(queryAllExpression(sel, "for (const el of els) el.setAttribute(a0, '1'); return els.length;", MASK_ATTR));
|
|
452
|
+
const verify = (sel) => page.evaluate(queryAllExpression(sel, 'return { total: els.length, marked: els.filter((e) => e.hasAttribute(a0)).length };', MASK_ATTR));
|
|
453
|
+
const unmark = () => page
|
|
454
|
+
.evaluate(queryAllExpression(`[${MASK_ATTR}]`, 'for (const el of els) el.removeAttribute(a0);', MASK_ATTR))
|
|
455
|
+
.catch(() => { });
|
|
456
|
+
// How many elements each selector marked. Verification re-resolves the
|
|
457
|
+
// selector, so an element that lost both its mark and its match would drop
|
|
458
|
+
// out of the re-resolved list and `every` would pass on the survivors
|
|
459
|
+
// (probe c: SECRET-C recorded). Comparing counts closes that.
|
|
460
|
+
const markedCounts = [];
|
|
461
|
+
try {
|
|
462
|
+
for (const sel of mask) {
|
|
463
|
+
const n = await mark(sel);
|
|
464
|
+
markedCounts.push(typeof n === 'number' ? n : 0);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
catch {
|
|
468
|
+
if (mask.length)
|
|
469
|
+
await unmark();
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
try {
|
|
473
|
+
const raw = (await page.send('DOMSnapshot.captureSnapshot', {
|
|
474
|
+
computedStyles: [...STRUCTURE_PROPS, 'visibility'],
|
|
475
|
+
includeDOMRects: true,
|
|
476
|
+
includePaintOrder: true,
|
|
477
|
+
}));
|
|
478
|
+
for (const [k, sel] of mask.entries()) {
|
|
479
|
+
const v = (await verify(sel));
|
|
480
|
+
// Every current match still marked, and none of the marked ones gone.
|
|
481
|
+
const intact = typeof v === 'object' &&
|
|
482
|
+
v !== null &&
|
|
483
|
+
v.marked === v.total &&
|
|
484
|
+
v.marked >= markedCounts[k];
|
|
485
|
+
if (!intact)
|
|
486
|
+
return undefined;
|
|
487
|
+
}
|
|
488
|
+
return normalizeStructure(raw, viewport);
|
|
489
|
+
}
|
|
490
|
+
catch {
|
|
491
|
+
return undefined;
|
|
492
|
+
}
|
|
493
|
+
finally {
|
|
494
|
+
if (mask.length)
|
|
495
|
+
await unmark();
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
//# sourceMappingURL=structure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structure.js","sourceRoot":"","sources":["../../src/capture/structure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ChangedRegion, StructureSnapshot, StructuralVerdict } from '../types.js';
|
|
2
|
+
import { type DiffOutput } from './diff.js';
|
|
3
|
+
export interface SnapSide {
|
|
4
|
+
image: Buffer;
|
|
5
|
+
structure?: StructureSnapshot;
|
|
6
|
+
}
|
|
7
|
+
export interface SnapComparison {
|
|
8
|
+
pixels: DiffOutput;
|
|
9
|
+
verdict: StructuralVerdict;
|
|
10
|
+
/** Every region no delta explains, in diff order, not the budget-fitted
|
|
11
|
+
* prefix on the verdict. `--crops` orders and labels from this. */
|
|
12
|
+
unexplainedRegions: ChangedRegion[];
|
|
13
|
+
/** The changed elements' boxes, in delta order: `--crops` falls back to
|
|
14
|
+
* these when the pixel diff marked nothing. */
|
|
15
|
+
elementRegions: ChangedRegion[];
|
|
16
|
+
}
|
|
17
|
+
export declare function compareSnaps(a: SnapSide, b: SnapSide, escalate: {
|
|
18
|
+
command: string;
|
|
19
|
+
}): Promise<SnapComparison>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Two snaps on disk → pixels + verdict. The public seam for `jux diff`: it
|
|
2
|
+
// keeps diffImages and the structural internals unexported while giving the
|
|
3
|
+
// CLI the one call it needs. No browser is involved anywhere below this line.
|
|
4
|
+
import { diffImages } from './diff.js';
|
|
5
|
+
import { structuralDiffWithCoverage } from './structural.js';
|
|
6
|
+
export async function compareSnaps(a, b, escalate) {
|
|
7
|
+
const pixels = await diffImages(a.image, b.image);
|
|
8
|
+
const { verdict, unexplainedRegions, elementRegions } = structuralDiffWithCoverage({
|
|
9
|
+
baseline: a.structure,
|
|
10
|
+
current: b.structure,
|
|
11
|
+
// Byte equality, not mismatchPixels === 0: a sub-threshold colour change
|
|
12
|
+
// has no mismatching pixels but is still a different image.
|
|
13
|
+
imagesIdentical: a.image.equals(b.image),
|
|
14
|
+
pixels,
|
|
15
|
+
escalate,
|
|
16
|
+
});
|
|
17
|
+
return { pixels, verdict, unexplainedRegions, elementRegions };
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=compare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/diff/compare.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,4EAA4E;AAC5E,8EAA8E;AAG9E,OAAO,EAAE,UAAU,EAAmB,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAkB7D,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,CAAW,EACX,CAAW,EACX,QAA6B;IAE7B,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,GAAG,0BAA0B,CAAC;QACjF,QAAQ,EAAE,CAAC,CAAC,SAAS;QACrB,OAAO,EAAE,CAAC,CAAC,SAAS;QACpB,yEAAyE;QACzE,4DAA4D;QAC5D,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QACxC,MAAM;QACN,QAAQ;KACT,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,CAAC;AACjE,CAAC"}
|