@muloka/figma-console-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +898 -0
- package/dist/apps/design-system-dashboard/scoring/accessibility.d.ts +14 -0
- package/dist/apps/design-system-dashboard/scoring/accessibility.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/accessibility.js +278 -0
- package/dist/apps/design-system-dashboard/scoring/accessibility.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/component-metadata.d.ts +29 -0
- package/dist/apps/design-system-dashboard/scoring/component-metadata.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/component-metadata.js +358 -0
- package/dist/apps/design-system-dashboard/scoring/component-metadata.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/consistency.d.ts +14 -0
- package/dist/apps/design-system-dashboard/scoring/consistency.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/consistency.js +342 -0
- package/dist/apps/design-system-dashboard/scoring/consistency.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/coverage.d.ts +14 -0
- package/dist/apps/design-system-dashboard/scoring/coverage.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/coverage.js +231 -0
- package/dist/apps/design-system-dashboard/scoring/coverage.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/engine.d.ts +27 -0
- package/dist/apps/design-system-dashboard/scoring/engine.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/engine.js +93 -0
- package/dist/apps/design-system-dashboard/scoring/engine.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/naming-semantics.d.ts +14 -0
- package/dist/apps/design-system-dashboard/scoring/naming-semantics.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/naming-semantics.js +309 -0
- package/dist/apps/design-system-dashboard/scoring/naming-semantics.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/token-architecture.d.ts +14 -0
- package/dist/apps/design-system-dashboard/scoring/token-architecture.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/token-architecture.js +350 -0
- package/dist/apps/design-system-dashboard/scoring/token-architecture.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/types.d.ts +89 -0
- package/dist/apps/design-system-dashboard/scoring/types.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/types.js +41 -0
- package/dist/apps/design-system-dashboard/scoring/types.js.map +1 -0
- package/dist/apps/design-system-dashboard/server.d.ts +24 -0
- package/dist/apps/design-system-dashboard/server.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/server.js +160 -0
- package/dist/apps/design-system-dashboard/server.js.map +1 -0
- package/dist/apps/token-browser/server.d.ts +26 -0
- package/dist/apps/token-browser/server.d.ts.map +1 -0
- package/dist/apps/token-browser/server.js +137 -0
- package/dist/apps/token-browser/server.js.map +1 -0
- package/dist/browser/base.d.ts +58 -0
- package/dist/browser/base.d.ts.map +1 -0
- package/dist/browser/base.js +6 -0
- package/dist/browser/base.js.map +1 -0
- package/dist/browser/local.d.ts +87 -0
- package/dist/browser/local.d.ts.map +1 -0
- package/dist/browser/local.js +318 -0
- package/dist/browser/local.js.map +1 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/accessibility.js +277 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/component-metadata.js +357 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/consistency.js +341 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/coverage.js +230 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/engine.js +92 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/naming-semantics.js +308 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/token-architecture.js +349 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/types.js +40 -0
- package/dist/cloudflare/apps/design-system-dashboard/server.js +159 -0
- package/dist/cloudflare/apps/token-browser/server.js +136 -0
- package/dist/cloudflare/browser-manager.js +157 -0
- package/dist/cloudflare/core/accessibility-tools.js +361 -0
- package/dist/cloudflare/core/annotation-tools.js +230 -0
- package/dist/cloudflare/core/cloud-websocket-connector.js +419 -0
- package/dist/cloudflare/core/cloud-websocket-relay.js +198 -0
- package/dist/cloudflare/core/comment-tools.js +292 -0
- package/dist/cloudflare/core/config.js +153 -0
- package/dist/cloudflare/core/console-monitor.js +427 -0
- package/dist/cloudflare/core/deep-component-tools.js +128 -0
- package/dist/cloudflare/core/design-code-tools.js +2793 -0
- package/dist/cloudflare/core/design-system-manifest.js +265 -0
- package/dist/cloudflare/core/design-system-tools.js +882 -0
- package/dist/cloudflare/core/diagnose-tool.js +100 -0
- package/dist/cloudflare/core/diff/changelog-formatter.js +275 -0
- package/dist/cloudflare/core/diff/diff-engine.js +334 -0
- package/dist/cloudflare/core/diff/property-compare.js +36 -0
- package/dist/cloudflare/core/diff/version-cache.js +74 -0
- package/dist/cloudflare/core/enrichment/enrichment-service.js +374 -0
- package/dist/cloudflare/core/enrichment/index.js +7 -0
- package/dist/cloudflare/core/enrichment/relationship-mapper.js +351 -0
- package/dist/cloudflare/core/enrichment/style-resolver.js +346 -0
- package/dist/cloudflare/core/figjam-tools.js +547 -0
- package/dist/cloudflare/core/figma-api.js +509 -0
- package/dist/cloudflare/core/figma-connector.js +7 -0
- package/dist/cloudflare/core/figma-reconstruction-spec.js +402 -0
- package/dist/cloudflare/core/figma-style-extractor.js +311 -0
- package/dist/cloudflare/core/figma-tools.js +3302 -0
- package/dist/cloudflare/core/identity.js +96 -0
- package/dist/cloudflare/core/library-tools.js +580 -0
- package/dist/cloudflare/core/logger.js +53 -0
- package/dist/cloudflare/core/port-discovery.js +935 -0
- package/dist/cloudflare/core/resolve-package-root.js +11 -0
- package/dist/cloudflare/core/slides-tools.js +714 -0
- package/dist/cloudflare/core/slot-tools.js +334 -0
- package/dist/cloudflare/core/snippet-injector.js +96 -0
- package/dist/cloudflare/core/tokens/alias-resolver.js +205 -0
- package/dist/cloudflare/core/tokens/config.js +294 -0
- package/dist/cloudflare/core/tokens/dialect.js +232 -0
- package/dist/cloudflare/core/tokens/figma-converter.js +323 -0
- package/dist/cloudflare/core/tokens/formatters/css-vars.js +338 -0
- package/dist/cloudflare/core/tokens/formatters/dtcg.js +376 -0
- package/dist/cloudflare/core/tokens/formatters/index.js +45 -0
- package/dist/cloudflare/core/tokens/formatters/json.js +205 -0
- package/dist/cloudflare/core/tokens/formatters/less.js +4 -0
- package/dist/cloudflare/core/tokens/formatters/scss.js +258 -0
- package/dist/cloudflare/core/tokens/formatters/stubs.js +13 -0
- package/dist/cloudflare/core/tokens/formatters/style-dictionary-v3.js +213 -0
- package/dist/cloudflare/core/tokens/formatters/tailwind-v3.js +237 -0
- package/dist/cloudflare/core/tokens/formatters/tailwind-v4.js +335 -0
- package/dist/cloudflare/core/tokens/formatters/tokens-studio.js +256 -0
- package/dist/cloudflare/core/tokens/formatters/ts-module.js +198 -0
- package/dist/cloudflare/core/tokens/index.js +16 -0
- package/dist/cloudflare/core/tokens/parsers/css-vars.js +4 -0
- package/dist/cloudflare/core/tokens/parsers/dtcg.js +280 -0
- package/dist/cloudflare/core/tokens/parsers/index.js +138 -0
- package/dist/cloudflare/core/tokens/parsers/json.js +7 -0
- package/dist/cloudflare/core/tokens/parsers/scss.js +4 -0
- package/dist/cloudflare/core/tokens/parsers/stubs.js +20 -0
- package/dist/cloudflare/core/tokens/parsers/style-dictionary-v3.js +4 -0
- package/dist/cloudflare/core/tokens/parsers/tailwind-v3.js +4 -0
- package/dist/cloudflare/core/tokens/parsers/tailwind-v4.js +4 -0
- package/dist/cloudflare/core/tokens/parsers/tokens-studio.js +4 -0
- package/dist/cloudflare/core/tokens/schemas.js +152 -0
- package/dist/cloudflare/core/tokens/transforms/color.js +12 -0
- package/dist/cloudflare/core/tokens/transforms/index.js +29 -0
- package/dist/cloudflare/core/tokens/transforms/size.js +7 -0
- package/dist/cloudflare/core/tokens/types.js +18 -0
- package/dist/cloudflare/core/tokens-tools.js +1788 -0
- package/dist/cloudflare/core/types/design-code.js +4 -0
- package/dist/cloudflare/core/types/enriched.js +5 -0
- package/dist/cloudflare/core/types/index.js +4 -0
- package/dist/cloudflare/core/variable-resolver.js +85 -0
- package/dist/cloudflare/core/version-tools.js +1199 -0
- package/dist/cloudflare/core/websocket-connector.js +436 -0
- package/dist/cloudflare/core/websocket-server.js +956 -0
- package/dist/cloudflare/core/write-tools.js +2506 -0
- package/dist/cloudflare/index.js +3010 -0
- package/dist/core/accessibility-tools.d.ts +21 -0
- package/dist/core/accessibility-tools.d.ts.map +1 -0
- package/dist/core/accessibility-tools.js +362 -0
- package/dist/core/accessibility-tools.js.map +1 -0
- package/dist/core/annotation-tools.d.ts +14 -0
- package/dist/core/annotation-tools.d.ts.map +1 -0
- package/dist/core/annotation-tools.js +231 -0
- package/dist/core/annotation-tools.js.map +1 -0
- package/dist/core/comment-tools.d.ts +11 -0
- package/dist/core/comment-tools.d.ts.map +1 -0
- package/dist/core/comment-tools.js +293 -0
- package/dist/core/comment-tools.js.map +1 -0
- package/dist/core/config.d.ts +17 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +154 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/console-monitor.d.ts +82 -0
- package/dist/core/console-monitor.d.ts.map +1 -0
- package/dist/core/console-monitor.js +428 -0
- package/dist/core/console-monitor.js.map +1 -0
- package/dist/core/deep-component-tools.d.ts +14 -0
- package/dist/core/deep-component-tools.d.ts.map +1 -0
- package/dist/core/deep-component-tools.js +129 -0
- package/dist/core/deep-component-tools.js.map +1 -0
- package/dist/core/design-code-tools.d.ts +116 -0
- package/dist/core/design-code-tools.d.ts.map +1 -0
- package/dist/core/design-code-tools.js +2794 -0
- package/dist/core/design-code-tools.js.map +1 -0
- package/dist/core/design-system-manifest.d.ts +273 -0
- package/dist/core/design-system-manifest.d.ts.map +1 -0
- package/dist/core/design-system-manifest.js +266 -0
- package/dist/core/design-system-manifest.js.map +1 -0
- package/dist/core/design-system-tools.d.ts +67 -0
- package/dist/core/design-system-tools.d.ts.map +1 -0
- package/dist/core/design-system-tools.js +883 -0
- package/dist/core/design-system-tools.js.map +1 -0
- package/dist/core/diagnose-tool.d.ts +41 -0
- package/dist/core/diagnose-tool.d.ts.map +1 -0
- package/dist/core/diagnose-tool.js +101 -0
- package/dist/core/diagnose-tool.js.map +1 -0
- package/dist/core/diff/changelog-formatter.d.ts +35 -0
- package/dist/core/diff/changelog-formatter.d.ts.map +1 -0
- package/dist/core/diff/changelog-formatter.js +276 -0
- package/dist/core/diff/changelog-formatter.js.map +1 -0
- package/dist/core/diff/diff-engine.d.ts +127 -0
- package/dist/core/diff/diff-engine.d.ts.map +1 -0
- package/dist/core/diff/diff-engine.js +335 -0
- package/dist/core/diff/diff-engine.js.map +1 -0
- package/dist/core/diff/property-compare.d.ts +19 -0
- package/dist/core/diff/property-compare.d.ts.map +1 -0
- package/dist/core/diff/property-compare.js +37 -0
- package/dist/core/diff/property-compare.js.map +1 -0
- package/dist/core/diff/version-cache.d.ts +40 -0
- package/dist/core/diff/version-cache.d.ts.map +1 -0
- package/dist/core/diff/version-cache.js +75 -0
- package/dist/core/diff/version-cache.js.map +1 -0
- package/dist/core/enrichment/enrichment-service.d.ts +52 -0
- package/dist/core/enrichment/enrichment-service.d.ts.map +1 -0
- package/dist/core/enrichment/enrichment-service.js +375 -0
- package/dist/core/enrichment/enrichment-service.js.map +1 -0
- package/dist/core/enrichment/index.d.ts +8 -0
- package/dist/core/enrichment/index.d.ts.map +1 -0
- package/dist/core/enrichment/index.js +8 -0
- package/dist/core/enrichment/index.js.map +1 -0
- package/dist/core/enrichment/relationship-mapper.d.ts +106 -0
- package/dist/core/enrichment/relationship-mapper.d.ts.map +1 -0
- package/dist/core/enrichment/relationship-mapper.js +352 -0
- package/dist/core/enrichment/relationship-mapper.js.map +1 -0
- package/dist/core/enrichment/style-resolver.d.ts +85 -0
- package/dist/core/enrichment/style-resolver.d.ts.map +1 -0
- package/dist/core/enrichment/style-resolver.js +347 -0
- package/dist/core/enrichment/style-resolver.js.map +1 -0
- package/dist/core/figjam-tools.d.ts +8 -0
- package/dist/core/figjam-tools.d.ts.map +1 -0
- package/dist/core/figjam-tools.js +548 -0
- package/dist/core/figjam-tools.js.map +1 -0
- package/dist/core/figma-api.d.ts +254 -0
- package/dist/core/figma-api.d.ts.map +1 -0
- package/dist/core/figma-api.js +510 -0
- package/dist/core/figma-api.js.map +1 -0
- package/dist/core/figma-connector.d.ts +214 -0
- package/dist/core/figma-connector.d.ts.map +1 -0
- package/dist/core/figma-connector.js +8 -0
- package/dist/core/figma-connector.js.map +1 -0
- package/dist/core/figma-desktop-connector.d.ts +312 -0
- package/dist/core/figma-desktop-connector.d.ts.map +1 -0
- package/dist/core/figma-desktop-connector.js +1298 -0
- package/dist/core/figma-desktop-connector.js.map +1 -0
- package/dist/core/figma-reconstruction-spec.d.ts +166 -0
- package/dist/core/figma-reconstruction-spec.d.ts.map +1 -0
- package/dist/core/figma-reconstruction-spec.js +403 -0
- package/dist/core/figma-reconstruction-spec.js.map +1 -0
- package/dist/core/figma-style-extractor.d.ts +76 -0
- package/dist/core/figma-style-extractor.d.ts.map +1 -0
- package/dist/core/figma-style-extractor.js +312 -0
- package/dist/core/figma-style-extractor.js.map +1 -0
- package/dist/core/figma-tools.d.ts +22 -0
- package/dist/core/figma-tools.d.ts.map +1 -0
- package/dist/core/figma-tools.js +3303 -0
- package/dist/core/figma-tools.js.map +1 -0
- package/dist/core/identity.d.ts +41 -0
- package/dist/core/identity.d.ts.map +1 -0
- package/dist/core/identity.js +97 -0
- package/dist/core/identity.js.map +1 -0
- package/dist/core/library-tools.d.ts +17 -0
- package/dist/core/library-tools.d.ts.map +1 -0
- package/dist/core/library-tools.js +581 -0
- package/dist/core/library-tools.js.map +1 -0
- package/dist/core/logger.d.ts +22 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +54 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/port-discovery.d.ts +211 -0
- package/dist/core/port-discovery.d.ts.map +1 -0
- package/dist/core/port-discovery.js +936 -0
- package/dist/core/port-discovery.js.map +1 -0
- package/dist/core/resolve-package-root.d.ts +2 -0
- package/dist/core/resolve-package-root.d.ts.map +1 -0
- package/dist/core/resolve-package-root.js +12 -0
- package/dist/core/resolve-package-root.js.map +1 -0
- package/dist/core/slides-tools.d.ts +8 -0
- package/dist/core/slides-tools.d.ts.map +1 -0
- package/dist/core/slides-tools.js +715 -0
- package/dist/core/slides-tools.js.map +1 -0
- package/dist/core/slot-tools.d.ts +7 -0
- package/dist/core/slot-tools.d.ts.map +1 -0
- package/dist/core/slot-tools.js +335 -0
- package/dist/core/slot-tools.js.map +1 -0
- package/dist/core/snippet-injector.d.ts +24 -0
- package/dist/core/snippet-injector.d.ts.map +1 -0
- package/dist/core/snippet-injector.js +97 -0
- package/dist/core/snippet-injector.js.map +1 -0
- package/dist/core/tokens/alias-resolver.d.ts +97 -0
- package/dist/core/tokens/alias-resolver.d.ts.map +1 -0
- package/dist/core/tokens/alias-resolver.js +206 -0
- package/dist/core/tokens/alias-resolver.js.map +1 -0
- package/dist/core/tokens/config.d.ts +380 -0
- package/dist/core/tokens/config.d.ts.map +1 -0
- package/dist/core/tokens/config.js +295 -0
- package/dist/core/tokens/config.js.map +1 -0
- package/dist/core/tokens/dialect.d.ts +107 -0
- package/dist/core/tokens/dialect.d.ts.map +1 -0
- package/dist/core/tokens/dialect.js +233 -0
- package/dist/core/tokens/dialect.js.map +1 -0
- package/dist/core/tokens/figma-converter.d.ts +102 -0
- package/dist/core/tokens/figma-converter.d.ts.map +1 -0
- package/dist/core/tokens/figma-converter.js +324 -0
- package/dist/core/tokens/figma-converter.js.map +1 -0
- package/dist/core/tokens/formatters/css-vars.d.ts +24 -0
- package/dist/core/tokens/formatters/css-vars.d.ts.map +1 -0
- package/dist/core/tokens/formatters/css-vars.js +339 -0
- package/dist/core/tokens/formatters/css-vars.js.map +1 -0
- package/dist/core/tokens/formatters/dtcg.d.ts +28 -0
- package/dist/core/tokens/formatters/dtcg.d.ts.map +1 -0
- package/dist/core/tokens/formatters/dtcg.js +377 -0
- package/dist/core/tokens/formatters/dtcg.js.map +1 -0
- package/dist/core/tokens/formatters/index.d.ts +30 -0
- package/dist/core/tokens/formatters/index.d.ts.map +1 -0
- package/dist/core/tokens/formatters/index.js +46 -0
- package/dist/core/tokens/formatters/index.js.map +1 -0
- package/dist/core/tokens/formatters/json.d.ts +37 -0
- package/dist/core/tokens/formatters/json.d.ts.map +1 -0
- package/dist/core/tokens/formatters/json.js +206 -0
- package/dist/core/tokens/formatters/json.js.map +1 -0
- package/dist/core/tokens/formatters/less.d.ts +4 -0
- package/dist/core/tokens/formatters/less.d.ts.map +1 -0
- package/dist/core/tokens/formatters/less.js +5 -0
- package/dist/core/tokens/formatters/less.js.map +1 -0
- package/dist/core/tokens/formatters/scss.d.ts +26 -0
- package/dist/core/tokens/formatters/scss.d.ts.map +1 -0
- package/dist/core/tokens/formatters/scss.js +259 -0
- package/dist/core/tokens/formatters/scss.js.map +1 -0
- package/dist/core/tokens/formatters/stubs.d.ts +9 -0
- package/dist/core/tokens/formatters/stubs.d.ts.map +1 -0
- package/dist/core/tokens/formatters/stubs.js +14 -0
- package/dist/core/tokens/formatters/stubs.js.map +1 -0
- package/dist/core/tokens/formatters/style-dictionary-v3.d.ts +45 -0
- package/dist/core/tokens/formatters/style-dictionary-v3.d.ts.map +1 -0
- package/dist/core/tokens/formatters/style-dictionary-v3.js +214 -0
- package/dist/core/tokens/formatters/style-dictionary-v3.js.map +1 -0
- package/dist/core/tokens/formatters/tailwind-v3.d.ts +37 -0
- package/dist/core/tokens/formatters/tailwind-v3.d.ts.map +1 -0
- package/dist/core/tokens/formatters/tailwind-v3.js +238 -0
- package/dist/core/tokens/formatters/tailwind-v3.js.map +1 -0
- package/dist/core/tokens/formatters/tailwind-v4.d.ts +41 -0
- package/dist/core/tokens/formatters/tailwind-v4.d.ts.map +1 -0
- package/dist/core/tokens/formatters/tailwind-v4.js +336 -0
- package/dist/core/tokens/formatters/tailwind-v4.js.map +1 -0
- package/dist/core/tokens/formatters/tokens-studio.d.ts +44 -0
- package/dist/core/tokens/formatters/tokens-studio.d.ts.map +1 -0
- package/dist/core/tokens/formatters/tokens-studio.js +257 -0
- package/dist/core/tokens/formatters/tokens-studio.js.map +1 -0
- package/dist/core/tokens/formatters/ts-module.d.ts +35 -0
- package/dist/core/tokens/formatters/ts-module.d.ts.map +1 -0
- package/dist/core/tokens/formatters/ts-module.js +199 -0
- package/dist/core/tokens/formatters/ts-module.js.map +1 -0
- package/dist/core/tokens/index.d.ts +18 -0
- package/dist/core/tokens/index.d.ts.map +1 -0
- package/dist/core/tokens/index.js +17 -0
- package/dist/core/tokens/index.js.map +1 -0
- package/dist/core/tokens/parsers/css-vars.d.ts +3 -0
- package/dist/core/tokens/parsers/css-vars.d.ts.map +1 -0
- package/dist/core/tokens/parsers/css-vars.js +5 -0
- package/dist/core/tokens/parsers/css-vars.js.map +1 -0
- package/dist/core/tokens/parsers/dtcg.d.ts +21 -0
- package/dist/core/tokens/parsers/dtcg.d.ts.map +1 -0
- package/dist/core/tokens/parsers/dtcg.js +281 -0
- package/dist/core/tokens/parsers/dtcg.js.map +1 -0
- package/dist/core/tokens/parsers/index.d.ts +37 -0
- package/dist/core/tokens/parsers/index.d.ts.map +1 -0
- package/dist/core/tokens/parsers/index.js +139 -0
- package/dist/core/tokens/parsers/index.js.map +1 -0
- package/dist/core/tokens/parsers/json.d.ts +4 -0
- package/dist/core/tokens/parsers/json.d.ts.map +1 -0
- package/dist/core/tokens/parsers/json.js +8 -0
- package/dist/core/tokens/parsers/json.js.map +1 -0
- package/dist/core/tokens/parsers/scss.d.ts +3 -0
- package/dist/core/tokens/parsers/scss.d.ts.map +1 -0
- package/dist/core/tokens/parsers/scss.js +5 -0
- package/dist/core/tokens/parsers/scss.js.map +1 -0
- package/dist/core/tokens/parsers/stubs.d.ts +15 -0
- package/dist/core/tokens/parsers/stubs.d.ts.map +1 -0
- package/dist/core/tokens/parsers/stubs.js +21 -0
- package/dist/core/tokens/parsers/stubs.js.map +1 -0
- package/dist/core/tokens/parsers/style-dictionary-v3.d.ts +3 -0
- package/dist/core/tokens/parsers/style-dictionary-v3.d.ts.map +1 -0
- package/dist/core/tokens/parsers/style-dictionary-v3.js +5 -0
- package/dist/core/tokens/parsers/style-dictionary-v3.js.map +1 -0
- package/dist/core/tokens/parsers/tailwind-v3.d.ts +3 -0
- package/dist/core/tokens/parsers/tailwind-v3.d.ts.map +1 -0
- package/dist/core/tokens/parsers/tailwind-v3.js +5 -0
- package/dist/core/tokens/parsers/tailwind-v3.js.map +1 -0
- package/dist/core/tokens/parsers/tailwind-v4.d.ts +3 -0
- package/dist/core/tokens/parsers/tailwind-v4.d.ts.map +1 -0
- package/dist/core/tokens/parsers/tailwind-v4.js +5 -0
- package/dist/core/tokens/parsers/tailwind-v4.js.map +1 -0
- package/dist/core/tokens/parsers/tokens-studio.d.ts +3 -0
- package/dist/core/tokens/parsers/tokens-studio.d.ts.map +1 -0
- package/dist/core/tokens/parsers/tokens-studio.js +5 -0
- package/dist/core/tokens/parsers/tokens-studio.js.map +1 -0
- package/dist/core/tokens/schemas.d.ts +155 -0
- package/dist/core/tokens/schemas.d.ts.map +1 -0
- package/dist/core/tokens/schemas.js +153 -0
- package/dist/core/tokens/schemas.js.map +1 -0
- package/dist/core/tokens/transforms/color.d.ts +9 -0
- package/dist/core/tokens/transforms/color.d.ts.map +1 -0
- package/dist/core/tokens/transforms/color.js +13 -0
- package/dist/core/tokens/transforms/color.js.map +1 -0
- package/dist/core/tokens/transforms/index.d.ts +36 -0
- package/dist/core/tokens/transforms/index.d.ts.map +1 -0
- package/dist/core/tokens/transforms/index.js +30 -0
- package/dist/core/tokens/transforms/index.js.map +1 -0
- package/dist/core/tokens/transforms/size.d.ts +7 -0
- package/dist/core/tokens/transforms/size.d.ts.map +1 -0
- package/dist/core/tokens/transforms/size.js +8 -0
- package/dist/core/tokens/transforms/size.js.map +1 -0
- package/dist/core/tokens/types.d.ts +284 -0
- package/dist/core/tokens/types.d.ts.map +1 -0
- package/dist/core/tokens/types.js +19 -0
- package/dist/core/tokens/types.js.map +1 -0
- package/dist/core/tokens-tools.d.ts +285 -0
- package/dist/core/tokens-tools.d.ts.map +1 -0
- package/dist/core/tokens-tools.js +1789 -0
- package/dist/core/tokens-tools.js.map +1 -0
- package/dist/core/types/design-code.d.ts +271 -0
- package/dist/core/types/design-code.d.ts.map +1 -0
- package/dist/core/types/design-code.js +5 -0
- package/dist/core/types/design-code.js.map +1 -0
- package/dist/core/types/enriched.d.ts +213 -0
- package/dist/core/types/enriched.d.ts.map +1 -0
- package/dist/core/types/enriched.js +6 -0
- package/dist/core/types/enriched.js.map +1 -0
- package/dist/core/types/index.d.ts +104 -0
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/core/types/index.js +5 -0
- package/dist/core/types/index.js.map +1 -0
- package/dist/core/variable-resolver.d.ts +45 -0
- package/dist/core/variable-resolver.d.ts.map +1 -0
- package/dist/core/variable-resolver.js +86 -0
- package/dist/core/variable-resolver.js.map +1 -0
- package/dist/core/version-tools.d.ts +59 -0
- package/dist/core/version-tools.d.ts.map +1 -0
- package/dist/core/version-tools.js +1200 -0
- package/dist/core/version-tools.js.map +1 -0
- package/dist/core/websocket-connector.d.ts +247 -0
- package/dist/core/websocket-connector.d.ts.map +1 -0
- package/dist/core/websocket-connector.js +437 -0
- package/dist/core/websocket-connector.js.map +1 -0
- package/dist/core/websocket-server.d.ts +290 -0
- package/dist/core/websocket-server.d.ts.map +1 -0
- package/dist/core/websocket-server.js +957 -0
- package/dist/core/websocket-server.js.map +1 -0
- package/dist/core/write-tools.d.ts +7 -0
- package/dist/core/write-tools.d.ts.map +1 -0
- package/dist/core/write-tools.js +2507 -0
- package/dist/core/write-tools.js.map +1 -0
- package/dist/local.d.ts +105 -0
- package/dist/local.d.ts.map +1 -0
- package/dist/local.js +3314 -0
- package/dist/local.js.map +1 -0
- package/figma-desktop-bridge/README.md +365 -0
- package/figma-desktop-bridge/code.js +7359 -0
- package/figma-desktop-bridge/icon.png +0 -0
- package/figma-desktop-bridge/manifest.json +67 -0
- package/figma-desktop-bridge/ui.html +2783 -0
- package/package.json +103 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tokens.config.json schema, loader, and autodiscovery for the figma-console-mcp
|
|
3
|
+
* token sync engine.
|
|
4
|
+
*
|
|
5
|
+
* Both figma_export_tokens and figma_import_tokens read this single config so
|
|
6
|
+
* follow-up calls in a project are zero-arg. Autodiscovery walks up from the
|
|
7
|
+
* current working directory looking for `tokens.config.json` at each level
|
|
8
|
+
* — same convention as `tsconfig.json`, `package.json`, `.eslintrc`, etc.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
11
|
+
import { dirname, join, resolve } from "node:path";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
/**
|
|
14
|
+
* Schema for a single output target in `tokens.config.json`. Each entry
|
|
15
|
+
* produces one or more files when figma_export_tokens runs.
|
|
16
|
+
*/
|
|
17
|
+
const OutputTargetSchema = z.object({
|
|
18
|
+
format: z.enum([
|
|
19
|
+
"dtcg",
|
|
20
|
+
"tokens-studio",
|
|
21
|
+
"css-vars",
|
|
22
|
+
"tailwind-v4",
|
|
23
|
+
"tailwind-v3",
|
|
24
|
+
"scss",
|
|
25
|
+
"less",
|
|
26
|
+
"ts-module",
|
|
27
|
+
"json-flat",
|
|
28
|
+
"json-nested",
|
|
29
|
+
"style-dictionary-v3",
|
|
30
|
+
]),
|
|
31
|
+
/** Optional filename override. Default is derived from format + scope. */
|
|
32
|
+
filename: z.string().optional(),
|
|
33
|
+
/** Output prefix applied to every token name (e.g. "ds-", "al-"). */
|
|
34
|
+
prefix: z.string().optional(),
|
|
35
|
+
/** Emit one file per mode (e.g. tokens-light.css, tokens-dark.css). */
|
|
36
|
+
splitByMode: z.boolean().optional(),
|
|
37
|
+
/** Emit one file per token set / Figma collection. */
|
|
38
|
+
splitByCollection: z.boolean().optional(),
|
|
39
|
+
/**
|
|
40
|
+
* If true, alias references are resolved to literal values in the output.
|
|
41
|
+
* If false, aliases are preserved (default for JSON formats, forced true
|
|
42
|
+
* for CSS/SCSS/Tailwind/etc. since they can't natively express aliases).
|
|
43
|
+
*/
|
|
44
|
+
resolveAliases: z.boolean().optional(),
|
|
45
|
+
/**
|
|
46
|
+
* DTCG dialect for dtcg/json outputs. 'legacy' (default): hex-string
|
|
47
|
+
* colors and bare-number dimensions, maximum compatibility (Style
|
|
48
|
+
* Dictionary v4, Tokens Studio). '2025': DTCG 2025.10 object colors
|
|
49
|
+
* ({ colorSpace, components, alpha?, hex }) and dimensions
|
|
50
|
+
* ({ value, unit }) for Style Dictionary v5+ and other 2025.10-aware
|
|
51
|
+
* tooling. Ignored by css/scss/tailwind/ts formatters, which render
|
|
52
|
+
* final code.
|
|
53
|
+
*/
|
|
54
|
+
dtcgDialect: z.enum(["legacy", "2025"]).optional(),
|
|
55
|
+
/** Per-target transform options. Override the global defaults. */
|
|
56
|
+
transforms: z
|
|
57
|
+
.object({
|
|
58
|
+
colorFormat: z.enum(["hex", "hex8", "rgba", "oklch", "hsl"]).optional(),
|
|
59
|
+
sizeUnit: z.enum(["px", "rem", "pt", "dp"]).optional(),
|
|
60
|
+
remBase: z.number().positive().optional(),
|
|
61
|
+
})
|
|
62
|
+
.optional(),
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* Full schema for `tokens.config.json`. Every field is optional so the
|
|
66
|
+
* minimum-viable config is `{ "figmaFile": "..." }` — the rest gets sensible
|
|
67
|
+
* defaults.
|
|
68
|
+
*/
|
|
69
|
+
export const TokensConfigSchema = z
|
|
70
|
+
.object({
|
|
71
|
+
/** Optional JSON Schema URL for editor autocompletion. */
|
|
72
|
+
$schema: z.string().optional(),
|
|
73
|
+
/**
|
|
74
|
+
* Figma file URL or fileKey. When omitted, tools fall back to the
|
|
75
|
+
* currently-connected Desktop Bridge plugin's file (Local Mode) or the
|
|
76
|
+
* file context bound by figma_pair_plugin (Cloud Mode).
|
|
77
|
+
*/
|
|
78
|
+
figmaFile: z.string().optional(),
|
|
79
|
+
/** Where the canonical (committed) token sources live. */
|
|
80
|
+
source: z
|
|
81
|
+
.object({
|
|
82
|
+
/** Directory holding the canonical token files. */
|
|
83
|
+
dir: z.string(),
|
|
84
|
+
/** Glob pattern within dir. Default: "*.tokens.json" */
|
|
85
|
+
pattern: z.string().optional(),
|
|
86
|
+
/**
|
|
87
|
+
* Canonical format for source files. DTCG is the recommended default;
|
|
88
|
+
* Tokens Studio is supported for users who already have a `$themes.json`
|
|
89
|
+
* setup (e.g. Altitude).
|
|
90
|
+
*/
|
|
91
|
+
canonical: z.enum(["dtcg", "tokens-studio"]).default("dtcg"),
|
|
92
|
+
})
|
|
93
|
+
.default({ dir: "src/styles/tokens", canonical: "dtcg" }),
|
|
94
|
+
/** Where build outputs (CSS, Tailwind, etc.) get written. */
|
|
95
|
+
generated: z
|
|
96
|
+
.object({
|
|
97
|
+
dir: z.string().default("src/styles/generated"),
|
|
98
|
+
formats: z.array(OutputTargetSchema).default([]),
|
|
99
|
+
})
|
|
100
|
+
.optional(),
|
|
101
|
+
/** Mode name mappings (Figma mode name → output mode name). */
|
|
102
|
+
modes: z
|
|
103
|
+
.object({
|
|
104
|
+
/** e.g. { "Light": "light", "Dark": "dark" } */
|
|
105
|
+
map: z.record(z.string()).optional(),
|
|
106
|
+
/** Default mode if a token has no explicit mode (e.g. "Light"). */
|
|
107
|
+
default: z.string().optional(),
|
|
108
|
+
})
|
|
109
|
+
.optional(),
|
|
110
|
+
/** Default conflict-resolution strategy when not specified per-call. */
|
|
111
|
+
conflictResolution: z
|
|
112
|
+
.enum(["ask", "figma-wins", "code-wins", "skip"])
|
|
113
|
+
.default("ask"),
|
|
114
|
+
/** Behavior for tokens that exist on one side but not the other. */
|
|
115
|
+
sync: z
|
|
116
|
+
.object({
|
|
117
|
+
onMissingInCode: z
|
|
118
|
+
.enum(["preserve", "delete", "warn"])
|
|
119
|
+
.default("preserve"),
|
|
120
|
+
onMissingInFigma: z
|
|
121
|
+
.enum(["preserve", "delete", "warn"])
|
|
122
|
+
.default("preserve"),
|
|
123
|
+
})
|
|
124
|
+
.optional(),
|
|
125
|
+
})
|
|
126
|
+
.strict();
|
|
127
|
+
/**
|
|
128
|
+
* Walk up from `startDir` looking for `tokens.config.json`. Returns the first
|
|
129
|
+
* match, or `null` if none found by the filesystem root.
|
|
130
|
+
*/
|
|
131
|
+
export function findTokensConfig(startDir) {
|
|
132
|
+
let dir = resolve(startDir);
|
|
133
|
+
// Hard cap on directory traversal so a misconfigured startDir can't loop
|
|
134
|
+
// forever (defense against symlinks/weird filesystems).
|
|
135
|
+
const maxDepth = 32;
|
|
136
|
+
for (let i = 0; i < maxDepth; i++) {
|
|
137
|
+
const candidate = join(dir, "tokens.config.json");
|
|
138
|
+
if (existsSync(candidate)) {
|
|
139
|
+
return candidate;
|
|
140
|
+
}
|
|
141
|
+
const parent = dirname(dir);
|
|
142
|
+
if (parent === dir) {
|
|
143
|
+
// Hit filesystem root, no config found.
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
dir = parent;
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Load and validate `tokens.config.json`. If `explicitPath` is provided, uses
|
|
152
|
+
* that; otherwise autodiscovers by walking up from `cwd` (default
|
|
153
|
+
* `process.cwd()`).
|
|
154
|
+
*
|
|
155
|
+
* Returns `null` if no config is found AND no explicit path was given. Throws
|
|
156
|
+
* if an explicit path doesn't exist, or if the discovered file fails schema
|
|
157
|
+
* validation.
|
|
158
|
+
*/
|
|
159
|
+
export function loadTokensConfig(opts = {}) {
|
|
160
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
161
|
+
const configPath = opts.explicitPath
|
|
162
|
+
? resolve(opts.explicitPath)
|
|
163
|
+
: findTokensConfig(cwd);
|
|
164
|
+
if (!configPath)
|
|
165
|
+
return null;
|
|
166
|
+
if (!existsSync(configPath)) {
|
|
167
|
+
throw new Error(`[figma-console-mcp] tokens.config.json not found at ${configPath}`);
|
|
168
|
+
}
|
|
169
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
170
|
+
let parsed;
|
|
171
|
+
try {
|
|
172
|
+
parsed = JSON.parse(raw);
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
throw new Error(`[figma-console-mcp] tokens.config.json at ${configPath} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
176
|
+
}
|
|
177
|
+
const result = TokensConfigSchema.safeParse(parsed);
|
|
178
|
+
if (!result.success) {
|
|
179
|
+
const issues = result.error.issues
|
|
180
|
+
.map((i) => ` • ${i.path.join(".")}: ${i.message}`)
|
|
181
|
+
.join("\n");
|
|
182
|
+
throw new Error(`[figma-console-mcp] tokens.config.json at ${configPath} failed validation:\n${issues}`);
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
config: result.data,
|
|
186
|
+
configPath,
|
|
187
|
+
projectRoot: dirname(configPath),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Default config used when none is found. Drives the "no-config detected"
|
|
192
|
+
* response shape from figma_export_tokens — the AI uses this to propose a
|
|
193
|
+
* scaffold to the user.
|
|
194
|
+
*/
|
|
195
|
+
export const DEFAULT_TOKENS_CONFIG = {
|
|
196
|
+
source: { dir: "src/styles/tokens", canonical: "dtcg" },
|
|
197
|
+
generated: {
|
|
198
|
+
dir: "src/styles/generated",
|
|
199
|
+
formats: [
|
|
200
|
+
{ format: "css-vars", splitByMode: true },
|
|
201
|
+
],
|
|
202
|
+
},
|
|
203
|
+
conflictResolution: "ask",
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Build a `suggestedScaffold` payload returned when a tool is called and no
|
|
207
|
+
* `tokens.config.json` exists. The AI presents this scaffold to the user,
|
|
208
|
+
* writes the files via its native edit/write tools, then calls the original
|
|
209
|
+
* tool again.
|
|
210
|
+
*/
|
|
211
|
+
export function buildSuggestedScaffold(opts) {
|
|
212
|
+
const config = {
|
|
213
|
+
$schema: "https://figma-console-mcp.southleft.com/schemas/tokens.config.v1.json",
|
|
214
|
+
source: { dir: "src/styles/tokens", canonical: "dtcg" },
|
|
215
|
+
generated: {
|
|
216
|
+
dir: "src/styles/generated",
|
|
217
|
+
formats: pickStartingFormats(opts.detectedFramework),
|
|
218
|
+
},
|
|
219
|
+
conflictResolution: "ask",
|
|
220
|
+
};
|
|
221
|
+
const stylesheetImport = pickStylesheetImport(opts.detectedFramework);
|
|
222
|
+
return {
|
|
223
|
+
configContent: JSON.stringify(config, null, 2),
|
|
224
|
+
directories: [config.source.dir, config.generated?.dir ?? "src/styles/generated"],
|
|
225
|
+
stylesheetImport,
|
|
226
|
+
nextSteps: [
|
|
227
|
+
"1. Write `tokens.config.json` at the project root using `configContent`.",
|
|
228
|
+
`2. Create the directories: ${config.source.dir} and ${config.generated?.dir}.`,
|
|
229
|
+
`3. Add this line to your main stylesheet:\n ${stylesheetImport}`,
|
|
230
|
+
"4. Run `figma_export_tokens` again — it'll pick up the new config and populate the source dir.",
|
|
231
|
+
].join("\n"),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function pickStartingFormats(framework) {
|
|
235
|
+
// Always emit DTCG as the canonical committed source; layer the
|
|
236
|
+
// framework-appropriate runtime format on top.
|
|
237
|
+
const base = [];
|
|
238
|
+
switch (framework) {
|
|
239
|
+
case "tailwind-v4":
|
|
240
|
+
base.push({ format: "tailwind-v4", splitByMode: true });
|
|
241
|
+
break;
|
|
242
|
+
case "tailwind-v3":
|
|
243
|
+
base.push({ format: "tailwind-v3" });
|
|
244
|
+
break;
|
|
245
|
+
case "scss":
|
|
246
|
+
base.push({ format: "scss", splitByMode: true });
|
|
247
|
+
break;
|
|
248
|
+
case "ts":
|
|
249
|
+
base.push({ format: "ts-module" });
|
|
250
|
+
base.push({ format: "css-vars", splitByMode: true });
|
|
251
|
+
break;
|
|
252
|
+
case "css":
|
|
253
|
+
default:
|
|
254
|
+
base.push({ format: "css-vars", splitByMode: true });
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
return base;
|
|
258
|
+
}
|
|
259
|
+
function pickStylesheetImport(framework) {
|
|
260
|
+
switch (framework) {
|
|
261
|
+
case "tailwind-v4":
|
|
262
|
+
return "@import './styles/generated/tailwind.theme.css';";
|
|
263
|
+
case "scss":
|
|
264
|
+
return "@use './styles/generated/tokens.scss' as *;";
|
|
265
|
+
case "ts":
|
|
266
|
+
case "css":
|
|
267
|
+
default:
|
|
268
|
+
return "@import './styles/generated/tokens.css';";
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Pick the export formats from a loaded config that map to a given runtime
|
|
273
|
+
* format. Used by figma_export_tokens to decide which generated files to
|
|
274
|
+
* write. Returns the list verbatim if the caller passed an explicit format.
|
|
275
|
+
*/
|
|
276
|
+
export function resolveOutputTargets(config, explicitFormat) {
|
|
277
|
+
if (explicitFormat) {
|
|
278
|
+
// Caller specified a format directly; ignore config's generated list.
|
|
279
|
+
return [{ format: explicitFormat }];
|
|
280
|
+
}
|
|
281
|
+
if (!config?.generated?.formats?.length) {
|
|
282
|
+
// No formats configured. Default to DTCG only — produces the canonical
|
|
283
|
+
// source files but no derived runtime outputs.
|
|
284
|
+
return [{ format: "dtcg" }];
|
|
285
|
+
}
|
|
286
|
+
return config.generated.formats;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Resolve the conflict-resolution strategy. Per-call argument wins over config
|
|
290
|
+
* default, which wins over the global default ("ask").
|
|
291
|
+
*/
|
|
292
|
+
export function resolveConflictStrategy(config, perCall) {
|
|
293
|
+
return perCall ?? config?.conflictResolution ?? "ask";
|
|
294
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DTCG dialect helpers — legacy vs 2025.10 value encodings.
|
|
3
|
+
*
|
|
4
|
+
* The token pipeline historically speaks the "legacy" DTCG dialect: colors
|
|
5
|
+
* as hex strings ("#4085F2"), FLOAT dimensions as bare numbers. The DTCG
|
|
6
|
+
* 2025.10 spec (https://tr.designtokens.org/format/) switched to object
|
|
7
|
+
* forms:
|
|
8
|
+
*
|
|
9
|
+
* color = { colorSpace: "srgb", components: [r, g, b], alpha?, hex? }
|
|
10
|
+
* dimension = { value: number, unit: "px" | "rem" }
|
|
11
|
+
* duration = { value: number, unit: "ms" | "s" } (we already emit this)
|
|
12
|
+
*
|
|
13
|
+
* Export stays legacy by default (downstream consumers depend on it) and
|
|
14
|
+
* opts into 2025 via the `dtcgDialect` option. Import accepts BOTH dialects
|
|
15
|
+
* unconditionally. This module centralizes:
|
|
16
|
+
*
|
|
17
|
+
* - 2025 encoding helpers used by the dtcg/json formatters at render time
|
|
18
|
+
* - dialect-agnostic canonicalization used by the import diff so a 2025
|
|
19
|
+
* color object compares equal to the same color's legacy hex string
|
|
20
|
+
* (both are quantized to 1/255 per channel, tolerating the 8-bit
|
|
21
|
+
* precision loss inherent to hex)
|
|
22
|
+
* - stripping of the transient `rawColor` field the converter carries on
|
|
23
|
+
* COLOR TokenValues (full-precision floats for 2025 components) so it
|
|
24
|
+
* never leaks into serialized output
|
|
25
|
+
*/
|
|
26
|
+
export function clamp01(n) {
|
|
27
|
+
if (Number.isNaN(n))
|
|
28
|
+
return 0;
|
|
29
|
+
return Math.max(0, Math.min(1, n));
|
|
30
|
+
}
|
|
31
|
+
function byteHex(f) {
|
|
32
|
+
return Math.round(clamp01(f) * 255)
|
|
33
|
+
.toString(16)
|
|
34
|
+
.padStart(2, "0");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Canonicalize any color-like literal to a lowercase 8-digit hex string
|
|
38
|
+
* (`#rrggbbaa`), or return null when the literal isn't recognizably a color.
|
|
39
|
+
*
|
|
40
|
+
* Accepts:
|
|
41
|
+
* - hex strings: #rgb, #rrggbb, #rrggbbaa
|
|
42
|
+
* - 2025.10 color objects with srgb (or unspecified) colorSpace +
|
|
43
|
+
* 3 numeric components (+ optional alpha)
|
|
44
|
+
* - color objects with a hex fallback field (any colorSpace) + optional alpha
|
|
45
|
+
*
|
|
46
|
+
* Both the components form and the hex form quantize to 1 / 255 per channel,
|
|
47
|
+
* so a full-precision components array compares equal to the hex string the
|
|
48
|
+
* legacy pipeline derived from the same Figma floats.
|
|
49
|
+
*/
|
|
50
|
+
export function colorLiteralToCanonicalHex(literal) {
|
|
51
|
+
if (typeof literal === "string") {
|
|
52
|
+
const m = literal
|
|
53
|
+
.trim()
|
|
54
|
+
.match(/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i);
|
|
55
|
+
if (!m)
|
|
56
|
+
return null;
|
|
57
|
+
let digits = m[1].toLowerCase();
|
|
58
|
+
if (digits.length === 3) {
|
|
59
|
+
digits = digits
|
|
60
|
+
.split("")
|
|
61
|
+
.map((c) => c + c)
|
|
62
|
+
.join("");
|
|
63
|
+
}
|
|
64
|
+
if (digits.length === 6)
|
|
65
|
+
digits += "ff";
|
|
66
|
+
return `#${digits}`;
|
|
67
|
+
}
|
|
68
|
+
if (literal && typeof literal === "object" && !Array.isArray(literal)) {
|
|
69
|
+
const o = literal;
|
|
70
|
+
const colorSpace = typeof o.colorSpace === "string" ? o.colorSpace : undefined;
|
|
71
|
+
const comps = o.components;
|
|
72
|
+
if ((colorSpace === undefined || colorSpace === "srgb") &&
|
|
73
|
+
Array.isArray(comps) &&
|
|
74
|
+
comps.length === 3 &&
|
|
75
|
+
comps.every((c) => typeof c === "number")) {
|
|
76
|
+
const [r, g, b] = comps;
|
|
77
|
+
const a = typeof o.alpha === "number" ? o.alpha : 1;
|
|
78
|
+
return `#${byteHex(r)}${byteHex(g)}${byteHex(b)}${byteHex(a)}`;
|
|
79
|
+
}
|
|
80
|
+
if (typeof o.hex === "string") {
|
|
81
|
+
const base = colorLiteralToCanonicalHex(o.hex);
|
|
82
|
+
if (!base)
|
|
83
|
+
return null;
|
|
84
|
+
if (typeof o.alpha === "number") {
|
|
85
|
+
return base.slice(0, 7) + byteHex(o.alpha);
|
|
86
|
+
}
|
|
87
|
+
return base;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Parse a hex color string to raw rgba floats (0–1). Returns null on
|
|
94
|
+
* anything that isn't a valid 3/6/8-digit hex string.
|
|
95
|
+
*/
|
|
96
|
+
export function hexToRawRgba(hex) {
|
|
97
|
+
const canonical = colorLiteralToCanonicalHex(hex);
|
|
98
|
+
if (!canonical)
|
|
99
|
+
return null;
|
|
100
|
+
const d = canonical.slice(1);
|
|
101
|
+
return {
|
|
102
|
+
r: parseInt(d.slice(0, 2), 16) / 255,
|
|
103
|
+
g: parseInt(d.slice(2, 4), 16) / 255,
|
|
104
|
+
b: parseInt(d.slice(4, 6), 16) / 255,
|
|
105
|
+
a: parseInt(d.slice(6, 8), 16) / 255,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Encode a color TokenValue in the DTCG 2025.10 object form.
|
|
110
|
+
*
|
|
111
|
+
* Prefers the converter's transient `rawColor` floats (full precision — NOT
|
|
112
|
+
* round-tripped through 8-bit hex); falls back to parsing a hex-string
|
|
113
|
+
* literal. Literals already in object form pass through verbatim. Returns
|
|
114
|
+
* null when the value can't be encoded (caller keeps the legacy rendering).
|
|
115
|
+
*
|
|
116
|
+
* `alpha` is emitted only when < 1; `hex` is always included as the interop
|
|
117
|
+
* courtesy field (#RRGGBB, alpha carried separately).
|
|
118
|
+
*/
|
|
119
|
+
export function colorValueTo2025(value) {
|
|
120
|
+
const lit = value.literal;
|
|
121
|
+
if (lit && typeof lit === "object" && !Array.isArray(lit)) {
|
|
122
|
+
// Already object-form (e.g. a re-exported 2025 document) — pass through.
|
|
123
|
+
const o = lit;
|
|
124
|
+
if ("colorSpace" in o || "components" in o || "hex" in o)
|
|
125
|
+
return o;
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
let floats = value.rawColor ?? null;
|
|
129
|
+
if (!floats && typeof lit === "string") {
|
|
130
|
+
floats = hexToRawRgba(lit);
|
|
131
|
+
}
|
|
132
|
+
if (!floats)
|
|
133
|
+
return null;
|
|
134
|
+
const { r, g, b, a } = floats;
|
|
135
|
+
return {
|
|
136
|
+
colorSpace: "srgb",
|
|
137
|
+
components: [r, g, b],
|
|
138
|
+
...(a < 1 ? { alpha: a } : {}),
|
|
139
|
+
hex: `#${byteHex(r)}${byteHex(g)}${byteHex(b)}`.toUpperCase(),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Encode a dimension literal in the DTCG 2025.10 object form. The converter
|
|
144
|
+
* emits Figma FLOAT dimensions as bare unitless numbers conventionally
|
|
145
|
+
* interpreted as px (the same convention the css/json formatters use), so
|
|
146
|
+
* only bare finite numbers are converted; everything else (unit strings,
|
|
147
|
+
* pre-encoded objects) keeps its current rendering.
|
|
148
|
+
*/
|
|
149
|
+
export function dimensionLiteralTo2025(literal) {
|
|
150
|
+
if (typeof literal === "number" && Number.isFinite(literal)) {
|
|
151
|
+
return { value: literal, unit: "px" };
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Normalize a TokenValue to a dialect-agnostic comparable form for diffing:
|
|
157
|
+
*
|
|
158
|
+
* - the transient `rawColor` field is dropped (Figma-side values carry it;
|
|
159
|
+
* parsed code-side values never do)
|
|
160
|
+
* - color-like literals (hex strings OR 2025 color objects) normalize to a
|
|
161
|
+
* lowercase 8-digit hex string, quantized to 1/255 per channel
|
|
162
|
+
* - `{ value, unit }` objects with px/ms normalize to the bare number
|
|
163
|
+
* ("s" converts to ms first), so `{value: 16, unit: "px"}` equals 16 and
|
|
164
|
+
* `{value: 0.3, unit: "s"}` equals `{value: 300, unit: "ms"}`
|
|
165
|
+
* - "16px"-style strings normalize to the bare number
|
|
166
|
+
*
|
|
167
|
+
* Conservative by design: anything not confidently recognized is returned
|
|
168
|
+
* unchanged (minus rawColor), falling back to the existing deep comparison.
|
|
169
|
+
*/
|
|
170
|
+
export function canonicalizeTokenValueForComparison(v) {
|
|
171
|
+
if (v === null || typeof v !== "object" || Array.isArray(v))
|
|
172
|
+
return v;
|
|
173
|
+
const obj = v;
|
|
174
|
+
if (!("literal" in obj) && !("reference" in obj))
|
|
175
|
+
return v;
|
|
176
|
+
const { rawColor: _rawColor, ...rest } = obj;
|
|
177
|
+
if (rest.literal !== undefined) {
|
|
178
|
+
const hex = colorLiteralToCanonicalHex(rest.literal);
|
|
179
|
+
if (hex !== null)
|
|
180
|
+
return { ...rest, literal: hex };
|
|
181
|
+
const num = numericLiteralToCanonical(rest.literal);
|
|
182
|
+
if (num !== null)
|
|
183
|
+
return { ...rest, literal: num };
|
|
184
|
+
}
|
|
185
|
+
return rest;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Normalize dimension/duration-shaped literals to a bare comparable number:
|
|
189
|
+
* - `{ value: n, unit: "px" | "ms" }` → n
|
|
190
|
+
* - `{ value: n, unit: "s" }` → n * 1000 (canonical ms)
|
|
191
|
+
* - `"16px"` strings → 16
|
|
192
|
+
* Returns null for everything else (including rem/em/% and objects with
|
|
193
|
+
* extra fields — those keep structural comparison).
|
|
194
|
+
*/
|
|
195
|
+
function numericLiteralToCanonical(literal) {
|
|
196
|
+
if (typeof literal === "string") {
|
|
197
|
+
const m = literal.trim().match(/^(-?(?:\d+\.?\d*|\.\d+))px$/i);
|
|
198
|
+
return m ? Number(m[1]) : null;
|
|
199
|
+
}
|
|
200
|
+
if (literal &&
|
|
201
|
+
typeof literal === "object" &&
|
|
202
|
+
!Array.isArray(literal) &&
|
|
203
|
+
Object.keys(literal).length === 2) {
|
|
204
|
+
const o = literal;
|
|
205
|
+
if (typeof o.value === "number" && typeof o.unit === "string") {
|
|
206
|
+
if (o.unit === "px" || o.unit === "ms")
|
|
207
|
+
return o.value;
|
|
208
|
+
if (o.unit === "s")
|
|
209
|
+
return o.value * 1000;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Return a copy of a mode-keyed TokenValue map with the transient `rawColor`
|
|
216
|
+
* field removed from every entry. Used wherever values get serialized
|
|
217
|
+
* (lastSyncedValue snapshots, diff-plan samples) so the transient field never
|
|
218
|
+
* appears in output — keeping legacy output byte-identical.
|
|
219
|
+
*/
|
|
220
|
+
export function stripRawColorFromValues(values) {
|
|
221
|
+
const out = {};
|
|
222
|
+
for (const [k, v] of Object.entries(values)) {
|
|
223
|
+
if (v && typeof v === "object" && "rawColor" in v) {
|
|
224
|
+
const { rawColor: _rawColor, ...rest } = v;
|
|
225
|
+
out[k] = rest;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
out[k] = v;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return out;
|
|
232
|
+
}
|