@hueest/xray 0.5.0 → 0.7.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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/client.d.ts +42 -51
- package/dist/client.js +136 -142
- package/dist/core.d.ts +42 -34
- package/dist/core.js +39 -33
- package/dist/css-escape-DJ-BsrNm.js +47 -0
- package/dist/hud.d.ts +7 -8
- package/dist/hud.js +5 -5
- package/dist/index.d.ts +268 -250
- package/dist/index.js +369 -240
- package/dist/measure-CUQxB-Ic.d.ts +524 -0
- package/dist/{plate-BRR6d8Se.js → plate-CXIh5_OB.js} +61 -45
- package/dist/react.core-BS2yvqeh.js +301 -0
- package/dist/react.core-BkJoCgWJ.d.ts +115 -0
- package/dist/react.d.ts +11 -13
- package/dist/react.dev.d.ts +4 -6
- package/dist/react.dev.js +58 -64
- package/dist/react.js +27 -25
- package/dist/{project-BZosujs9.js → serialize-Cj-EHvMv.js} +877 -1027
- package/package.json +8 -6
- package/virtual.d.ts +25 -32
- package/dist/css-escape-N7bOusGW.js +0 -52
- package/dist/react.core-BC02ukac.js +0 -294
- package/dist/react.core-NhWc9qan.d.ts +0 -89
- package/dist/serialize-BgdGt34A.d.ts +0 -501
|
@@ -1,501 +0,0 @@
|
|
|
1
|
-
//#region src/diagnostics.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Dev-only capture diagnostics: a small, serializable record of why a Plate may
|
|
4
|
-
* be incomplete or lower-fidelity, plus the one shared formatter both the
|
|
5
|
-
* browser console (`client.ts`) and the Vite server output (`index.ts`) print.
|
|
6
|
-
*
|
|
7
|
-
* Motivation: the serializer silently swallows a handful of capture omissions
|
|
8
|
-
* (an unreadable cross-origin stylesheet, skipped pseudo-elements, off-screen
|
|
9
|
-
* bones dropped at the fold, an over-the-limit subtree). Early adopters asking "why does this
|
|
10
|
-
* skeleton look wrong?" had to read the serializer source to find out. These
|
|
11
|
-
* diagnostics surface those omissions as data the capture process returns, so a
|
|
12
|
-
* caller can log them — without the core performing any console side effects.
|
|
13
|
-
*
|
|
14
|
-
* Strictly DEV-ONLY (see the plan's decisions and ADR 0008): this type is NOT a
|
|
15
|
-
* public package export and MUST NEVER reach the persisted Plate JSON, the
|
|
16
|
-
* `MergedPlate`, or the production adapter. It rides on the TRANSIENT
|
|
17
|
-
* `ViewIR.diagnostics` field only, which `captureView` populates and the
|
|
18
|
-
* dev client strips before posting (so committed `plates/<name>.json` stays
|
|
19
|
-
* byte-identical to a capture that produced no diagnostics).
|
|
20
|
-
*
|
|
21
|
-
* Centralized on purpose: a follow-up plan (capture-input-validation) reuses
|
|
22
|
-
* this same messaging for invalid posted/committed plates, so the code table
|
|
23
|
-
* and formatter are kept reusable. Browser and server share `formatDiagnostic`
|
|
24
|
-
* so their warning text cannot drift.
|
|
25
|
-
*
|
|
26
|
-
* @module
|
|
27
|
-
*/
|
|
28
|
-
/**
|
|
29
|
-
* One aggregated capture omission. Serializable on purpose: NO DOM nodes, NO
|
|
30
|
-
* CSS bodies, NO captured text — only a stable `code`, a human message, an
|
|
31
|
-
* optional aggregate `count`, and an optional short `detail` (e.g. a plate name
|
|
32
|
-
* or a node count, never user content). `count` aggregates occurrences: there
|
|
33
|
-
* is at most one record per code per capture, never one per skipped selector or
|
|
34
|
-
* node.
|
|
35
|
-
*/
|
|
36
|
-
interface CaptureDiagnostic {
|
|
37
|
-
code: DiagnosticCode;
|
|
38
|
-
message: string;
|
|
39
|
-
count?: number;
|
|
40
|
-
detail?: string;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* The closed set of capture-omission codes. Each maps to one silent site in the
|
|
44
|
-
* serializer (or an existing oversized-capture warning folded into the same
|
|
45
|
-
* vocabulary). Kept as a const union so the message table is exhaustive.
|
|
46
|
-
*/
|
|
47
|
-
type DiagnosticCode = 'unreadable-stylesheet' | 'unreadable-import' | 'skipped-dynamic-pseudo' | 'skipped-pseudo-element' | 'unsupported-rule' | 'dropped-tag' | 'dropped-subset' | 'dropped-cropped' | 'too-large' | 'invalid-plate-file';
|
|
48
|
-
//#endregion
|
|
49
|
-
//#region src/plate.d.ts
|
|
50
|
-
type LeafKind = 'text' | 'text-block' | 'media' | 'box';
|
|
51
|
-
/**
|
|
52
|
-
* The shipped structural capture of a component's rendered DOM — the data a
|
|
53
|
-
* Skeleton renders from (see CONTEXT.md). Self-contained: pre-serialized chunks
|
|
54
|
-
* plus one scoped CSS string; depends on nothing in the consumer's build (ADR
|
|
55
|
-
* 0003). Built from the RenderNode tree at plugin load (see chunk.ts), so the
|
|
56
|
-
* adapter injects strings instead of walking a tree on the latency-critical
|
|
57
|
-
* first paint — and no per-framework serializer ships to the client (ADR 0008).
|
|
58
|
-
*/
|
|
59
|
-
interface Plate {
|
|
60
|
-
v: number;
|
|
61
|
-
/** Capture name; comes from the virtual-module specifier, never typed at a call site. */
|
|
62
|
-
name: string;
|
|
63
|
-
/**
|
|
64
|
-
* The root's children, pre-serialized (ADR 0008): a stitch-free run is one
|
|
65
|
-
* HTML `string`; a stitch is `{ r: name }`; a stitch-bearing element is
|
|
66
|
-
* `{ c: className, k: chunk[] }`. Null until first capture.
|
|
67
|
-
*/
|
|
68
|
-
chunks: Chunk[] | null;
|
|
69
|
-
/** The root node's own content classes (its inherited font context), if any. */
|
|
70
|
-
rootCls?: string;
|
|
71
|
-
/** Layout-relevant CSS (incl. `@media`) scoped under the plate root, paint stripped. */
|
|
72
|
-
css: string;
|
|
73
|
-
/**
|
|
74
|
-
* Child plates named by the chunks' `{ r }` stitches, resolved through the
|
|
75
|
-
* import graph (ADR 0006). Populated by the loader's generated imports, never
|
|
76
|
-
* serialized into the plates JSON; absent in production when there are no
|
|
77
|
-
* stitches. In dev the live store takes precedence, so this need not be present.
|
|
78
|
-
*/
|
|
79
|
-
refs?: Record<string, Plate>;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* One serialized child of a plate root (or of a stitch-bearing node): a
|
|
83
|
-
* stitch-free HTML run (`string`), a stitch to a child plate (`{ r: name }`),
|
|
84
|
-
* a stitch-bearing element kept real so its inner stitches can mount
|
|
85
|
-
* (`{ c: className, k: chunk[] }`), or a templated uniform run (`{ t: html, n }`):
|
|
86
|
-
* the cell's HTML once plus a repeat count the adapter expands to N copies (Phase
|
|
87
|
-
* 2). The framework-neutral render contract: an adapter injects the strings,
|
|
88
|
-
* mounts a child plate at each stitch, and repeats each template (ADR 0008).
|
|
89
|
-
*/
|
|
90
|
-
type Chunk = string | {
|
|
91
|
-
r: string;
|
|
92
|
-
} | {
|
|
93
|
-
c: string;
|
|
94
|
-
k: Chunk[];
|
|
95
|
-
} | {
|
|
96
|
-
t: string;
|
|
97
|
-
n: number;
|
|
98
|
-
};
|
|
99
|
-
/**
|
|
100
|
-
* A plate after the in-browser Serialize (emit + merge/gate + classify) but
|
|
101
|
-
* before chunk serialization: the build-time RenderNode tree plus its scoped
|
|
102
|
-
* CSS. Produced by `serializePlateIR` (the structural part of `StoredPlate`) and
|
|
103
|
-
* the single-View `capture`, then serialized into the shipped `Plate` (chunks) at
|
|
104
|
-
* load (`serializePlate`). Never shipped to the client.
|
|
105
|
-
*/
|
|
106
|
-
interface MergedPlate {
|
|
107
|
-
v: number;
|
|
108
|
-
name: string;
|
|
109
|
-
tree: RenderNode | null;
|
|
110
|
-
css: string;
|
|
111
|
-
}
|
|
112
|
-
interface PlateNode {
|
|
113
|
-
/** Plate-local id; rules reference it pre-classify. Stripped from the shipped tree. */
|
|
114
|
-
id: number;
|
|
115
|
-
/** Present on paint leaves; absent on layout containers. */
|
|
116
|
-
leaf?: LeafKind;
|
|
117
|
-
/**
|
|
118
|
-
* A stitch: render the named child plate's skeleton here instead of own
|
|
119
|
-
* structure (ADR 0006). Mutually exclusive with `leaf`/`kids`. Resolved
|
|
120
|
-
* against `Plate.refs` (prod) or the live store (dev).
|
|
121
|
-
*/
|
|
122
|
-
ref?: string;
|
|
123
|
-
/**
|
|
124
|
-
* A templated uniform run (Phase 2): render this node's subtree `count` times.
|
|
125
|
-
* The serializer emits the subtree's HTML once plus the count; the adapter
|
|
126
|
-
* expands it to N copies at render. Absent on ordinary nodes.
|
|
127
|
-
*/
|
|
128
|
-
count?: number;
|
|
129
|
-
kids?: PlateNode[];
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* A node in the shipped tree, after classify (ADR 0007). Carries the
|
|
133
|
-
* content-addressed style classes it needs instead of an id — the CSS targets
|
|
134
|
-
* those classes, not a per-node `data-xr` value, so node scoping (the old
|
|
135
|
-
* `nodeKey`) is gone. `cls` is a space-joined class-token list.
|
|
136
|
-
*/
|
|
137
|
-
interface RenderNode {
|
|
138
|
-
leaf?: LeafKind;
|
|
139
|
-
ref?: string;
|
|
140
|
-
cls?: string;
|
|
141
|
-
/** A templated uniform run (Phase 2): serialize this subtree once + a count the adapter repeats. */
|
|
142
|
-
count?: number;
|
|
143
|
-
kids?: RenderNode[];
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* A captured style rule in id form — selectors are generated at render time,
|
|
147
|
-
* so view merging can remap node ids without string surgery. `ids: []`
|
|
148
|
-
* targets the plate root.
|
|
149
|
-
*/
|
|
150
|
-
interface PlateRule {
|
|
151
|
-
ids: number[];
|
|
152
|
-
decls: string[];
|
|
153
|
-
/** Media-condition stack, outermost first; conditions AND together. */
|
|
154
|
-
media?: string[];
|
|
155
|
-
/** `@container`-condition stack, outermost first; conditions AND together. Absent when none. */
|
|
156
|
-
container?: string[];
|
|
157
|
-
layered?: boolean;
|
|
158
|
-
spec: number;
|
|
159
|
-
order: number;
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* One capture of a component within one viewport view — `[min, max)` in px,
|
|
163
|
-
* either side open-ended when undefined. The id-form `{ tree, rules }` shape
|
|
164
|
-
* `emit` projects a measured View into (ADR 0004). NO LONGER the disk/wire shape
|
|
165
|
-
* after the ADR 0022 cutover — `StoredPlate` (below) is. Kept as the
|
|
166
|
-
* framework-neutral per-View capture shape, exported for consumers reading the
|
|
167
|
-
* id-form projection directly.
|
|
168
|
-
*/
|
|
169
|
-
interface ViewCapture {
|
|
170
|
-
/** Viewport width at capture time. */
|
|
171
|
-
width: number;
|
|
172
|
-
min?: number;
|
|
173
|
-
max?: number;
|
|
174
|
-
tree: PlateNode;
|
|
175
|
-
rules: PlateRule[];
|
|
176
|
-
/**
|
|
177
|
-
* TRANSIENT, dev-only capture diagnostics (why this view may be lower
|
|
178
|
-
* fidelity). Captured in the browser (mirrored onto `ViewIR.diagnostics`); the
|
|
179
|
-
* dev client logs it and posts it alongside the `StoredPlate` (so the Vite
|
|
180
|
-
* server can print the same text). It MUST NEVER be persisted: it is not part
|
|
181
|
-
* of the committed
|
|
182
|
-
* `StoredPlate` disk shape, the validator does not carry it, and the POST
|
|
183
|
-
* envelope keeps it in a SIBLING field that never reaches the stored artifact
|
|
184
|
-
* (ADR 0008). Absent in production (the prod adapter ships no capture). See
|
|
185
|
-
* diagnostics.ts and ADR 0008.
|
|
186
|
-
*/
|
|
187
|
-
diagnostics?: CaptureDiagnostic[];
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* The committed `plates/<name>.json` shape AFTER the ADR 0022 cutover: the whole
|
|
191
|
-
* Plate already projected in the browser (the in-browser Serialize folds emit +
|
|
192
|
-
* the multi-View merge/gate + classify in one session), so disk holds ONE gated,
|
|
193
|
-
* content-addressed tree + css instead of per-View captures merged at load. It is
|
|
194
|
-
* a `MergedPlate` (the structural `{tree, css}` `serializePlate` consumes) PLUS the
|
|
195
|
-
* `breakpoints` the HUD coverage reads — the analysis-only geometry never crosses
|
|
196
|
-
* the wire (ADR 0021). The gen-side runs `serializePlate(stored) → Plate` (chunks)
|
|
197
|
-
* at module-load, leaving the Tailwind/Bundle passthrough a clean gen-side seam.
|
|
198
|
-
* Replaces `PlateFile` (+ `ViewCapture`) on disk and on the `/__xray` wire.
|
|
199
|
-
*/
|
|
200
|
-
interface StoredPlate extends MergedPlate {
|
|
201
|
-
/** Width thresholds (view boundaries); the HUD coverage derives its bands from these. */
|
|
202
|
-
breakpoints: number[];
|
|
203
|
-
}
|
|
204
|
-
/** The (unserialized) plate an import resolves to before anything has been captured. */
|
|
205
|
-
declare function emptyPlate(name: string): MergedPlate;
|
|
206
|
-
/**
|
|
207
|
-
* A dev-only sticky boolean toggle (get/set/subscribe), persisted per tab.
|
|
208
|
-
* Used for both "light box" (render every `<Skeleton>` regardless of readiness)
|
|
209
|
-
* and "capture" (whether browsing re-captures plates).
|
|
210
|
-
*/
|
|
211
|
-
interface ToggleStore {
|
|
212
|
-
get: () => boolean;
|
|
213
|
-
set: (value: boolean) => void;
|
|
214
|
-
subscribe: (onChange: () => void) => () => void;
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Dev-only store of the freshest plate per name, updated in place when a
|
|
218
|
-
* capture lands. `<Skeleton>` reads through it so a new plate re-renders the
|
|
219
|
-
* site rather than reloading the module — which would remount the capture
|
|
220
|
-
* boundary and re-fire the capture, a feedback loop.
|
|
221
|
-
*/
|
|
222
|
-
interface PlateStore {
|
|
223
|
-
get: (name: string) => Plate | undefined;
|
|
224
|
-
subscribe: (name: string, onChange: () => void) => () => void;
|
|
225
|
-
/**
|
|
226
|
-
* Register a plate imported via the ref graph if the store has none yet — so a
|
|
227
|
-
* stitch resolves even before its child is re-captured, and survives a parent
|
|
228
|
-
* hot-swap (whose pushed plate carries no resolved `refs`). Never overwrites a
|
|
229
|
-
* live capture.
|
|
230
|
-
*/
|
|
231
|
-
seed: (name: string, plate: Plate) => void;
|
|
232
|
-
}
|
|
233
|
-
/** A view interval `[min, max)`; an open end is undefined (ADR 0004). */
|
|
234
|
-
interface Span {
|
|
235
|
-
min?: number;
|
|
236
|
-
max?: number;
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Dev-only Fixture store (ADR 0015): stored render-INPUT `data` per Plate,
|
|
240
|
-
* recorded to and replayed from a `plates/<name>.fixture.json` sidecar. Entirely
|
|
241
|
-
* dev-only — devalue and this store never reach the production bundle.
|
|
242
|
-
*
|
|
243
|
-
* Two cooperating halves, both flowing through the render-prop `data` seam (ADR
|
|
244
|
-
* 0014):
|
|
245
|
-
* - The dev adapter (`react.dev.tsx`) calls `register(name, data)` at
|
|
246
|
-
* `loading=false` with the live `data` it is about to render, so the latest
|
|
247
|
-
* recordable input for each mounted Plate is always in scope for Record.
|
|
248
|
-
* - `record(name)` serializes that registered live `data` with devalue and POSTs
|
|
249
|
-
* it to the sidecar (the HUD button and the `first-ready`/`always` modes call
|
|
250
|
-
* it). `has(name)` reports whether a Fixture exists (HUD coverage marker), and
|
|
251
|
-
* `read(name)` returns the parsed Fixture `data` for Replay to substitute in
|
|
252
|
-
* front of the render prop.
|
|
253
|
-
*
|
|
254
|
-
* The store holds DECODED values (the dev client owns the devalue parse, since it
|
|
255
|
-
* has the live runtime); only the on-disk sidecar and the wire carry the opaque
|
|
256
|
-
* devalue string.
|
|
257
|
-
*/
|
|
258
|
-
interface FixtureStore {
|
|
259
|
-
/**
|
|
260
|
-
* Record the latest live `data` the dev adapter is about to render for `name`,
|
|
261
|
-
* so Record always has the current recordable input in scope. A `register` with
|
|
262
|
-
* the same value is cheap; the adapter calls it on every ready render. Returns a
|
|
263
|
-
* disposer the adapter runs on unmount so an unmounted Skeleton's `data` never
|
|
264
|
-
* lingers in the store: an unmounted instance must never be recorded or shadow a
|
|
265
|
-
* still-mounted one (ADR 0015). With several Skeletons of the same plate name
|
|
266
|
-
* mounted, the live value is the most-recently-registered still-mounted instance.
|
|
267
|
-
*/
|
|
268
|
-
register: (name: string, data: unknown) => () => void;
|
|
269
|
-
/** True once a recorded Fixture exists for `name` (drives the HUD coverage marker). */
|
|
270
|
-
has: (name: string) => boolean;
|
|
271
|
-
/** The parsed Fixture `data` for `name`, or `undefined` when none is recorded. */
|
|
272
|
-
read: (name: string) => {
|
|
273
|
-
data: unknown;
|
|
274
|
-
} | undefined;
|
|
275
|
-
/**
|
|
276
|
-
* Serialize the registered live `data` for `name` with devalue and POST it to
|
|
277
|
-
* the sidecar. Returns a promise that resolves once the write is
|
|
278
|
-
* server-confirmed (so the HUD can surface a failed Record). Throws loudly when
|
|
279
|
-
* the live `data` is unrecordable (devalue's contract) or no live `data` was
|
|
280
|
-
* registered (a plain-children `<Skeleton>` has none).
|
|
281
|
-
*/
|
|
282
|
-
record: (name: string) => Promise<void>;
|
|
283
|
-
/**
|
|
284
|
-
* Record every Skeleton that currently has live `data` registered (the HUD's
|
|
285
|
-
* single "Record fixture" button — one click captures the inputs of all mounted
|
|
286
|
-
* render-prop Skeletons). Resolves once all writes are server-confirmed; a
|
|
287
|
-
* rejected write surfaces to the HUD.
|
|
288
|
-
*/
|
|
289
|
-
recordAll: () => Promise<void>;
|
|
290
|
-
/**
|
|
291
|
-
* Seed the store from the on-disk sidecars on boot: a `{ <name>: devalueString }`
|
|
292
|
-
* map (the opaque strings the server serves). The client decodes each with
|
|
293
|
-
* devalue. Existing entries are not clobbered, so a Fixture recorded this
|
|
294
|
-
* session survives a re-seed.
|
|
295
|
-
*/
|
|
296
|
-
seed: (encoded: Record<string, string>) => void;
|
|
297
|
-
/** React subscription so the HUD re-renders when a Fixture is recorded or seeded. */
|
|
298
|
-
subscribe: (onChange: () => void) => () => void;
|
|
299
|
-
}
|
|
300
|
-
/** A plate's detected width thresholds and the spans actually captured, from disk. */
|
|
301
|
-
interface PlateCoverage {
|
|
302
|
-
breakpoints: number[];
|
|
303
|
-
spans: Span[];
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* Dev-only per-plate coverage, sourced from the committed plate files (not the
|
|
307
|
-
* session): the breakpoints detected so far and which view spans are captured.
|
|
308
|
-
* The HUD renders every band — covered ones lit, the rest dim — and the
|
|
309
|
-
* capture-all sweep derives its target widths from the breakpoints.
|
|
310
|
-
*/
|
|
311
|
-
interface CoverageStore {
|
|
312
|
-
get: () => ReadonlyMap<string, PlateCoverage>;
|
|
313
|
-
set: (name: string, coverage: PlateCoverage) => void;
|
|
314
|
-
subscribe: (onChange: () => void) => () => void;
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* Dev-only capture hook, installed by the dev client before the app boots.
|
|
318
|
-
* Absent in production builds, so `<Skeleton>` carries zero capture weight.
|
|
319
|
-
* `captured` returns a dispose callback (stop observing this site).
|
|
320
|
-
*/
|
|
321
|
-
interface CaptureHook {
|
|
322
|
-
captured: (name: string, el: Element, opts?: {
|
|
323
|
-
delay?: number;
|
|
324
|
-
walker?: unknown;
|
|
325
|
-
mode?: 'auto' | 'manual';
|
|
326
|
-
collect?: {
|
|
327
|
-
maxNodes?: number;
|
|
328
|
-
maxBreadth?: number;
|
|
329
|
-
maxDepth?: number;
|
|
330
|
-
};
|
|
331
|
-
}) => (() => void) | undefined;
|
|
332
|
-
/** Light Box toggle: force every `<Skeleton>` to its skeleton, read by `<Skeleton>`. */
|
|
333
|
-
lightbox?: ToggleStore;
|
|
334
|
-
/** Capture toggle: whether browsing re-captures plates, flipped from the HUD. */
|
|
335
|
-
capture?: ToggleStore;
|
|
336
|
-
/** Read side for `<Skeleton>`. */
|
|
337
|
-
plates?: PlateStore;
|
|
338
|
-
/** Write side for the dev client's HMR-event handler. Returns whether the plate changed. */
|
|
339
|
-
updatePlate?: (name: string, plate: Plate) => boolean;
|
|
340
|
-
/** Dev-only: run the HUD-triggered capture-all-views sweep via the extension (ADR 0010). */
|
|
341
|
-
captureAllViews?: () => Promise<void>;
|
|
342
|
-
/** Dev-only per-plate breakpoints + captured spans, from disk; fed by the bootstrap. */
|
|
343
|
-
coverage?: CoverageStore;
|
|
344
|
-
/**
|
|
345
|
-
* Replay toggle (ADR 0015): when active, the dev adapter substitutes a recorded
|
|
346
|
-
* Fixture's `data` for the live `data` at `loading=false`. The boolean is the
|
|
347
|
-
* coarse on/off the HUD owns per tab; the per-mode policy (`prefer` vs
|
|
348
|
-
* `missing-only`) is carried alongside in `replayMode`.
|
|
349
|
-
*/
|
|
350
|
-
replay?: ToggleStore;
|
|
351
|
-
/** Dev-only Replay policy: how a Fixture substitutes for live `data` (ADR 0015). */
|
|
352
|
-
replayMode?: 'prefer' | 'missing-only';
|
|
353
|
-
/**
|
|
354
|
-
* Dev-only Record policy (ADR 0015): when the dev adapter records the live
|
|
355
|
-
* `data` it is about to render. `'manual'` (the default) records nothing
|
|
356
|
-
* automatically — only the HUD button does; `'first-ready'` records once when a
|
|
357
|
-
* Skeleton goes ready and has no Fixture yet; `'always'` records on every ready
|
|
358
|
-
* render.
|
|
359
|
-
*/
|
|
360
|
-
recordMode?: 'manual' | 'first-ready' | 'always';
|
|
361
|
-
/** Dev-only Fixture record/replay store (ADR 0015); never present in production. */
|
|
362
|
-
fixtures?: FixtureStore;
|
|
363
|
-
}
|
|
364
|
-
declare global {
|
|
365
|
-
var __XRAY__: CaptureHook | undefined;
|
|
366
|
-
}
|
|
367
|
-
//#endregion
|
|
368
|
-
//#region src/serialize.d.ts
|
|
369
|
-
/**
|
|
370
|
-
* Browser-side capture: walk a live rendered subtree into a Plate — one node
|
|
371
|
-
* tree plus one self-contained, scoped CSS string (ADR 0003). The CSS is
|
|
372
|
-
* lifted from the author rules that matched each node, rewritten to
|
|
373
|
-
* plate-local selectors — it carries `@media` for free and keeps layout live
|
|
374
|
-
* (the M1 bake-off winner; ADR 0005).
|
|
375
|
-
*/
|
|
376
|
-
interface CaptureOptions {
|
|
377
|
-
/** Plate name; comes from the virtual-module specifier. */
|
|
378
|
-
name: string;
|
|
379
|
-
/** Collect limits (ADR 0022): refuse a capture whose measured tree exceeds any axis. */
|
|
380
|
-
collect?: CollectLimits;
|
|
381
|
-
/**
|
|
382
|
-
* Optional programmable capture walker (ADR 0018). The declarative `data-xr-*`
|
|
383
|
-
* annotations cover the 90%; this is the escape hatch for the 10% a markup
|
|
384
|
-
* attribute cannot express. Capture-only: it shapes the resulting `PlateNode`
|
|
385
|
-
* tree but is never persisted into the Plate, and the production adapter never
|
|
386
|
-
* captures so it ignores this entirely.
|
|
387
|
-
*/
|
|
388
|
-
walker?: XrayCaptureWalker;
|
|
389
|
-
/**
|
|
390
|
-
* Whether the top-level capture roots ARE this plate's own boundary, so the
|
|
391
|
-
* stitch guard must be SKIPPED for them (ADR 0006/0014, finding #6). True ONLY
|
|
392
|
-
* for a MANUAL root: there `site.el` is the consumer's own element and its
|
|
393
|
-
* `data-xr-boundary` marks the boundary of THIS plate, so the root must be
|
|
394
|
-
* serialized as a real Entry (its box/classes/padding/border) rather than a
|
|
395
|
-
* stitch-to-itself. Defaults to `false` — the auto path, where the top-level
|
|
396
|
-
* roots are the wrapper's CHILDREN and any boundary marker on a direct-child
|
|
397
|
-
* root is a NESTED `<Skeleton>` that MUST stitch (the capture-leak guard).
|
|
398
|
-
*/
|
|
399
|
-
captureRootIsBoundary?: boolean;
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* What a capture walker decides for one element (ADR 0018; ADR 0022 §5). The
|
|
403
|
-
* `applyWalker` PASS reads the decision and applies it to the measured IR node —
|
|
404
|
-
* a walker NEVER hand-builds a `PlateNode`, so xray keeps ownership of the Plate
|
|
405
|
-
* format. `ignore` drops the element + its subtree; `bone` collapses it to one
|
|
406
|
-
* Bone leaf (inferring the kind when omitted); `keep` defers to the default
|
|
407
|
-
* classifier (`markInk`).
|
|
408
|
-
*/
|
|
409
|
-
type WalkerDecision = {
|
|
410
|
-
type: 'ignore';
|
|
411
|
-
} | {
|
|
412
|
-
type: 'bone';
|
|
413
|
-
kind?: LeafKind;
|
|
414
|
-
} | {
|
|
415
|
-
type: 'keep';
|
|
416
|
-
};
|
|
417
|
-
/**
|
|
418
|
-
* The context handed to a capture walker's `element` hook (ADR 0018). The
|
|
419
|
-
* helpers are PURE — each returns a `WalkerDecision` the `applyWalker` pass
|
|
420
|
-
* applies; they do NOT mutate. `el` is the element under consideration.
|
|
421
|
-
*/
|
|
422
|
-
interface CaptureWalkerContext {
|
|
423
|
-
/** The element currently being classified. */
|
|
424
|
-
el: Element;
|
|
425
|
-
/** Drop this element AND its whole subtree (no bone). */
|
|
426
|
-
ignore(): WalkerDecision;
|
|
427
|
-
/**
|
|
428
|
-
* Collapse this element's subtree into ONE Bone leaf. `kind` omitted shares
|
|
429
|
-
* the default classifier's kind-inference heuristic (`inferLeafKind`; ADR 0018,
|
|
430
|
-
* Q4 — ONE code path).
|
|
431
|
-
*/
|
|
432
|
-
bone(opts?: {
|
|
433
|
-
kind?: LeafKind;
|
|
434
|
-
}): WalkerDecision;
|
|
435
|
-
/** Defer to the default classifier (`markInk`) — recurse into the subtree. */
|
|
436
|
-
keep(): WalkerDecision;
|
|
437
|
-
}
|
|
438
|
-
/**
|
|
439
|
-
* The programmable capture walker (ADR 0018; ADR 0022 §5). `element` is offered
|
|
440
|
-
* each non-boundary element TOP-DOWN over the measured IR (the `applyWalker`
|
|
441
|
-
* pass, NOT the DOM walk) and returns a `WalkerDecision` the pass applies. The
|
|
442
|
-
* declarative `data-xr-*` annotations cover the 90%; this is the 10% escape
|
|
443
|
-
* hatch for what a markup attribute cannot express.
|
|
444
|
-
*/
|
|
445
|
-
interface XrayCaptureWalker {
|
|
446
|
-
/**
|
|
447
|
-
* Called for every non-boundary element node (a stitch carries no element and
|
|
448
|
-
* is skipped — ADR 0006 — so a boundary never reaches here). Return one of
|
|
449
|
-
* `ctx.ignore()`, `ctx.bone()`, or `ctx.keep()`. An `ignore`/`bone` decision
|
|
450
|
-
* stops the descent (the subtree lowers); `keep` recurses.
|
|
451
|
-
*/
|
|
452
|
-
element?(ctx: CaptureWalkerContext): WalkerDecision;
|
|
453
|
-
}
|
|
454
|
-
/**
|
|
455
|
-
* Typed identity wrapper for authoring a capture walker (ADR 0018) — the
|
|
456
|
-
* `defineConfig` pattern. It returns its argument unchanged at runtime; its only
|
|
457
|
-
* job is to infer and check the `XrayCaptureWalker` shape at the call site so an
|
|
458
|
-
* author gets completion and a typo in a hook name is caught.
|
|
459
|
-
*/
|
|
460
|
-
declare function defineXrayCaptureWalker(walker: XrayCaptureWalker): XrayCaptureWalker;
|
|
461
|
-
/**
|
|
462
|
-
* Thrown when a subtree has more nodes than the capture limit — almost always
|
|
463
|
-
* a `<Skeleton>` sitting too high in the tree. Raised after the cheap walk and
|
|
464
|
-
* before the O(rules × nodes) CSS extraction, so an oversized capture is
|
|
465
|
-
* refused without freezing the main thread on it.
|
|
466
|
-
*/
|
|
467
|
-
/** The measured size of a capture's surviving tree, one number per Collect axis (ADR 0022). */
|
|
468
|
-
type CaptureSize = {
|
|
469
|
-
nodes: number;
|
|
470
|
-
breadth: number;
|
|
471
|
-
depth: number;
|
|
472
|
-
};
|
|
473
|
-
/** Which Collect axis a too-large capture tripped. */
|
|
474
|
-
type CollectAxis = 'nodes' | 'breadth' | 'depth';
|
|
475
|
-
declare class CaptureTooLargeError extends Error {
|
|
476
|
-
/** The full measured size of the surviving tree that tripped the gate. */
|
|
477
|
-
readonly size: CaptureSize;
|
|
478
|
-
/** Which axis exceeded its cap, and the cap it exceeded. */
|
|
479
|
-
readonly axis: CollectAxis;
|
|
480
|
-
readonly max: number;
|
|
481
|
-
/** Back-compat alias for `size.nodes` (the sole axis before breadth/depth). */
|
|
482
|
-
readonly nodeCount: number;
|
|
483
|
-
/** Folds the oversized-capture warning into the shared diagnostics vocabulary (diagnostics.ts). */
|
|
484
|
-
readonly code: "too-large";
|
|
485
|
-
constructor(size: CaptureSize, axis: CollectAxis, max: number);
|
|
486
|
-
}
|
|
487
|
-
/**
|
|
488
|
-
* Collect-stage size limits (ADR 0022): refuse to capture a boundary whose
|
|
489
|
-
* measured tree exceeds any axis. `maxNodes` caps the total surviving-node count;
|
|
490
|
-
* `maxBreadth` the widest level (most nodes at any one depth); `maxDepth` the
|
|
491
|
-
* nesting depth. Each axis is enforced only when its cap is defined. The defaults
|
|
492
|
-
* and the `maxNodes = round(maxBreadth × maxDepth / 4)` derivation live in the
|
|
493
|
-
* client (where the other defaults live); this core only enforces what it is handed.
|
|
494
|
-
*/
|
|
495
|
-
type CollectLimits = {
|
|
496
|
-
maxNodes?: number;
|
|
497
|
-
maxBreadth?: number;
|
|
498
|
-
maxDepth?: number;
|
|
499
|
-
};
|
|
500
|
-
//#endregion
|
|
501
|
-
export { emptyPlate as _, CollectAxis as a, XrayCaptureWalker as c, MergedPlate as d, Plate as f, ViewCapture as g, StoredPlate as h, CaptureWalkerContext as i, defineXrayCaptureWalker as l, RenderNode as m, CaptureSize as n, CollectLimits as o, PlateNode as p, CaptureTooLargeError as r, WalkerDecision as s, CaptureOptions as t, LeafKind as u, CaptureDiagnostic as v };
|