@invarn/cibuild 2.1.9 → 2.2.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.
|
@@ -39,6 +39,12 @@ export interface LayoutNode {
|
|
|
39
39
|
/** Legacy clip hint (parent clips its children). The current emitter writes a
|
|
40
40
|
* constant false; used only for the legacy (no-`unclippedBounds`) fallback. */
|
|
41
41
|
clipsChildren: boolean;
|
|
42
|
+
/** Accessible text content. */
|
|
43
|
+
text?: string;
|
|
44
|
+
/** Fill (background) color, hex. */
|
|
45
|
+
fillColor?: string;
|
|
46
|
+
/** Text (foreground) color, hex. */
|
|
47
|
+
textColor?: string;
|
|
42
48
|
}
|
|
43
49
|
export interface LayoutDump {
|
|
44
50
|
/** The captured canvas / root bounds in px. */
|
|
@@ -185,7 +191,67 @@ export interface StructuralBlock {
|
|
|
185
191
|
summary: StructuralSummary;
|
|
186
192
|
facts: StructuralFact[];
|
|
187
193
|
geometry?: StructuralGeometry;
|
|
194
|
+
appearance?: StructuralAppearance;
|
|
188
195
|
}
|
|
196
|
+
/** Which reference the appearance facts were diffed against. `previous_render`
|
|
197
|
+
* facts are regressions/drift, NOT design divergences (the no-Figma path). */
|
|
198
|
+
export type AppearanceBaseline = 'figma' | 'previous_render';
|
|
199
|
+
export type AppearanceFact = {
|
|
200
|
+
kind: 'color';
|
|
201
|
+
elementId: string;
|
|
202
|
+
channel: 'fill' | 'text';
|
|
203
|
+
rendered: string;
|
|
204
|
+
reference: string;
|
|
205
|
+
/** CIEDE2000 perceptual distance — measurement only, no significance. */
|
|
206
|
+
deltaE: number;
|
|
207
|
+
} | {
|
|
208
|
+
kind: 'text_mismatch';
|
|
209
|
+
elementId: string;
|
|
210
|
+
rendered: string;
|
|
211
|
+
reference: string;
|
|
212
|
+
} | {
|
|
213
|
+
kind: 'text_missing';
|
|
214
|
+
elementId: string;
|
|
215
|
+
reference: string;
|
|
216
|
+
}
|
|
217
|
+
/** In the reference, not rendered. */
|
|
218
|
+
| {
|
|
219
|
+
kind: 'element_missing';
|
|
220
|
+
elementId: string;
|
|
221
|
+
}
|
|
222
|
+
/** Rendered, not in the reference. */
|
|
223
|
+
| {
|
|
224
|
+
kind: 'element_extra';
|
|
225
|
+
elementId: string;
|
|
226
|
+
};
|
|
227
|
+
export interface StructuralAppearance {
|
|
228
|
+
baseline: AppearanceBaseline;
|
|
229
|
+
facts: AppearanceFact[];
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* The reference side of the appearance diff, passed into `buildStructuralBlock`.
|
|
233
|
+
* `elementIds` is the reference element-id set (Figma node ids on the `figma`
|
|
234
|
+
* baseline; the previous render's element ids on `previous_render`). This slice
|
|
235
|
+
* derives presence only; the copy/color slices extend this with reference text /
|
|
236
|
+
* colors keyed by element id.
|
|
237
|
+
*/
|
|
238
|
+
export interface AppearanceReference {
|
|
239
|
+
baseline: AppearanceBaseline;
|
|
240
|
+
elementIds: string[];
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Element-presence facts from the set difference of the rendered element-id set
|
|
244
|
+
* and the reference element-id set, keyed on the stable element id shared with
|
|
245
|
+
* Signal B. An id present in the reference but not rendered is `element_missing`;
|
|
246
|
+
* an id rendered but not in the reference is `element_extra`.
|
|
247
|
+
*
|
|
248
|
+
* Pure and platform-agnostic: it takes two id collections and is order-
|
|
249
|
+
* independent — the result depends only on the two SETS, not on input order or
|
|
250
|
+
* duplicates. Output is sorted (missing before extra, each by id) so callers get
|
|
251
|
+
* a deterministic list. The deriver reports facts only; significance is a later,
|
|
252
|
+
* separately-wired concern.
|
|
253
|
+
*/
|
|
254
|
+
export declare function derivePresenceFacts(renderedIds: Iterable<string>, referenceIds: Iterable<string>): AppearanceFact[];
|
|
189
255
|
/**
|
|
190
256
|
* Assemble the inline `structural` block (ADR-0004): Signal-A facts always, plus
|
|
191
257
|
* the Signal-B geometry block when `referenceGeometry` is supplied. Size (w/h)
|
|
@@ -195,7 +261,7 @@ export interface StructuralBlock {
|
|
|
195
261
|
export declare function buildStructuralBlock(dump: LayoutDump, referenceGeometry?: ReferenceGeometry | null, density?: number, options?: {
|
|
196
262
|
sizeTolerancePx?: number;
|
|
197
263
|
overhangTolerancePx?: number;
|
|
198
|
-
}): StructuralBlock;
|
|
264
|
+
}, appearanceReference?: AppearanceReference | null): StructuralBlock;
|
|
199
265
|
export interface ReviewRow {
|
|
200
266
|
element: string;
|
|
201
267
|
rendered: string | null;
|
|
@@ -265,10 +331,11 @@ export declare function getGeometryStageInternals(): {
|
|
|
265
331
|
buildStructuralBlock: (dump: LayoutDump, referenceGeometry?: ReferenceGeometry | null, density?: number, options?: {
|
|
266
332
|
sizeTolerancePx?: number;
|
|
267
333
|
overhangTolerancePx?: number;
|
|
268
|
-
}) => StructuralBlock;
|
|
334
|
+
}, appearanceReference?: AppearanceReference | null) => StructuralBlock;
|
|
269
335
|
buildReviewScaffold: (structural: {
|
|
270
336
|
facts?: StructuralFact[];
|
|
271
337
|
geometry?: StructuralGeometry | null;
|
|
272
338
|
}) => ReviewScaffold;
|
|
339
|
+
derivePresenceFacts: (renderedIds: Iterable<string>, referenceIds: Iterable<string>) => AppearanceFact[];
|
|
273
340
|
};
|
|
274
341
|
//# sourceMappingURL=structural-facts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structural-facts.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/structural-facts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX;6CACyC;IACzC,MAAM,EAAE,YAAY,CAAC;IACrB;;;+EAG2E;IAC3E,eAAe,CAAC,EAAE,YAAY,CAAC;IAC/B,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;oFACgF;IAChF,aAAa,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"structural-facts.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/structural-facts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX;6CACyC;IACzC,MAAM,EAAE,YAAY,CAAC;IACrB;;;+EAG2E;IAC3E,eAAe,CAAC,EAAE,YAAY,CAAC;IAC/B,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;oFACgF;IAChF,aAAa,EAAE,OAAO,CAAC;IAKvB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEvD,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3C,GACD;IACE,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1C,GACD;IACE,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5C,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,MAAM,WAAW,4BAA4B;IAC3C;yEACqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;mCAC+B;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAoCD,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,4BAAiC,GACzC,cAAc,EAAE,CAuHlB;AAkBD,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AACD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAC7D,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAKD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EAC5C,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACrC,aAAa,EAAE,CAqBjB;AAED,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GAAG,MAAM,CACpC,MAAM,EACN;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CACnD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACxC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACtC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,QAAQ,EAAE,OAAO,CAAC;IAClB;oEACgE;IAChE,UAAU,EAAE,OAAO,CAAC;IACpB;kFAC8E;IAC9E,aAAa,EAAE,OAAO,CAAC;IACvB;;kFAE8E;IAC9E,cAAc,EAAE,OAAO,CAAC;CACzB;AACD,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IAMX,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjF,MAAM,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnE,QAAQ,EAAE,OAAO,CAAC;IAClB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AACD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,yBAAyB,EAAE,CAAC;CACvC;AACD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,yEAAyE;IACzE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AACD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,UAAU,CAAC,EAAE,oBAAoB,CAAC;CACnC;AAiBD;+EAC+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,iBAAiB,CAAC;AAE7D,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACjF;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAChE,sCAAsC;GACpC;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAChD,sCAAsC;GACpC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC7B,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC7B,cAAc,EAAE,CAWlB;AAgKD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,EAChB,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI,EAC5C,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAO,EACxE,mBAAmB,CAAC,EAAE,mBAAmB,GAAG,IAAI,GAC/C,eAAe,CA8FjB;AAaD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,IAAI,CAAC;CACf;AACD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,IAAI,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAgFD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE;IAC9C,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACtC,GAAG,cAAc,CA2CjB;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAgJvC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gCAAgC,IAAI;IAClD,qBAAqB,EAAE,CACrB,IAAI,EAAE,UAAU,EAChB,OAAO,CAAC,EAAE,4BAA4B,KACnC,cAAc,EAAE,CAAC;CACvB,CAWA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,EAAE,MA8a1C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI;IAC3C,eAAe,EAAE,CACf,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EAC5C,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,KAC/B,aAAa,EAAE,CAAC;IACrB,oBAAoB,EAAE,CACpB,IAAI,EAAE,UAAU,EAChB,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI,EAC5C,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAE,EACpE,mBAAmB,CAAC,EAAE,mBAAmB,GAAG,IAAI,KAC7C,eAAe,CAAC;IACrB,mBAAmB,EAAE,CAAC,UAAU,EAAE;QAChC,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;QACzB,QAAQ,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;KACtC,KAAK,cAAc,CAAC;IACrB,mBAAmB,EAAE,CACnB,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC7B,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,KAC3B,cAAc,EAAE,CAAC;CACvB,CAOA"}
|
|
Binary file
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* overflowing voucher tag; the deriver must surface the bottom clip as a
|
|
9
9
|
* fact so it is never again skipped by eye.
|
|
10
10
|
*/
|
|
11
|
-
import { deriveStructuralFacts, diffKeyGeometry, buildStructuralBlock, buildReviewScaffold, getStructuralFactsStageInternals, getGeometryStageInternals, } from './structural-facts.js';
|
|
11
|
+
import { deriveStructuralFacts, derivePresenceFacts, diffKeyGeometry, buildStructuralBlock, buildReviewScaffold, getStructuralFactsStageInternals, getGeometryStageInternals, } from './structural-facts.js';
|
|
12
12
|
// 200x400 canvas in px for all fixtures unless noted.
|
|
13
13
|
const CANVAS = { left: 0, top: 0, right: 200, bottom: 400 };
|
|
14
14
|
describe('deriveStructuralFacts — containment', () => {
|
|
@@ -484,6 +484,74 @@ describe('buildReviewScaffold — run-only verdict obligation', () => {
|
|
|
484
484
|
});
|
|
485
485
|
});
|
|
486
486
|
});
|
|
487
|
+
// ---- Signal C: element-presence facts (appearance container) ----
|
|
488
|
+
describe('derivePresenceFacts — set difference over element ids', () => {
|
|
489
|
+
test('equal element sets produce no facts', () => {
|
|
490
|
+
expect(derivePresenceFacts(['a', 'b', 'c'], ['a', 'b', 'c'])).toEqual([]);
|
|
491
|
+
});
|
|
492
|
+
test('an id only in the reference yields element_missing', () => {
|
|
493
|
+
// rendered lacks `voucher`, which the reference declares.
|
|
494
|
+
expect(derivePresenceFacts(['banner'], ['banner', 'voucher'])).toEqual([
|
|
495
|
+
{ kind: 'element_missing', elementId: 'voucher' },
|
|
496
|
+
]);
|
|
497
|
+
});
|
|
498
|
+
test('an id only in the render yields element_extra', () => {
|
|
499
|
+
// rendered has an extra `debugOverlay` the reference does not declare.
|
|
500
|
+
expect(derivePresenceFacts(['banner', 'debugOverlay'], ['banner'])).toEqual([
|
|
501
|
+
{ kind: 'element_extra', elementId: 'debugOverlay' },
|
|
502
|
+
]);
|
|
503
|
+
});
|
|
504
|
+
test('reports both a missing and an extra id, missing before extra', () => {
|
|
505
|
+
expect(derivePresenceFacts(['banner', 'extra'], ['banner', 'gone'])).toEqual([
|
|
506
|
+
{ kind: 'element_missing', elementId: 'gone' },
|
|
507
|
+
{ kind: 'element_extra', elementId: 'extra' },
|
|
508
|
+
]);
|
|
509
|
+
});
|
|
510
|
+
test('result is order-independent — same sets in any input order give the same facts', () => {
|
|
511
|
+
const a = derivePresenceFacts(['a', 'b', 'c'], ['b', 'd', 'a']);
|
|
512
|
+
const b = derivePresenceFacts(['c', 'b', 'a'], ['d', 'a', 'b']);
|
|
513
|
+
expect(a).toEqual(b);
|
|
514
|
+
// d missing, c extra — independent of how the ids were ordered or duplicated.
|
|
515
|
+
expect(derivePresenceFacts(['c', 'c', 'b', 'a'], ['a', 'b', 'd', 'd'])).toEqual([
|
|
516
|
+
{ kind: 'element_missing', elementId: 'd' },
|
|
517
|
+
{ kind: 'element_extra', elementId: 'c' },
|
|
518
|
+
]);
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
describe('buildStructuralBlock — appearance container (Signal C, additive)', () => {
|
|
522
|
+
test('no appearanceReference → no appearance container; facts + geometry unchanged', () => {
|
|
523
|
+
const withC = buildStructuralBlock(HUB_PROMO_DUMP, HUB_PROMO_REFERENCE, 2);
|
|
524
|
+
const without = buildStructuralBlock(HUB_PROMO_DUMP, HUB_PROMO_REFERENCE, 2, undefined, null);
|
|
525
|
+
expect(withC.appearance).toBeUndefined();
|
|
526
|
+
// Signal A facts and Signal B geometry are byte-identical whether or not the
|
|
527
|
+
// appearance arg is threaded.
|
|
528
|
+
expect(without).toEqual(withC);
|
|
529
|
+
});
|
|
530
|
+
test('with a figma appearanceReference → presence facts from rendered vs reference ids', () => {
|
|
531
|
+
// dump node ids: node-1, banner, voucher, copy; reference declares banner+voucher.
|
|
532
|
+
const block = buildStructuralBlock(HUB_PROMO_DUMP, HUB_PROMO_REFERENCE, 2, undefined, {
|
|
533
|
+
baseline: 'figma',
|
|
534
|
+
elementIds: ['banner', 'voucher'],
|
|
535
|
+
});
|
|
536
|
+
expect(block.appearance).toEqual({
|
|
537
|
+
baseline: 'figma',
|
|
538
|
+
facts: [
|
|
539
|
+
{ kind: 'element_extra', elementId: 'copy' },
|
|
540
|
+
{ kind: 'element_extra', elementId: 'node-1' },
|
|
541
|
+
],
|
|
542
|
+
});
|
|
543
|
+
// Additive: the existing Signal A facts and Signal B geometry are untouched.
|
|
544
|
+
expect(block.facts).toEqual(buildStructuralBlock(HUB_PROMO_DUMP, HUB_PROMO_REFERENCE, 2).facts);
|
|
545
|
+
expect(block.geometry).toEqual(buildStructuralBlock(HUB_PROMO_DUMP, HUB_PROMO_REFERENCE, 2).geometry);
|
|
546
|
+
});
|
|
547
|
+
test('an appearanceReference matching the render → ran-and-clean (baseline, zero facts)', () => {
|
|
548
|
+
const block = buildStructuralBlock(HUB_PROMO_DUMP, null, 2, undefined, {
|
|
549
|
+
baseline: 'figma',
|
|
550
|
+
elementIds: ['node-1', 'banner', 'voucher', 'copy'],
|
|
551
|
+
});
|
|
552
|
+
expect(block.appearance).toEqual({ baseline: 'figma', facts: [] });
|
|
553
|
+
});
|
|
554
|
+
});
|
|
487
555
|
describe('embedded geometry stage parity', () => {
|
|
488
556
|
// The render ships a JS-source port of the differ + assembler. It must produce
|
|
489
557
|
// byte-identical blocks to the canonical typed module, or run-side structural
|
|
@@ -494,6 +562,23 @@ describe('embedded geometry stage parity', () => {
|
|
|
494
562
|
const reference = { card: { width: 328, height: 72 } };
|
|
495
563
|
expect(embedded.diffKeyGeometry(generated, reference)).toEqual(diffKeyGeometry(generated, reference));
|
|
496
564
|
});
|
|
565
|
+
test('embedded derivePresenceFacts matches the module (Signal C)', () => {
|
|
566
|
+
const cases = [
|
|
567
|
+
[['a', 'b', 'c'], ['a', 'b', 'c']],
|
|
568
|
+
[['banner'], ['banner', 'voucher']],
|
|
569
|
+
[['banner', 'debugOverlay'], ['banner']],
|
|
570
|
+
[['c', 'b', 'a'], ['d', 'a', 'b']],
|
|
571
|
+
[[], ['x', 'y']],
|
|
572
|
+
[['x', 'y'], []],
|
|
573
|
+
];
|
|
574
|
+
for (const [rendered, reference] of cases) {
|
|
575
|
+
expect(embedded.derivePresenceFacts(rendered, reference)).toEqual(derivePresenceFacts(rendered, reference));
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
test('embedded buildStructuralBlock matches the module with an appearanceReference', () => {
|
|
579
|
+
const appearanceReference = { baseline: 'figma', elementIds: ['banner', 'voucher'] };
|
|
580
|
+
expect(embedded.buildStructuralBlock(HUB_PROMO_DUMP, HUB_PROMO_REFERENCE, 2, undefined, appearanceReference)).toEqual(buildStructuralBlock(HUB_PROMO_DUMP, HUB_PROMO_REFERENCE, 2, undefined, appearanceReference));
|
|
581
|
+
});
|
|
497
582
|
const parityCases = [
|
|
498
583
|
{ name: 'factsOnly', dump: HUB_PROMO_DUMP, ref: null },
|
|
499
584
|
{ name: 'withGeometry', dump: HUB_PROMO_DUMP, ref: HUB_PROMO_REFERENCE },
|