@calibrate-ds/core 0.1.41 → 0.1.42

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.
@@ -1,4 +1,5 @@
1
- export type { VerifyReport, VerifyScreenshots, PixelMatchResult, AIFeedback, AIDifference, } from "./types.js";
1
+ export type { VerifyReport, VerifyScreenshots, PixelMatchResult, AIFeedback, AIDifference, StructureExpectations, StructureFound, } from "./types.js";
2
2
  export { fetchFigmaScreenshot } from "./fetch-figma-screenshot.js";
3
3
  export { runPixelDiff } from "./pixel-diff.js";
4
+ export { extractStructuralExpectations, computeStructureScore } from "./structure-check.js";
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/verify/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACR,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,YAAY,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/verify/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACR,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,qBAAqB,EACrB,cAAc,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export { fetchFigmaScreenshot } from "./fetch-figma-screenshot.js";
2
2
  export { runPixelDiff } from "./pixel-diff.js";
3
+ export { extractStructuralExpectations, computeStructureScore } from "./structure-check.js";
3
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/verify/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/verify/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { StructureExpectations, StructureFound } from "./types.js";
2
+ /**
3
+ * Walks a LayoutTreeNode tree (children only, not childOverrides which are
4
+ * variant branches) and counts structural slot types that must be present
5
+ * in the rendered DOM for a faithful implementation.
6
+ */
7
+ export declare function extractStructuralExpectations(renderTree: any): StructureExpectations;
8
+ /**
9
+ * Returns a 0–1 structure score — the fraction of expected structural slots
10
+ * that are present and non-empty in the rendered DOM.
11
+ *
12
+ * Returns undefined when there are no trackable slots (e.g. icon components),
13
+ * signalling the caller to fall back to the pixel score.
14
+ *
15
+ * Scoring weights:
16
+ * - text slots: 70% of the total (more numerous and meaningful)
17
+ * - image slots: 30% (binary — either the <img> exists or it doesn't)
18
+ * When only one slot type is present its weight becomes 100%.
19
+ */
20
+ export declare function computeStructureScore(exp: StructureExpectations, found: StructureFound): number | undefined;
21
+ //# sourceMappingURL=structure-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structure-check.d.ts","sourceRoot":"","sources":["../../src/verify/structure-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAExE;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,GAAG,GAAG,qBAAqB,CA8BpF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACjC,GAAG,EAAE,qBAAqB,EAC1B,KAAK,EAAE,cAAc,GACtB,MAAM,GAAG,SAAS,CAqBpB"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Walks a LayoutTreeNode tree (children only, not childOverrides which are
3
+ * variant branches) and counts structural slot types that must be present
4
+ * in the rendered DOM for a faithful implementation.
5
+ */
6
+ export function extractStructuralExpectations(renderTree) {
7
+ let textSlots = 0;
8
+ let imageSlots = 0;
9
+ const TEXT_ROLES = new Set([
10
+ "text", "title", "label", "description",
11
+ "placeholder-text", "error-text", "helper-text",
12
+ ]);
13
+ function walk(node) {
14
+ if (!node)
15
+ return;
16
+ const isTextByRole = TEXT_ROLES.has(node.role ?? "");
17
+ const isTextByType = node.rawStyles?.nodeType === "TEXT";
18
+ const isTextByValue = node.textContent !== undefined && node.type === "leaf";
19
+ if (isTextByRole || isTextByType || isTextByValue) {
20
+ textSlots++;
21
+ }
22
+ if (node.imageAssetPath) {
23
+ imageSlots++;
24
+ }
25
+ for (const child of node.children ?? [])
26
+ walk(child);
27
+ // intentionally skip childOverrides — those are variant branches, not distinct slots
28
+ }
29
+ walk(renderTree);
30
+ return { textSlots, imageSlots };
31
+ }
32
+ /**
33
+ * Returns a 0–1 structure score — the fraction of expected structural slots
34
+ * that are present and non-empty in the rendered DOM.
35
+ *
36
+ * Returns undefined when there are no trackable slots (e.g. icon components),
37
+ * signalling the caller to fall back to the pixel score.
38
+ *
39
+ * Scoring weights:
40
+ * - text slots: 70% of the total (more numerous and meaningful)
41
+ * - image slots: 30% (binary — either the <img> exists or it doesn't)
42
+ * When only one slot type is present its weight becomes 100%.
43
+ */
44
+ export function computeStructureScore(exp, found) {
45
+ const hasText = exp.textSlots > 0;
46
+ const hasImage = exp.imageSlots > 0;
47
+ if (!hasText && !hasImage)
48
+ return undefined;
49
+ const parts = [];
50
+ if (hasText) {
51
+ // Partial credit: having MORE text nodes than expected is fine (min cap at 1).
52
+ // A rendered component that has all slots is worth 1; each missing slot reduces.
53
+ parts.push({ value: Math.min(1, found.textNodes / exp.textSlots), weight: 0.7 });
54
+ }
55
+ if (hasImage) {
56
+ // Binary: either the image region is rendered or it isn't.
57
+ parts.push({ value: found.imageElements > 0 ? 1 : 0, weight: 0.3 });
58
+ }
59
+ const totalWeight = parts.reduce((s, p) => s + p.weight, 0);
60
+ const weighted = parts.reduce((s, p) => s + p.value * p.weight, 0);
61
+ return parseFloat((weighted / totalWeight).toFixed(4));
62
+ }
63
+ //# sourceMappingURL=structure-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structure-check.js","sourceRoot":"","sources":["../../src/verify/structure-check.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,UAAe;IACzD,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;QACvB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa;QACvC,kBAAkB,EAAE,YAAY,EAAE,aAAa;KAClD,CAAC,CAAC;IAEH,SAAS,IAAI,CAAC,IAAS;QACnB,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,MAAM,YAAY,GAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QACtD,MAAM,YAAY,GAAI,IAAI,CAAC,SAAS,EAAE,QAAQ,KAAK,MAAM,CAAC;QAC1D,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;QAE7E,IAAI,YAAY,IAAI,YAAY,IAAI,aAAa,EAAE,CAAC;YAChD,SAAS,EAAE,CAAC;QAChB,CAAC;QAED,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACtB,UAAU,EAAE,CAAC;QACjB,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE;YAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACrD,qFAAqF;IACzF,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,CAAC;IACjB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACjC,GAA0B,EAC1B,KAAqB;IAErB,MAAM,OAAO,GAAI,GAAG,CAAC,SAAS,GAAI,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC;IAEpC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAE5C,MAAM,KAAK,GAA6C,EAAE,CAAC;IAE3D,IAAI,OAAO,EAAE,CAAC;QACV,+EAA+E;QAC/E,iFAAiF;QACjF,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,QAAQ,EAAE,CAAC;QACX,2DAA2D;QAC3D,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAM,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACtE,OAAO,UAAU,CAAC,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC"}
@@ -5,6 +5,18 @@ export type VerifyScreenshots = {
5
5
  impl: string | null;
6
6
  diff: string | null;
7
7
  };
