@calibrate-ds/core 0.1.85 → 0.1.87
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 +108 -200
- package/NOTICE +19 -0
- package/dist/config/config-schema.d.ts +2 -2
- package/dist/doctor/check-config.js +27 -0
- package/dist/tokens/build-token-model.js +16 -0
- package/dist/tokens/normalize-token-collections.js +52 -17
- package/dist/verify/pixel-diff.js +51 -2
- package/dist/verify/types.d.ts +10 -0
- package/dist/verify/verdict.d.ts +8 -0
- package/dist/verify/verdict.js +23 -0
- package/package.json +9 -6
- package/dist/__tests__/check-component.test.d.ts.map +0 -1
- package/dist/__tests__/check-component.test.js.map +0 -1
- package/dist/__tests__/compare-components.test.d.ts.map +0 -1
- package/dist/__tests__/compare-components.test.js.map +0 -1
- package/dist/__tests__/compare-tokens.test.d.ts.map +0 -1
- package/dist/__tests__/compare-tokens.test.js.map +0 -1
- package/dist/__tests__/get-component-context.test.d.ts.map +0 -1
- package/dist/__tests__/get-component-context.test.js.map +0 -1
- package/dist/__tests__/naming-strategy.test.d.ts.map +0 -1
- package/dist/__tests__/naming-strategy.test.js.map +0 -1
- package/dist/__tests__/token-resolution.test.d.ts.map +0 -1
- package/dist/__tests__/token-resolution.test.js.map +0 -1
- package/dist/ai/index.d.ts.map +0 -1
- package/dist/ai/index.js.map +0 -1
- package/dist/ai/provider.d.ts.map +0 -1
- package/dist/ai/provider.js.map +0 -1
- package/dist/ai/resolve-provider.d.ts.map +0 -1
- package/dist/ai/resolve-provider.js.map +0 -1
- package/dist/bootstrap/generate-library-files.d.ts.map +0 -1
- package/dist/bootstrap/generate-library-files.js.map +0 -1
- package/dist/bootstrap/index.d.ts.map +0 -1
- package/dist/bootstrap/index.js.map +0 -1
- package/dist/bootstrap/types.d.ts.map +0 -1
- package/dist/bootstrap/types.js.map +0 -1
- package/dist/bootstrap/write-library-bootstrap.d.ts.map +0 -1
- package/dist/bootstrap/write-library-bootstrap.js.map +0 -1
- package/dist/config/config-schema.d.ts.map +0 -1
- package/dist/config/config-schema.js.map +0 -1
- package/dist/config/credentials.d.ts.map +0 -1
- package/dist/config/credentials.js.map +0 -1
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/index.js.map +0 -1
- package/dist/config/load-config.d.ts.map +0 -1
- package/dist/config/load-config.js.map +0 -1
- package/dist/context/compressed-context.d.ts.map +0 -1
- package/dist/context/compressed-context.js.map +0 -1
- package/dist/context/context-index.d.ts.map +0 -1
- package/dist/context/context-index.js.map +0 -1
- package/dist/context/export-context.d.ts.map +0 -1
- package/dist/context/export-context.js.map +0 -1
- package/dist/context/get-component-context.d.ts.map +0 -1
- package/dist/context/get-component-context.js.map +0 -1
- package/dist/context/hashing.d.ts.map +0 -1
- package/dist/context/hashing.js.map +0 -1
- package/dist/context/metadata-extraction.d.ts.map +0 -1
- package/dist/context/metadata-extraction.js.map +0 -1
- package/dist/design-tool/figma-adapter.d.ts.map +0 -1
- package/dist/design-tool/figma-adapter.js.map +0 -1
- package/dist/design-tool/index.d.ts.map +0 -1
- package/dist/design-tool/index.js.map +0 -1
- package/dist/design-tool/registry.d.ts.map +0 -1
- package/dist/design-tool/registry.js.map +0 -1
- package/dist/design-tool/types.d.ts.map +0 -1
- package/dist/design-tool/types.js.map +0 -1
- package/dist/diff/compare-components.d.ts.map +0 -1
- package/dist/diff/compare-components.js.map +0 -1
- package/dist/diff/compare-dependencies.d.ts.map +0 -1
- package/dist/diff/compare-dependencies.js.map +0 -1
- package/dist/diff/compare-tokens.d.ts.map +0 -1
- package/dist/diff/compare-tokens.js.map +0 -1
- package/dist/diff/compute-design-diff.d.ts.map +0 -1
- package/dist/diff/compute-design-diff.js.map +0 -1
- package/dist/diff/format-diff-summary.d.ts.map +0 -1
- package/dist/diff/format-diff-summary.js.map +0 -1
- package/dist/diff/index.d.ts.map +0 -1
- package/dist/diff/index.js.map +0 -1
- package/dist/diff/resolve-design-diff.d.ts.map +0 -1
- package/dist/diff/resolve-design-diff.js.map +0 -1
- package/dist/docs/generate-component-doc.d.ts.map +0 -1
- package/dist/docs/generate-component-doc.js.map +0 -1
- package/dist/docs/generate-component-stories.d.ts.map +0 -1
- package/dist/docs/generate-component-stories.js.map +0 -1
- package/dist/docs/generate-system-doc.d.ts.map +0 -1
- package/dist/docs/generate-system-doc.js.map +0 -1
- package/dist/docs/index.d.ts.map +0 -1
- package/dist/docs/index.js.map +0 -1
- package/dist/docs/setup-storybook.d.ts.map +0 -1
- package/dist/docs/setup-storybook.js.map +0 -1
- package/dist/doctor/check-component.d.ts.map +0 -1
- package/dist/doctor/check-component.js.map +0 -1
- package/dist/doctor/check-config.d.ts.map +0 -1
- package/dist/doctor/check-config.js.map +0 -1
- package/dist/doctor/check-tokens.d.ts.map +0 -1
- package/dist/doctor/check-tokens.js.map +0 -1
- package/dist/doctor/index.d.ts.map +0 -1
- package/dist/doctor/index.js.map +0 -1
- package/dist/doctor/types.d.ts.map +0 -1
- package/dist/doctor/types.js.map +0 -1
- package/dist/filesystem/ensure-dir.d.ts.map +0 -1
- package/dist/filesystem/ensure-dir.js.map +0 -1
- package/dist/filesystem/index.d.ts.map +0 -1
- package/dist/filesystem/index.js.map +0 -1
- package/dist/filesystem/prune-stale-components.d.ts.map +0 -1
- package/dist/filesystem/prune-stale-components.js.map +0 -1
- package/dist/filesystem/resolve-component-path.d.ts.map +0 -1
- package/dist/filesystem/resolve-component-path.js.map +0 -1
- package/dist/filesystem/resolve-ds-paths.d.ts.map +0 -1
- package/dist/filesystem/resolve-ds-paths.js.map +0 -1
- package/dist/filesystem/workspace-root.d.ts.map +0 -1
- package/dist/filesystem/workspace-root.js.map +0 -1
- package/dist/filesystem/write-json.d.ts.map +0 -1
- package/dist/filesystem/write-json.js.map +0 -1
- package/dist/filesystem/write-text.d.ts.map +0 -1
- package/dist/filesystem/write-text.js.map +0 -1
- package/dist/generators/components/generate-component-css.d.ts.map +0 -1
- package/dist/generators/components/generate-component-css.js.map +0 -1
- package/dist/generators/components/generate-component-file.d.ts.map +0 -1
- package/dist/generators/components/generate-component-file.js.map +0 -1
- package/dist/generators/components/generate-composite-file.d.ts.map +0 -1
- package/dist/generators/components/generate-composite-file.js.map +0 -1
- package/dist/generators/components/generate-composite-types.d.ts.map +0 -1
- package/dist/generators/components/generate-composite-types.js.map +0 -1
- package/dist/generators/components/generate-types-file.d.ts.map +0 -1
- package/dist/generators/components/generate-types-file.js.map +0 -1
- package/dist/generators/components/helpers.d.ts.map +0 -1
- package/dist/generators/components/helpers.js.map +0 -1
- package/dist/generators/components/index.d.ts.map +0 -1
- package/dist/generators/components/index.js.map +0 -1
- package/dist/generators/components/layout-jsx.d.ts.map +0 -1
- package/dist/generators/components/layout-jsx.js.map +0 -1
- package/dist/generators/components/prune-components.d.ts.map +0 -1
- package/dist/generators/components/prune-components.js.map +0 -1
- package/dist/generators/components/token-helpers.d.ts.map +0 -1
- package/dist/generators/components/token-helpers.js.map +0 -1
- package/dist/generators/components/write-components.d.ts.map +0 -1
- package/dist/generators/components/write-components.js.map +0 -1
- package/dist/generators/components/write-composites.d.ts.map +0 -1
- package/dist/generators/components/write-composites.js.map +0 -1
- package/dist/generators/composites/generate-composite-file.d.ts.map +0 -1
- package/dist/generators/composites/generate-composite-file.js.map +0 -1
- package/dist/generators/composites/generate-composite-types.d.ts.map +0 -1
- package/dist/generators/composites/generate-composite-types.js.map +0 -1
- package/dist/generators/composites/index.d.ts.map +0 -1
- package/dist/generators/composites/index.js.map +0 -1
- package/dist/generators/composites/write-composites.d.ts.map +0 -1
- package/dist/generators/composites/write-composites.js.map +0 -1
- package/dist/generators/registry.d.ts.map +0 -1
- package/dist/generators/registry.js.map +0 -1
- package/dist/generators/scaffold/generate-placeholder-component-content.d.ts.map +0 -1
- package/dist/generators/scaffold/generate-placeholder-component-content.js.map +0 -1
- package/dist/generators/scaffold/index.d.ts.map +0 -1
- package/dist/generators/scaffold/index.js.map +0 -1
- package/dist/generators/scaffold/write-scaffold.d.ts.map +0 -1
- package/dist/generators/scaffold/write-scaffold.js.map +0 -1
- package/dist/generators/tokens/generate-token-css.d.ts.map +0 -1
- package/dist/generators/tokens/generate-token-css.js.map +0 -1
- package/dist/generators/tokens/generate-token-file-content.d.ts.map +0 -1
- package/dist/generators/tokens/generate-token-file-content.js.map +0 -1
- package/dist/generators/tokens/index.d.ts.map +0 -1
- package/dist/generators/tokens/index.js.map +0 -1
- package/dist/generators/tokens/write-tokens.d.ts.map +0 -1
- package/dist/generators/tokens/write-tokens.js.map +0 -1
- package/dist/generators/types.d.ts.map +0 -1
- package/dist/generators/types.js.map +0 -1
- package/dist/icons/enrich-bitmap-assets.d.ts.map +0 -1
- package/dist/icons/enrich-bitmap-assets.js.map +0 -1
- package/dist/icons/enrich-icon-svgs.d.ts.map +0 -1
- package/dist/icons/enrich-icon-svgs.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/manifest/index.d.ts.map +0 -1
- package/dist/manifest/index.js.map +0 -1
- package/dist/mappings/build-file-mappings.d.ts.map +0 -1
- package/dist/mappings/build-file-mappings.js.map +0 -1
- package/dist/mappings/index.d.ts.map +0 -1
- package/dist/mappings/index.js.map +0 -1
- package/dist/mappings/naming-strategy.d.ts.map +0 -1
- package/dist/mappings/naming-strategy.js.map +0 -1
- package/dist/model/build-design-system-model.d.ts.map +0 -1
- package/dist/model/build-design-system-model.js.map +0 -1
- package/dist/model/index.d.ts.map +0 -1
- package/dist/model/index.js.map +0 -1
- package/dist/model/resolve-component.d.ts.map +0 -1
- package/dist/model/resolve-component.js.map +0 -1
- package/dist/normalizer/classify-entities.d.ts.map +0 -1
- package/dist/normalizer/classify-entities.js.map +0 -1
- package/dist/normalizer/classify-group-intent.d.ts.map +0 -1
- package/dist/normalizer/classify-group-intent.js.map +0 -1
- package/dist/normalizer/helpers.d.ts.map +0 -1
- package/dist/normalizer/helpers.js.map +0 -1
- package/dist/normalizer/index.d.ts.map +0 -1
- package/dist/normalizer/index.js.map +0 -1
- package/dist/normalizer/instance-resolver.d.ts.map +0 -1
- package/dist/normalizer/instance-resolver.js.map +0 -1
- package/dist/normalizer/layout-tree.d.ts.map +0 -1
- package/dist/normalizer/layout-tree.js.map +0 -1
- package/dist/normalizer/naming.d.ts.map +0 -1
- package/dist/normalizer/naming.js.map +0 -1
- package/dist/normalizer/normalize-components.d.ts.map +0 -1
- package/dist/normalizer/normalize-components.js.map +0 -1
- package/dist/normalizer/normalize-composites.d.ts.map +0 -1
- package/dist/normalizer/normalize-composites.js.map +0 -1
- package/dist/normalizer/normalize-instances.d.ts.map +0 -1
- package/dist/normalizer/normalize-instances.js.map +0 -1
- package/dist/normalizer/sanitize-property-names.d.ts.map +0 -1
- package/dist/normalizer/sanitize-property-names.js.map +0 -1
- package/dist/normalizer/types.d.ts.map +0 -1
- package/dist/normalizer/types.js.map +0 -1
- package/dist/normalizer/variant-diff.d.ts.map +0 -1
- package/dist/normalizer/variant-diff.js.map +0 -1
- package/dist/plan/implementation-plan.d.ts.map +0 -1
- package/dist/plan/implementation-plan.js.map +0 -1
- package/dist/plan/index.d.ts.map +0 -1
- package/dist/plan/index.js.map +0 -1
- package/dist/plan/resolve-affected-files.d.ts.map +0 -1
- package/dist/plan/resolve-affected-files.js.map +0 -1
- package/dist/playground/scaffold-playground.d.ts.map +0 -1
- package/dist/playground/scaffold-playground.js.map +0 -1
- package/dist/prompt/generate-component-prompt.d.ts.map +0 -1
- package/dist/prompt/generate-component-prompt.js.map +0 -1
- package/dist/registry/ai-provider-registry.d.ts.map +0 -1
- package/dist/registry/ai-provider-registry.js.map +0 -1
- package/dist/registry/build-component-registry.d.ts.map +0 -1
- package/dist/registry/build-component-registry.js.map +0 -1
- package/dist/registry/build-dependency-graph.d.ts.map +0 -1
- package/dist/registry/build-dependency-graph.js.map +0 -1
- package/dist/registry/generator-registry.d.ts.map +0 -1
- package/dist/registry/generator-registry.js.map +0 -1
- package/dist/registry/index.d.ts.map +0 -1
- package/dist/registry/index.js.map +0 -1
- package/dist/scaffold-plan/build-scaffold-plan.d.ts.map +0 -1
- package/dist/scaffold-plan/build-scaffold-plan.js.map +0 -1
- package/dist/scaffold-plan/index.d.ts.map +0 -1
- package/dist/scaffold-plan/index.js.map +0 -1
- package/dist/scanner/collect-components.d.ts.map +0 -1
- package/dist/scanner/collect-components.js.map +0 -1
- package/dist/scanner/collect-instances.d.ts.map +0 -1
- package/dist/scanner/collect-instances.js.map +0 -1
- package/dist/scanner/index.d.ts.map +0 -1
- package/dist/scanner/index.js.map +0 -1
- package/dist/scanner/scan-file.d.ts.map +0 -1
- package/dist/scanner/scan-file.js.map +0 -1
- package/dist/scanner/traverse-nodes.d.ts.map +0 -1
- package/dist/scanner/traverse-nodes.js.map +0 -1
- package/dist/scanner/types.d.ts.map +0 -1
- package/dist/scanner/types.js.map +0 -1
- package/dist/snapshots/clear-diff-baseline.d.ts.map +0 -1
- package/dist/snapshots/clear-diff-baseline.js.map +0 -1
- package/dist/snapshots/index.d.ts.map +0 -1
- package/dist/snapshots/index.js.map +0 -1
- package/dist/snapshots/load-imported-tokens.d.ts.map +0 -1
- package/dist/snapshots/load-imported-tokens.js.map +0 -1
- package/dist/snapshots/load-latest-snapshot.d.ts.map +0 -1
- package/dist/snapshots/load-latest-snapshot.js.map +0 -1
- package/dist/snapshots/load-previous-snapshot.d.ts.map +0 -1
- package/dist/snapshots/load-previous-snapshot.js.map +0 -1
- package/dist/snapshots/sanitize-model.d.ts.map +0 -1
- package/dist/snapshots/sanitize-model.js.map +0 -1
- package/dist/snapshots/save-imported-tokens.d.ts.map +0 -1
- package/dist/snapshots/save-imported-tokens.js.map +0 -1
- package/dist/snapshots/save-snapshot.d.ts.map +0 -1
- package/dist/snapshots/save-snapshot.js.map +0 -1
- package/dist/test-null-safety.d.ts.map +0 -1
- package/dist/test-null-safety.js.map +0 -1
- package/dist/test-regex.d.ts.map +0 -1
- package/dist/test-regex.js.map +0 -1
- package/dist/test-token-resolution.d.ts.map +0 -1
- package/dist/test-token-resolution.js.map +0 -1
- package/dist/test-typography.d.ts.map +0 -1
- package/dist/test-typography.js.map +0 -1
- package/dist/thumbnails/enrich-thumbnails.d.ts.map +0 -1
- package/dist/thumbnails/enrich-thumbnails.js.map +0 -1
- package/dist/tokens/adapters/generic-adapter.d.ts.map +0 -1
- package/dist/tokens/adapters/generic-adapter.js.map +0 -1
- package/dist/tokens/adapters/index.d.ts.map +0 -1
- package/dist/tokens/adapters/index.js.map +0 -1
- package/dist/tokens/adapters/ptb-adapter.d.ts.map +0 -1
- package/dist/tokens/adapters/ptb-adapter.js.map +0 -1
- package/dist/tokens/build-token-model.d.ts.map +0 -1
- package/dist/tokens/build-token-model.js.map +0 -1
- package/dist/tokens/classify-token-kind.d.ts.map +0 -1
- package/dist/tokens/classify-token-kind.js.map +0 -1
- package/dist/tokens/detect-format.d.ts.map +0 -1
- package/dist/tokens/detect-format.js.map +0 -1
- package/dist/tokens/import-schema.d.ts.map +0 -1
- package/dist/tokens/import-schema.js.map +0 -1
- package/dist/tokens/import-tokens.d.ts.map +0 -1
- package/dist/tokens/import-tokens.js.map +0 -1
- package/dist/tokens/index.d.ts.map +0 -1
- package/dist/tokens/index.js.map +0 -1
- package/dist/tokens/naming.d.ts.map +0 -1
- package/dist/tokens/naming.js.map +0 -1
- package/dist/tokens/normalize-token-collections.d.ts.map +0 -1
- package/dist/tokens/normalize-token-collections.js.map +0 -1
- package/dist/tokens/resolution.d.ts.map +0 -1
- package/dist/tokens/resolution.js.map +0 -1
- package/dist/tokens/resolve-token-source.d.ts.map +0 -1
- package/dist/tokens/resolve-token-source.js.map +0 -1
- package/dist/tokens/types.d.ts.map +0 -1
- package/dist/tokens/types.js.map +0 -1
- package/dist/verify/fetch-figma-screenshot.d.ts.map +0 -1
- package/dist/verify/fetch-figma-screenshot.js.map +0 -1
- package/dist/verify/index.d.ts.map +0 -1
- package/dist/verify/index.js.map +0 -1
- package/dist/verify/pixel-diff.d.ts.map +0 -1
- package/dist/verify/pixel-diff.js.map +0 -1
- package/dist/verify/structure-check.d.ts.map +0 -1
- package/dist/verify/structure-check.js.map +0 -1
- package/dist/verify/types.d.ts.map +0 -1
- package/dist/verify/types.js.map +0 -1
- package/dist/verify/verdict.d.ts.map +0 -1
- package/dist/verify/verdict.js.map +0 -1
package/LICENSE
CHANGED
|
@@ -1,201 +1,109 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, MIT Future License
|
|
1
2
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
include a readable copy of the attribution notices contained
|
|
110
|
-
within such NOTICE file, excluding any notices that do not
|
|
111
|
-
pertain to any part of the Derivative Works, in at least one
|
|
112
|
-
of the following places: within a NOTICE text file distributed
|
|
113
|
-
as part of the Derivative Works; within the Source form or
|
|
114
|
-
documentation, if provided along with the Derivative Works; or,
|
|
115
|
-
within a display generated by the Derivative Works, if and
|
|
116
|
-
wherever such third-party notices normally appear. The contents
|
|
117
|
-
of the NOTICE file are for informational purposes only and
|
|
118
|
-
do not modify the License. You may add Your own attribution
|
|
119
|
-
notices within Derivative Works that You distribute, alongside
|
|
120
|
-
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
-
that such additional attribution notices cannot be construed
|
|
122
|
-
as modifying the License.
|
|
123
|
-
|
|
124
|
-
You may add Your own copyright statement to Your modifications and
|
|
125
|
-
may provide additional or different license terms and conditions
|
|
126
|
-
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
-
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
-
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
-
the conditions stated in this License.
|
|
130
|
-
|
|
131
|
-
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
-
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
-
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
-
this License, without any additional terms or conditions.
|
|
135
|
-
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
-
the terms of any separate license agreement you may have executed
|
|
137
|
-
with Licensor regarding such Contributions.
|
|
138
|
-
|
|
139
|
-
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
-
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
-
except as required for reasonable and customary use in describing the
|
|
142
|
-
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
-
|
|
144
|
-
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
-
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
-
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
-
implied, including, without limitation, any warranties or conditions
|
|
149
|
-
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
-
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
-
appropriateness of using or redistributing the Work and assume any
|
|
152
|
-
risks associated with Your exercise of permissions under this License.
|
|
153
|
-
|
|
154
|
-
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
-
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
-
unless required by applicable law (such as deliberate and grossly
|
|
157
|
-
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
-
liable to You for damages, including any direct, indirect, special,
|
|
159
|
-
incidental, or consequential damages of any character arising as a
|
|
160
|
-
result of this License or out of the use or inability to use the
|
|
161
|
-
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
-
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
-
other commercial damages or losses), even if such Contributor
|
|
164
|
-
has been advised of the possibility of such damages.
|
|
165
|
-
|
|
166
|
-
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
-
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
-
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
-
or other liability obligations and/or rights consistent with this
|
|
170
|
-
License. However, in accepting such obligations, You may act only
|
|
171
|
-
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
-
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
-
defend, and hold each Contributor harmless for any liability
|
|
174
|
-
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
-
of your accepting any such warranty or additional liability.
|
|
176
|
-
|
|
177
|
-
END OF TERMS AND CONDITIONS
|
|
178
|
-
|
|
179
|
-
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
-
|
|
181
|
-
To apply the Apache License to your work, attach the following
|
|
182
|
-
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
-
replaced with your own identifying information. (Don't include
|
|
184
|
-
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
-
comment syntax for the file format. Please also get an
|
|
186
|
-
"Alarm or alarm@" e-mail address from Apache to receive
|
|
187
|
-
notifications of activity on this work.
|
|
188
|
-
|
|
189
|
-
Copyright 2025 Deep Adalja
|
|
190
|
-
|
|
191
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
-
you may not use this file except in compliance with the License.
|
|
193
|
-
You may obtain a copy of the License at
|
|
194
|
-
|
|
195
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
-
|
|
197
|
-
Unless required by applicable law or agreed to in writing, software
|
|
198
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
-
See the License for the specific language governing permissions and
|
|
201
|
-
limitations under the License.
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-MIT
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 Deep Adalja
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to use,
|
|
27
|
+
copy, modify, create derivative works, publicly perform, publicly display and
|
|
28
|
+
redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or service
|
|
34
|
+
that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software that
|
|
39
|
+
exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee using
|
|
52
|
+
the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to the
|
|
59
|
+
infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software, you
|
|
68
|
+
must include a copy of or a link to these Terms and Conditions and not remove any
|
|
69
|
+
copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
75
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, EVEN
|
|
79
|
+
IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of the
|
|
84
|
+
Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the MIT License that is effective on the second anniversary of the date we make
|
|
91
|
+
the Software available. On or after that date, you may use the Software under the
|
|
92
|
+
MIT License, in which case the following will apply:
|
|
93
|
+
|
|
94
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
95
|
+
the Software and associated documentation files (the "Software"), to deal in the
|
|
96
|
+
Software without restriction, including without limitation the rights to use,
|
|
97
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
|
98
|
+
Software, and to permit persons to whom the Software is furnished to do so,
|
|
99
|
+
subject to the following conditions:
|
|
100
|
+
|
|
101
|
+
The above copyright notice and this permission notice shall be included in all
|
|
102
|
+
copies or substantial portions of the Software.
|
|
103
|
+
|
|
104
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
105
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
106
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
107
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
108
|
+
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
109
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Calibrate / PTB (@calibrate-ds)
|
|
2
|
+
Copyright 2026 Deep Adalja
|
|
3
|
+
|
|
4
|
+
## License
|
|
5
|
+
|
|
6
|
+
As of version 0.1.87, this software is licensed under the
|
|
7
|
+
Functional Source License, Version 1.1, MIT Future License (FSL-1.1-MIT).
|
|
8
|
+
See the LICENSE file for the full text.
|
|
9
|
+
|
|
10
|
+
In short: you may read, use, copy, modify, and redistribute this software for
|
|
11
|
+
any purpose EXCEPT offering a competing commercial product or service. Two years
|
|
12
|
+
after each version is published, that version additionally becomes available
|
|
13
|
+
under the MIT License.
|
|
14
|
+
|
|
15
|
+
## Prior versions
|
|
16
|
+
|
|
17
|
+
Versions 0.1.0 through 0.1.86 were released under the Apache License, Version 2.0,
|
|
18
|
+
and remain available under that license. The license change applies only to
|
|
19
|
+
version 0.1.87 and later.
|
|
@@ -57,9 +57,9 @@ export declare const AIConfigSchema: z.ZodPipe<z.ZodTransform<any, any>, z.ZodOb
|
|
|
57
57
|
}, z.core.$strip>>;
|
|
58
58
|
export declare const DocsConfigSchema: z.ZodObject<{
|
|
59
59
|
tool: z.ZodEnum<{
|
|
60
|
-
none: "none";
|
|
61
60
|
storybook: "storybook";
|
|
62
61
|
docusaurus: "docusaurus";
|
|
62
|
+
none: "none";
|
|
63
63
|
}>;
|
|
64
64
|
}, z.core.$strip>;
|
|
65
65
|
export declare const ScanConfigSchema: z.ZodObject<{
|
|
@@ -127,9 +127,9 @@ export declare const PTBConfigSchema: z.ZodPipe<z.ZodTransform<any, any>, z.ZodO
|
|
|
127
127
|
}, z.core.$strip>>>;
|
|
128
128
|
docs: z.ZodOptional<z.ZodObject<{
|
|
129
129
|
tool: z.ZodEnum<{
|
|
130
|
-
none: "none";
|
|
131
130
|
storybook: "storybook";
|
|
132
131
|
docusaurus: "docusaurus";
|
|
132
|
+
none: "none";
|
|
133
133
|
}>;
|
|
134
134
|
}, z.core.$strip>>;
|
|
135
135
|
scan: z.ZodOptional<z.ZodObject<{
|
|
@@ -62,6 +62,33 @@ export async function checkConfig(config) {
|
|
|
62
62
|
suggestion: "Run ptb scan to fetch and save the design system from Figma",
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
|
+
// B-3: when the project is configured for Storybook, verify its config actually
|
|
66
|
+
// exists. `storybook init` can exit 0 without writing .storybook/main.* (its
|
|
67
|
+
// interactive builder prompt gets skipped non-interactively), leaving a
|
|
68
|
+
// "storybook dev" script that fails — and verify needs Storybook. Surface it
|
|
69
|
+
// here so `ptb doctor` catches the broken funnel before the user hits verify.
|
|
70
|
+
if (config.docs?.tool === "storybook") {
|
|
71
|
+
const { packageRoot } = resolveDSPaths(config);
|
|
72
|
+
const mainExists = await (async () => {
|
|
73
|
+
for (const f of ["main.ts", "main.js", "main.mjs", "main.cjs"]) {
|
|
74
|
+
if (await fs.access(path.join(packageRoot, ".storybook", f)).then(() => true).catch(() => false)) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
})();
|
|
80
|
+
if (!mainExists) {
|
|
81
|
+
issues.push({
|
|
82
|
+
severity: "warning",
|
|
83
|
+
check: "storybook",
|
|
84
|
+
message: "Storybook is configured but .storybook/main.* is missing",
|
|
85
|
+
suggestion: "Run: ptb document component . (or: cd <ui package> && npx storybook@latest init --no-dev --type react)",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
issues.push({ severity: "pass", check: "storybook", message: "Storybook config present", suggestion: "" });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
65
92
|
return { issues, snapshotAge };
|
|
66
93
|
}
|
|
67
94
|
//# sourceMappingURL=check-config.js.map
|
|
@@ -43,19 +43,35 @@ export function adaptCanonicalToTokenCollections(exportData) {
|
|
|
43
43
|
aliasTargetId = rawAliasId.replace(/^VariableID:/i, "");
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
+
// E-19: preserve every mode's value, not just the default. Collections
|
|
47
|
+
// with >1 mode (Figma variable modes, e.g. Light/Dark) carry the full
|
|
48
|
+
// theme set here; the CSS emitter turns non-default modes into
|
|
49
|
+
// [data-theme] override blocks. Single-mode collections skip this
|
|
50
|
+
// entirely (valuesByMode stays undefined) to keep the model lean.
|
|
51
|
+
const hasMultipleModes = col.modes.length > 1;
|
|
52
|
+
const valuesByMode = hasMultipleModes
|
|
53
|
+
? Object.fromEntries(col.modes
|
|
54
|
+
.filter((m) => t.valuesByMode[m.id] !== undefined)
|
|
55
|
+
.map((m) => [m.id, t.valuesByMode[m.id].value]))
|
|
56
|
+
: undefined;
|
|
46
57
|
const token = {
|
|
47
58
|
id: t.id,
|
|
48
59
|
name: t.name,
|
|
49
60
|
type: typeString,
|
|
50
61
|
value: modeVal.value,
|
|
62
|
+
...(valuesByMode && Object.keys(valuesByMode).length > 1 ? { valuesByMode } : {}),
|
|
51
63
|
...(aliasTargetId ? { aliasTargetId } : {}),
|
|
52
64
|
};
|
|
53
65
|
return token;
|
|
54
66
|
});
|
|
67
|
+
const hasMultipleModes = col.modes.length > 1;
|
|
55
68
|
return {
|
|
56
69
|
id: col.id,
|
|
57
70
|
name: col.name,
|
|
58
71
|
tokens,
|
|
72
|
+
...(hasMultipleModes
|
|
73
|
+
? { modes: col.modes.map((m) => ({ id: m.id, name: m.name })), defaultModeId: col.modes[0]?.id }
|
|
74
|
+
: {}),
|
|
59
75
|
};
|
|
60
76
|
});
|
|
61
77
|
}
|
|
@@ -14,6 +14,11 @@ export function normalizeTokenCollections(variablesMeta, includeHiddenCollection
|
|
|
14
14
|
continue; // Skip collections hidden from consumers (for export; keep for resolution)
|
|
15
15
|
}
|
|
16
16
|
const defaultModeId = rawCollection.defaultModeId;
|
|
17
|
+
// E-19: a collection with >1 mode carries multiple themes (e.g. Light/Dark).
|
|
18
|
+
// Preserve every mode's value so the emitter can produce [data-theme] blocks;
|
|
19
|
+
// single-mode collections keep the lean single-scalar shape (no valuesByMode).
|
|
20
|
+
const collectionModes = rawCollection.modes ?? [];
|
|
21
|
+
const hasMultipleModes = collectionModes.length > 1;
|
|
17
22
|
const tokens = [];
|
|
18
23
|
for (const variableId of rawCollection.variableIds) {
|
|
19
24
|
const rawVar = variables[variableId];
|
|
@@ -25,24 +30,22 @@ export function normalizeTokenCollections(variablesMeta, includeHiddenCollection
|
|
|
25
30
|
// Extract the value for the primary mode. If a collection has no modes
|
|
26
31
|
// for some reason, we fallback to the first object key value.
|
|
27
32
|
const valueForMode = rawVar.valuesByMode[defaultModeId] ?? Object.values(rawVar.valuesByMode)[0];
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
let
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
const { normalizedValue, aliasTargetId } = normalizeVariableValue(valueForMode, variables);
|
|
34
|
+
// Per-mode values for multi-mode collections. Alias targets can differ per
|
|
35
|
+
// mode, but for the model we key on the value string and let the var()
|
|
36
|
+
// cascade in the emitter handle aliases; here we just capture each mode's
|
|
37
|
+
// normalized value so non-default modes can override in CSS.
|
|
38
|
+
let valuesByMode;
|
|
39
|
+
if (hasMultipleModes) {
|
|
40
|
+
const entries = [];
|
|
41
|
+
for (const m of collectionModes) {
|
|
42
|
+
const rawModeVal = rawVar.valuesByMode[m.modeId];
|
|
43
|
+
if (rawModeVal === undefined)
|
|
44
|
+
continue; // token missing this mode's value
|
|
45
|
+
entries.push([m.modeId, String(normalizeVariableValue(rawModeVal, variables).normalizedValue)]);
|
|
37
46
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
normalizedValue = rgbaToHex(valueForMode);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
// Number, String, Boolean
|
|
45
|
-
normalizedValue = valueForMode;
|
|
47
|
+
if (entries.length > 1)
|
|
48
|
+
valuesByMode = Object.fromEntries(entries);
|
|
46
49
|
}
|
|
47
50
|
tokens.push({
|
|
48
51
|
id: rawVar.id,
|
|
@@ -51,6 +54,7 @@ export function normalizeTokenCollections(variablesMeta, includeHiddenCollection
|
|
|
51
54
|
value: String(normalizedValue), // Store as string for flexibility inside model for now
|
|
52
55
|
type: classifyTokenKind(rawCollection.name), // Base type heavily off the parent classification collection
|
|
53
56
|
description: rawVar.description || undefined,
|
|
57
|
+
...(valuesByMode ? { valuesByMode } : {}),
|
|
54
58
|
...(aliasTargetId ? { aliasTargetId } : {}),
|
|
55
59
|
});
|
|
56
60
|
}
|
|
@@ -59,11 +63,42 @@ export function normalizeTokenCollections(variablesMeta, includeHiddenCollection
|
|
|
59
63
|
id: collectionId,
|
|
60
64
|
name: rawCollection.name,
|
|
61
65
|
tokens,
|
|
66
|
+
...(hasMultipleModes
|
|
67
|
+
? {
|
|
68
|
+
modes: collectionModes.map((m) => ({ id: m.modeId, name: m.name })),
|
|
69
|
+
defaultModeId,
|
|
70
|
+
}
|
|
71
|
+
: {}),
|
|
62
72
|
});
|
|
63
73
|
}
|
|
64
74
|
}
|
|
65
75
|
return collections;
|
|
66
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Normalizes a single raw Figma variable value (for one mode) into the model's
|
|
79
|
+
* scalar form: aliases → `{alias-name}` + aliasTargetId, colors → hex, primitives
|
|
80
|
+
* pass through. Shared by the default-value path and the per-mode (E-19) path so
|
|
81
|
+
* both stay identical.
|
|
82
|
+
*/
|
|
83
|
+
function normalizeVariableValue(valueForMode, variables) {
|
|
84
|
+
let normalizedValue = "";
|
|
85
|
+
let aliasTargetId;
|
|
86
|
+
if (typeof valueForMode === "object" && valueForMode !== null) {
|
|
87
|
+
if ("type" in valueForMode && valueForMode.type === "VARIABLE_ALIAS") {
|
|
88
|
+
const aliasedVar = variables[valueForMode.id];
|
|
89
|
+
normalizedValue = aliasedVar ? `{${aliasedVar.name.replace(/\//g, "-").replace(/\s+/g, "-")}}` : "[Unknown Alias]";
|
|
90
|
+
aliasTargetId = valueForMode.id;
|
|
91
|
+
}
|
|
92
|
+
else if ("r" in valueForMode) {
|
|
93
|
+
normalizedValue = rgbaToHex(valueForMode);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else if (valueForMode !== undefined) {
|
|
97
|
+
// Number, String, Boolean
|
|
98
|
+
normalizedValue = valueForMode;
|
|
99
|
+
}
|
|
100
|
+
return { normalizedValue, aliasTargetId };
|
|
101
|
+
}
|
|
67
102
|
// Convert 0-1 RGBA channels to Hex string (uppercase to match rgbToHex in normalize-components)
|
|
68
103
|
function rgbaToHex(color) {
|
|
69
104
|
const r = Math.round(color.r * 255).toString(16).padStart(2, "0");
|
|
@@ -76,6 +76,53 @@ function applyRasterMask(target, mask, patchSize, patchCols, imgWidth, imgHeight
|
|
|
76
76
|
}
|
|
77
77
|
return maskedPixels;
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Estimates the reference background color from its four corners (each averaged
|
|
81
|
+
* over a small patch). UI frames are near-universally rendered on a uniform
|
|
82
|
+
* background, so the corners are a robust background sample.
|
|
83
|
+
*/
|
|
84
|
+
function estimateBackground(data, w, h) {
|
|
85
|
+
const S = 4; // corner patch size
|
|
86
|
+
const samples = [
|
|
87
|
+
[0, 0], [w - S, 0], [0, h - S], [w - S, h - S],
|
|
88
|
+
];
|
|
89
|
+
let r = 0, g = 0, b = 0, n = 0;
|
|
90
|
+
for (const [ox, oy] of samples) {
|
|
91
|
+
for (let y = oy; y < oy + S && y < h; y++) {
|
|
92
|
+
for (let x = ox; x < ox + S && x < w; x++) {
|
|
93
|
+
const i = (y * w + x) * 4;
|
|
94
|
+
r += data[i];
|
|
95
|
+
g += data[i + 1];
|
|
96
|
+
b += data[i + 2];
|
|
97
|
+
n++;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return n === 0 ? [255, 255, 255] : [r / n, g / n, b / n];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* FLOOR-CALIB: content-coverage metric. Of the reference pixels that are "ink"
|
|
105
|
+
* (far enough from the background to be content), returns the fraction the impl
|
|
106
|
+
* also renders as ink at the same position. A blank scaffold draws background
|
|
107
|
+
* where the reference has content → ~0; a real implementation → high. Returns
|
|
108
|
+
* undefined when the reference has no detectable ink (nothing to cover).
|
|
109
|
+
*/
|
|
110
|
+
function computeContentCoverage(figmaData, implData, w, h) {
|
|
111
|
+
const bg = estimateBackground(figmaData, w, h);
|
|
112
|
+
const INK = 60; // summed per-channel distance from background to count as content
|
|
113
|
+
const dist = (data, i) => Math.abs(data[i] - bg[0]) + Math.abs(data[i + 1] - bg[1]) + Math.abs(data[i + 2] - bg[2]);
|
|
114
|
+
let refInk = 0, covered = 0;
|
|
115
|
+
for (let i = 0; i < w * h * 4; i += 4) {
|
|
116
|
+
if (dist(figmaData, i) > INK) {
|
|
117
|
+
refInk++;
|
|
118
|
+
if (dist(implData, i) > INK)
|
|
119
|
+
covered++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (refInk === 0)
|
|
123
|
+
return undefined;
|
|
124
|
+
return parseFloat((covered / refInk).toFixed(4));
|
|
125
|
+
}
|
|
79
126
|
/**
|
|
80
127
|
* Compares two PNG files pixel-by-pixel using pixelmatch.
|
|
81
128
|
* Saves an annotated diff image to diffOutputPath.
|
|
@@ -108,11 +155,13 @@ export async function runPixelDiff(figmaPath, implPath, diffOutputPath) {
|
|
|
108
155
|
await fs.mkdir(path.dirname(diffOutputPath), { recursive: true });
|
|
109
156
|
await fs.writeFile(diffOutputPath, PNG.sync.write(diffPng));
|
|
110
157
|
const score = parseFloat((1 - diffPixels / totalPixels).toFixed(4));
|
|
158
|
+
// FLOOR-CALIB: how much of the reference's actual content the impl renders.
|
|
159
|
+
const contentCoverage = computeContentCoverage(figmaPng.data, implPng.data, width, height);
|
|
111
160
|
// ── Content-only score (exclude raster image patches) ────────────────
|
|
112
161
|
const { mask, patchCols } = buildRasterMask(figmaPng.data, width, height, PATCH_SIZE, RASTER_VARIANCE_THRESHOLD);
|
|
113
162
|
const rasterPatchCount = mask.filter(Boolean).length;
|
|
114
163
|
if (rasterPatchCount === 0) {
|
|
115
|
-
return { score, diffPixels, totalPixels };
|
|
164
|
+
return { score, contentCoverage, diffPixels, totalPixels };
|
|
116
165
|
}
|
|
117
166
|
// At least one raster patch: run a second comparison on masked copies.
|
|
118
167
|
// Both images get the same patches filled with mid-gray → pixelmatch sees
|
|
@@ -126,7 +175,7 @@ export async function runPixelDiff(figmaPath, implPath, diffOutputPath) {
|
|
|
126
175
|
const contentPixels = totalPixels - maskedPixels;
|
|
127
176
|
const contentScore = parseFloat((contentPixels > 0 ? 1 - contentDiffPixels / contentPixels : 1).toFixed(4));
|
|
128
177
|
const rasterPixelRatio = parseFloat((maskedPixels / totalPixels).toFixed(4));
|
|
129
|
-
return { score, contentScore, rasterPixelRatio, diffPixels, totalPixels };
|
|
178
|
+
return { score, contentScore, rasterPixelRatio, contentCoverage, diffPixels, totalPixels };
|
|
130
179
|
}
|
|
131
180
|
catch {
|
|
132
181
|
return null;
|
package/dist/verify/types.d.ts
CHANGED
|
@@ -28,6 +28,16 @@ export type PixelMatchResult = {
|
|
|
28
28
|
contentScore?: number;
|
|
29
29
|
/** Fraction of total pixels identified as raster image regions (0–1). */
|
|
30
30
|
rasterPixelRatio?: number;
|
|
31
|
+
/**
|
|
32
|
+
* FLOOR-CALIB: of the pixels that are actual *content* (ink — differ from the
|
|
33
|
+
* reference's background) in the Figma reference, the fraction the implementation
|
|
34
|
+
* also renders as content at the same positions (0–1). Independent of visual
|
|
35
|
+
* complexity, unlike `score`: a blank scaffold on a visually-simple component
|
|
36
|
+
* still scores high on `score` (mostly background in both images) but ~0 here,
|
|
37
|
+
* because it draws nothing where the reference has content. Undefined when the
|
|
38
|
+
* reference has no detectable content (fully blank).
|
|
39
|
+
*/
|
|
40
|
+
contentCoverage?: number;
|
|
31
41
|
diffPixels: number;
|
|
32
42
|
totalPixels: number;
|
|
33
43
|
};
|