@calibrate-ds/core 0.1.7 → 0.1.9

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.
Files changed (36) hide show
  1. package/dist/context/get-component-context.d.ts.map +1 -1
  2. package/dist/context/get-component-context.js +16 -7
  3. package/dist/context/get-component-context.js.map +1 -1
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/normalizer/normalize-components.d.ts +1 -1
  9. package/dist/normalizer/normalize-components.d.ts.map +1 -1
  10. package/dist/normalizer/normalize-components.js +12 -5
  11. package/dist/normalizer/normalize-components.js.map +1 -1
  12. package/dist/prompt/generate-component-prompt.d.ts.map +1 -1
  13. package/dist/prompt/generate-component-prompt.js +27 -21
  14. package/dist/prompt/generate-component-prompt.js.map +1 -1
  15. package/dist/scanner/collect-components.d.ts.map +1 -1
  16. package/dist/scanner/collect-components.js +2 -0
  17. package/dist/scanner/collect-components.js.map +1 -1
  18. package/dist/scanner/types.d.ts +2 -0
  19. package/dist/scanner/types.d.ts.map +1 -1
  20. package/dist/verify/fetch-figma-screenshot.d.ts +7 -0
  21. package/dist/verify/fetch-figma-screenshot.d.ts.map +1 -0
  22. package/dist/verify/fetch-figma-screenshot.js +38 -0
  23. package/dist/verify/fetch-figma-screenshot.js.map +1 -0
  24. package/dist/verify/index.d.ts +4 -0
  25. package/dist/verify/index.d.ts.map +1 -0
  26. package/dist/verify/index.js +3 -0
  27. package/dist/verify/index.js.map +1 -0
  28. package/dist/verify/pixel-diff.d.ts +12 -0
  29. package/dist/verify/pixel-diff.d.ts.map +1 -0
  30. package/dist/verify/pixel-diff.js +58 -0
  31. package/dist/verify/pixel-diff.js.map +1 -0
  32. package/dist/verify/types.d.ts +31 -0
  33. package/dist/verify/types.d.ts.map +1 -0
  34. package/dist/verify/types.js +2 -0
  35. package/dist/verify/types.js.map +1 -0
  36. package/package.json +7 -3
@@ -0,0 +1,58 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ /**
4
+ * Compares two PNG files pixel-by-pixel using pixelmatch.
5
+ * Saves an annotated diff image to diffOutputPath.
6
+ * Returns the match score (0–1, 1 = identical), or null if comparison fails.
7
+ *
8
+ * If the images have different dimensions the implementation image is cropped
9
+ * or padded with transparency to match the Figma reference size — this is
10
+ * intentional: the Figma frame size is the authoritative target viewport.
11
+ */
12
+ export async function runPixelDiff(figmaPath, implPath, diffOutputPath) {
13
+ try {
14
+ const { PNG } = await import("pngjs");
15
+ const pixelmatch = (await import("pixelmatch")).default;
16
+ const figmaPng = PNG.sync.read(await fs.readFile(figmaPath));
17
+ let implPng = PNG.sync.read(await fs.readFile(implPath));
18
+ const { width, height } = figmaPng;
19
+ // Align impl to Figma dimensions so pixelmatch can compare.
20
+ if (implPng.width !== width || implPng.height !== height) {
21
+ const aligned = new PNG({ width, height });
22
+ // Fill with white background (matches typical browser default)
23
+ for (let i = 0; i < aligned.data.length; i += 4) {
24
+ aligned.data[i] = 255;
25
+ aligned.data[i + 1] = 255;
26
+ aligned.data[i + 2] = 255;
27
+ aligned.data[i + 3] = 255;
28
+ }
29
+ const copyW = Math.min(width, implPng.width);
30
+ const copyH = Math.min(height, implPng.height);
31
+ for (let y = 0; y < copyH; y++) {
32
+ for (let x = 0; x < copyW; x++) {
33
+ const s = (y * implPng.width + x) * 4;
34
+ const d = (y * width + x) * 4;
35
+ aligned.data[d] = implPng.data[s];
36
+ aligned.data[d + 1] = implPng.data[s + 1];
37
+ aligned.data[d + 2] = implPng.data[s + 2];
38
+ aligned.data[d + 3] = implPng.data[s + 3];
39
+ }
40
+ }
41
+ implPng = aligned;
42
+ }
43
+ const diffPng = new PNG({ width, height });
44
+ const totalPixels = width * height;
45
+ const diffPixels = pixelmatch(figmaPng.data, implPng.data, diffPng.data, width, height, { threshold: 0.1, includeAA: false });
46
+ await fs.mkdir(path.dirname(diffOutputPath), { recursive: true });
47
+ await fs.writeFile(diffOutputPath, PNG.sync.write(diffPng));
48
+ return {
49
+ score: parseFloat((1 - diffPixels / totalPixels).toFixed(4)),
50
+ diffPixels,
51
+ totalPixels,
52
+ };
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ //# sourceMappingURL=pixel-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pixel-diff.js","sourceRoot":"","sources":["../../src/verify/pixel-diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export type VerifyScreenshots = {
2
+ figma: string | null;
3
+ impl: string | null;
4
+ diff: string | null;
5
+ };
6
+ export type PixelMatchResult = {
7
+ score: number;
8
+ diffPixels: number;
9
+ totalPixels: number;
10
+ };
11
+ export type AIDifference = {
12
+ property: string;
13
+ expected: string;
14
+ observed: string;
15
+ };
16
+ export type AIFeedback = {
17
+ summary: string;
18
+ differences: AIDifference[];
19
+ overallAssessment: "matches" | "minor-differences" | "significant-differences";
20
+ };
21
+ export type VerifyReport = {
22
+ componentName: string;
23
+ slug: string;
24
+ checkedAt: string;
25
+ figmaNodeId: string | null;
26
+ screenshots: VerifyScreenshots;
27
+ pixelMatch: PixelMatchResult | null;
28
+ aiFeedback: AIFeedback | null;
29
+ error?: string;
30
+ };
31
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +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,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,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,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/verify/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calibrate-ds/core",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -19,12 +19,16 @@
19
19
  }
20
20
  },
21
21
  "devDependencies": {
22
+ "@types/pixelmatch": "^5.2.6",
23
+ "@types/pngjs": "^6.0.5",
22
24
  "vitest": "^2.0.0"
23
25
  },
24
26
  "dependencies": {
27
+ "pixelmatch": "^6.0.0",
28
+ "pngjs": "^7.0.0",
25
29
  "zod": "^4.3.6",
26
- "@calibrate-ds/shared-types": "^0.1.7",
27
- "@calibrate-ds/figma-client": "^0.1.7"
30
+ "@calibrate-ds/shared-types": "^0.1.9",
31
+ "@calibrate-ds/figma-client": "^0.1.9"
28
32
  },
29
33
  "scripts": {
30
34
  "build": "tsc -p tsconfig.json",