@invarn/cibuild 2.2.2 → 2.2.4
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.
|
@@ -263,6 +263,47 @@ export interface AppearanceReference {
|
|
|
263
263
|
* color facts are derived against the render's per-node colors. */
|
|
264
264
|
color?: ColorSource;
|
|
265
265
|
}
|
|
266
|
+
/** The per-screen reference params the runner assembles an `AppearanceReference`
|
|
267
|
+
* from (the slices of `params.reference_*` for one screen). */
|
|
268
|
+
export interface AppearanceReferenceParams {
|
|
269
|
+
/** Per-screen `reference_geometry` (design/baseline geometry). Its keys seed
|
|
270
|
+
* the element-id set. */
|
|
271
|
+
refGeom?: ReferenceGeometry | null;
|
|
272
|
+
/** Per-screen `reference_text` (text per element id). */
|
|
273
|
+
refText?: TextSource | null;
|
|
274
|
+
/** Per-screen `reference_color` (fill/text color per element id). */
|
|
275
|
+
refColor?: ColorSource | null;
|
|
276
|
+
baseline: AppearanceBaseline;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Assemble the `AppearanceReference` from a screen's reference params. Issue 05
|
|
280
|
+
* decouples the appearance container from `reference_geometry`: the reference is
|
|
281
|
+
* built when ANY of geometry / text / color is present, with `elementIds` = the
|
|
282
|
+
* UNION of their keys (geometry first, then text, then color — deduped, order
|
|
283
|
+
* preserved). So a run carrying `reference_color` but no `reference_geometry` now
|
|
284
|
+
* yields a reference (→ color facts), while a geometry-only run is byte-identical
|
|
285
|
+
* to before (color/text keys are a subset). `text`/`color` are attached only when
|
|
286
|
+
* present. No reference of any kind → null (no appearance container).
|
|
287
|
+
*/
|
|
288
|
+
export declare function buildAppearanceReferenceFromParams(params: AppearanceReferenceParams): AppearanceReference | null;
|
|
289
|
+
/**
|
|
290
|
+
* Map a previous catalog render's persisted appearance snapshot
|
|
291
|
+
* (`StructuralAppearance.rendered` — element ids + per-element colors) into the
|
|
292
|
+
* `previous_render` AppearanceReference the next render diffs against. The
|
|
293
|
+
* no-Figma drift path: the colors/ids the next render compares itself to are the
|
|
294
|
+
* LAST render's, so a diverging fill surfaces as a regression (drift), marked
|
|
295
|
+
* `baseline: 'previous_render'`, distinct from a design divergence.
|
|
296
|
+
*
|
|
297
|
+
* Pure (no I/O) — the testable core the thin catalog-fetch adapter wraps,
|
|
298
|
+
* mirroring how the geometry baseline reuses the previous render's persisted
|
|
299
|
+
* `geometry`. `color` is carried only when the previous render exposed colors;
|
|
300
|
+
* a previous render with no extractable color yields a presence-only reference
|
|
301
|
+
* (element ids, no color). A genuinely absent previous render (no snapshot) →
|
|
302
|
+
* null, so the next render carries no appearance container, exactly as before.
|
|
303
|
+
* Issue 01 carries the color channels; the previous render's `text` (copy) is a
|
|
304
|
+
* later slice's concern and is intentionally not mapped here.
|
|
305
|
+
*/
|
|
306
|
+
export declare function appearanceReferenceFromPreviousRender(previous: AppearanceRendered | null | undefined): AppearanceReference | null;
|
|
266
307
|
/**
|
|
267
308
|
* Element-presence facts from the set difference of the rendered element-id set
|
|
268
309
|
* and the reference element-id set, keyed on the stable element id shared with
|
|
@@ -418,6 +459,7 @@ export declare function getGeometryStageInternals(): {
|
|
|
418
459
|
derivePresenceFacts: (renderedIds: Iterable<string>, referenceIds: Iterable<string>) => AppearanceFact[];
|
|
419
460
|
deriveCopyFacts: (rendered: TextSource, reference: TextSource) => AppearanceFact[];
|
|
420
461
|
deriveColorFacts: (rendered: ColorSource, reference: ColorSource) => AppearanceFact[];
|
|
462
|
+
buildAppearanceReferenceFromParams: (params: AppearanceReferenceParams) => AppearanceReference | null;
|
|
421
463
|
ciede2000: (lab1: Lab, lab2: Lab) => number;
|
|
422
464
|
hexToLab: (hex: string) => Lab;
|
|
423
465
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structural-facts.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/structural-facts.ts"],"names":[],"mappings":"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
|
|
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;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB;0DACsD;IACtD,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;oFAEgF;IAChF,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;wEAEoE;IACpE,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;gEACgE;AAChE,MAAM,WAAW,yBAAyB;IACxC;8BAC0B;IAC1B,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACnC,yDAAyD;IACzD,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,kBAAkB,CAAC;CAC9B;AAMD;;;;;;;;;GASG;AACH,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,yBAAyB,GAChC,mBAAmB,GAAG,IAAI,CAsB5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,GAC9C,mBAAmB,GAAG,IAAI,CAU5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC7B,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC7B,cAAc,EAAE,CAWlB;AAED;;;yEAGyE;AACzE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAO5D;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,UAAU,EACpB,SAAS,EAAE,UAAU,GACpB,cAAc,EAAE,CAalB;AASD,+BAA+B;AAC/B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE3C;uEACuE;AACvE,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AACD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAyBxD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAYzC;AAKD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,MAAM,CA2DtD;AASD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,WAAW,GACrB,cAAc,EAAE,CAsBlB;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,CAuHjB;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,MAynB1C,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;IACtB,eAAe,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,KAAK,cAAc,EAAE,CAAC;IACnF,gBAAgB,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,KAAK,cAAc,EAAE,CAAC;IACtF,kCAAkC,EAAE,CAClC,MAAM,EAAE,yBAAyB,KAC9B,mBAAmB,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC;IAC5C,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,GAAG,CAAC;CAChC,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, derivePresenceFacts, deriveCopyFacts, deriveColorFacts, ciede2000, hexToLab, diffKeyGeometry, buildStructuralBlock, buildReviewScaffold, getStructuralFactsStageInternals, getGeometryStageInternals, } from './structural-facts.js';
|
|
11
|
+
import { deriveStructuralFacts, derivePresenceFacts, deriveCopyFacts, deriveColorFacts, ciede2000, hexToLab, diffKeyGeometry, buildStructuralBlock, buildReviewScaffold, appearanceReferenceFromPreviousRender, buildAppearanceReferenceFromParams, 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', () => {
|
|
@@ -741,6 +741,33 @@ describe('buildStructuralBlock — appearance container (Signal C, additive)', (
|
|
|
741
741
|
},
|
|
742
742
|
]);
|
|
743
743
|
});
|
|
744
|
+
test('with reference text color → a text-channel color fact (issue 02)', () => {
|
|
745
|
+
// COLOR_DUMP renders `card` text #000000; the reference declares #ffffff for
|
|
746
|
+
// the text channel and the matching fill — so exactly one fact, channel:'text'.
|
|
747
|
+
const block = buildStructuralBlock(COLOR_DUMP, null, 2, undefined, {
|
|
748
|
+
baseline: 'figma',
|
|
749
|
+
elementIds: ['card'],
|
|
750
|
+
color: { card: { fill: '#ff0000', text: '#ffffff' } },
|
|
751
|
+
});
|
|
752
|
+
expect(block.appearance?.facts).toEqual([
|
|
753
|
+
{
|
|
754
|
+
kind: 'color',
|
|
755
|
+
elementId: 'card',
|
|
756
|
+
channel: 'text',
|
|
757
|
+
rendered: '#000000',
|
|
758
|
+
reference: '#ffffff',
|
|
759
|
+
deltaE: ciede2000(hexToLab('#000000'), hexToLab('#ffffff')),
|
|
760
|
+
},
|
|
761
|
+
]);
|
|
762
|
+
});
|
|
763
|
+
test('an identical text color → no text fact (issue 02)', () => {
|
|
764
|
+
const block = buildStructuralBlock(COLOR_DUMP, null, 2, undefined, {
|
|
765
|
+
baseline: 'figma',
|
|
766
|
+
elementIds: ['card'],
|
|
767
|
+
color: { card: { fill: '#ff0000', text: '#000000' } },
|
|
768
|
+
});
|
|
769
|
+
expect(block.appearance?.facts).toEqual([]);
|
|
770
|
+
});
|
|
744
771
|
test('an appearanceReference without color → no color facts (presence only)', () => {
|
|
745
772
|
const block = buildStructuralBlock(COLOR_DUMP, null, 2, undefined, {
|
|
746
773
|
baseline: 'figma',
|
|
@@ -802,6 +829,222 @@ describe('buildStructuralBlock — appearance container (Signal C, additive)', (
|
|
|
802
829
|
expect(block.appearance).toBeUndefined();
|
|
803
830
|
});
|
|
804
831
|
});
|
|
832
|
+
// ---- Signal C: previous-render → AppearanceReference mapper (issue 01) ----
|
|
833
|
+
//
|
|
834
|
+
// The no-Figma drift path: a previous catalog render persisted its own
|
|
835
|
+
// appearance snapshot (`appearance.rendered`: element ids + per-element colors).
|
|
836
|
+
// This pure mapper turns that snapshot into the `previous_render`
|
|
837
|
+
// AppearanceReference the next render diffs against — the colors/ids to compare,
|
|
838
|
+
// marked as drift (regression vs the last render), not a design divergence. It is
|
|
839
|
+
// the testable core the thin catalog-fetch adapter wraps; no I/O here.
|
|
840
|
+
describe('appearanceReferenceFromPreviousRender — previous render snapshot → reference', () => {
|
|
841
|
+
test('a previous render with per-element fill colors → a previous_render reference carrying color + ids', () => {
|
|
842
|
+
const previous = {
|
|
843
|
+
elementIds: ['banner', 'voucher'],
|
|
844
|
+
color: { banner: { fill: '#fff0ee' } },
|
|
845
|
+
};
|
|
846
|
+
expect(appearanceReferenceFromPreviousRender(previous)).toEqual({
|
|
847
|
+
baseline: 'previous_render',
|
|
848
|
+
elementIds: ['banner', 'voucher'],
|
|
849
|
+
color: { banner: { fill: '#fff0ee' } },
|
|
850
|
+
});
|
|
851
|
+
});
|
|
852
|
+
test('a previous render with per-element text colors → the text channel rides through into the reference (issue 02)', () => {
|
|
853
|
+
// The mapper carries the whole previous color map, so the foreground (text)
|
|
854
|
+
// channel reaches the reference exactly as the fill channel does — channel
|
|
855
|
+
// genericity, not a fill-only carry.
|
|
856
|
+
const previous = {
|
|
857
|
+
elementIds: ['banner', 'copy'],
|
|
858
|
+
color: { banner: { fill: '#fff0ee' }, copy: { text: '#1b1b1b' } },
|
|
859
|
+
};
|
|
860
|
+
expect(appearanceReferenceFromPreviousRender(previous)).toEqual({
|
|
861
|
+
baseline: 'previous_render',
|
|
862
|
+
elementIds: ['banner', 'copy'],
|
|
863
|
+
color: { banner: { fill: '#fff0ee' }, copy: { text: '#1b1b1b' } },
|
|
864
|
+
});
|
|
865
|
+
});
|
|
866
|
+
test('a previous render with no extractable color → a presence-only reference (ids, no color)', () => {
|
|
867
|
+
const previous = { elementIds: ['banner', 'voucher'] };
|
|
868
|
+
expect(appearanceReferenceFromPreviousRender(previous)).toEqual({
|
|
869
|
+
baseline: 'previous_render',
|
|
870
|
+
elementIds: ['banner', 'voucher'],
|
|
871
|
+
});
|
|
872
|
+
});
|
|
873
|
+
test('an empty color map is treated as no color signal (presence-only)', () => {
|
|
874
|
+
const previous = { elementIds: ['banner'], color: {} };
|
|
875
|
+
expect(appearanceReferenceFromPreviousRender(previous)).toEqual({
|
|
876
|
+
baseline: 'previous_render',
|
|
877
|
+
elementIds: ['banner'],
|
|
878
|
+
});
|
|
879
|
+
});
|
|
880
|
+
test('a genuinely absent previous render → null (no appearance container downstream)', () => {
|
|
881
|
+
expect(appearanceReferenceFromPreviousRender(null)).toBeNull();
|
|
882
|
+
expect(appearanceReferenceFromPreviousRender(undefined)).toBeNull();
|
|
883
|
+
expect(appearanceReferenceFromPreviousRender({})).toBeNull();
|
|
884
|
+
});
|
|
885
|
+
test('fed into buildStructuralBlock, a drifted fill produces a previous_render color fact (the tracer)', () => {
|
|
886
|
+
// The render now paints the banner the wrong fill (#1e88e5); the previous
|
|
887
|
+
// render painted #fff0ee. The mapper turns that previous snapshot into the
|
|
888
|
+
// drift reference, and the assembled block carries one fill color fact with a
|
|
889
|
+
// large positive ΔE — exactly the blue-banner divergence, proven through the
|
|
890
|
+
// public interface (the e2e proves the same on a real render).
|
|
891
|
+
const driftedDump = {
|
|
892
|
+
canvas: { left: 0, top: 0, right: 686, bottom: 282 },
|
|
893
|
+
nodes: [
|
|
894
|
+
{ id: 'banner', bounds: { left: 0, top: 0, right: 686, bottom: 282 }, parentId: null, clipsChildren: false, fillColor: '#1e88e5' },
|
|
895
|
+
],
|
|
896
|
+
};
|
|
897
|
+
const previous = { elementIds: ['banner'], color: { banner: { fill: '#fff0ee' } } };
|
|
898
|
+
const reference = appearanceReferenceFromPreviousRender(previous);
|
|
899
|
+
const block = buildStructuralBlock(driftedDump, null, 2, undefined, reference);
|
|
900
|
+
expect(block.appearance?.baseline).toBe('previous_render');
|
|
901
|
+
const colorFacts = (block.appearance?.facts ?? []).filter((f) => f.kind === 'color');
|
|
902
|
+
expect(colorFacts).toEqual([
|
|
903
|
+
{
|
|
904
|
+
kind: 'color',
|
|
905
|
+
elementId: 'banner',
|
|
906
|
+
channel: 'fill',
|
|
907
|
+
rendered: '#1e88e5',
|
|
908
|
+
reference: '#fff0ee',
|
|
909
|
+
deltaE: ciede2000(hexToLab('#1e88e5'), hexToLab('#fff0ee')),
|
|
910
|
+
},
|
|
911
|
+
]);
|
|
912
|
+
expect(colorFacts[0].kind === 'color' && colorFacts[0].deltaE).toBeGreaterThan(10);
|
|
913
|
+
});
|
|
914
|
+
test('fed into buildStructuralBlock, a drifted text color produces a previous_render text-channel fact (issue 02)', () => {
|
|
915
|
+
// The render paints `copy` the wrong foreground color (#1e88e5); the previous
|
|
916
|
+
// render painted #1b1b1b. The mapper carries the text channel through, and the
|
|
917
|
+
// assembled block carries one text color fact with a large positive ΔE —
|
|
918
|
+
// distinct from fill, proven through the public interface.
|
|
919
|
+
const driftedDump = {
|
|
920
|
+
canvas: { left: 0, top: 0, right: 686, bottom: 282 },
|
|
921
|
+
nodes: [
|
|
922
|
+
{ id: 'copy', bounds: { left: 0, top: 0, right: 343, bottom: 40 }, parentId: null, clipsChildren: false, textColor: '#1e88e5' },
|
|
923
|
+
],
|
|
924
|
+
};
|
|
925
|
+
const previous = { elementIds: ['copy'], color: { copy: { text: '#1b1b1b' } } };
|
|
926
|
+
const reference = appearanceReferenceFromPreviousRender(previous);
|
|
927
|
+
const block = buildStructuralBlock(driftedDump, null, 2, undefined, reference);
|
|
928
|
+
expect(block.appearance?.baseline).toBe('previous_render');
|
|
929
|
+
const colorFacts = (block.appearance?.facts ?? []).filter((f) => f.kind === 'color');
|
|
930
|
+
expect(colorFacts).toEqual([
|
|
931
|
+
{
|
|
932
|
+
kind: 'color',
|
|
933
|
+
elementId: 'copy',
|
|
934
|
+
channel: 'text',
|
|
935
|
+
rendered: '#1e88e5',
|
|
936
|
+
reference: '#1b1b1b',
|
|
937
|
+
deltaE: ciede2000(hexToLab('#1e88e5'), hexToLab('#1b1b1b')),
|
|
938
|
+
},
|
|
939
|
+
]);
|
|
940
|
+
expect(colorFacts[0].kind === 'color' && colorFacts[0].deltaE).toBeGreaterThan(10);
|
|
941
|
+
});
|
|
942
|
+
test('a correct fill with a wrong text color yields a text-channel fact only — the two never collapse (issue 02)', () => {
|
|
943
|
+
// One element carries both channels: fill matches the previous render, text
|
|
944
|
+
// drifts. Exactly one fact, channel:'text' — the correct fill produces none.
|
|
945
|
+
const dump = {
|
|
946
|
+
canvas: { left: 0, top: 0, right: 343, bottom: 72 },
|
|
947
|
+
nodes: [
|
|
948
|
+
{ id: 'banner', bounds: { left: 0, top: 0, right: 343, bottom: 72 }, parentId: null, clipsChildren: false, fillColor: '#fff0ee', textColor: '#1e88e5' },
|
|
949
|
+
],
|
|
950
|
+
};
|
|
951
|
+
const previous = {
|
|
952
|
+
elementIds: ['banner'],
|
|
953
|
+
color: { banner: { fill: '#fff0ee', text: '#1b1b1b' } },
|
|
954
|
+
};
|
|
955
|
+
const block = buildStructuralBlock(dump, null, 2, undefined, appearanceReferenceFromPreviousRender(previous));
|
|
956
|
+
const colorFacts = (block.appearance?.facts ?? []).filter((f) => f.kind === 'color');
|
|
957
|
+
expect(colorFacts).toEqual([
|
|
958
|
+
{
|
|
959
|
+
kind: 'color',
|
|
960
|
+
elementId: 'banner',
|
|
961
|
+
channel: 'text',
|
|
962
|
+
rendered: '#1e88e5',
|
|
963
|
+
reference: '#1b1b1b',
|
|
964
|
+
deltaE: ciede2000(hexToLab('#1e88e5'), hexToLab('#1b1b1b')),
|
|
965
|
+
},
|
|
966
|
+
]);
|
|
967
|
+
});
|
|
968
|
+
});
|
|
969
|
+
// ---- Signal C: build the appearance reference from run params (issue 05) ----
|
|
970
|
+
//
|
|
971
|
+
// The runner builds the appearanceReference from the per-screen reference_geometry
|
|
972
|
+
// / reference_text / reference_color params. Issue 05 decouples the container from
|
|
973
|
+
// reference_geometry: it is assembled when ANY of the three is present, with
|
|
974
|
+
// elementIds = the UNION of their keys, so a run with reference_color but no
|
|
975
|
+
// reference_geometry still emits color facts.
|
|
976
|
+
describe('buildAppearanceReferenceFromParams — union of geometry/text/color ids', () => {
|
|
977
|
+
test('color only (no geometry) → a reference carrying color, ids from the color keys', () => {
|
|
978
|
+
const ref = buildAppearanceReferenceFromParams({
|
|
979
|
+
refColor: { banner: { fill: '#fff0ee' } },
|
|
980
|
+
baseline: 'previous_render',
|
|
981
|
+
});
|
|
982
|
+
expect(ref).toEqual({
|
|
983
|
+
baseline: 'previous_render',
|
|
984
|
+
elementIds: ['banner'],
|
|
985
|
+
color: { banner: { fill: '#fff0ee' } },
|
|
986
|
+
});
|
|
987
|
+
});
|
|
988
|
+
test('geometry only → ids from the geometry keys, no text/color attached', () => {
|
|
989
|
+
const ref = buildAppearanceReferenceFromParams({
|
|
990
|
+
refGeom: { banner: { w: 343, h: 96 }, voucher: { w: 81, h: 81 } },
|
|
991
|
+
baseline: 'figma',
|
|
992
|
+
});
|
|
993
|
+
expect(ref).toEqual({ baseline: 'figma', elementIds: ['banner', 'voucher'] });
|
|
994
|
+
});
|
|
995
|
+
test('geometry + color (color ids ⊆ geometry ids) → ids unchanged (additive, no regression)', () => {
|
|
996
|
+
const ref = buildAppearanceReferenceFromParams({
|
|
997
|
+
refGeom: { banner: { w: 343, h: 96 }, voucher: { w: 81, h: 81 } },
|
|
998
|
+
refColor: { banner: { fill: '#fff0ee' } },
|
|
999
|
+
baseline: 'figma',
|
|
1000
|
+
});
|
|
1001
|
+
expect(ref).toEqual({
|
|
1002
|
+
baseline: 'figma',
|
|
1003
|
+
elementIds: ['banner', 'voucher'],
|
|
1004
|
+
color: { banner: { fill: '#fff0ee' } },
|
|
1005
|
+
});
|
|
1006
|
+
});
|
|
1007
|
+
test('text + color, no geometry → union ids, both attached', () => {
|
|
1008
|
+
const ref = buildAppearanceReferenceFromParams({
|
|
1009
|
+
refText: { copy: 'Get 5 € off' },
|
|
1010
|
+
refColor: { banner: { fill: '#fff0ee' } },
|
|
1011
|
+
baseline: 'previous_render',
|
|
1012
|
+
});
|
|
1013
|
+
expect(ref).toEqual({
|
|
1014
|
+
baseline: 'previous_render',
|
|
1015
|
+
elementIds: ['copy', 'banner'],
|
|
1016
|
+
text: { copy: 'Get 5 € off' },
|
|
1017
|
+
color: { banner: { fill: '#fff0ee' } },
|
|
1018
|
+
});
|
|
1019
|
+
});
|
|
1020
|
+
test('none present → null (no appearance container)', () => {
|
|
1021
|
+
expect(buildAppearanceReferenceFromParams({ baseline: 'figma' })).toBeNull();
|
|
1022
|
+
expect(buildAppearanceReferenceFromParams({ baseline: 'figma', refGeom: {}, refColor: {}, refText: {} })).toBeNull();
|
|
1023
|
+
});
|
|
1024
|
+
test('fed into buildStructuralBlock, a color-only reference still emits the color fact', () => {
|
|
1025
|
+
const dump = {
|
|
1026
|
+
canvas: { left: 0, top: 0, right: 686, bottom: 282 },
|
|
1027
|
+
nodes: [
|
|
1028
|
+
{ id: 'banner', bounds: { left: 0, top: 0, right: 686, bottom: 282 }, parentId: null, clipsChildren: false, fillColor: '#1e88e5' },
|
|
1029
|
+
],
|
|
1030
|
+
};
|
|
1031
|
+
const ref = buildAppearanceReferenceFromParams({
|
|
1032
|
+
refColor: { banner: { fill: '#fff0ee' } },
|
|
1033
|
+
baseline: 'previous_render',
|
|
1034
|
+
});
|
|
1035
|
+
const block = buildStructuralBlock(dump, null, 2, undefined, ref);
|
|
1036
|
+
expect(block.appearance?.facts).toEqual([
|
|
1037
|
+
{
|
|
1038
|
+
kind: 'color',
|
|
1039
|
+
elementId: 'banner',
|
|
1040
|
+
channel: 'fill',
|
|
1041
|
+
rendered: '#1e88e5',
|
|
1042
|
+
reference: '#fff0ee',
|
|
1043
|
+
deltaE: ciede2000(hexToLab('#1e88e5'), hexToLab('#fff0ee')),
|
|
1044
|
+
},
|
|
1045
|
+
]);
|
|
1046
|
+
});
|
|
1047
|
+
});
|
|
805
1048
|
describe('embedded geometry stage parity', () => {
|
|
806
1049
|
// The render ships a JS-source port of the differ + assembler. It must produce
|
|
807
1050
|
// byte-identical blocks to the canonical typed module, or run-side structural
|
|
@@ -871,6 +1114,20 @@ describe('embedded geometry stage parity', () => {
|
|
|
871
1114
|
expect(embedded.hexToLab(hex)).toEqual(hexToLab(hex));
|
|
872
1115
|
}
|
|
873
1116
|
});
|
|
1117
|
+
test('embedded buildAppearanceReferenceFromParams matches the module (Signal C, issue 05)', () => {
|
|
1118
|
+
const cases = [
|
|
1119
|
+
{ refColor: { banner: { fill: '#fff0ee' } }, baseline: 'previous_render' },
|
|
1120
|
+
{ refGeom: { banner: { w: 343, h: 96 }, voucher: { w: 81, h: 81 } }, baseline: 'figma' },
|
|
1121
|
+
{ refGeom: { banner: { w: 343 } }, refColor: { banner: { fill: '#fff0ee' } }, baseline: 'figma' },
|
|
1122
|
+
{ refText: { copy: 'Get 5 € off' }, refColor: { banner: { fill: '#fff0ee' } }, baseline: 'previous_render' },
|
|
1123
|
+
{ refGeom: { banner: { w: 1 } }, refText: { copy: 'x' }, refColor: { logo: { fill: '#000000' } }, baseline: 'figma' },
|
|
1124
|
+
{ baseline: 'figma' },
|
|
1125
|
+
{ refGeom: {}, refText: {}, refColor: {}, baseline: 'figma' },
|
|
1126
|
+
];
|
|
1127
|
+
for (const c of cases) {
|
|
1128
|
+
expect(embedded.buildAppearanceReferenceFromParams(c)).toEqual(buildAppearanceReferenceFromParams(c));
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
874
1131
|
test('embedded deriveColorFacts matches the module (Signal C)', () => {
|
|
875
1132
|
const cases = [
|
|
876
1133
|
[{ card: { fill: '#ff0000' } }, { card: { fill: '#ff0000' } }],
|
|
@@ -897,6 +1154,22 @@ describe('embedded geometry stage parity', () => {
|
|
|
897
1154
|
};
|
|
898
1155
|
expect(embedded.buildStructuralBlock(dumpWithColor, null, 2, undefined, appearanceReference)).toEqual(buildStructuralBlock(dumpWithColor, null, 2, undefined, appearanceReference));
|
|
899
1156
|
});
|
|
1157
|
+
test('embedded buildStructuralBlock matches the module for a text-only color drift (issue 02)', () => {
|
|
1158
|
+
// Correct fill + wrong text: the embedded port must emit the same single
|
|
1159
|
+
// text-channel fact (no collapse), matching the typed module exactly.
|
|
1160
|
+
const dumpWithText = {
|
|
1161
|
+
canvas: { left: 0, top: 0, right: 343, bottom: 72 },
|
|
1162
|
+
nodes: [
|
|
1163
|
+
{ id: 'banner', bounds: { left: 0, top: 0, right: 343, bottom: 72 }, parentId: null, clipsChildren: false, fillColor: '#fff0ee', textColor: '#1e88e5' },
|
|
1164
|
+
],
|
|
1165
|
+
};
|
|
1166
|
+
const appearanceReference = {
|
|
1167
|
+
baseline: 'previous_render',
|
|
1168
|
+
elementIds: ['banner'],
|
|
1169
|
+
color: { banner: { fill: '#fff0ee', text: '#1b1b1b' } },
|
|
1170
|
+
};
|
|
1171
|
+
expect(embedded.buildStructuralBlock(dumpWithText, null, 2, undefined, appearanceReference)).toEqual(buildStructuralBlock(dumpWithText, null, 2, undefined, appearanceReference));
|
|
1172
|
+
});
|
|
900
1173
|
const parityCases = [
|
|
901
1174
|
{ name: 'factsOnly', dump: HUB_PROMO_DUMP, ref: null },
|
|
902
1175
|
{ name: 'withGeometry', dump: HUB_PROMO_DUMP, ref: HUB_PROMO_REFERENCE },
|