8
+ export type StructureExpectations = {
9
+ /** Number of text-type leaf slots detected in the Figma renderTree. */
10
+ textSlots: number;
11
+ /** Number of image-fill slots detected in the Figma renderTree. */
12
+ imageSlots: number;
13
+ };
14
+ export type StructureFound = {
15
+ /** Non-empty leaf text elements in the rendered DOM. */
16
+ textNodes: number;
17
+ /** <img> elements + elements with a background-image CSS value. */
18
+ imageElements: number;
19
+ };
8
20
  export type PixelMatchResult = {
9
21
  /** Full-frame raw pixel match score (0–1, 1 = identical). */
10
22
  score: number;
@@ -43,5 +55,16 @@ export type VerifyReport = {
43
55
  resolvedStoryId?: string;
44
56
  /** Human-readable error when resolved=false. */
45
57
  error?: string;
58
+ /**
59
+ * Structural slot presence score (0–1). Measures whether the expected number
60
+ * of text and image regions from the Figma renderTree are rendered in the DOM —
61
+ * independent of what text is actually shown (props are dynamic).
62
+ * Undefined for components with no trackable slots (e.g. icons).
63
+ */
64
+ structureScore?: number;
65
+ /** Slot counts extracted from the Figma renderTree. */
66
+ structureExpectations?: StructureExpectations;
67
+ /** Slot counts found in the rendered Storybook DOM. */
68
+ structureFound?: StructureFound;
46
69
  };
47
70
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/verify/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,yFAAyF;IACzF,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IACzC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC3B,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B,iBAAiB,EAAE,SAAS,GAAG,mBAAmB,GAAG,yBAAyB,CAAC;CAClF,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,iBAAiB,CAAC;IAC/B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,qFAAqF;IACrF,QAAQ,EAAE,OAAO,CAAC;IAClB,gGAAgG;IAChG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/verify/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,yFAAyF;IACzF,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IACzC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAChC,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IACzB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,aAAa,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC3B,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B,iBAAiB,EAAE,SAAS,GAAG,mBAAmB,GAAG,yBAAyB,CAAC;CAClF,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,iBAAiB,CAAC;IAC/B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,qFAAqF;IACrF,QAAQ,EAAE,OAAO,CAAC;IAClB,gGAAgG;IAChG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,uDAAuD;IACvD,cAAc,CAAC,EAAE,cAAc,CAAC;CACnC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calibrate-ds/core",
3
- "version": "0.1.41",
3
+ "version": "0.1.42",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -27,8 +27,8 @@
27
27
  "pixelmatch": "^6.0.0",
28
28
  "pngjs": "^7.0.0",
29
29
  "zod": "^4.3.6",
30
- "@calibrate-ds/shared-types": "^0.1.41",
31
- "@calibrate-ds/figma-client": "^0.1.41"
30
+ "@calibrate-ds/shared-types": "^0.1.42",
31
+ "@calibrate-ds/figma-client": "^0.1.42"
32
32
  },
33
33
  "scripts": {
34
34
  "build": "tsc -p tsconfig.json",