@3fn/core 14.0.0 → 15.0.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.
Files changed (1442) hide show
  1. package/.kiro/steering/AI-Collaboration-Principles.md +9 -3
  2. package/.kiro/steering/Agent-Directory.md +31 -7
  3. package/.kiro/steering/Civitas-System-Overview.md +5 -14
  4. package/.kiro/steering/DesignerPunk-Systems-Overview.md +3 -3
  5. package/.kiro/steering/Spec-Feedback-Protocol.md +2 -11
  6. package/.kiro/steering/Task-Completion-Protocol.md +17 -16
  7. package/.kiro/steering/start-up-tasks.md +15 -7
  8. package/CHANGELOG.md +74 -0
  9. package/README.md +26 -21
  10. package/application-mcp-server/src/__tests__/consumerRootLiveReindex.test.ts +118 -0
  11. package/application-mcp-server/src/__tests__/errorCatalogWiring.test.ts +73 -0
  12. package/application-mcp-server/src/__tests__/mcpDataRootsDeclaration.test.ts +107 -0
  13. package/application-mcp-server/src/__tests__/tool-boundary.contract.test.ts +55 -0
  14. package/application-mcp-server/src/index.ts +249 -59
  15. package/application-mcp-server/src/indexer/ComponentIndexer.ts +273 -46
  16. package/application-mcp-server/src/indexer/ModeClassifier.ts +23 -16
  17. package/application-mcp-server/src/indexer/SemanticOverrideReader.ts +113 -0
  18. package/application-mcp-server/src/indexer/TokenIndexer.ts +195 -3
  19. package/application-mcp-server/src/indexer/__tests__/MultiRootIndexing.test.ts +134 -0
  20. package/application-mcp-server/src/indexer/__tests__/ThemeResolution.test.ts +241 -0
  21. package/application-mcp-server/src/indexer/__tests__/ThemeRootFollowsIndex.test.ts +216 -0
  22. package/application-mcp-server/src/indexer/__tests__/fixtures/consumerFixture.ts +84 -0
  23. package/application-mcp-server/src/indexer/resolveThemeTierRoot.ts +61 -0
  24. package/application-mcp-server/src/watcher/FileWatcher.ts +20 -7
  25. package/dist/ComponentTokens.android.kt +12 -12
  26. package/dist/ComponentTokens.ios.swift +12 -12
  27. package/dist/ComponentTokens.web.css +3 -3
  28. package/dist/DesignTokens.android.kt +1 -5
  29. package/dist/DesignTokens.dtcg.json +388 -122
  30. package/dist/DesignTokens.figma.json +281 -941
  31. package/dist/DesignTokens.ios.swift +1 -5
  32. package/dist/DesignTokens.web.css +5 -5
  33. package/dist/browser/designerpunk.esm.js +174 -103
  34. package/dist/browser/designerpunk.esm.min.js +58 -55
  35. package/dist/browser/designerpunk.umd.js +174 -103
  36. package/dist/browser/designerpunk.umd.min.js +58 -55
  37. package/dist/browser/tokens.css +7 -7
  38. package/dist/build/platforms/AndroidMotionTokenFormatter.d.ts +101 -0
  39. package/dist/build/platforms/AndroidMotionTokenFormatter.js +220 -0
  40. package/dist/build/platforms/WebMotionTokenFormatter.d.ts +85 -0
  41. package/dist/build/platforms/WebMotionTokenFormatter.js +167 -0
  42. package/dist/build/platforms/iOSMotionTokenFormatter.d.ts +99 -0
  43. package/dist/build/platforms/iOSMotionTokenFormatter.js +221 -0
  44. package/dist/build/tokens/defineComponentTokens.d.ts +10 -0
  45. package/dist/build/tokens/defineComponentTokens.js +26 -0
  46. package/dist/build/validation/index.d.ts +0 -4
  47. package/dist/build/validation/index.js +1 -8
  48. package/dist/cli/attach.d.ts +153 -0
  49. package/dist/cli/attach.js +423 -0
  50. package/dist/cli/designerpunk.d.ts +46 -0
  51. package/dist/cli/designerpunk.js +171 -34
  52. package/dist/cli/figma-extract.js +10 -1
  53. package/dist/cli/figma-push.js +11 -2
  54. package/dist/cli/init.d.ts +36 -5
  55. package/dist/cli/init.js +348 -143
  56. package/dist/cli/loadComponentTokens.d.ts +25 -0
  57. package/dist/cli/loadComponentTokens.js +87 -8
  58. package/dist/cli/shared/bornRepo.d.ts +50 -0
  59. package/dist/cli/shared/bornRepo.js +199 -0
  60. package/dist/cli/shared/errorCatalog.d.ts +130 -0
  61. package/dist/cli/shared/errorCatalog.js +148 -0
  62. package/dist/cli/shared/mcpConfig/cc.d.ts +25 -0
  63. package/dist/cli/shared/mcpConfig/cc.js +156 -0
  64. package/dist/cli/shared/mcpConfig/kiro.d.ts +53 -0
  65. package/dist/cli/shared/mcpConfig/kiro.js +140 -0
  66. package/dist/cli/shared/mcpDataRoots.d.ts +88 -1
  67. package/dist/cli/shared/mcpDataRoots.js +76 -2
  68. package/dist/cli/shared/transforms.d.ts +64 -0
  69. package/dist/cli/shared/transforms.js +138 -0
  70. package/dist/cli/shared/vocabulary.d.ts +50 -0
  71. package/dist/cli/shared/vocabulary.js +62 -0
  72. package/dist/cli/sync/Applier.d.ts +25 -26
  73. package/dist/cli/sync/Applier.js +37 -73
  74. package/dist/cli/sync/Classifier.d.ts +70 -6
  75. package/dist/cli/sync/Classifier.js +123 -84
  76. package/dist/cli/sync/FileScanner.d.ts +19 -10
  77. package/dist/cli/sync/FileScanner.js +33 -25
  78. package/dist/cli/sync/KeyGrain.d.ts +106 -0
  79. package/dist/cli/sync/KeyGrain.js +301 -0
  80. package/dist/cli/sync/Manifest.d.ts +147 -12
  81. package/dist/cli/sync/Manifest.js +276 -21
  82. package/dist/cli/sync/Migration.d.ts +271 -0
  83. package/dist/cli/sync/Migration.js +764 -0
  84. package/dist/cli/sync/NameContract.d.ts +169 -0
  85. package/dist/cli/sync/NameContract.js +246 -0
  86. package/dist/cli/sync/RegionGrain.d.ts +118 -0
  87. package/dist/cli/sync/RegionGrain.js +167 -0
  88. package/dist/cli/sync/Reporter.d.ts +33 -4
  89. package/dist/cli/sync/Reporter.js +112 -53
  90. package/dist/cli/sync/SteeringDirCheck.d.ts +32 -4
  91. package/dist/cli/sync/SteeringDirCheck.js +62 -14
  92. package/dist/cli/sync/index.d.ts +125 -6
  93. package/dist/cli/sync/index.js +716 -66
  94. package/dist/color/OklchValidator.d.ts +43 -3
  95. package/dist/color/OklchValidator.js +46 -8
  96. package/dist/components/core/Avatar-Base/avatar.tokens.d.ts +21 -26
  97. package/dist/components/core/Avatar-Base/avatar.tokens.js +31 -34
  98. package/dist/components/core/Avatar-Base/index.d.ts +1 -1
  99. package/dist/components/core/Avatar-Base/index.js +2 -2
  100. package/dist/components/core/Button-CTA/Button-CTA.refs.d.ts +83 -0
  101. package/dist/components/core/Button-CTA/Button-CTA.refs.js +86 -0
  102. package/dist/components/core/Button-CTA/Button-CTA.tokens.d.ts +20 -10
  103. package/dist/components/core/Button-CTA/Button-CTA.tokens.js +21 -10
  104. package/dist/components/core/Button-CTA/index.d.ts +2 -2
  105. package/dist/components/core/Button-CTA/index.js +3 -3
  106. package/dist/components/core/Button-Icon/buttonIcon.tokens.d.ts +28 -14
  107. package/dist/components/core/Button-Icon/buttonIcon.tokens.js +35 -20
  108. package/dist/components/core/Button-VerticalList-Item/platforms/web/ButtonVerticalListItem.web.d.ts +11 -30
  109. package/dist/components/core/Button-VerticalList-Item/platforms/web/ButtonVerticalListItem.web.js +16 -49
  110. package/dist/components/core/Container-Base/Container-Base.refs.d.ts +181 -0
  111. package/dist/components/core/Container-Base/Container-Base.refs.js +223 -0
  112. package/dist/components/core/Container-Base/index.d.ts +2 -2
  113. package/dist/components/core/Container-Base/index.js +10 -10
  114. package/dist/components/core/Container-Base/platforms/web/ContainerBase.web.js +1 -1
  115. package/dist/components/core/Container-Base/platforms/web/token-mapping.d.ts +27 -9
  116. package/dist/components/core/Container-Base/platforms/web/token-mapping.js +50 -22
  117. package/dist/components/core/Container-Card-Base/Container-Card-Base.refs.d.ts +149 -0
  118. package/dist/components/core/Container-Card-Base/Container-Card-Base.refs.js +207 -0
  119. package/dist/components/core/Container-Card-Base/index.d.ts +1 -1
  120. package/dist/components/core/Container-Card-Base/index.js +19 -19
  121. package/dist/components/core/Container-Card-Base/platforms/web/ContainerCardBase.web.js +7 -6
  122. package/dist/components/core/Input-Radio-Base/platforms/web/InputRadioBase.web.d.ts +15 -0
  123. package/dist/components/core/Input-Radio-Base/platforms/web/InputRadioBase.web.js +41 -1
  124. package/dist/components/core/Input-Text-Base/Input-Text-Base.refs.d.ts +331 -0
  125. package/dist/components/core/Input-Text-Base/Input-Text-Base.refs.js +164 -0
  126. package/dist/components/core/Input-Text-Base/platforms/web/InputTextBase.web.js +1 -1
  127. package/dist/components/core/Input-Text-Email/Input-Text-Email.refs.d.ts +20 -0
  128. package/dist/components/core/Input-Text-Email/Input-Text-Email.refs.js +34 -0
  129. package/dist/components/core/Input-Text-Password/Input-Text-Password.refs.d.ts +20 -0
  130. package/dist/components/core/Input-Text-Password/Input-Text-Password.refs.js +34 -0
  131. package/dist/components/core/Input-Text-Password/platforms/web/InputTextPassword.web.d.ts +30 -0
  132. package/dist/components/core/Input-Text-Password/platforms/web/InputTextPassword.web.js +72 -3
  133. package/dist/components/core/Input-Text-PhoneNumber/Input-Text-PhoneNumber.refs.d.ts +20 -0
  134. package/dist/components/core/Input-Text-PhoneNumber/Input-Text-PhoneNumber.refs.js +34 -0
  135. package/dist/consumer-canonical/agents/ada.md +331 -0
  136. package/dist/consumer-canonical/agents/data.md +429 -0
  137. package/dist/consumer-canonical/agents/kenya.md +400 -0
  138. package/dist/consumer-canonical/agents/leonardo.md +524 -0
  139. package/dist/consumer-canonical/agents/lina.md +501 -0
  140. package/dist/consumer-canonical/agents/sparky.md +395 -0
  141. package/dist/consumer-canonical/agents/stacy.md +515 -0
  142. package/dist/consumer-canonical/agents/thurgood.md +463 -0
  143. package/dist/consumer-canonical/always-set/agent-directory.dispositions.yaml +21 -0
  144. package/dist/consumer-canonical/always-set/agent-directory.overlay.md +51 -0
  145. package/dist/consumer-canonical/always-set/ai-collaboration-principles.dispositions.yaml +15 -0
  146. package/dist/consumer-canonical/always-set/ai-collaboration-principles.overlay.md +26 -0
  147. package/dist/consumer-canonical/always-set/civitas-system-overview.dispositions.yaml +15 -0
  148. package/dist/consumer-canonical/always-set/civitas-system-overview.overlay.md +70 -0
  149. package/dist/consumer-canonical/always-set/core-goals.dispositions.yaml +9 -0
  150. package/dist/consumer-canonical/always-set/core-goals.overlay.md +74 -0
  151. package/dist/consumer-canonical/always-set/designerpunk-systems-overview.dispositions.yaml +16 -0
  152. package/dist/consumer-canonical/always-set/designerpunk-systems-overview.overlay.md +44 -0
  153. package/dist/consumer-canonical/always-set/spec-feedback-protocol.dispositions.yaml +21 -0
  154. package/dist/consumer-canonical/always-set/spec-feedback-protocol.overlay.md +44 -0
  155. package/dist/consumer-canonical/always-set/start-up-tasks.dispositions.yaml +15 -0
  156. package/dist/consumer-canonical/always-set/start-up-tasks.overlay.md +25 -0
  157. package/dist/consumer-canonical/always-set/task-completion-protocol.dispositions.yaml +19 -0
  158. package/dist/consumer-canonical/always-set/task-completion-protocol.overlay.md +116 -0
  159. package/dist/consumer-canonical/consumer-profile.yaml +9 -0
  160. package/dist/consumer-canonical/shared/always-set.yaml +113 -0
  161. package/dist/consumer-canonical/shared/field-dispositions.yaml +85 -0
  162. package/dist/consumer-canonical/shared/shared-catalog.yaml +19 -0
  163. package/dist/consumer-canonical/shared/skills-map.yaml +33 -0
  164. package/dist/consumer-canonical/skills/adaptive/SKILL.md +301 -0
  165. package/dist/consumer-canonical/skills/adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/container-behavior.md +112 -0
  166. package/dist/consumer-canonical/skills/adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/get-started.md +69 -0
  167. package/dist/consumer-canonical/skills/adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/index.md +81 -0
  168. package/dist/consumer-canonical/skills/adaptive/references/android/develop/ui/compose/layouts/adaptive/flexbox/item-behavior.md +170 -0
  169. package/dist/consumer-canonical/skills/adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/container-properties.md +238 -0
  170. package/dist/consumer-canonical/skills/adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/get-started.md +51 -0
  171. package/dist/consumer-canonical/skills/adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/index.md +73 -0
  172. package/dist/consumer-canonical/skills/adaptive/references/android/develop/ui/compose/layouts/adaptive/grid/item-properties.md +168 -0
  173. package/dist/consumer-canonical/skills/adaptive/references/android/develop/ui/compose/layouts/adaptive/mediaquery/index.md +329 -0
  174. package/dist/consumer-canonical/skills/adaptive/references/android/develop/ui/compose/tooling/debug.md +114 -0
  175. package/dist/consumer-canonical/skills/adaptive/references/android/guide/navigation/navigation-3/recipes/material-listdetail.md +141 -0
  176. package/dist/consumer-canonical/skills/edge-to-edge/SKILL.md +426 -0
  177. package/dist/consumer-canonical/skills/impeccable/SKILL.md +237 -0
  178. package/dist/consumer-canonical/skills/impeccable/detector-exclusions.md +42 -0
  179. package/dist/consumer-canonical/skills/impeccable/reference/adapt.md +190 -0
  180. package/dist/consumer-canonical/skills/impeccable/reference/animate.md +194 -0
  181. package/dist/consumer-canonical/skills/impeccable/reference/audit.md +150 -0
  182. package/dist/consumer-canonical/skills/impeccable/reference/bolder.md +113 -0
  183. package/dist/consumer-canonical/skills/impeccable/reference/brand-dp.md +103 -0
  184. package/dist/consumer-canonical/skills/impeccable/reference/clarify.md +174 -0
  185. package/dist/consumer-canonical/skills/impeccable/reference/codex.md +105 -0
  186. package/dist/consumer-canonical/skills/impeccable/reference/cognitive-load.md +106 -0
  187. package/dist/consumer-canonical/skills/impeccable/reference/color-and-contrast.md +122 -0
  188. package/dist/consumer-canonical/skills/impeccable/reference/colorize.md +155 -0
  189. package/dist/consumer-canonical/skills/impeccable/reference/craft.md +123 -0
  190. package/dist/consumer-canonical/skills/impeccable/reference/critique.md +245 -0
  191. package/dist/consumer-canonical/skills/impeccable/reference/delight.md +302 -0
  192. package/dist/consumer-canonical/skills/impeccable/reference/distill.md +111 -0
  193. package/dist/consumer-canonical/skills/impeccable/reference/extract-dp.md +43 -0
  194. package/dist/consumer-canonical/skills/impeccable/reference/harden.md +347 -0
  195. package/dist/consumer-canonical/skills/impeccable/reference/heuristics-scoring.md +234 -0
  196. package/dist/consumer-canonical/skills/impeccable/reference/interaction-design.md +195 -0
  197. package/dist/consumer-canonical/skills/impeccable/reference/layout.md +141 -0
  198. package/dist/consumer-canonical/skills/impeccable/reference/live.md +622 -0
  199. package/dist/consumer-canonical/skills/impeccable/reference/motion-design.md +109 -0
  200. package/dist/consumer-canonical/skills/impeccable/reference/onboard.md +234 -0
  201. package/dist/consumer-canonical/skills/impeccable/reference/optimize.md +258 -0
  202. package/dist/consumer-canonical/skills/impeccable/reference/overdrive.md +130 -0
  203. package/dist/consumer-canonical/skills/impeccable/reference/personas.md +179 -0
  204. package/dist/consumer-canonical/skills/impeccable/reference/polish.md +242 -0
  205. package/dist/consumer-canonical/skills/impeccable/reference/product-dp.md +79 -0
  206. package/dist/consumer-canonical/skills/impeccable/reference/quieter.md +99 -0
  207. package/dist/consumer-canonical/skills/impeccable/reference/responsive-design.md +114 -0
  208. package/dist/consumer-canonical/skills/impeccable/reference/shape.md +165 -0
  209. package/dist/consumer-canonical/skills/impeccable/reference/spatial-design.md +100 -0
  210. package/dist/consumer-canonical/skills/impeccable/reference/typeset.md +126 -0
  211. package/dist/consumer-canonical/skills/impeccable/reference/typography.md +159 -0
  212. package/dist/consumer-canonical/skills/impeccable/reference/ux-writing.md +107 -0
  213. package/dist/consumer-canonical/skills/impeccable/scripts/detect.mjs +21 -0
  214. package/dist/consumer-canonical/skills/impeccable/scripts/detector/browser/injected/index.mjs +1725 -0
  215. package/dist/consumer-canonical/skills/impeccable/scripts/detector/cli/main.mjs +244 -0
  216. package/dist/consumer-canonical/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +4567 -0
  217. package/dist/consumer-canonical/skills/impeccable/scripts/detector/detect-antipatterns.mjs +43 -0
  218. package/dist/consumer-canonical/skills/impeccable/scripts/detector/engines/browser/detect-url.mjs +252 -0
  219. package/dist/consumer-canonical/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +535 -0
  220. package/dist/consumer-canonical/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +986 -0
  221. package/dist/consumer-canonical/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +208 -0
  222. package/dist/consumer-canonical/skills/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs +189 -0
  223. package/dist/consumer-canonical/skills/impeccable/scripts/detector/findings.mjs +12 -0
  224. package/dist/consumer-canonical/skills/impeccable/scripts/detector/node/file-system.mjs +198 -0
  225. package/dist/consumer-canonical/skills/impeccable/scripts/detector/profile/profiler.mjs +166 -0
  226. package/dist/consumer-canonical/skills/impeccable/scripts/detector/registry/antipatterns.mjs +419 -0
  227. package/dist/consumer-canonical/skills/impeccable/scripts/detector/rules/checks.mjs +2316 -0
  228. package/dist/consumer-canonical/skills/impeccable/scripts/detector/shared/color.mjs +156 -0
  229. package/dist/consumer-canonical/skills/impeccable/scripts/detector/shared/constants.mjs +101 -0
  230. package/dist/consumer-canonical/skills/impeccable/scripts/detector/shared/page.mjs +7 -0
  231. package/dist/consumer-canonical/skills/navigation-3/SKILL.md +110 -0
  232. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/index.md +38 -0
  233. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/migration-guide.md +498 -0
  234. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/animations.md +147 -0
  235. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/basic.md +89 -0
  236. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/basicdsl.md +85 -0
  237. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/basicsaveable.md +90 -0
  238. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/bottomsheet.md +195 -0
  239. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/common-ui.md +200 -0
  240. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/conditional.md +230 -0
  241. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/deeplinks-advanced.md +155 -0
  242. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/deeplinks-basic.md +744 -0
  243. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/dialog.md +107 -0
  244. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/material-listdetail.md +141 -0
  245. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/material-supportingpane.md +145 -0
  246. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/modular-hilt.md +283 -0
  247. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/modular-koin.md +287 -0
  248. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/multiple-backstacks.md +436 -0
  249. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/passingarguments.md +371 -0
  250. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/results-event.md +272 -0
  251. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/results-state.md +266 -0
  252. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/scenes-listdetail.md +435 -0
  253. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/navigation-3/recipes/scenes-twopane.md +244 -0
  254. package/dist/consumer-canonical/skills/navigation-3/references/android/guide/navigation/type-safe-destinations.md +129 -0
  255. package/dist/consumer-canonical/skills/theming-styles/SKILL.md +220 -0
  256. package/dist/consumer-canonical/skills/theming-styles/references/android/develop/ui/compose/designsystems/custom.md +459 -0
  257. package/dist/consumer-canonical/skills/theming-styles/references/android/develop/ui/compose/styles/fundamentals.md +420 -0
  258. package/dist/consumer-canonical/skills/theming-styles/references/android/develop/ui/compose/styles/state-animations.md +461 -0
  259. package/dist/consumer-canonical/skills/theming-styles/references/android/develop/ui/compose/styles/styles-vs-modifiers.md +48 -0
  260. package/dist/consumer-canonical/skills/theming-styles/references/android/develop/ui/compose/styles/theming.md +257 -0
  261. package/dist/generator/consumer-entry.js +5939 -0
  262. package/dist/generators/DTCGFormatGenerator.d.ts +14 -4
  263. package/dist/generators/DTCGFormatGenerator.js +35 -18
  264. package/dist/generators/TokenFileGenerator.js +20 -15
  265. package/dist/generators/generateTokenIndex.d.ts +14 -0
  266. package/dist/generators/generateTokenIndex.js +23 -0
  267. package/dist/generators/transformers/FigmaTransformer.d.ts +35 -0
  268. package/dist/generators/transformers/FigmaTransformer.js +101 -13
  269. package/dist/generators/types/DTCGTypes.d.ts +10 -0
  270. package/dist/mcp/application-mcp.js +1062 -261
  271. package/dist/mcp/docs-mcp.js +93 -13
  272. package/dist/mcp/product-mcp.js +539 -41
  273. package/dist/mcp/tool-manifest.json +184 -0
  274. package/dist/name-contract.json +4283 -0
  275. package/dist/tokens/BlurTokens.d.ts +3 -1
  276. package/dist/tokens/BlurTokens.js +6 -4
  277. package/dist/tokens/ShadowOffsetTokens.js +14 -14
  278. package/dist/tokens/SizingTokens.js +3 -3
  279. package/dist/tokens/TapAreaTokens.d.ts +13 -2
  280. package/dist/tokens/TapAreaTokens.js +19 -8
  281. package/dist/tokens/component/progress.d.ts +65 -5
  282. package/dist/tokens/component/progress.js +79 -18
  283. package/dist/tokens/semantic/ColorTokens.js +50 -5
  284. package/dist/tokens/semantic/TypographyTokens.js +10 -10
  285. package/dist/tokens/themes/dark/SemanticOverrides.js +21 -4
  286. package/dist/tools/integrity/Invariants.d.ts +23 -8
  287. package/dist/tools/integrity/Invariants.js +27 -8
  288. package/dist/tools/integrity/cli/run-audit.js +1 -1
  289. package/dist/types/PrimitiveToken.d.ts +15 -1
  290. package/dist/types/generated/TokenTypes.d.ts +1 -1
  291. package/dist/types/generated/TokenTypes.js +1 -1
  292. package/dist/types/index.d.ts +1 -0
  293. package/governance/AI-Collaboration-Framework.md +19 -10
  294. package/governance/BUILD-SYSTEM-SETUP.md +1 -2
  295. package/governance/Component-Development-Guide.md +1 -1
  296. package/governance/Component-Development-Standards.md +19 -18
  297. package/governance/Component-Family-Avatar.md +6 -6
  298. package/governance/Component-Family-Badge.md +19 -19
  299. package/governance/Component-Family-Button.md +26 -26
  300. package/governance/Component-Family-Chip.md +14 -14
  301. package/governance/Component-Family-Container.md +12 -12
  302. package/governance/Component-Family-Form-Inputs.md +61 -61
  303. package/governance/Component-Family-Icon.md +8 -8
  304. package/governance/Component-Family-Navigation.md +3 -3
  305. package/governance/Component-Inheritance-Structures.md +29 -28
  306. package/governance/Component-Readiness-Status.md +6 -7
  307. package/governance/Component-Templates.md +26 -26
  308. package/governance/Contract-System-Reference.md +1 -1
  309. package/governance/DTCG-Integration-Guide.md +63 -36
  310. package/governance/DesignerPunk-Integration-Guide.md +57 -61
  311. package/governance/Figma-Workflow-Guide.md +15 -8
  312. package/governance/Process-Development-Workflow.md +4 -4
  313. package/governance/Process-File-Organization.md +1 -4
  314. package/governance/Process-Hook-Operations.md +6 -7
  315. package/governance/Process-Integration-Methodology.md +5 -5
  316. package/governance/Process-Spec-Planning.md +187 -68
  317. package/governance/Product-Handoff-Protocol.md +27 -2
  318. package/governance/Rosetta-System-Architecture.md +7 -5
  319. package/governance/Test-Behavioral-Contract-Validation.md +5 -0
  320. package/governance/Test-Development-Standards.md +4 -4
  321. package/governance/Token-Family-Accessibility.md +18 -14
  322. package/governance/Token-Family-Blend.md +5 -4
  323. package/governance/Token-Family-Blur.md +8 -8
  324. package/governance/Token-Family-Color.md +40 -22
  325. package/governance/Token-Family-Glow.md +26 -24
  326. package/governance/Token-Family-Layering.md +1 -0
  327. package/governance/Token-Family-Motion.md +22 -13
  328. package/governance/Token-Family-Opacity.md +20 -34
  329. package/governance/Token-Family-Radius.md +4 -2
  330. package/governance/Token-Family-Responsive.md +4 -4
  331. package/governance/Token-Family-Shadow.md +69 -46
  332. package/governance/Token-Family-Spacing.md +22 -12
  333. package/governance/Token-Family-Typography.md +86 -85
  334. package/governance/Token-Governance.md +5 -1
  335. package/governance/Token-Quick-Reference.md +97 -80
  336. package/governance/Transformer-Development-Guide.md +5 -4
  337. package/governance/Web-Authoring-Standards.md +1 -1
  338. package/governance/classification-map.md +706 -10
  339. package/governance/completion-documentation-guide.md +298 -33
  340. package/governance/platform-implementation-guidelines.md +3 -3
  341. package/governance/release-management-system.md +28 -63
  342. package/mcp-server/src/index.ts +16 -12
  343. package/mcp-server/src/relocation-integrity-gate/__tests__/relocation-integrity-gate.test.ts +3 -3
  344. package/mcp-server/src/relocation-integrity-gate/relocation-integrity-gate.ts +70 -49
  345. package/mcp-server/src/tools/find-docs.ts +1 -0
  346. package/mcp-server/src/tools/get-document-full.ts +1 -0
  347. package/mcp-server/src/tools/get-document-summary.ts +1 -0
  348. package/mcp-server/src/tools/get-index-health.ts +1 -0
  349. package/mcp-server/src/tools/get-section.ts +1 -0
  350. package/mcp-server/src/tools/list-cross-references.ts +1 -0
  351. package/mcp-server/src/tools/rebuild-index.ts +1 -0
  352. package/mcp-server/src/tools/validate-metadata.ts +1 -0
  353. package/package.json +76 -16
  354. package/src/build/tokens/defineComponentTokens.ts +43 -1
  355. package/src/cli/templates/mcp-config.json.template +15 -20
  356. package/src/components/core/Avatar-Base/platforms/android/AvatarPreview.kt +9 -2
  357. package/src/components/core/Container-Base/Container-Base.schema.yaml +9 -11
  358. package/src/components/core/Container-Base/platforms/android/ContainerBase.android.kt +5 -5
  359. package/src/components/core/Container-Base/platforms/ios/ContainerBase.ios.swift +5 -5
  360. package/src/components/core/Container-Card-Base/platforms/android/ContainerCardBase.android.kt +3 -3
  361. package/src/components/core/Container-Card-Base/platforms/ios/ContainerCardBase.ios.swift +2 -2
  362. package/src/components/core/Nav-Header-App/contracts.yaml +1 -1
  363. package/src/components/core/Nav-Header-Base/component-meta.yaml +0 -1
  364. package/src/components/core/Nav-Header-Base/contracts.yaml +1 -1
  365. package/src/components/core/Nav-Header-Page/contracts.yaml +1 -1
  366. package/src/components/core/Nav-TabBar-Base/contracts.yaml +1 -1
  367. package/src/components/core/Progress-Bar-Base/contracts.yaml +1 -1
  368. package/src/tokens/BlurTokens.ts +6 -4
  369. package/src/tokens/ShadowOffsetTokens.ts +14 -14
  370. package/src/tokens/SizingTokens.ts +3 -3
  371. package/src/tokens/TapAreaTokens.ts +20 -8
  372. package/src/tokens/__tests__/BaselineGridAlignmentFlag.test.ts +116 -0
  373. package/src/tokens/__tests__/BlurTokens.test.ts +10 -2
  374. package/src/tokens/__tests__/ProgressTokenCompliance.test.ts +5 -3
  375. package/src/tokens/__tests__/ProgressTokenFormulas.test.ts +11 -11
  376. package/src/tokens/__tests__/ProgressTokenTranslation.test.ts +22 -20
  377. package/src/tokens/__tests__/SemanticColorContrast.test.ts +339 -0
  378. package/src/tokens/__tests__/ShadowOffsetTokens.test.ts +8 -7
  379. package/src/tokens/__tests__/SizingTokens.test.ts +10 -2
  380. package/src/tokens/__tests__/TokenCategories.test.ts +1 -1
  381. package/src/tokens/__tests__/neutral-partition.test.ts +28 -0
  382. package/src/tokens/component/progress.ts +83 -21
  383. package/src/tokens/semantic/AccessibilityTokens.README.md +2 -2
  384. package/src/tokens/semantic/ColorTokens.ts +50 -5
  385. package/src/tokens/semantic/TypographyTokens.ts +10 -10
  386. package/src/tokens/semantic/__tests__/ColorTokens.test.ts +8 -4
  387. package/src/tokens/themes/dark/SemanticOverrides.ts +23 -4
  388. package/src/types/PrimitiveToken.ts +15 -1
  389. package/token-index/components.yaml +8 -8
  390. package/token-index/meta.json +3 -0
  391. package/token-index/semantics.yaml +21 -15
  392. package/.kiro/agents/ada-prompt.md +0 -213
  393. package/.kiro/agents/ada-prompt.md.attribution.json +0 -45
  394. package/.kiro/agents/ada.json +0 -72
  395. package/.kiro/agents/ada.json.attribution.json +0 -13
  396. package/.kiro/agents/data-prompt.md +0 -324
  397. package/.kiro/agents/data-prompt.md.attribution.json +0 -53
  398. package/.kiro/agents/data.json +0 -51
  399. package/.kiro/agents/data.json.attribution.json +0 -13
  400. package/.kiro/agents/kenya-prompt.md +0 -309
  401. package/.kiro/agents/kenya-prompt.md.attribution.json +0 -53
  402. package/.kiro/agents/kenya.json +0 -46
  403. package/.kiro/agents/kenya.json.attribution.json +0 -13
  404. package/.kiro/agents/leonardo-prompt.md +0 -359
  405. package/.kiro/agents/leonardo-prompt.md.attribution.json +0 -45
  406. package/.kiro/agents/leonardo.json +0 -47
  407. package/.kiro/agents/leonardo.json.attribution.json +0 -13
  408. package/.kiro/agents/lina-prompt.md +0 -344
  409. package/.kiro/agents/lina-prompt.md.attribution.json +0 -53
  410. package/.kiro/agents/lina.json +0 -64
  411. package/.kiro/agents/lina.json.attribution.json +0 -13
  412. package/.kiro/agents/sparky-prompt.md +0 -312
  413. package/.kiro/agents/sparky-prompt.md.attribution.json +0 -53
  414. package/.kiro/agents/sparky.json +0 -56
  415. package/.kiro/agents/sparky.json.attribution.json +0 -13
  416. package/.kiro/agents/stacy-prompt.md +0 -304
  417. package/.kiro/agents/stacy-prompt.md.attribution.json +0 -45
  418. package/.kiro/agents/stacy.json +0 -46
  419. package/.kiro/agents/stacy.json.attribution.json +0 -13
  420. package/.kiro/agents/thurgood-prompt.md +0 -363
  421. package/.kiro/agents/thurgood-prompt.md.attribution.json +0 -45
  422. package/.kiro/agents/thurgood.json +0 -47
  423. package/.kiro/agents/thurgood.json.attribution.json +0 -13
  424. package/.kiro/steering/personal-note.md +0 -35
  425. package/designerpunk.config.ts +0 -27
  426. package/dist/android/DesignTokens.android.kt +0 -695
  427. package/dist/components/core/Input-Text-Base/platforms/web/InputTextBase.browser.d.ts +0 -26
  428. package/dist/components/core/Input-Text-Base/platforms/web/InputTextBase.browser.js +0 -224
  429. package/dist/components/core/Input-Text-Email/platforms/web/InputTextEmail.browser.d.ts +0 -30
  430. package/dist/components/core/Input-Text-Email/platforms/web/InputTextEmail.browser.js +0 -254
  431. package/dist/components/core/Input-Text-Password/platforms/web/InputTextPassword.browser.d.ts +0 -44
  432. package/dist/components/core/Input-Text-Password/platforms/web/InputTextPassword.browser.js +0 -376
  433. package/dist/components/core/Input-Text-PhoneNumber/platforms/web/InputTextPhoneNumber.browser.d.ts +0 -38
  434. package/dist/components/core/Input-Text-PhoneNumber/platforms/web/InputTextPhoneNumber.browser.js +0 -328
  435. package/dist/ios/DesignTokens.ios.swift +0 -697
  436. package/dist/web/DesignTokens.web.css +0 -929
  437. package/product-template/agents/README.md +0 -73
  438. package/product-template/agents/ada-prompt.md +0 -83
  439. package/product-template/agents/data-prompt.md +0 -74
  440. package/product-template/agents/kenya-prompt.md +0 -74
  441. package/product-template/agents/leonardo-prompt.md +0 -99
  442. package/product-template/agents/lina-prompt.md +0 -61
  443. package/product-template/agents/sparky-prompt.md +0 -66
  444. package/product-template/agents/stacy-prompt.md +0 -51
  445. package/product-template/agents/thurgood-prompt.md +0 -64
  446. package/src/TokenEngine.ts +0 -628
  447. package/src/__tests__/BuildSystemIntegration.test.ts +0 -485
  448. package/src/__tests__/ProductMCPIntegration.test.ts +0 -204
  449. package/src/__tests__/__mocks__/styleMock.js +0 -18
  450. package/src/__tests__/browser-distribution/build-error-handling.test.ts +0 -143
  451. package/src/__tests__/browser-distribution/bundle-loading.test.ts +0 -353
  452. package/src/__tests__/browser-distribution/bundler-resolution.test.ts +0 -223
  453. package/src/__tests__/browser-distribution/component-registration.test.ts +0 -217
  454. package/src/__tests__/browser-distribution/css-bundling.test.ts +0 -233
  455. package/src/__tests__/browser-distribution/demo-system.test.ts +0 -588
  456. package/src/__tests__/browser-distribution/mcp-format-compliance.property.test.ts +0 -379
  457. package/src/__tests__/browser-distribution/mcp-queryability.test.ts +0 -342
  458. package/src/__tests__/browser-distribution/minification-effectiveness.property.test.ts +0 -188
  459. package/src/__tests__/browser-distribution/registration-idempotency.property.test.ts +0 -372
  460. package/src/__tests__/browser-distribution/soft-ceiling-warning.test.ts +0 -161
  461. package/src/__tests__/browser-distribution/token-completeness.property.test.ts +0 -412
  462. package/src/__tests__/browser-distribution/token-loading.test.ts +0 -344
  463. package/src/__tests__/browser-distribution/umd-bundle-loading.test.ts +0 -169
  464. package/src/__tests__/console-allowlist.json +0 -14
  465. package/src/__tests__/console-fail-setup.ts +0 -169
  466. package/src/__tests__/examples/improved-test-example.test.ts +0 -120
  467. package/src/__tests__/expected-exports.json +0 -66
  468. package/src/__tests__/export-contracts.test.ts +0 -83
  469. package/src/__tests__/fixtures/acknowledged-differences.json +0 -127
  470. package/src/__tests__/fixtures/acknowledged-differences.schema.json +0 -113
  471. package/src/__tests__/fixtures/acknowledged-differences.types.ts +0 -230
  472. package/src/__tests__/fixtures/tokenFixtures.ts +0 -248
  473. package/src/__tests__/helpers/configModuleLoader.ts +0 -20
  474. package/src/__tests__/helpers/tsModuleLoader.ts +0 -24
  475. package/src/__tests__/helpers/web-component-test-utils.ts +0 -39
  476. package/src/__tests__/integration/BlendCrossPlatformConsistency.test.ts +0 -505
  477. package/src/__tests__/integration/BuildSystemCompatibility.test.ts +0 -551
  478. package/src/__tests__/integration/CrossPlatformConsistency.test.ts +0 -855
  479. package/src/__tests__/integration/EndToEndWorkflow.test.ts +0 -601
  480. package/src/__tests__/integration/ErrorHandling.test.ts +0 -459
  481. package/src/__tests__/integration/OpacityPlatformTranslation.test.ts +0 -364
  482. package/src/__tests__/integration/PerformanceValidation.test.ts +0 -887
  483. package/src/__tests__/integration/SemanticTokenGeneration.test.ts +0 -451
  484. package/src/__tests__/integration/Spec107-DesignLanguageContext.test.ts +0 -139
  485. package/src/__tests__/integration/TokenSystemIntegration.test.ts +0 -890
  486. package/src/__tests__/integration/ValidationPipeline.test.ts +0 -404
  487. package/src/__tests__/package-drift-validation.test.ts +0 -249
  488. package/src/__tests__/performance/GenerationPerformance.test.ts +0 -409
  489. package/src/__tests__/performance/OptimizationValidation.test.ts +0 -509
  490. package/src/__tests__/platform-parity/ProgressPlatformParity.test.ts +0 -546
  491. package/src/__tests__/spec073-opacity-architecture.test.ts +0 -344
  492. package/src/__tests__/stemma-system/behavioral-contract-validation.test.ts +0 -520
  493. package/src/__tests__/stemma-system/composition-compliance-validation.test.ts +0 -162
  494. package/src/__tests__/stemma-system/contract-catalog-name-validation.test.ts +0 -184
  495. package/src/__tests__/stemma-system/contract-existence-validation.test.ts +0 -43
  496. package/src/__tests__/stemma-system/contract-test-reporter.ts +0 -269
  497. package/src/__tests__/stemma-system/cross-platform-consistency.test.ts +0 -564
  498. package/src/__tests__/stemma-system/form-inputs-contracts.test.ts +0 -710
  499. package/src/__tests__/stemma-system/input-text-native-base-call-alignment.test.ts +0 -298
  500. package/src/__tests__/stemma-system/mcp-component-integration.test.ts +0 -445
  501. package/src/analytics/PrimitiveTokenFallbackTracker.ts +0 -228
  502. package/src/analytics/SemanticTokenUsageTracker.ts +0 -193
  503. package/src/analytics/StrategicFlexibilityTracker.ts +0 -226
  504. package/src/analytics/TokenUsageTracker.ts +0 -177
  505. package/src/analytics/UsagePatternAnalyzer.ts +0 -177
  506. package/src/analytics/__tests__/UsageTracking.test.ts +0 -647
  507. package/src/analytics/index.ts +0 -42
  508. package/src/assets/fonts/__tests__/androidFontLoadingValidation.test.ts +0 -600
  509. package/src/assets/fonts/__tests__/fontLoading.test.ts +0 -341
  510. package/src/assets/fonts/__tests__/iosFontConfiguration.test.ts +0 -256
  511. package/src/assets/fonts/__tests__/iosFontLoadingValidation.test.ts +0 -465
  512. package/src/assets/fonts/inter/Inter-Bold.ttf +0 -0
  513. package/src/assets/fonts/inter/Inter-Bold.woff2 +0 -0
  514. package/src/assets/fonts/inter/Inter-Medium.ttf +0 -0
  515. package/src/assets/fonts/inter/Inter-Medium.woff2 +0 -0
  516. package/src/assets/fonts/inter/Inter-Regular.ttf +0 -0
  517. package/src/assets/fonts/inter/Inter-Regular.woff2 +0 -0
  518. package/src/assets/fonts/inter/Inter-SemiBold.ttf +0 -0
  519. package/src/assets/fonts/inter/Inter-SemiBold.woff2 +0 -0
  520. package/src/assets/fonts/inter/inter.css +0 -49
  521. package/src/blend/BlendCalculator.ts +0 -120
  522. package/src/blend/ColorSpaceUtils.ts +0 -325
  523. package/src/blend/OklchBlendCalculator.ts +0 -82
  524. package/src/blend/ThemeAwareBlendUtilities.web.ts +0 -323
  525. package/src/blend/__tests__/BlendCalculator.test.ts +0 -393
  526. package/src/blend/__tests__/BlendUtilities.property.test.ts +0 -600
  527. package/src/blend/__tests__/ColorSpaceUtils.test.ts +0 -885
  528. package/src/blend/__tests__/InteractionStateAudit.test.ts +0 -238
  529. package/src/blend/__tests__/OklchBlendCalculator.test.ts +0 -134
  530. package/src/blend/__tests__/ThemeAwareBlendUtilities.test.ts +0 -200
  531. package/src/blend/__tests__/ThemeSwitching.test.ts +0 -508
  532. package/src/blend/index.ts +0 -37
  533. package/src/browser-entry.ts +0 -270
  534. package/src/build/.gitkeep +0 -1
  535. package/src/build/BuildOrchestrator.ts +0 -663
  536. package/src/build/__tests__/AndroidBuildIntegration.test.ts +0 -437
  537. package/src/build/__tests__/AndroidMotionTokenGeneration.test.ts +0 -256
  538. package/src/build/__tests__/BuildOrchestrator.test.ts +0 -562
  539. package/src/build/__tests__/MotionTokenCrossPlatformIntegration.test.ts +0 -424
  540. package/src/build/__tests__/WebCSSTokenGeneration.test.ts +0 -271
  541. package/src/build/__tests__/WebMotionTokenGeneration.test.ts +0 -305
  542. package/src/build/__tests__/WebNPMPackageStructure.test.ts +0 -447
  543. package/src/build/__tests__/iOSMotionTokenGeneration.test.ts +0 -298
  544. package/src/build/errors/BuildError.ts +0 -140
  545. package/src/build/errors/ErrorDocumentation.ts +0 -638
  546. package/src/build/errors/ErrorHandler.ts +0 -406
  547. package/src/build/errors/ErrorReporter.ts +0 -573
  548. package/src/build/errors/PlatformGenerationError.ts +0 -201
  549. package/src/build/errors/README.md +0 -486
  550. package/src/build/errors/RecoveryStrategy.ts +0 -393
  551. package/src/build/errors/TokenGenerationError.ts +0 -196
  552. package/src/build/errors/TokenReferenceError.ts +0 -204
  553. package/src/build/errors/__tests__/BuildError.test.ts +0 -212
  554. package/src/build/errors/__tests__/ErrorDocumentation.example.ts +0 -272
  555. package/src/build/errors/__tests__/ErrorDocumentation.test.ts +0 -458
  556. package/src/build/errors/__tests__/ErrorHandler.integration.test.ts +0 -303
  557. package/src/build/errors/__tests__/ErrorHandler.test.ts +0 -502
  558. package/src/build/errors/__tests__/ErrorReporter.test.ts +0 -581
  559. package/src/build/errors/__tests__/MotionTokenErrors.test.ts +0 -392
  560. package/src/build/errors/__tests__/RecoveryStrategy.test.ts +0 -643
  561. package/src/build/errors/index.ts +0 -90
  562. package/src/build/index.ts +0 -73
  563. package/src/build/orchestration/IncrementalBuilder.ts +0 -532
  564. package/src/build/orchestration/ParallelExecutor.ts +0 -336
  565. package/src/build/orchestration/ProgressTracker.ts +0 -582
  566. package/src/build/orchestration/SequentialExecutor.ts +0 -305
  567. package/src/build/orchestration/__tests__/IncrementalBuilder.test.ts +0 -354
  568. package/src/build/orchestration/__tests__/ParallelExecutor.integration.test.ts +0 -295
  569. package/src/build/orchestration/__tests__/ParallelExecutor.test.ts +0 -493
  570. package/src/build/orchestration/__tests__/ProgressTracker.test.ts +0 -529
  571. package/src/build/orchestration/__tests__/SequentialExecutor.integration.test.ts +0 -202
  572. package/src/build/orchestration/__tests__/SequentialExecutor.test.ts +0 -232
  573. package/src/build/orchestration/index.ts +0 -35
  574. package/src/build/platforms/.gitkeep +0 -1
  575. package/src/build/platforms/AndroidBuilder.ts +0 -1366
  576. package/src/build/platforms/AndroidShadowGenerator.ts +0 -394
  577. package/src/build/platforms/IOSShadowGenerator.ts +0 -324
  578. package/src/build/platforms/PlatformBuilder.ts +0 -131
  579. package/src/build/platforms/WebBuilder.ts +0 -1414
  580. package/src/build/platforms/WebShadowGenerator.ts +0 -288
  581. package/src/build/platforms/__tests__/AndroidBuilder.tokenGeneration.test.ts +0 -146
  582. package/src/build/platforms/__tests__/AndroidShadowGenerator.test.ts +0 -195
  583. package/src/build/platforms/__tests__/IOSShadowGenerator.test.ts +0 -156
  584. package/src/build/platforms/__tests__/WebShadowGenerator.test.ts +0 -123
  585. package/src/build/platforms/__tests__/iOSBuilder.test.ts +0 -1599
  586. package/src/build/platforms/iOSBuilder.ts +0 -1746
  587. package/src/build/platforms/index.ts +0 -9
  588. package/src/build/product/ProductTokenGenerator.ts +0 -162
  589. package/src/build/product/TokenIndexReader.ts +0 -78
  590. package/src/build/product/__tests__/KotlinEmitter.test.ts +0 -109
  591. package/src/build/product/__tests__/ProductTokenGenerator.test.ts +0 -135
  592. package/src/build/product/__tests__/SwiftEmitter.test.ts +0 -90
  593. package/src/build/product/__tests__/TokenIndexReader.test.ts +0 -85
  594. package/src/build/product/__tests__/WebEmitter.test.ts +0 -111
  595. package/src/build/product/__tests__/fixtures/tokens/layout.yaml +0 -21
  596. package/src/build/product/__tests__/fixtures/tokens/motion.yaml +0 -11
  597. package/src/build/product/__tests__/fixtures/tokens/visualization.yaml +0 -8
  598. package/src/build/product/emitters/KotlinEmitter.ts +0 -83
  599. package/src/build/product/emitters/SwiftEmitter.ts +0 -95
  600. package/src/build/product/emitters/WebEmitter.ts +0 -69
  601. package/src/build/tokens/.gitkeep +0 -1
  602. package/src/build/tokens/__tests__/ClassInvariantGuard.test.ts +0 -167
  603. package/src/build/tokens/__tests__/ComponentTokenGenerator.test.ts +0 -285
  604. package/src/build/tokens/__tests__/TokenIntegrator.test.ts +0 -319
  605. package/src/build/tokens/__tests__/TokenSelector.test.ts +0 -264
  606. package/src/build/tokens/__tests__/UnitConverter.applyScaleWithRounding.test.ts +0 -160
  607. package/src/build/tokens/__tests__/UnitConverter.test.ts +0 -331
  608. package/src/build/tokens/__tests__/brand-dual-instance.test.ts +0 -135
  609. package/src/build/tokens/__tests__/defineComponentTokens.test.ts +0 -440
  610. package/src/build/types/.gitkeep +0 -1
  611. package/src/build/types/BuildConfig.ts +0 -123
  612. package/src/build/types/BuildOrchestrator.ts +0 -114
  613. package/src/build/types/BuildResult.ts +0 -125
  614. package/src/build/types/index.ts +0 -39
  615. package/src/build/validation/.gitkeep +0 -1
  616. package/src/build/validation/AndroidBuildValidator.ts +0 -630
  617. package/src/build/validation/CrossPlatformValidationReporter.ts +0 -1267
  618. package/src/build/validation/InterfaceContractValidator.ts +0 -417
  619. package/src/build/validation/InterfaceValidator.ts +0 -326
  620. package/src/build/validation/MathematicalConsistencyValidator.ts +0 -874
  621. package/src/build/validation/MethodSignatureValidator.ts +0 -374
  622. package/src/build/validation/PropertyTypeValidator.ts +0 -312
  623. package/src/build/validation/TokenComparator.ts +0 -796
  624. package/src/build/validation/ValidationReporter.example.ts +0 -310
  625. package/src/build/validation/ValidationReporter.ts +0 -745
  626. package/src/build/validation/WebBuildValidator.ts +0 -583
  627. package/src/build/validation/__tests__/AndroidBuildValidator.test.ts +0 -522
  628. package/src/build/validation/__tests__/CrossPlatformValidationReporter.test.ts +0 -593
  629. package/src/build/validation/__tests__/InterfaceContractValidator.test.ts +0 -647
  630. package/src/build/validation/__tests__/InterfaceValidation.functional.test.ts +0 -360
  631. package/src/build/validation/__tests__/InterfaceValidator.test.ts +0 -318
  632. package/src/build/validation/__tests__/MethodSignatureValidator.test.ts +0 -625
  633. package/src/build/validation/__tests__/MotionTokenCrossPlatformValidation.test.ts +0 -305
  634. package/src/build/validation/__tests__/MotionTokenValidation.test.ts +0 -309
  635. package/src/build/validation/__tests__/PropertyTypeValidator.test.ts +0 -557
  636. package/src/build/validation/__tests__/TokenComparator.test.ts +0 -358
  637. package/src/build/validation/__tests__/ValidationReporter.integration.test.ts +0 -424
  638. package/src/build/validation/__tests__/ValidationReporter.test.ts +0 -793
  639. package/src/build/validation/__tests__/WebBuildValidator.test.ts +0 -495
  640. package/src/build/validation/iOSBuildValidator.ts +0 -783
  641. package/src/build/validation/index.ts +0 -74
  642. package/src/build/validation/types/InterfaceDefinition.ts +0 -101
  643. package/src/build/validation/types/ValidationResult.ts +0 -114
  644. package/src/build/workflow/BuildMode.ts +0 -336
  645. package/src/build/workflow/CICDIntegration.ts +0 -503
  646. package/src/build/workflow/ConfigHelpers.example.ts +0 -317
  647. package/src/build/workflow/ConfigHelpers.ts +0 -834
  648. package/src/build/workflow/README.md +0 -327
  649. package/src/build/workflow/SourceMapGenerator.ts +0 -362
  650. package/src/build/workflow/__tests__/BuildMode.test.ts +0 -544
  651. package/src/build/workflow/__tests__/CICDIntegration.test.ts +0 -602
  652. package/src/build/workflow/__tests__/ConfigHelpers.test.ts +0 -559
  653. package/src/build/workflow/__tests__/SourceMapGenerator.test.ts +0 -421
  654. package/src/build/workflow/index.ts +0 -42
  655. package/src/cli/__tests__/Applier.test.ts +0 -202
  656. package/src/cli/__tests__/Classifier.test.ts +0 -187
  657. package/src/cli/__tests__/FileScanner.test.ts +0 -108
  658. package/src/cli/__tests__/IgnoreFilter.test.ts +0 -92
  659. package/src/cli/__tests__/Manifest.test.ts +0 -107
  660. package/src/cli/__tests__/PackageResolver.test.ts +0 -66
  661. package/src/cli/__tests__/Prompter.test.ts +0 -165
  662. package/src/cli/__tests__/Reporter.test.ts +0 -128
  663. package/src/cli/__tests__/backward-compat.test.ts +0 -142
  664. package/src/cli/__tests__/figma-extract.test.ts +0 -342
  665. package/src/cli/__tests__/figma-push.test.ts +0 -350
  666. package/src/cli/__tests__/init.test.ts +0 -293
  667. package/src/cli/__tests__/loadComponentTokens.test.ts +0 -187
  668. package/src/cli/__tests__/pipeline-independence.test.ts +0 -127
  669. package/src/cli/__tests__/product-only.test.ts +0 -130
  670. package/src/cli/__tests__/resolveTokens.test.ts +0 -88
  671. package/src/cli/__tests__/staleness.test.ts +0 -132
  672. package/src/cli/__tests__/sync.test.ts +0 -199
  673. package/src/cli/__tests__/validate.test.ts +0 -69
  674. package/src/cli/designerpunk.ts +0 -410
  675. package/src/cli/figma-extract.ts +0 -331
  676. package/src/cli/figma-push.ts +0 -288
  677. package/src/cli/generateProductTokens.ts +0 -69
  678. package/src/cli/init.ts +0 -481
  679. package/src/cli/loadComponentTokens.ts +0 -145
  680. package/src/cli/resolveTokens.ts +0 -123
  681. package/src/cli/shared/mcpDataRoots.ts +0 -122
  682. package/src/cli/shared/resolvePackageRoot.ts +0 -58
  683. package/src/cli/shared/transforms.ts +0 -18
  684. package/src/cli/staleness.ts +0 -81
  685. package/src/cli/sync/Applier.ts +0 -128
  686. package/src/cli/sync/Classifier.ts +0 -130
  687. package/src/cli/sync/FileScanner.ts +0 -64
  688. package/src/cli/sync/IgnoreFilter.ts +0 -44
  689. package/src/cli/sync/Manifest.ts +0 -64
  690. package/src/cli/sync/PackageResolver.ts +0 -40
  691. package/src/cli/sync/Prompter.ts +0 -173
  692. package/src/cli/sync/Reporter.ts +0 -78
  693. package/src/cli/sync/SteeringDirCheck.ts +0 -166
  694. package/src/cli/sync/index.ts +0 -115
  695. package/src/cli/validate.ts +0 -135
  696. package/src/cli/validateProductTokens.ts +0 -55
  697. package/src/color/OklchConverter.ts +0 -284
  698. package/src/color/OklchValidator.ts +0 -186
  699. package/src/color/__tests__/OklchConverter.test.ts +0 -232
  700. package/src/color/__tests__/OklchRegression.test.ts +0 -101
  701. package/src/color/__tests__/OklchValidator.test.ts +0 -199
  702. package/src/color/__tests__/WcagContrast.test.ts +0 -76
  703. package/src/components/__tests__/BlendTokenUsageValidation.test.ts +0 -726
  704. package/src/components/__tests__/DynamicImportGuard.test.ts +0 -226
  705. package/src/components/__tests__/ExtensionLintPolicy.test.ts +0 -113
  706. package/src/components/__tests__/TokenCompliance.test.ts +0 -921
  707. package/src/components/__tests__/colorInheritanceValidation.test.ts +0 -267
  708. package/src/components/__tests__/componentTypographyInheritance.test.ts +0 -326
  709. package/src/components/core/Avatar-Base/README.md +0 -366
  710. package/src/components/core/Avatar-Base/__tests__/.gitkeep +0 -3
  711. package/src/components/core/Avatar-Base/__tests__/Avatar.accessibility.test.ts +0 -597
  712. package/src/components/core/Avatar-Base/__tests__/Avatar.icon-integration.test.ts +0 -656
  713. package/src/components/core/Avatar-Base/__tests__/Avatar.image.test.ts +0 -396
  714. package/src/components/core/Avatar-Base/__tests__/Avatar.lifecycle.test.ts +0 -545
  715. package/src/components/core/Avatar-Base/__tests__/Avatar.rendering.test.ts +0 -505
  716. package/src/components/core/Avatar-Base/__tests__/Avatar.test.ts +0 -701
  717. package/src/components/core/Avatar-Base/avatar.tokens.ts +0 -376
  718. package/src/components/core/Avatar-Base/index.ts +0 -25
  719. package/src/components/core/Avatar-Base/platforms/ios/.gitkeep +0 -3
  720. package/src/components/core/Avatar-Base/platforms/web/.gitkeep +0 -3
  721. package/src/components/core/Avatar-Base/platforms/web/Avatar.styles.css +0 -595
  722. package/src/components/core/Avatar-Base/platforms/web/Avatar.web.ts +0 -892
  723. package/src/components/core/Avatar-Base/platforms/web/hexagon-clip.svg +0 -87
  724. package/src/components/core/Avatar-Base/tokens/.gitkeep +0 -4
  725. package/src/components/core/Avatar-Base/types.ts +0 -86
  726. package/src/components/core/Badge-Count-Base/README.md +0 -323
  727. package/src/components/core/Badge-Count-Base/__tests__/BadgeCountBase.stemma.test.ts +0 -548
  728. package/src/components/core/Badge-Count-Base/__tests__/BadgeCountBase.test.ts +0 -452
  729. package/src/components/core/Badge-Count-Base/__tests__/test-utils.ts +0 -244
  730. package/src/components/core/Badge-Count-Base/index.ts +0 -37
  731. package/src/components/core/Badge-Count-Base/platforms/ios/.gitkeep +0 -1
  732. package/src/components/core/Badge-Count-Base/platforms/web/BadgeCountBase.styles.css +0 -148
  733. package/src/components/core/Badge-Count-Base/platforms/web/BadgeCountBase.web.ts +0 -363
  734. package/src/components/core/Badge-Count-Base/types.ts +0 -150
  735. package/src/components/core/Badge-Count-Notification/README.md +0 -396
  736. package/src/components/core/Badge-Count-Notification/__tests__/BadgeCountNotification.stemma.test.ts +0 -571
  737. package/src/components/core/Badge-Count-Notification/__tests__/BadgeCountNotification.test.ts +0 -490
  738. package/src/components/core/Badge-Count-Notification/__tests__/test-utils.ts +0 -256
  739. package/src/components/core/Badge-Count-Notification/index.ts +0 -60
  740. package/src/components/core/Badge-Count-Notification/platforms/web/BadgeCountNotification.styles.css +0 -182
  741. package/src/components/core/Badge-Count-Notification/platforms/web/BadgeCountNotification.web.ts +0 -401
  742. package/src/components/core/Badge-Count-Notification/tokens.ts +0 -124
  743. package/src/components/core/Badge-Count-Notification/types.ts +0 -119
  744. package/src/components/core/Badge-Label-Base/README.md +0 -251
  745. package/src/components/core/Badge-Label-Base/__tests__/BadgeLabelBase.stemma.test.ts +0 -549
  746. package/src/components/core/Badge-Label-Base/__tests__/BadgeLabelBase.test.ts +0 -439
  747. package/src/components/core/Badge-Label-Base/__tests__/test-utils.ts +0 -269
  748. package/src/components/core/Badge-Label-Base/__tests__/tokens.test.ts +0 -88
  749. package/src/components/core/Badge-Label-Base/index.ts +0 -41
  750. package/src/components/core/Badge-Label-Base/platforms/web/BadgeLabelBase.styles.css +0 -166
  751. package/src/components/core/Badge-Label-Base/platforms/web/BadgeLabelBase.web.ts +0 -340
  752. package/src/components/core/Badge-Label-Base/tokens.ts +0 -80
  753. package/src/components/core/Badge-Label-Base/types.ts +0 -148
  754. package/src/components/core/Button-CTA/Button-CTA.tokens.ts +0 -79
  755. package/src/components/core/Button-CTA/README.md +0 -293
  756. package/src/components/core/Button-CTA/__tests__/ButtonCTA.alignment.test.ts +0 -355
  757. package/src/components/core/Button-CTA/__tests__/ButtonCTA.test.ts +0 -698
  758. package/src/components/core/Button-CTA/__tests__/ButtonCTA.tokens.test.ts +0 -89
  759. package/src/components/core/Button-CTA/__tests__/setup.test.ts +0 -209
  760. package/src/components/core/Button-CTA/__tests__/test-utils.ts +0 -185
  761. package/src/components/core/Button-CTA/examples/BasicUsage.html +0 -133
  762. package/src/components/core/Button-CTA/examples/BasicUsage.tsx +0 -219
  763. package/src/components/core/Button-CTA/examples/Variants.html +0 -263
  764. package/src/components/core/Button-CTA/examples/WithIcon.html +0 -166
  765. package/src/components/core/Button-CTA/index.ts +0 -20
  766. package/src/components/core/Button-CTA/platforms/web/ButtonCTA.web.css +0 -395
  767. package/src/components/core/Button-CTA/platforms/web/ButtonCTA.web.ts +0 -644
  768. package/src/components/core/Button-CTA/platforms/web/__tests__/ButtonCTA.icon-integration.test.ts +0 -476
  769. package/src/components/core/Button-CTA/types.ts +0 -239
  770. package/src/components/core/Button-Icon/README.md +0 -371
  771. package/src/components/core/Button-Icon/__tests__/ButtonIcon.alignment.test.ts +0 -358
  772. package/src/components/core/Button-Icon/__tests__/ButtonIcon.properties-8-13.test.ts +0 -953
  773. package/src/components/core/Button-Icon/__tests__/ButtonIcon.properties.test.ts +0 -920
  774. package/src/components/core/Button-Icon/__tests__/ButtonIcon.stemma.test.ts +0 -622
  775. package/src/components/core/Button-Icon/__tests__/ButtonIcon.unit.test.ts +0 -560
  776. package/src/components/core/Button-Icon/__tests__/setup.test.ts +0 -361
  777. package/src/components/core/Button-Icon/__tests__/test-utils.ts +0 -248
  778. package/src/components/core/Button-Icon/buttonIcon.tokens.ts +0 -202
  779. package/src/components/core/Button-Icon/platforms/web/.gitkeep +0 -4
  780. package/src/components/core/Button-Icon/platforms/web/ButtonIcon.web.css +0 -600
  781. package/src/components/core/Button-Icon/platforms/web/ButtonIcon.web.ts +0 -625
  782. package/src/components/core/Button-Icon/types.ts +0 -186
  783. package/src/components/core/Button-VerticalList-Item/Button-VerticalList-Item.tokens.ts +0 -112
  784. package/src/components/core/Button-VerticalList-Item/README.md +0 -450
  785. package/src/components/core/Button-VerticalList-Item/__tests__/.gitkeep +0 -2
  786. package/src/components/core/Button-VerticalList-Item/__tests__/ButtonVerticalListItem.alignment.test.ts +0 -271
  787. package/src/components/core/Button-VerticalList-Item/__tests__/ButtonVerticalListItem.failLoudly.test.ts +0 -106
  788. package/src/components/core/Button-VerticalList-Item/__tests__/ButtonVerticalListItem.integration.test.ts +0 -480
  789. package/src/components/core/Button-VerticalList-Item/__tests__/ButtonVerticalListItem.properties.test.ts +0 -634
  790. package/src/components/core/Button-VerticalList-Item/__tests__/ButtonVerticalListItem.unit.test.ts +0 -746
  791. package/src/components/core/Button-VerticalList-Item/__tests__/rtlSupport.test.ts +0 -206
  792. package/src/components/core/Button-VerticalList-Item/__tests__/test-utils.ts +0 -297
  793. package/src/components/core/Button-VerticalList-Item/__tests__/visualStateMapping.test.ts +0 -419
  794. package/src/components/core/Button-VerticalList-Item/index.ts +0 -49
  795. package/src/components/core/Button-VerticalList-Item/platforms/android/VerticalListButtonItemTest.kt +0 -1109
  796. package/src/components/core/Button-VerticalList-Item/platforms/ios/.gitkeep +0 -2
  797. package/src/components/core/Button-VerticalList-Item/platforms/ios/VerticalListButtonItemTests.swift +0 -794
  798. package/src/components/core/Button-VerticalList-Item/platforms/web/.gitkeep +0 -2
  799. package/src/components/core/Button-VerticalList-Item/platforms/web/ButtonVerticalListItem.styles.css +0 -459
  800. package/src/components/core/Button-VerticalList-Item/platforms/web/ButtonVerticalListItem.web.ts +0 -1030
  801. package/src/components/core/Button-VerticalList-Item/platforms/web/visualStateMapping.ts +0 -411
  802. package/src/components/core/Button-VerticalList-Item/types.ts +0 -338
  803. package/src/components/core/Button-VerticalList-Set/README.md +0 -578
  804. package/src/components/core/Button-VerticalList-Set/__tests__/.gitkeep +0 -5
  805. package/src/components/core/Button-VerticalList-Set/__tests__/ButtonVerticalListSet.integration.test.ts +0 -676
  806. package/src/components/core/Button-VerticalList-Set/__tests__/ButtonVerticalListSet.property.test.ts +0 -786
  807. package/src/components/core/Button-VerticalList-Set/__tests__/ButtonVerticalListSet.property2.test.ts +0 -1109
  808. package/src/components/core/Button-VerticalList-Set/__tests__/ButtonVerticalListSet.unit.test.ts +0 -924
  809. package/src/components/core/Button-VerticalList-Set/__tests__/animationTiming.test.ts +0 -182
  810. package/src/components/core/Button-VerticalList-Set/__tests__/crossPlatformConsistency.test.ts +0 -685
  811. package/src/components/core/Button-VerticalList-Set/__tests__/deriveItemStates.test.ts +0 -179
  812. package/src/components/core/Button-VerticalList-Set/__tests__/validation.test.ts +0 -275
  813. package/src/components/core/Button-VerticalList-Set/index.ts +0 -32
  814. package/src/components/core/Button-VerticalList-Set/platforms/android/ButtonVerticalListSetTest.kt +0 -961
  815. package/src/components/core/Button-VerticalList-Set/platforms/ios/.gitkeep +0 -0
  816. package/src/components/core/Button-VerticalList-Set/platforms/ios/ButtonVerticalListSetTests.swift +0 -475
  817. package/src/components/core/Button-VerticalList-Set/platforms/web/.gitkeep +0 -4
  818. package/src/components/core/Button-VerticalList-Set/platforms/web/Button-VerticalList-Set.styles.css +0 -167
  819. package/src/components/core/Button-VerticalList-Set/platforms/web/ButtonVerticalListSet.web.ts +0 -1446
  820. package/src/components/core/Button-VerticalList-Set/types.ts +0 -788
  821. package/src/components/core/Chip-Base/__tests__/ChipBase.test.ts +0 -534
  822. package/src/components/core/Chip-Base/index.ts +0 -40
  823. package/src/components/core/Chip-Base/platforms/ios/.gitkeep +0 -3
  824. package/src/components/core/Chip-Base/platforms/web/.gitkeep +0 -5
  825. package/src/components/core/Chip-Base/platforms/web/ChipBase.styles.css +0 -280
  826. package/src/components/core/Chip-Base/platforms/web/ChipBase.web.ts +0 -480
  827. package/src/components/core/Chip-Base/types.ts +0 -189
  828. package/src/components/core/Chip-Filter/__tests__/ChipFilter.test.ts +0 -592
  829. package/src/components/core/Chip-Filter/index.ts +0 -34
  830. package/src/components/core/Chip-Filter/platforms/web/ChipFilter.styles.css +0 -105
  831. package/src/components/core/Chip-Filter/platforms/web/ChipFilter.web.ts +0 -539
  832. package/src/components/core/Chip-Filter/types.ts +0 -47
  833. package/src/components/core/Chip-Input/__tests__/ChipInput.test.ts +0 -472
  834. package/src/components/core/Chip-Input/index.ts +0 -35
  835. package/src/components/core/Chip-Input/platforms/ios/.gitkeep +0 -3
  836. package/src/components/core/Chip-Input/platforms/web/ChipInput.styles.css +0 -99
  837. package/src/components/core/Chip-Input/platforms/web/ChipInput.web.ts +0 -485
  838. package/src/components/core/Chip-Input/types.ts +0 -35
  839. package/src/components/core/Container-Base/README.md +0 -450
  840. package/src/components/core/Container-Base/__tests__/ContainerBase.test.ts +0 -712
  841. package/src/components/core/Container-Base/index.ts +0 -47
  842. package/src/components/core/Container-Base/platforms/web/ContainerBase.web.ts +0 -405
  843. package/src/components/core/Container-Base/platforms/web/styles.css +0 -198
  844. package/src/components/core/Container-Base/platforms/web/token-mapping.ts +0 -573
  845. package/src/components/core/Container-Base/tokens.ts +0 -241
  846. package/src/components/core/Container-Base/types.ts +0 -307
  847. package/src/components/core/Container-Card-Base/README.md +0 -506
  848. package/src/components/core/Container-Card-Base/__tests__/ContainerCardBase.composition.test.ts +0 -167
  849. package/src/components/core/Container-Card-Base/__tests__/ContainerCardBase.test.ts +0 -646
  850. package/src/components/core/Container-Card-Base/index.ts +0 -64
  851. package/src/components/core/Container-Card-Base/platforms/web/ContainerCardBase.web.ts +0 -373
  852. package/src/components/core/Container-Card-Base/tokens.ts +0 -224
  853. package/src/components/core/Container-Card-Base/types.ts +0 -332
  854. package/src/components/core/Icon-Base/README.md +0 -168
  855. package/src/components/core/Icon-Base/__tests__/IconBase.test.ts +0 -192
  856. package/src/components/core/Icon-Base/index.ts +0 -34
  857. package/src/components/core/Icon-Base/platforms/ios/ASSET_CATALOG_SETUP.md +0 -239
  858. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Contents.json +0 -6
  859. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/Contents.json +0 -9
  860. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/alert-circle.imageset/Contents.json +0 -15
  861. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/alert-circle.imageset/alert-circle.svg +0 -1
  862. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/arrow-down.imageset/Contents.json +0 -15
  863. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/arrow-down.imageset/arrow-down.svg +0 -1
  864. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/arrow-left.imageset/Contents.json +0 -15
  865. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/arrow-left.imageset/arrow-left.svg +0 -1
  866. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/arrow-right.imageset/Contents.json +0 -15
  867. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/arrow-right.imageset/arrow-right.svg +0 -1
  868. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/arrow-up.imageset/Contents.json +0 -15
  869. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/arrow-up.imageset/arrow-up.svg +0 -1
  870. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/award.imageset/Contents.json +0 -15
  871. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/award.imageset/award.svg +0 -1
  872. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/bell.imageset/Contents.json +0 -15
  873. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/bell.imageset/bell.svg +0 -1
  874. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/briefcase.imageset/Contents.json +0 -15
  875. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/briefcase.imageset/briefcase.svg +0 -1
  876. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/calendar.imageset/Contents.json +0 -15
  877. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/calendar.imageset/calendar.svg +0 -1
  878. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/check-circle.imageset/Contents.json +0 -15
  879. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/check-circle.imageset/check-circle.svg +0 -1
  880. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/check.imageset/Contents.json +0 -15
  881. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/check.imageset/check.svg +0 -1
  882. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/chevron-down.imageset/Contents.json +0 -15
  883. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/chevron-down.imageset/chevron-down.svg +0 -1
  884. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/chevron-left.imageset/Contents.json +0 -15
  885. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/chevron-left.imageset/chevron-left.svg +0 -1
  886. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/chevron-right.imageset/Contents.json +0 -15
  887. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/chevron-right.imageset/chevron-right.svg +0 -1
  888. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/circle.imageset/Contents.json +0 -15
  889. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/circle.imageset/circle.svg +0 -1
  890. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/clock.imageset/Contents.json +0 -15
  891. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/clock.imageset/clock.svg +0 -1
  892. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/credit-card.imageset/Contents.json +0 -15
  893. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/credit-card.imageset/credit-card.svg +0 -1
  894. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/dollar-sign.imageset/Contents.json +0 -15
  895. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/dollar-sign.imageset/dollar-sign.svg +0 -1
  896. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/external-link.imageset/Contents.json +0 -15
  897. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/external-link.imageset/external-link.svg +0 -1
  898. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/eye-off.imageset/Contents.json +0 -15
  899. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/eye-off.imageset/eye-off.svg +0 -1
  900. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/eye.imageset/Contents.json +0 -15
  901. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/eye.imageset/eye.svg +0 -1
  902. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/file-text.imageset/Contents.json +0 -15
  903. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/file-text.imageset/file-text.svg +0 -1
  904. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/filter.imageset/Contents.json +0 -15
  905. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/filter.imageset/filter.svg +0 -1
  906. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/globe.imageset/Contents.json +0 -15
  907. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/globe.imageset/globe.svg +0 -1
  908. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/heart.imageset/Contents.json +0 -15
  909. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/heart.imageset/heart.svg +0 -1
  910. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/info.imageset/Contents.json +0 -15
  911. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/info.imageset/info.svg +0 -1
  912. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/mail.imageset/Contents.json +0 -15
  913. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/mail.imageset/mail.svg +0 -1
  914. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/map-pin.imageset/Contents.json +0 -15
  915. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/map-pin.imageset/map-pin.svg +0 -1
  916. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/minus.imageset/Contents.json +0 -15
  917. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/minus.imageset/minus.svg +0 -1
  918. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/more-horizontal.imageset/Contents.json +0 -15
  919. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/more-horizontal.imageset/more-horizontal.svg +0 -1
  920. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/more-vertical.imageset/Contents.json +0 -15
  921. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/more-vertical.imageset/more-vertical.svg +0 -1
  922. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/phone.imageset/Contents.json +0 -15
  923. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/phone.imageset/phone.svg +0 -1
  924. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/plus.imageset/Contents.json +0 -15
  925. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/plus.imageset/plus.svg +0 -1
  926. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/refresh-cw.imageset/Contents.json +0 -15
  927. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/refresh-cw.imageset/refresh-cw.svg +0 -1
  928. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/save.imageset/Contents.json +0 -15
  929. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/save.imageset/save.svg +0 -1
  930. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/search.imageset/Contents.json +0 -15
  931. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/search.imageset/search.svg +0 -1
  932. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/settings.imageset/Contents.json +0 -15
  933. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/settings.imageset/settings.svg +0 -1
  934. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/share-2.imageset/Contents.json +0 -15
  935. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/share-2.imageset/share-2.svg +0 -1
  936. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/share.imageset/Contents.json +0 -15
  937. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/share.imageset/share.svg +0 -1
  938. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/shield.imageset/Contents.json +0 -15
  939. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/shield.imageset/shield.svg +0 -1
  940. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/smartphone.imageset/Contents.json +0 -15
  941. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/smartphone.imageset/smartphone.svg +0 -1
  942. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/smile.imageset/Contents.json +0 -15
  943. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/smile.imageset/smile.svg +0 -1
  944. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/star.imageset/Contents.json +0 -15
  945. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/star.imageset/star.svg +0 -1
  946. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/trending-up.imageset/Contents.json +0 -15
  947. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/trending-up.imageset/trending-up.svg +0 -1
  948. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/user-check.imageset/Contents.json +0 -15
  949. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/user-check.imageset/user-check.svg +0 -1
  950. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/user-x.imageset/Contents.json +0 -15
  951. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/user-x.imageset/user-x.svg +0 -1
  952. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/user.imageset/Contents.json +0 -15
  953. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/user.imageset/user.svg +0 -1
  954. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/users.imageset/Contents.json +0 -15
  955. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/users.imageset/users.svg +0 -1
  956. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/wifi.imageset/Contents.json +0 -15
  957. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/wifi.imageset/wifi.svg +0 -1
  958. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/x.imageset/Contents.json +0 -15
  959. package/src/components/core/Icon-Base/platforms/ios/Icons.xcassets/Icons/x.imageset/x.svg +0 -1
  960. package/src/components/core/Icon-Base/platforms/web/IconBase.web.ts +0 -553
  961. package/src/components/core/Icon-Base/platforms/web/assets/alert-circle.svg +0 -1
  962. package/src/components/core/Icon-Base/platforms/web/assets/arrow-down.svg +0 -1
  963. package/src/components/core/Icon-Base/platforms/web/assets/arrow-left.svg +0 -1
  964. package/src/components/core/Icon-Base/platforms/web/assets/arrow-right.svg +0 -1
  965. package/src/components/core/Icon-Base/platforms/web/assets/arrow-up.svg +0 -1
  966. package/src/components/core/Icon-Base/platforms/web/assets/award.svg +0 -1
  967. package/src/components/core/Icon-Base/platforms/web/assets/bell.svg +0 -1
  968. package/src/components/core/Icon-Base/platforms/web/assets/briefcase.svg +0 -1
  969. package/src/components/core/Icon-Base/platforms/web/assets/calendar.svg +0 -1
  970. package/src/components/core/Icon-Base/platforms/web/assets/check-circle.svg +0 -1
  971. package/src/components/core/Icon-Base/platforms/web/assets/check.svg +0 -1
  972. package/src/components/core/Icon-Base/platforms/web/assets/chevron-down.svg +0 -1
  973. package/src/components/core/Icon-Base/platforms/web/assets/chevron-left.svg +0 -1
  974. package/src/components/core/Icon-Base/platforms/web/assets/chevron-right.svg +0 -1
  975. package/src/components/core/Icon-Base/platforms/web/assets/circle.svg +0 -1
  976. package/src/components/core/Icon-Base/platforms/web/assets/clock.svg +0 -1
  977. package/src/components/core/Icon-Base/platforms/web/assets/credit-card.svg +0 -1
  978. package/src/components/core/Icon-Base/platforms/web/assets/dollar-sign.svg +0 -1
  979. package/src/components/core/Icon-Base/platforms/web/assets/external-link.svg +0 -1
  980. package/src/components/core/Icon-Base/platforms/web/assets/eye-off.svg +0 -1
  981. package/src/components/core/Icon-Base/platforms/web/assets/eye.svg +0 -1
  982. package/src/components/core/Icon-Base/platforms/web/assets/file-text.svg +0 -1
  983. package/src/components/core/Icon-Base/platforms/web/assets/filter.svg +0 -1
  984. package/src/components/core/Icon-Base/platforms/web/assets/globe.svg +0 -1
  985. package/src/components/core/Icon-Base/platforms/web/assets/heart.svg +0 -1
  986. package/src/components/core/Icon-Base/platforms/web/assets/info.svg +0 -1
  987. package/src/components/core/Icon-Base/platforms/web/assets/mail.svg +0 -1
  988. package/src/components/core/Icon-Base/platforms/web/assets/map-pin.svg +0 -1
  989. package/src/components/core/Icon-Base/platforms/web/assets/minus.svg +0 -1
  990. package/src/components/core/Icon-Base/platforms/web/assets/more-horizontal.svg +0 -1
  991. package/src/components/core/Icon-Base/platforms/web/assets/more-vertical.svg +0 -1
  992. package/src/components/core/Icon-Base/platforms/web/assets/phone.svg +0 -1
  993. package/src/components/core/Icon-Base/platforms/web/assets/plus.svg +0 -1
  994. package/src/components/core/Icon-Base/platforms/web/assets/refresh-cw.svg +0 -1
  995. package/src/components/core/Icon-Base/platforms/web/assets/save.svg +0 -1
  996. package/src/components/core/Icon-Base/platforms/web/assets/search.svg +0 -1
  997. package/src/components/core/Icon-Base/platforms/web/assets/settings.svg +0 -1
  998. package/src/components/core/Icon-Base/platforms/web/assets/share-2.svg +0 -1
  999. package/src/components/core/Icon-Base/platforms/web/assets/share.svg +0 -1
  1000. package/src/components/core/Icon-Base/platforms/web/assets/shield.svg +0 -1
  1001. package/src/components/core/Icon-Base/platforms/web/assets/smartphone.svg +0 -1
  1002. package/src/components/core/Icon-Base/platforms/web/assets/smile.svg +0 -1
  1003. package/src/components/core/Icon-Base/platforms/web/assets/star.svg +0 -1
  1004. package/src/components/core/Icon-Base/platforms/web/assets/trending-up.svg +0 -1
  1005. package/src/components/core/Icon-Base/platforms/web/assets/user-check.svg +0 -1
  1006. package/src/components/core/Icon-Base/platforms/web/assets/user-x.svg +0 -1
  1007. package/src/components/core/Icon-Base/platforms/web/assets/user.svg +0 -1
  1008. package/src/components/core/Icon-Base/platforms/web/assets/users.svg +0 -1
  1009. package/src/components/core/Icon-Base/platforms/web/assets/wifi.svg +0 -1
  1010. package/src/components/core/Icon-Base/platforms/web/assets/x.svg +0 -1
  1011. package/src/components/core/Icon-Base/platforms/web/styles.css +0 -203
  1012. package/src/components/core/Icon-Base/types.ts +0 -338
  1013. package/src/components/core/Input-Checkbox-Base/README.md +0 -390
  1014. package/src/components/core/Input-Checkbox-Base/__tests__/InputCheckboxBase.stemma.test.ts +0 -552
  1015. package/src/components/core/Input-Checkbox-Base/__tests__/InputCheckboxBase.test.ts +0 -878
  1016. package/src/components/core/Input-Checkbox-Base/checkbox-sizing.tokens.ts +0 -37
  1017. package/src/components/core/Input-Checkbox-Base/platforms/web/InputCheckboxBase.web.css +0 -477
  1018. package/src/components/core/Input-Checkbox-Base/platforms/web/InputCheckboxBase.web.ts +0 -561
  1019. package/src/components/core/Input-Checkbox-Base/types.ts +0 -399
  1020. package/src/components/core/Input-Checkbox-Legal/README.md +0 -554
  1021. package/src/components/core/Input-Checkbox-Legal/__tests__/InputCheckboxLegal.test.ts +0 -727
  1022. package/src/components/core/Input-Checkbox-Legal/platforms/ios/.gitkeep +0 -2
  1023. package/src/components/core/Input-Checkbox-Legal/platforms/web/InputCheckboxLegal.web.css +0 -112
  1024. package/src/components/core/Input-Checkbox-Legal/platforms/web/InputCheckboxLegal.web.ts +0 -505
  1025. package/src/components/core/Input-Checkbox-Legal/types.ts +0 -348
  1026. package/src/components/core/Input-Radio-Base/.gitkeep +0 -2
  1027. package/src/components/core/Input-Radio-Base/README.md +0 -427
  1028. package/src/components/core/Input-Radio-Base/__tests__/.gitkeep +0 -1
  1029. package/src/components/core/Input-Radio-Base/__tests__/InputRadioBase.form.test.ts +0 -299
  1030. package/src/components/core/Input-Radio-Base/__tests__/InputRadioBase.stemma.test.ts +0 -543
  1031. package/src/components/core/Input-Radio-Base/__tests__/InputRadioBase.test.ts +0 -429
  1032. package/src/components/core/Input-Radio-Base/platforms/ios/.gitkeep +0 -1
  1033. package/src/components/core/Input-Radio-Base/platforms/web/.gitkeep +0 -1
  1034. package/src/components/core/Input-Radio-Base/platforms/web/InputRadioBase.web.css +0 -504
  1035. package/src/components/core/Input-Radio-Base/platforms/web/InputRadioBase.web.ts +0 -648
  1036. package/src/components/core/Input-Radio-Base/radio-sizing.tokens.ts +0 -37
  1037. package/src/components/core/Input-Radio-Base/types.ts +0 -362
  1038. package/src/components/core/Input-Radio-Set/README.md +0 -373
  1039. package/src/components/core/Input-Radio-Set/__tests__/.gitkeep +0 -0
  1040. package/src/components/core/Input-Radio-Set/__tests__/InputRadioSet.stemma.test.ts +0 -493
  1041. package/src/components/core/Input-Radio-Set/__tests__/InputRadioSet.test.ts +0 -499
  1042. package/src/components/core/Input-Radio-Set/platforms/web/InputRadioSet.web.css +0 -99
  1043. package/src/components/core/Input-Radio-Set/platforms/web/InputRadioSet.web.ts +0 -790
  1044. package/src/components/core/Input-Radio-Set/types.ts +0 -301
  1045. package/src/components/core/Input-Text-Base/README.md +0 -258
  1046. package/src/components/core/Input-Text-Base/__tests__/focusIndicators.test.ts +0 -311
  1047. package/src/components/core/Input-Text-Base/__tests__/keyboardNavigation.test.ts +0 -444
  1048. package/src/components/core/Input-Text-Base/__tests__/labelAssociation.test.ts +0 -418
  1049. package/src/components/core/Input-Text-Base/__tests__/screenReaderSupport.test.ts +0 -405
  1050. package/src/components/core/Input-Text-Base/__tests__/setup.ts +0 -17
  1051. package/src/components/core/Input-Text-Base/__tests__/stateManagement.test.ts +0 -718
  1052. package/src/components/core/Input-Text-Base/__tests__/test-utils.ts +0 -81
  1053. package/src/components/core/Input-Text-Base/__tests__/touchTargetSizing.test.ts +0 -319
  1054. package/src/components/core/Input-Text-Base/platforms/web/InputTextBase.browser.ts +0 -241
  1055. package/src/components/core/Input-Text-Base/platforms/web/InputTextBase.web.css +0 -293
  1056. package/src/components/core/Input-Text-Base/platforms/web/InputTextBase.web.ts +0 -448
  1057. package/src/components/core/Input-Text-Base/stateManagement.ts +0 -267
  1058. package/src/components/core/Input-Text-Base/tokens.ts +0 -210
  1059. package/src/components/core/Input-Text-Base/types.ts +0 -114
  1060. package/src/components/core/Input-Text-Email/README.md +0 -252
  1061. package/src/components/core/Input-Text-Email/__tests__/validation.test.ts +0 -127
  1062. package/src/components/core/Input-Text-Email/platforms/web/InputTextEmail.browser.ts +0 -276
  1063. package/src/components/core/Input-Text-Email/platforms/web/InputTextEmail.web.ts +0 -319
  1064. package/src/components/core/Input-Text-Email/stateManagement.ts +0 -160
  1065. package/src/components/core/Input-Text-Email/tokens.ts +0 -33
  1066. package/src/components/core/Input-Text-Email/types.ts +0 -72
  1067. package/src/components/core/Input-Text-Email/validation.ts +0 -130
  1068. package/src/components/core/Input-Text-Password/README.md +0 -360
  1069. package/src/components/core/Input-Text-Password/__tests__/validation.test.ts +0 -362
  1070. package/src/components/core/Input-Text-Password/platforms/web/InputTextPassword.browser.ts +0 -434
  1071. package/src/components/core/Input-Text-Password/platforms/web/InputTextPassword.web.ts +0 -512
  1072. package/src/components/core/Input-Text-Password/stateManagement.ts +0 -244
  1073. package/src/components/core/Input-Text-Password/tokens.ts +0 -32
  1074. package/src/components/core/Input-Text-Password/types.ts +0 -177
  1075. package/src/components/core/Input-Text-Password/validation.ts +0 -207
  1076. package/src/components/core/Input-Text-PhoneNumber/README.md +0 -276
  1077. package/src/components/core/Input-Text-PhoneNumber/__tests__/validation.test.ts +0 -301
  1078. package/src/components/core/Input-Text-PhoneNumber/platforms/web/InputTextPhoneNumber.browser.ts +0 -370
  1079. package/src/components/core/Input-Text-PhoneNumber/platforms/web/InputTextPhoneNumber.web.ts +0 -393
  1080. package/src/components/core/Input-Text-PhoneNumber/stateManagement.ts +0 -250
  1081. package/src/components/core/Input-Text-PhoneNumber/tokens.ts +0 -33
  1082. package/src/components/core/Input-Text-PhoneNumber/types.ts +0 -135
  1083. package/src/components/core/Input-Text-PhoneNumber/validation.ts +0 -302
  1084. package/src/components/core/Nav-Header-App/README.md +0 -29
  1085. package/src/components/core/Nav-Header-App/index.ts +0 -5
  1086. package/src/components/core/Nav-Header-App/platforms/web/NavHeaderApp.web.ts +0 -37
  1087. package/src/components/core/Nav-Header-App/types.ts +0 -32
  1088. package/src/components/core/Nav-Header-Base/README.md +0 -21
  1089. package/src/components/core/Nav-Header-Base/index.ts +0 -12
  1090. package/src/components/core/Nav-Header-Base/platforms/web/NavHeaderBase.styles.css +0 -75
  1091. package/src/components/core/Nav-Header-Base/platforms/web/NavHeaderBase.web.ts +0 -120
  1092. package/src/components/core/Nav-Header-Base/types.ts +0 -63
  1093. package/src/components/core/Nav-Header-Page/README.md +0 -34
  1094. package/src/components/core/Nav-Header-Page/__tests__/NavHeaderPage.test.ts +0 -250
  1095. package/src/components/core/Nav-Header-Page/index.ts +0 -12
  1096. package/src/components/core/Nav-Header-Page/platforms/web/NavHeaderPage.styles.css +0 -90
  1097. package/src/components/core/Nav-Header-Page/platforms/web/NavHeaderPage.web.ts +0 -169
  1098. package/src/components/core/Nav-Header-Page/types.ts +0 -55
  1099. package/src/components/core/Nav-SegmentedChoice-Base/README.md +0 -327
  1100. package/src/components/core/Nav-SegmentedChoice-Base/__tests__/NavSegmentedChoiceBase.android.test.ts +0 -218
  1101. package/src/components/core/Nav-SegmentedChoice-Base/__tests__/NavSegmentedChoiceBase.interaction.test.ts +0 -419
  1102. package/src/components/core/Nav-SegmentedChoice-Base/__tests__/NavSegmentedChoiceBase.ios.test.ts +0 -207
  1103. package/src/components/core/Nav-SegmentedChoice-Base/__tests__/NavSegmentedChoiceBase.visual.test.ts +0 -371
  1104. package/src/components/core/Nav-SegmentedChoice-Base/index.ts +0 -38
  1105. package/src/components/core/Nav-SegmentedChoice-Base/platforms/web/NavSegmentedChoiceBase.styles.css +0 -160
  1106. package/src/components/core/Nav-SegmentedChoice-Base/platforms/web/NavSegmentedChoiceBase.web.ts +0 -477
  1107. package/src/components/core/Nav-SegmentedChoice-Base/types.ts +0 -65
  1108. package/src/components/core/Nav-TabBar-Base/README.md +0 -264
  1109. package/src/components/core/Nav-TabBar-Base/__tests__/NavTabBarBase.android.test.ts +0 -270
  1110. package/src/components/core/Nav-TabBar-Base/__tests__/NavTabBarBase.ios.test.ts +0 -221
  1111. package/src/components/core/Nav-TabBar-Base/__tests__/NavTabBarBase.test.ts +0 -421
  1112. package/src/components/core/Nav-TabBar-Base/examples/BasicUsage.html +0 -2
  1113. package/src/components/core/Nav-TabBar-Base/examples/BasicUsage.tsx +0 -2
  1114. package/src/components/core/Nav-TabBar-Base/index.ts +0 -20
  1115. package/src/components/core/Nav-TabBar-Base/platforms/web/NavTabBarBase.styles.css +0 -281
  1116. package/src/components/core/Nav-TabBar-Base/platforms/web/NavTabBarBase.web.ts +0 -420
  1117. package/src/components/core/Nav-TabBar-Base/types.ts +0 -43
  1118. package/src/components/core/Progress-Bar-Base/README.md +0 -31
  1119. package/src/components/core/Progress-Bar-Base/__tests__/ProgressBarBase.test.ts +0 -202
  1120. package/src/components/core/Progress-Bar-Base/index.ts +0 -6
  1121. package/src/components/core/Progress-Bar-Base/platforms/web/ProgressBarBase.styles.css +0 -52
  1122. package/src/components/core/Progress-Bar-Base/platforms/web/ProgressBarBase.web.ts +0 -135
  1123. package/src/components/core/Progress-Bar-Base/types.ts +0 -46
  1124. package/src/components/core/Progress-Indicator-Connector-Base/README.md +0 -169
  1125. package/src/components/core/Progress-Indicator-Connector-Base/index.ts +0 -33
  1126. package/src/components/core/Progress-Indicator-Connector-Base/platforms/web/ProgressIndicatorConnectorBase.styles.css +0 -50
  1127. package/src/components/core/Progress-Indicator-Connector-Base/platforms/web/ProgressIndicatorConnectorBase.web.ts +0 -141
  1128. package/src/components/core/Progress-Indicator-Connector-Base/types.ts +0 -67
  1129. package/src/components/core/Progress-Indicator-Label-Base/README.md +0 -191
  1130. package/src/components/core/Progress-Indicator-Label-Base/index.ts +0 -28
  1131. package/src/components/core/Progress-Indicator-Label-Base/platforms/web/ProgressIndicatorLabelBase.styles.css +0 -81
  1132. package/src/components/core/Progress-Indicator-Label-Base/platforms/web/ProgressIndicatorLabelBase.web.ts +0 -174
  1133. package/src/components/core/Progress-Indicator-Label-Base/types.ts +0 -64
  1134. package/src/components/core/Progress-Indicator-Node-Base/README.md +0 -206
  1135. package/src/components/core/Progress-Indicator-Node-Base/__tests__/VisualStates.test.ts +0 -259
  1136. package/src/components/core/Progress-Indicator-Node-Base/index.ts +0 -36
  1137. package/src/components/core/Progress-Indicator-Node-Base/platforms/web/ProgressIndicatorNodeBase.styles.css +0 -193
  1138. package/src/components/core/Progress-Indicator-Node-Base/platforms/web/ProgressIndicatorNodeBase.web.ts +0 -226
  1139. package/src/components/core/Progress-Indicator-Node-Base/types.ts +0 -142
  1140. package/src/components/core/Progress-Pagination-Base/README.md +0 -290
  1141. package/src/components/core/Progress-Pagination-Base/__tests__/PaginationBase.test.ts +0 -290
  1142. package/src/components/core/Progress-Pagination-Base/index.ts +0 -40
  1143. package/src/components/core/Progress-Pagination-Base/platforms/web/ProgressPaginationBase.styles.css +0 -80
  1144. package/src/components/core/Progress-Pagination-Base/platforms/web/ProgressPaginationBase.web.ts +0 -293
  1145. package/src/components/core/Progress-Pagination-Base/types.ts +0 -112
  1146. package/src/components/core/Progress-Stepper-Base/README.md +0 -311
  1147. package/src/components/core/Progress-Stepper-Base/__tests__/StepperBase.test.ts +0 -345
  1148. package/src/components/core/Progress-Stepper-Base/index.ts +0 -43
  1149. package/src/components/core/Progress-Stepper-Base/platforms/web/ProgressStepperBase.styles.css +0 -49
  1150. package/src/components/core/Progress-Stepper-Base/platforms/web/ProgressStepperBase.web.ts +0 -288
  1151. package/src/components/core/Progress-Stepper-Base/types.ts +0 -175
  1152. package/src/components/core/Progress-Stepper-Detailed/README.md +0 -401
  1153. package/src/components/core/Progress-Stepper-Detailed/__tests__/StepperDetailed.test.ts +0 -481
  1154. package/src/components/core/Progress-Stepper-Detailed/index.ts +0 -48
  1155. package/src/components/core/Progress-Stepper-Detailed/platforms/web/ProgressStepperDetailed.styles.css +0 -106
  1156. package/src/components/core/Progress-Stepper-Detailed/platforms/web/ProgressStepperDetailed.web.ts +0 -336
  1157. package/src/components/core/Progress-Stepper-Detailed/types.ts +0 -195
  1158. package/src/composition/BlendComposition.ts +0 -46
  1159. package/src/composition/BlendCompositionParser.ts +0 -215
  1160. package/src/composition/OpacityComposition.ts +0 -62
  1161. package/src/composition/OpacityCompositionParser.ts +0 -308
  1162. package/src/composition/__tests__/BlendCompositionParser.test.ts +0 -431
  1163. package/src/composition/__tests__/OpacityCompositionParser.test.ts +0 -539
  1164. package/src/composition/index.ts +0 -20
  1165. package/src/config/ConfigLoader.ts +0 -143
  1166. package/src/config/__resolution-matrix__/README.md +0 -76
  1167. package/src/config/__resolution-matrix__/fixtures/faithful-cjs/compiled/defineConfig.js +0 -9
  1168. package/src/config/__resolution-matrix__/fixtures/faithful-cjs/designerpunk.config.ts +0 -20
  1169. package/src/config/__resolution-matrix__/fixtures/faithful-cjs/my-overrides.ts +0 -8
  1170. package/src/config/__resolution-matrix__/fixtures/faithful-esm/compiled/defineConfig.js +0 -11
  1171. package/src/config/__resolution-matrix__/fixtures/faithful-esm/designerpunk.config.ts +0 -23
  1172. package/src/config/__resolution-matrix__/fixtures/faithful-esm/my-overrides.ts +0 -6
  1173. package/src/config/__resolution-matrix__/fixtures/source-dir-cjs/designerpunk.config.ts +0 -11
  1174. package/src/config/__resolution-matrix__/fixtures/source-dir-cjs/src/config/index.ts +0 -15
  1175. package/src/config/__resolution-matrix__/fixtures/source-dir-esm/designerpunk.config.ts +0 -15
  1176. package/src/config/__resolution-matrix__/fixtures/source-dir-esm/src/config/index.ts +0 -13
  1177. package/src/config/__resolution-matrix__/run-matrix.js +0 -107
  1178. package/src/config/__resolution-matrix__/runner.js +0 -153
  1179. package/src/config/__resolution-matrix__/verify-real-loadconfig.js +0 -122
  1180. package/src/config/__tests__/ConfigLoader.test.ts +0 -115
  1181. package/src/config/defineConfig.ts +0 -71
  1182. package/src/config/index.ts +0 -7
  1183. package/src/config/scopedTsRequire.ts +0 -62
  1184. package/src/constants/BaselineGrid.ts +0 -41
  1185. package/src/constants/SpacingTokens.ts +0 -55
  1186. package/src/figma/ComponentAnalysis.ts +0 -292
  1187. package/src/figma/ComponentAnalysisGenerator.ts +0 -444
  1188. package/src/figma/ConsoleMCPClient.ts +0 -168
  1189. package/src/figma/ConsoleMCPClientImpl.ts +0 -1034
  1190. package/src/figma/DesignExtractor.ts +0 -3620
  1191. package/src/figma/TokenSyncWorkflow.ts +0 -915
  1192. package/src/figma/TokenTranslator.ts +0 -891
  1193. package/src/figma/VariantAnalyzer.ts +0 -712
  1194. package/src/figma/__tests__/ComponentAnalysisGenerator.json.test.ts +0 -429
  1195. package/src/figma/__tests__/ComponentAnalysisGenerator.markdown.test.ts +0 -428
  1196. package/src/figma/__tests__/ConsoleMCPClient.bugfix.test.ts +0 -261
  1197. package/src/figma/__tests__/ConsoleMCPClient.preservation.test.ts +0 -395
  1198. package/src/figma/__tests__/ConsoleMCPClient.test.ts +0 -375
  1199. package/src/figma/__tests__/DesignExtractor.boundVariableResolution.test.ts +0 -580
  1200. package/src/figma/__tests__/DesignExtractor.buildNodeTree.test.ts +0 -535
  1201. package/src/figma/__tests__/DesignExtractor.captureComponentScreenshot.test.ts +0 -176
  1202. package/src/figma/__tests__/DesignExtractor.detectBehavioralContracts.test.ts +0 -263
  1203. package/src/figma/__tests__/DesignExtractor.detectComponentTokenDecisions.test.ts +0 -379
  1204. package/src/figma/__tests__/DesignExtractor.detectCompositionPatterns.test.ts +0 -507
  1205. package/src/figma/__tests__/DesignExtractor.detectPlatformParity.test.ts +0 -406
  1206. package/src/figma/__tests__/DesignExtractor.queryContext.test.ts +0 -214
  1207. package/src/figma/__tests__/DesignExtractor.readFigmaComponent.test.ts +0 -431
  1208. package/src/figma/__tests__/DesignExtractor.readStyles.test.ts +0 -204
  1209. package/src/figma/__tests__/DesignExtractor.readTokenBindings.test.ts +0 -268
  1210. package/src/figma/__tests__/DesignExtractor.reconstructCompositeTokens.test.ts +0 -403
  1211. package/src/figma/__tests__/DesignExtractor.resolveUnknownVariableIds.test.ts +0 -259
  1212. package/src/figma/__tests__/DesignExtractor.translateTokens.test.ts +0 -433
  1213. package/src/figma/__tests__/DesignExtractor.validateModes.test.ts +0 -350
  1214. package/src/figma/__tests__/TokenSyncWorkflow.batch.test.ts +0 -277
  1215. package/src/figma/__tests__/TokenSyncWorkflow.drift.test.ts +0 -187
  1216. package/src/figma/__tests__/TokenSyncWorkflow.preservation.test.ts +0 -544
  1217. package/src/figma/__tests__/TokenSyncWorkflow.styles.test.ts +0 -245
  1218. package/src/figma/__tests__/TokenSyncWorkflow.sync.test.ts +0 -217
  1219. package/src/figma/__tests__/TokenTranslator.test.ts +0 -757
  1220. package/src/figma/__tests__/VariantAnalyzer.detectConflicts.test.ts +0 -126
  1221. package/src/figma/__tests__/VariantAnalyzer.test.ts +0 -633
  1222. package/src/figma/__tests__/error-reporting.test.ts +0 -254
  1223. package/src/figma/__tests__/preflight.test.ts +0 -94
  1224. package/src/figma/error-reporting.ts +0 -260
  1225. package/src/figma/index.ts +0 -98
  1226. package/src/figma/portCleanup.ts +0 -86
  1227. package/src/figma/preflight.ts +0 -120
  1228. package/src/generators/BlendUtilityGenerator.ts +0 -847
  1229. package/src/generators/BlendValueGenerator.ts +0 -198
  1230. package/src/generators/DTCGFormatGenerator.ts +0 -1355
  1231. package/src/generators/DTCGGeneratorConfig.ts +0 -46
  1232. package/src/generators/ModeResolvedTokens.ts +0 -58
  1233. package/src/generators/ResponsiveGridGenerator.ts +0 -273
  1234. package/src/generators/TokenFileGenerator.ts +0 -2070
  1235. package/src/generators/__tests__/AccessibilityTokenGeneration.test.ts +0 -350
  1236. package/src/generators/__tests__/BlendUtilityGenerator.test.ts +0 -829
  1237. package/src/generators/__tests__/BlendValueGenerator.test.ts +0 -200
  1238. package/src/generators/__tests__/BreakpointTokenGeneration.test.ts +0 -172
  1239. package/src/generators/__tests__/CSSThemeScoping.test.ts +0 -153
  1240. package/src/generators/__tests__/DTCGConfigOptions.test.ts +0 -271
  1241. package/src/generators/__tests__/DTCGErrorHandling.test.ts +0 -139
  1242. package/src/generators/__tests__/DTCGFormatGenerator.integration.test.ts +0 -346
  1243. package/src/generators/__tests__/DTCGFormatGenerator.property.test.ts +0 -497
  1244. package/src/generators/__tests__/DTCGFormatGenerator.test.ts +0 -469
  1245. package/src/generators/__tests__/FigmaTransformer.styles.test.ts +0 -398
  1246. package/src/generators/__tests__/FigmaTransformer.variables.test.ts +0 -540
  1247. package/src/generators/__tests__/GridSpacingTokenGeneration.test.ts +0 -254
  1248. package/src/generators/__tests__/IconTokenGeneration.test.ts +0 -452
  1249. package/src/generators/__tests__/KotlinThemeTypes.test.ts +0 -110
  1250. package/src/generators/__tests__/ModeAwareGeneration.test.ts +0 -160
  1251. package/src/generators/__tests__/NativeOklchOutput.test.ts +0 -56
  1252. package/src/generators/__tests__/OklchExport.test.ts +0 -71
  1253. package/src/generators/__tests__/ProductRepoSimulation.test.ts +0 -91
  1254. package/src/generators/__tests__/ResponsiveGridGeneration.test.ts +0 -291
  1255. package/src/generators/__tests__/Spec076TokenMigration.test.ts +0 -106
  1256. package/src/generators/__tests__/Spec077ModesVerification.test.ts +0 -52
  1257. package/src/generators/__tests__/SwiftThemeTypes.test.ts +0 -122
  1258. package/src/generators/__tests__/TokenFileGenerator.test.ts +0 -914
  1259. package/src/generators/__tests__/TransformerRegistry.test.ts +0 -118
  1260. package/src/generators/__tests__/WcagValueExportSupport.test.ts +0 -84
  1261. package/src/generators/__tests__/WcagValueInfrastructure.test.ts +0 -122
  1262. package/src/generators/__tests__/WebOklchOutput.test.ts +0 -72
  1263. package/src/generators/__tests__/generateTokenIndex.test.ts +0 -204
  1264. package/src/generators/__tests__/helpers/defaultSemanticOptions.ts +0 -24
  1265. package/src/generators/generateTokenFiles.ts +0 -337
  1266. package/src/generators/generateTokenIndex.ts +0 -258
  1267. package/src/generators/oklch/OklchExportUtils.ts +0 -57
  1268. package/src/generators/oklch/OklchTokenIndexMetadata.ts +0 -30
  1269. package/src/generators/transformers/FigmaTransformer.ts +0 -912
  1270. package/src/generators/transformers/ITokenTransformer.ts +0 -56
  1271. package/src/generators/transformers/TransformerRegistry.ts +0 -63
  1272. package/src/generators/transformers/index.ts +0 -52
  1273. package/src/generators/types/DTCGTypes.ts +0 -101
  1274. package/src/integration/BuildErrorHandler.ts +0 -440
  1275. package/src/integration/BuildSystemInterface.ts +0 -338
  1276. package/src/integration/PlatformFileSelector.ts +0 -288
  1277. package/src/integration/RegistryCoordinator.ts +0 -404
  1278. package/src/integration/TranslationCoordinator.ts +0 -458
  1279. package/src/integration/TreeShakingOptimizer.ts +0 -350
  1280. package/src/integration/ValidationCoordinator.ts +0 -780
  1281. package/src/integration/__tests__/ComponentTokenValidation.test.ts +0 -762
  1282. package/src/integration/__tests__/ValidationCoordinator.test.ts +0 -609
  1283. package/src/integration/__tests__/performance/ComponentTokenValidationPerformance.test.ts +0 -161
  1284. package/src/integration/index.ts +0 -55
  1285. package/src/naming/NamingConventionManager.ts +0 -318
  1286. package/src/naming/PlatformNamingRules.ts +0 -278
  1287. package/src/naming/__tests__/NamingConventions.test.ts +0 -224
  1288. package/src/naming/index.ts +0 -23
  1289. package/src/parent-completion.md +0 -1
  1290. package/src/performance/CachingStrategy.ts +0 -426
  1291. package/src/performance/FileGenerationOptimizer.ts +0 -294
  1292. package/src/performance/PerformanceMonitor.ts +0 -185
  1293. package/src/performance/PerformanceOptimizer.ts +0 -348
  1294. package/src/performance/index.ts +0 -30
  1295. package/src/providers/AndroidFileOrganizer.ts +0 -241
  1296. package/src/providers/AndroidFormatGenerator.ts +0 -750
  1297. package/src/providers/AndroidUnitConverter.ts +0 -177
  1298. package/src/providers/FormatProvider.ts +0 -187
  1299. package/src/providers/PathProvider.ts +0 -197
  1300. package/src/providers/UnitProvider.ts +0 -106
  1301. package/src/providers/WebFileOrganizer.ts +0 -121
  1302. package/src/providers/WebFormatGenerator.ts +0 -611
  1303. package/src/providers/WebUnitConverter.ts +0 -116
  1304. package/src/providers/__tests__/AndroidAccessibilityTokens.test.ts +0 -86
  1305. package/src/providers/__tests__/AndroidFormatGenerator-semantic.test.ts +0 -494
  1306. package/src/providers/__tests__/FormatProviders.test.ts +0 -828
  1307. package/src/providers/__tests__/InsetTokenGeneration.test.ts +0 -627
  1308. package/src/providers/__tests__/PathProviders.test.ts +0 -512
  1309. package/src/providers/__tests__/PlatformOutputFormat.test.ts +0 -252
  1310. package/src/providers/__tests__/UnitProviders.test.ts +0 -721
  1311. package/src/providers/__tests__/WebFormatGenerator-semantic.test.ts +0 -293
  1312. package/src/providers/__tests__/iOSFormatGenerator-semantic.test.ts +0 -410
  1313. package/src/providers/iOSFileOrganizer.ts +0 -162
  1314. package/src/providers/iOSFormatGenerator.ts +0 -599
  1315. package/src/providers/iOSUnitConverter.ts +0 -125
  1316. package/src/providers/index.ts +0 -26
  1317. package/src/registries/ComponentTokenRegistry.ts +0 -292
  1318. package/src/registries/IRegistry.ts +0 -170
  1319. package/src/registries/__tests__/ComponentTokenRegistry.test.ts +0 -446
  1320. package/src/registries/__tests__/IRegistry.test.ts +0 -250
  1321. package/src/registries/__tests__/PrimitiveTokenRegistry.test.ts +0 -342
  1322. package/src/registries/__tests__/SemanticTokenRegistry.test.ts +0 -444
  1323. package/src/resolvers/AndroidColorResolver.ts +0 -333
  1324. package/src/resolvers/ModeThemeResolver.ts +0 -152
  1325. package/src/resolvers/SemanticOverrideResolver.ts +0 -155
  1326. package/src/resolvers/SemanticValueResolver.ts +0 -133
  1327. package/src/resolvers/WebColorResolver.ts +0 -240
  1328. package/src/resolvers/__tests__/AndroidColorResolver.test.ts +0 -507
  1329. package/src/resolvers/__tests__/ModeThemeResolver.test.ts +0 -411
  1330. package/src/resolvers/__tests__/SemanticOverrideResolver.test.ts +0 -186
  1331. package/src/resolvers/__tests__/WebColorResolver.test.ts +0 -405
  1332. package/src/resolvers/__tests__/iOSColorResolver.test.ts +0 -432
  1333. package/src/resolvers/iOSColorResolver.ts +0 -224
  1334. package/src/resolvers/index.ts +0 -11
  1335. package/src/security/AIAgentRestrictions.ts +0 -298
  1336. package/src/security/ContaminationAuditor.ts +0 -393
  1337. package/src/security/ContaminationPrevention.ts +0 -275
  1338. package/src/security/DocumentationGuard.ts +0 -258
  1339. package/src/security/FlexibilityTokenGuard.ts +0 -256
  1340. package/src/security/HumanApprovalWorkflow.ts +0 -319
  1341. package/src/security/__tests__/AIAgentRestrictions.test.ts +0 -482
  1342. package/src/security/__tests__/ContaminationPrevention.test.ts +0 -424
  1343. package/src/security/__tests__/SecurityIntegration.test.ts +0 -505
  1344. package/src/security/index.ts +0 -48
  1345. package/src/testing/__tests__/utilities.test.ts +0 -175
  1346. package/src/testing/index.ts +0 -154
  1347. package/src/testing/jest-preset.ts +0 -62
  1348. package/src/testing/style-mock.ts +0 -7
  1349. package/src/testing/validators.ts +0 -10
  1350. package/src/themes/ResolvedThemeSet.ts +0 -22
  1351. package/src/themes/ThemeRegistry.ts +0 -97
  1352. package/src/themes/__tests__/ThemeRegistry.test.ts +0 -162
  1353. package/src/tools/ThemeFileGenerator.ts +0 -109
  1354. package/src/tools/integrity/DiskFreshGenerator.ts +0 -36
  1355. package/src/tools/integrity/GenerationIntegrityCheck.ts +0 -132
  1356. package/src/tools/integrity/Invariants.ts +0 -228
  1357. package/src/tools/integrity/Normalizer.ts +0 -94
  1358. package/src/tools/integrity/SemanticComparator.ts +0 -127
  1359. package/src/tools/integrity/__tests__/GenerationIntegrityCheck.test.ts +0 -132
  1360. package/src/tools/integrity/__tests__/Invariants.test.ts +0 -142
  1361. package/src/tools/integrity/__tests__/Normalizer.test.ts +0 -65
  1362. package/src/tools/integrity/__tests__/SemanticComparator.test.ts +0 -62
  1363. package/src/tools/integrity/__tests__/consumer-package-mode.test.ts +0 -205
  1364. package/src/tools/integrity/cli/run-audit.ts +0 -150
  1365. package/src/tools/integrity/inventory.ts +0 -51
  1366. package/src/tools/integrity/manifest.ts +0 -56
  1367. package/src/tools/integrity/types/index.ts +0 -183
  1368. package/src/tools/release/__tests__/ChangeClassifier.test.ts +0 -133
  1369. package/src/tools/release/__tests__/ChangeExtractor.test.ts +0 -222
  1370. package/src/tools/release/__tests__/GitHubPublisher.test.ts +0 -240
  1371. package/src/tools/release/__tests__/NotesRenderer.test.ts +0 -142
  1372. package/src/tools/release/__tests__/NpmPublisher.test.ts +0 -289
  1373. package/src/tools/release/__tests__/PipelineIntegration.test.ts +0 -188
  1374. package/src/tools/release/__tests__/ReleasePipeline.test.ts +0 -192
  1375. package/src/tools/release/__tests__/SemanticVersionValidator.test.ts +0 -49
  1376. package/src/tools/release/__tests__/SummaryScanner.test.ts +0 -141
  1377. package/src/tools/release/__tests__/TagResolver.test.ts +0 -91
  1378. package/src/tools/release/__tests__/VersionCalculator.test.ts +0 -270
  1379. package/src/tools/release/__tests__/helpers/NpmMockHelper.ts +0 -80
  1380. package/src/tools/release/cli/ReleasePipeline.ts +0 -165
  1381. package/src/tools/release/cli/release-tool.ts +0 -107
  1382. package/src/tools/release/pipeline/ChangeClassifier.ts +0 -61
  1383. package/src/tools/release/pipeline/ChangeExtractor.ts +0 -87
  1384. package/src/tools/release/pipeline/NotesRenderer.ts +0 -66
  1385. package/src/tools/release/pipeline/SummaryScanner.ts +0 -70
  1386. package/src/tools/release/pipeline/TagResolver.ts +0 -40
  1387. package/src/tools/release/pipeline/VersionCalculator.ts +0 -375
  1388. package/src/tools/release/publishers/GitHubPublisher.ts +0 -228
  1389. package/src/tools/release/publishers/NpmPublisher.ts +0 -196
  1390. package/src/tools/release/release-config.json +0 -5
  1391. package/src/tools/release/types/index.ts +0 -282
  1392. package/src/tools/release/validators/SemanticVersionValidator.ts +0 -67
  1393. package/src/types/ComponentTypes.ts +0 -76
  1394. package/src/types/TranslationOutput.ts +0 -105
  1395. package/src/types/ValidationResult.ts +0 -74
  1396. package/src/types/__tests__/ComponentTypes.test.ts +0 -73
  1397. package/src/types/css.d.ts +0 -35
  1398. package/src/types/generated/TokenTypes.ts +0 -142
  1399. package/src/types/index.ts +0 -42
  1400. package/src/validators/BaselineGridValidator.ts +0 -119
  1401. package/src/validators/CompositionPatternValidator.ts +0 -259
  1402. package/src/validators/CrossPlatformConsistencyValidator.ts +0 -498
  1403. package/src/validators/ErrorValidator.ts +0 -998
  1404. package/src/validators/IValidator.ts +0 -273
  1405. package/src/validators/MathematicalRelationshipParser.ts +0 -434
  1406. package/src/validators/ModeParity.ts +0 -123
  1407. package/src/validators/PassValidator.ts +0 -533
  1408. package/src/validators/PlatformConstraintHandler.ts +0 -453
  1409. package/src/validators/PrimitiveReferenceValidator.ts +0 -284
  1410. package/src/validators/SemanticTokenValidator.ts +0 -496
  1411. package/src/validators/StemmaComponentNamingValidator.ts +0 -524
  1412. package/src/validators/StemmaErrorGuidanceSystem.ts +0 -1600
  1413. package/src/validators/StemmaPropertyAccessibilityValidator.ts +0 -823
  1414. package/src/validators/StemmaTokenUsageValidator.ts +0 -651
  1415. package/src/validators/SyntaxValidator.ts +0 -537
  1416. package/src/validators/ThreeTierValidator.ts +0 -822
  1417. package/src/validators/ToleranceCalculator.ts +0 -324
  1418. package/src/validators/ValidationReasoning.ts +0 -464
  1419. package/src/validators/WCAGValidator.ts +0 -219
  1420. package/src/validators/WarningValidator.ts +0 -626
  1421. package/src/validators/__tests__/BaselineGridValidator.test.ts +0 -292
  1422. package/src/validators/__tests__/BorderWidthValidation.test.ts +0 -595
  1423. package/src/validators/__tests__/CompositionPatterns.test.ts +0 -463
  1424. package/src/validators/__tests__/CrossPlatformConsistency.test.ts +0 -834
  1425. package/src/validators/__tests__/IValidator.test.ts +0 -258
  1426. package/src/validators/__tests__/MathematicalRelationshipParser.test.ts +0 -465
  1427. package/src/validators/__tests__/PlatformConstraints.test.ts +0 -486
  1428. package/src/validators/__tests__/SemanticTokenValidator.test.ts +0 -723
  1429. package/src/validators/__tests__/StemmaComponentNamingValidator.test.ts +0 -597
  1430. package/src/validators/__tests__/StemmaErrorGuidanceSystem.test.ts +0 -717
  1431. package/src/validators/__tests__/StemmaPropertyAccessibilityValidator.test.ts +0 -349
  1432. package/src/validators/__tests__/StemmaTokenUsageValidator.test.ts +0 -432
  1433. package/src/validators/__tests__/SyntaxValidator.test.ts +0 -360
  1434. package/src/validators/__tests__/ThreeTierValidator.test.ts +0 -906
  1435. package/src/validators/__tests__/ValidationReasoning.test.ts +0 -636
  1436. package/src/validators/__tests__/WCAGValidator.test.ts +0 -243
  1437. package/src/validators/buildValidation.ts +0 -170
  1438. package/src/validators/index.ts +0 -144
  1439. package/src/workflows/ConsistencyValidator.ts +0 -339
  1440. package/src/workflows/TokenGenerationWorkflow.ts +0 -460
  1441. package/src/workflows/ValidationPipeline.ts +0 -284
  1442. package/src/workflows/WorkflowErrorHandler.ts +0 -441
@@ -1,3620 +0,0 @@
1
- /**
2
- * DesignExtractor — Reads Figma designs via dual-MCP strategy and generates
3
- * design-outline.md documents with confidence flags.
4
- *
5
- * Uses Kiro Figma Power for rich design context and figma-console-mcp for
6
- * variable/style data. Orchestrates TokenTranslator for value matching and
7
- * VariantAnalyzer for context-aware recommendations.
8
- *
9
- * @see Design: .kiro/specs/054b-figma-design-extract/design.md
10
- * @requirements Req 1 (DesignExtractor Implementation)
11
- * @spec 054b-figma-design-extract
12
- */
13
-
14
- import type { ConsoleMCPClient } from './ConsoleMCPClient';
15
- import type { TokenTranslator, TranslationResult, TokenCategory } from './TokenTranslator';
16
- import type { VariantAnalyzer, ExtractionContext, VariantMapping, MCPDocClient } from './VariantAnalyzer';
17
- import type { DTCGTokenFile } from '../generators/types/DTCGTypes';
18
- import type { NodeWithClassifications, FigmaNodeType, CompositionPattern, UnresolvedBinding, UnresolvedBindingReason, ScreenshotMetadata, ComponentAnalysis, ClassifiedToken } from './ComponentAnalysis';
19
- import * as fs from 'fs';
20
- import * as path from 'path';
21
- import https from 'https';
22
- import http from 'http';
23
-
24
- // ---------------------------------------------------------------------------
25
- // Kiro Figma Power Client Interface
26
- // ---------------------------------------------------------------------------
27
-
28
- /**
29
- * Response from Kiro Figma Power `get_design_context` tool.
30
- *
31
- * Contains generated code and asset download URLs. The code string
32
- * is parsed to extract component structure, layout, and visual properties.
33
- */
34
- export interface DesignContextResponse {
35
- /** Generated code string (HTML/CSS/TS) describing the component. */
36
- code?: string;
37
- /** Asset download URLs referenced in the code. */
38
- assets?: Record<string, string>;
39
- /** Raw response metadata. */
40
- [key: string]: unknown;
41
- }
42
-
43
- /**
44
- * Response from Kiro Figma Power `get_metadata` tool.
45
- *
46
- * XML-formatted metadata containing node IDs, layer types, names,
47
- * positions, and sizes for structural overview.
48
- */
49
- export interface MetadataResponse {
50
- /** XML string describing the node tree structure. */
51
- xml?: string;
52
- /** Raw response metadata. */
53
- [key: string]: unknown;
54
- }
55
-
56
- /**
57
- * Response from figma-console-mcp `figma_get_component` tool.
58
- *
59
- * Contains component reconstruction spec with variants, properties,
60
- * and structure information.
61
- */
62
- export interface FigmaComponentResponse {
63
- /** Component name. */
64
- name?: string;
65
- /** Component description. */
66
- description?: string;
67
- /** Component key. */
68
- key?: string;
69
- /** Variant properties and their options. */
70
- variantProperties?: Record<string, string[]>;
71
- /** Raw component data. */
72
- [key: string]: unknown;
73
- }
74
-
75
- /**
76
- * Client interface for Kiro Figma Power MCP operations.
77
- *
78
- * Provides design context and metadata queries for rich component
79
- * structure extraction. Abstracted for testability.
80
- */
81
- export interface KiroFigmaPowerClient {
82
- /**
83
- * Get rich design context for a Figma node.
84
- *
85
- * Returns generated code and assets that describe the component's
86
- * layout, properties, and visual states.
87
- */
88
- getDesignContext(
89
- fileKey: string,
90
- nodeId: string,
91
- ): Promise<DesignContextResponse>;
92
-
93
- /**
94
- * Get structural metadata for a Figma node.
95
- *
96
- * Returns XML-formatted overview of node tree with IDs, types,
97
- * names, positions, and sizes.
98
- */
99
- getMetadata(
100
- fileKey: string,
101
- nodeId: string,
102
- ): Promise<MetadataResponse>;
103
- }
104
-
105
- // ---------------------------------------------------------------------------
106
- // Extracted Component (rich representation from dual-MCP)
107
- // ---------------------------------------------------------------------------
108
-
109
- /**
110
- * Layout information extracted from a Figma component.
111
- */
112
- export interface ExtractedLayout {
113
- /** Layout mode: auto-layout direction or none. */
114
- mode: 'horizontal' | 'vertical' | 'none';
115
- /** Spacing between children (px). */
116
- itemSpacing?: number;
117
- /** Padding values (px). */
118
- padding?: {
119
- top?: number;
120
- right?: number;
121
- bottom?: number;
122
- left?: number;
123
- };
124
- }
125
-
126
- /**
127
- * Rich component representation extracted from Figma via dual-MCP.
128
- *
129
- * Extends the minimal FigmaComponent from VariantAnalyzer with layout,
130
- * property definitions, and raw source data for downstream processing.
131
- */
132
- export interface ExtractedComponent {
133
- /** Component name from Figma. */
134
- name: string;
135
- /** Component description from Figma. */
136
- description: string;
137
- /** Variant definitions with their property values. */
138
- variants: VariantDefinition[];
139
- /** Visual states detected (hover, focus, disabled, pressed). */
140
- states: StateDefinition[];
141
- /** Component properties (boolean, text, instance swap, etc.). */
142
- properties: PropertyDefinition[];
143
- /** Layout information (auto-layout, spacing, padding). */
144
- layout: ExtractedLayout;
145
- /** Raw design context code from Kiro Power (for downstream parsing). */
146
- rawDesignContext?: string;
147
- /** Raw metadata XML from Kiro Power (for downstream parsing). */
148
- rawMetadata?: string;
149
- /** Which MCP source provided the primary data. */
150
- source: 'kiro-power' | 'console-mcp-fallback';
151
- /**
152
- * Direct variable bindings from Figma component children.
153
- *
154
- * Maps Figma property names (e.g. "paddingLeft", "itemSpacing", "cornerRadius")
155
- * to their bound variable names (e.g. "space/100", "radius/200").
156
- * Extracted from `boundVariables` on child nodes via Console MCP.
157
- * Enables binding-first token translation without value scanning.
158
- */
159
- boundVariableMap?: Map<string, string>;
160
- /** Corner radius value (px) extracted from component children. */
161
- cornerRadius?: number;
162
- /** Fill colors extracted from component children (hex or rgba). */
163
- fills?: Array<{ type: string; color?: string; opacity?: number }>;
164
- }
165
-
166
- // ---------------------------------------------------------------------------
167
- // Interfaces
168
- // ---------------------------------------------------------------------------
169
-
170
- /** Confidence level for an extracted value. */
171
- export type ConfidenceLevel = 'exact' | 'approximate' | 'no-match';
172
-
173
- /** How a token match was found. */
174
- export type MatchMethod = 'binding' | 'value';
175
-
176
- /**
177
- * A single token reference extracted from a Figma component property.
178
- */
179
- export interface TokenReference {
180
- /** CSS property or Figma property name (e.g. "padding-left", "fill"). */
181
- property: string;
182
- /** Matched DesignerPunk token path (dot notation). */
183
- token: string;
184
- /** Match confidence. */
185
- confidence: ConfidenceLevel;
186
- /** How the match was found. */
187
- matchMethod: MatchMethod;
188
- /** Primitive token path if resolved. */
189
- primitive?: string;
190
- /** Semantic token path if resolved. */
191
- semantic?: string;
192
- /** Difference from matched token value (e.g. "±1px"). */
193
- delta?: string;
194
- /** Original Figma value as string (preserved for no-match reporting). */
195
- rawValue?: string;
196
- /** Suggested closest token when no exact match found. */
197
- suggestion?: string;
198
- }
199
-
200
- /**
201
- * Aggregated token usage across all properties of a component.
202
- */
203
- export interface TokenUsage {
204
- spacing: TokenReference[];
205
- colors: TokenReference[];
206
- typography: TokenReference[];
207
- radius: TokenReference[];
208
- shadows: TokenReference[];
209
- }
210
-
211
- /**
212
- * A Figma variable binding on a component element.
213
- *
214
- * Represents the relationship between a Figma variable and its resolved
215
- * values across modes (light/dark).
216
- */
217
- export interface TokenBinding {
218
- /** Figma variable name in slash notation (e.g. "space/100"). */
219
- variableName: string;
220
- /** Figma variable ID. */
221
- variableId: string;
222
- /** Collection name (e.g. "Primitives", "Semantics"). */
223
- collectionName: string;
224
- /** Resolved variable type: FLOAT, COLOR, STRING. */
225
- resolvedType: string;
226
- /** Values keyed by mode name or mode ID. */
227
- valuesByMode: Record<string, unknown>;
228
- /** Whether this variable is a semantic alias. */
229
- isAlias: boolean;
230
- /** Primitive variable name if this is an alias. */
231
- aliasTarget?: string;
232
- }
233
-
234
- /**
235
- * A Figma style (effect or text) read from the file.
236
- */
237
- export interface FigmaStyle {
238
- /** Style name (e.g. "shadow.elevation200", "typography.heading200"). */
239
- name: string;
240
- /** Style type. */
241
- type: 'EFFECT' | 'TEXT';
242
- /** Raw style properties from Figma. */
243
- properties: Record<string, unknown>;
244
- }
245
-
246
- /**
247
- * Variant definition extracted from a Figma component.
248
- */
249
- export interface VariantDefinition {
250
- name: string;
251
- properties: Record<string, string>;
252
- }
253
-
254
- /**
255
- * Visual state extracted from a Figma component (e.g. hover, focus, disabled).
256
- */
257
- export interface StateDefinition {
258
- name: string;
259
- description?: string;
260
- }
261
-
262
- /**
263
- * A component property extracted from Figma.
264
- */
265
- export interface PropertyDefinition {
266
- name: string;
267
- type: string;
268
- defaultValue?: string;
269
- }
270
-
271
- /**
272
- * Inheritance pattern for a component within its family.
273
- */
274
- export interface InheritancePattern {
275
- familyName: string;
276
- pattern: string;
277
- baseComponent?: string;
278
- }
279
-
280
- /**
281
- * Status of behavioral contracts for a component.
282
- *
283
- * Interactive components (buttons, inputs) require explicit behavioral
284
- * contracts. Static components (badges, dividers) get auto-generated
285
- * "no interaction" contracts.
286
- */
287
- export interface BehavioralContractStatus {
288
- /** Whether the component is classified as interactive or static. */
289
- classification: 'interactive' | 'static';
290
- /** Visual states detected from Figma (hover, focus, disabled, pressed). */
291
- detectedStates: string[];
292
- /** Whether behavioral contracts are defined. */
293
- contractsDefined: boolean;
294
- /** Auto-generated contract for static components, or undefined for interactive. */
295
- autoContract?: string;
296
- /** Confidence flag for the behavioral contract status. */
297
- confidence: '✅' | '⚠️' | '❌';
298
- }
299
-
300
- /**
301
- * Platform parity check result for a component.
302
- *
303
- * Flags platform-specific interactions (hover = web-only, press = mobile)
304
- * and provides recommendations for cross-platform consistency.
305
- */
306
- export interface PlatformParityCheck {
307
- /** Platform-specific interactions detected. */
308
- interactions: PlatformInteraction[];
309
- /** Overall parity status. */
310
- hasConcerns: boolean;
311
- }
312
-
313
- /** A single platform-specific interaction. */
314
- export interface PlatformInteraction {
315
- /** Interaction name (e.g. "hover", "press", "long-press"). */
316
- interaction: string;
317
- /** Which platforms support this interaction. */
318
- platforms: ('web' | 'ios' | 'android')[];
319
- /** Recommendation for cross-platform handling. */
320
- recommendation: string;
321
- }
322
-
323
- /**
324
- * A component token decision point surfaced for Ada's review.
325
- *
326
- * Detects repeated primitive token usage and provides illustrative
327
- * component token suggestions. All suggestions are explicitly labeled
328
- * as pending human review.
329
- */
330
- export interface ComponentTokenDecision {
331
- /** The primitive token being used repeatedly. */
332
- primitiveToken: string;
333
- /** Number of times the primitive is used across component properties. */
334
- usageCount: number;
335
- /** Where the primitive is used (e.g. "padding-left: 5 variants"). */
336
- locations: string[];
337
- /** Illustrative component token name suggestion. */
338
- illustrativeSuggestion: string;
339
- /** Why this pattern is notable. */
340
- rationale: string;
341
- }
342
-
343
- /**
344
- * Mode validation result for token bindings.
345
- */
346
- export interface ModeValidationResult {
347
- /** Discrepancies found between modes. */
348
- discrepancies: ModeDiscrepancy[];
349
- /** Whether any unexpected discrepancies were found. */
350
- hasUnexpectedDiscrepancies: boolean;
351
- }
352
-
353
- /** A single mode discrepancy for a token binding. */
354
- export interface ModeDiscrepancy {
355
- /** Variable name with the discrepancy. */
356
- variableName: string;
357
- /** Light mode value. */
358
- lightValue: unknown;
359
- /** Dark mode value. */
360
- darkValue: unknown;
361
- /** Whether this discrepancy is expected or unexpected. */
362
- category: 'expected' | 'unexpected';
363
- }
364
-
365
- /**
366
- * Confidence report for the overall extraction.
367
- */
368
- export interface ConfidenceReport {
369
- /** Overall confidence: high, medium, or low. */
370
- overall: 'high' | 'medium' | 'low';
371
- /** Number of exact matches. */
372
- exactMatches: number;
373
- /** Number of approximate matches. */
374
- approximateMatches: number;
375
- /** Number of no-match values. */
376
- noMatches: number;
377
- /** Whether human input is required before proceeding. */
378
- requiresHumanInput: boolean;
379
- /** Specific items requiring human review. */
380
- reviewItems: string[];
381
- }
382
-
383
- // ---------------------------------------------------------------------------
384
- // Bound Variable Batch Resolution
385
- // ---------------------------------------------------------------------------
386
-
387
- /**
388
- * Entry representing a single bound variable found during node tree traversal.
389
- *
390
- * Captures the variable ID, the property it was bound to, and full node
391
- * context (nodeId, nodeName, ancestorChain) so that unresolved bindings
392
- * can be reported with enough information for human review.
393
- */
394
- export interface BoundVariableEntry {
395
- /** Figma variable ID (e.g. 'VariableID:1224:14083'). */
396
- variableId: string;
397
- /** Property where the binding was found (e.g. 'padding-top', 'fill'). */
398
- property: string;
399
- /** Figma node ID where the binding was found. */
400
- nodeId: string;
401
- /** Name of the node where the binding was found. */
402
- nodeName: string;
403
- /** Ancestor chain of the node for context. */
404
- ancestorChain: string[];
405
- /** Raw Figma value for the property. */
406
- rawValue: number | string;
407
- /** Token category for translation. */
408
- category: TokenCategory;
409
- }
410
-
411
- // ---------------------------------------------------------------------------
412
- // DesignExtractor
413
- // ---------------------------------------------------------------------------
414
-
415
- /**
416
- * Orchestrates extraction from Figma via dual-MCP strategy and generates
417
- * design-outline.md documents.
418
- *
419
- * Uses:
420
- * - Kiro Figma Power for rich design context (component structure, layout)
421
- * - figma-console-mcp via ConsoleMCPClient for variables and styles
422
- * - TokenTranslator for Figma value → DesignerPunk token matching
423
- * - VariantAnalyzer for context-aware variant mapping recommendations
424
- */
425
- export class DesignExtractor {
426
- /** Platform-interaction heuristics: interaction → supported platforms. */
427
- private static readonly PLATFORM_HEURISTICS: Record<string, ('web' | 'ios' | 'android')[]> = {
428
- hover: ['web'],
429
- focus: ['web', 'ios', 'android'],
430
- pressed: ['web', 'ios', 'android'],
431
- disabled: ['web', 'ios', 'android'],
432
- active: ['web', 'ios', 'android'],
433
- selected: ['web', 'ios', 'android'],
434
- 'long-press': ['ios', 'android'],
435
- loading: ['web', 'ios', 'android'],
436
- error: ['web', 'ios', 'android'],
437
- };
438
-
439
- constructor(
440
- private readonly consoleMcp: ConsoleMCPClient,
441
- private readonly translator: TokenTranslator,
442
- private readonly analyzer: VariantAnalyzer,
443
- private readonly kiroPower?: KiroFigmaPowerClient,
444
- private readonly mcpDocs?: MCPDocClient,
445
- ) {}
446
-
447
- // -------------------------------------------------------------------------
448
- // readFigmaComponent (Task 3.2)
449
- // -------------------------------------------------------------------------
450
-
451
- /**
452
- * Read a Figma component via dual-MCP strategy.
453
- *
454
- * Primary: Kiro Figma Power `get_design_context` for rich component
455
- * structure (layout, properties, visual states).
456
- * Fallback: `get_metadata` + figma-console-mcp `figma_get_component`
457
- * if `get_design_context` lacks detail or Kiro Power is unavailable.
458
- *
459
- * @param fileKey - The Figma file key.
460
- * @param nodeId - The node ID of the component to extract.
461
- * @returns An ExtractedComponent with structure, layout, and states.
462
- * @throws Error if component cannot be read from either MCP source.
463
- */
464
- async readFigmaComponent(
465
- fileKey: string,
466
- nodeId: string,
467
- ): Promise<ExtractedComponent> {
468
- // Try primary path: Kiro Figma Power
469
- if (this.kiroPower) {
470
- try {
471
- const designContext = await this.kiroPower.getDesignContext(fileKey, nodeId);
472
-
473
- if (designContext.code && designContext.code.trim().length > 0) {
474
- const extracted = this.parseDesignContext(designContext);
475
- if (extracted.name) {
476
- return {
477
- ...extracted,
478
- rawDesignContext: designContext.code,
479
- source: 'kiro-power',
480
- };
481
- }
482
- }
483
- } catch {
484
- // Kiro Power failed — fall through to fallback
485
- }
486
- }
487
-
488
- // Fallback: get_metadata + figma_get_component
489
- return this.readFigmaComponentFallback(fileKey, nodeId);
490
- }
491
-
492
- /**
493
- * Parse Kiro Figma Power `get_design_context` response into an
494
- * ExtractedComponent.
495
- *
496
- * Extracts component name, description, variants, states, properties,
497
- * and layout from the generated code string.
498
- */
499
- private parseDesignContext(response: DesignContextResponse): ExtractedComponent {
500
- const code = response.code ?? '';
501
-
502
- return {
503
- name: this.extractComponentName(code),
504
- description: this.extractDescription(code),
505
- variants: this.extractVariants(code),
506
- states: this.extractStates(code),
507
- properties: this.extractProperties(code),
508
- layout: this.extractLayout(code),
509
- source: 'kiro-power',
510
- };
511
- }
512
-
513
- /**
514
- * Fallback component reading via get_metadata + figma_get_component.
515
- *
516
- * Primary extraction path when Kiro Power is unavailable (which is the
517
- * common case). Extracts structured layout data, boundVariables, fills,
518
- * and cornerRadius directly from the Console MCP component response.
519
- */
520
- private async readFigmaComponentFallback(
521
- fileKey: string,
522
- nodeId: string,
523
- ): Promise<ExtractedComponent> {
524
- // Try metadata from Kiro Power if available
525
- let rawMetadata: string | undefined;
526
- if (this.kiroPower) {
527
- try {
528
- const metadata = await this.kiroPower.getMetadata(fileKey, nodeId);
529
- rawMetadata = metadata.xml;
530
- } catch {
531
- // Metadata unavailable — continue without it
532
- }
533
- }
534
-
535
- // Get component data from figma-console-mcp
536
- let componentData: FigmaComponentResponse;
537
- try {
538
- componentData = await this.consoleMcp.getComponent(fileKey, nodeId);
539
- } catch (error) {
540
- const msg = error instanceof Error ? error.message : String(error);
541
- throw new Error(
542
- `Failed to read Figma component (file: ${fileKey}, node: ${nodeId}): ${msg}`,
543
- );
544
- }
545
-
546
- if (!componentData.name) {
547
- throw new Error(
548
- `Component not found or invalid node ID (file: ${fileKey}, node: ${nodeId})`,
549
- );
550
- }
551
-
552
- // Build variants from variantProperties map
553
- const variants: VariantDefinition[] = [];
554
- if (componentData.variantProperties) {
555
- const propEntries = Object.entries(componentData.variantProperties);
556
- if (propEntries.length > 0) {
557
- // Generate variant combinations from the first property's values
558
- const [firstProp, firstValues] = propEntries[0];
559
- for (const val of firstValues) {
560
- variants.push({
561
- name: `${firstProp}=${val}`,
562
- properties: { [firstProp]: val },
563
- });
564
- }
565
- }
566
- }
567
-
568
- // Extract component properties and states from children's componentProperties.
569
- // Children of a COMPONENT_SET carry componentProperties like:
570
- // { "State": { value: "Incomplete", type: "VARIANT" },
571
- // "Size": { value: "Sm", type: "VARIANT" },
572
- // "Show Label#1231:0": { type: "BOOLEAN", value: false } }
573
- const { properties, states: childStates } = this.extractChildComponentProperties(componentData);
574
-
575
- // Extract states from metadata XML if available, merge with child states
576
- const metadataStates = rawMetadata ? this.extractStatesFromMetadata(rawMetadata) : [];
577
- const stateNames = new Set(metadataStates.map(s => s.name));
578
- for (const cs of childStates) {
579
- if (!stateNames.has(cs.name)) {
580
- metadataStates.push(cs);
581
- stateNames.add(cs.name);
582
- }
583
- }
584
-
585
- // Extract structured layout data from component children
586
- const { layout, boundVariableMap, cornerRadius, fills } =
587
- this.extractLayoutFromComponentData(componentData);
588
-
589
- return {
590
- name: componentData.name,
591
- description: componentData.description ?? '',
592
- variants,
593
- states: metadataStates,
594
- properties,
595
- layout,
596
- boundVariableMap,
597
- cornerRadius,
598
- fills,
599
- rawMetadata,
600
- source: 'console-mcp-fallback',
601
- };
602
- }
603
-
604
- /**
605
- * Extract structured layout data from a Console MCP component response.
606
- *
607
- * Walks the component's children (variant instances in a component set)
608
- * to extract padding, itemSpacing, cornerRadius, fills, and boundVariables.
609
- * Uses the first child with layout data as the representative, since
610
- * variant children typically share the same structural tokens.
611
- *
612
- * boundVariables entries use VARIABLE_ALIAS format:
613
- * { "paddingLeft": { "type": "VARIABLE_ALIAS", "id": "VariableID:..." } }
614
- *
615
- * We resolve variable IDs to names via the bindings loaded separately
616
- * in readTokenBindings(). Here we store the raw property→variableId map
617
- * and also extract any inline variable name references.
618
- */
619
- /**
620
- * Extract structured layout data from a Console MCP component response.
621
- *
622
- * Walks the component's children recursively to extract padding,
623
- * itemSpacing, cornerRadius, fills, and boundVariables. Uses the first
624
- * child with layout data as the representative for spacing/layout, and
625
- * collects boundVariables from all levels of the tree (since bindings
626
- * often live on grandchildren — e.g. fill color bindings on inner frames).
627
- *
628
- * boundVariables entries use VARIABLE_ALIAS format:
629
- * { "paddingLeft": { "type": "VARIABLE_ALIAS", "id": "VariableID:..." } }
630
- *
631
- * Fill-level boundVariables are nested inside the fills array:
632
- * fills: [{ color: {...}, boundVariables: { color: { id: "..." } } }]
633
- *
634
- * We resolve variable IDs to names via the bindings loaded separately
635
- * in readTokenBindings(). Here we store the raw property→variableId map.
636
- */
637
- private extractLayoutFromComponentData(
638
- componentData: FigmaComponentResponse,
639
- ): {
640
- layout: ExtractedLayout;
641
- boundVariableMap: Map<string, string>;
642
- cornerRadius?: number;
643
- fills?: Array<{ type: string; color?: string; opacity?: number }>;
644
- } {
645
- const boundVariableMap = new Map<string, string>();
646
- let layout: ExtractedLayout = { mode: 'none' };
647
- let cornerRadius: number | undefined;
648
- let fills: Array<{ type: string; color?: string; opacity?: number }> | undefined;
649
-
650
- // The component data may be a component set (with children) or a single component.
651
- // Try children first, then fall back to the component itself.
652
- const raw = componentData as Record<string, unknown>;
653
- const children = raw.children as Array<Record<string, unknown>> | undefined;
654
- const nodesToInspect = children && children.length > 0
655
- ? children
656
- : [raw];
657
-
658
- for (const node of nodesToInspect) {
659
- // Extract layout mode from layoutMode field
660
- const layoutMode = node.layoutMode as string | undefined;
661
- if (layoutMode && layout.mode === 'none') {
662
- if (layoutMode === 'HORIZONTAL') layout.mode = 'horizontal';
663
- else if (layoutMode === 'VERTICAL') layout.mode = 'vertical';
664
- }
665
-
666
- // Extract spacing values — use first node that has them
667
- const itemSpacing = node.itemSpacing as number | undefined;
668
- if (itemSpacing != null && layout.itemSpacing == null) {
669
- layout.itemSpacing = itemSpacing;
670
- }
671
-
672
- // Extract padding
673
- const pTop = node.paddingTop as number | undefined;
674
- const pRight = node.paddingRight as number | undefined;
675
- const pBottom = node.paddingBottom as number | undefined;
676
- const pLeft = node.paddingLeft as number | undefined;
677
- if ((pTop != null || pRight != null || pBottom != null || pLeft != null) && !layout.padding) {
678
- layout.padding = {
679
- top: pTop,
680
- right: pRight,
681
- bottom: pBottom,
682
- left: pLeft,
683
- };
684
- }
685
-
686
- // Extract corner radius
687
- const cr = node.cornerRadius as number | undefined;
688
- if (cr != null && cornerRadius == null) {
689
- cornerRadius = cr;
690
- }
691
-
692
- // Extract fills from this node (top-level fills for the component)
693
- const nodeFills = node.fills as Array<Record<string, unknown>> | undefined;
694
- if (nodeFills && nodeFills.length > 0 && !fills) {
695
- fills = nodeFills.map((f) => {
696
- const color = f.color as Record<string, number> | undefined;
697
- let colorStr: string | undefined;
698
- if (color) {
699
- const r = Math.round((color.r ?? 0) * 255);
700
- const g = Math.round((color.g ?? 0) * 255);
701
- const b = Math.round((color.b ?? 0) * 255);
702
- colorStr = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
703
- }
704
- // Extract fill-level boundVariables (e.g. color bound to a variable)
705
- const fillBoundVars = f.boundVariables as Record<string, unknown> | undefined;
706
- if (fillBoundVars) {
707
- this.extractBoundVariables(fillBoundVars, boundVariableMap);
708
- }
709
- return {
710
- type: String(f.type ?? 'SOLID'),
711
- color: colorStr,
712
- opacity: f.opacity as number | undefined,
713
- };
714
- });
715
- }
716
-
717
- // Extract node-level boundVariables (spacing, padding, radius bindings)
718
- const boundVars = node.boundVariables as Record<string, unknown> | undefined;
719
- if (boundVars) {
720
- this.extractBoundVariables(boundVars, boundVariableMap);
721
- }
722
-
723
- // Stop scanning siblings once we have layout data (spacing/padding)
724
- if (layout.mode !== 'none') break;
725
- }
726
-
727
- // Always walk the full tree for boundVariables and deep fills.
728
- // boundVariables and color bindings often live on grandchildren
729
- // (e.g. fill color bindings on inner frames within instance children).
730
- // We collect ALL of them, not just the first match.
731
- for (const node of nodesToInspect) {
732
- this.collectBoundVariablesRecursive(node, boundVariableMap, 0, 4);
733
- }
734
-
735
- // Collect fills from deep children that have boundVariables on their
736
- // fills — these represent designer-intentional color assignments that
737
- // the top-level fills may not capture.
738
- const deepFills = this.collectDeepFills(nodesToInspect);
739
- if (deepFills.length > 0) {
740
- // Merge deep fills with top-level fills, deduplicating by color value
741
- const existingColors = new Set((fills ?? []).map(f => f.color));
742
- for (const df of deepFills) {
743
- if (df.color && !existingColors.has(df.color)) {
744
- if (!fills) fills = [];
745
- fills.push(df);
746
- existingColors.add(df.color);
747
- }
748
- }
749
- }
750
-
751
- return { layout, boundVariableMap, cornerRadius, fills };
752
- }
753
-
754
- /**
755
- * Extract component properties and visual states from children's
756
- * componentProperties fields.
757
- *
758
- * Walks all children (and grandchildren) looking for `componentProperties`
759
- * objects. Extracts:
760
- * - VARIANT properties with value matching known state names → StateDefinition
761
- * - VARIANT properties → PropertyDefinition (with type from variant options)
762
- * - BOOLEAN properties → PropertyDefinition
763
- *
764
- * Deduplicates by property name (strips Figma hash suffixes like "#1231:0").
765
- */
766
- private extractChildComponentProperties(
767
- componentData: FigmaComponentResponse,
768
- ): { properties: PropertyDefinition[]; states: StateDefinition[] } {
769
- const properties: PropertyDefinition[] = [];
770
- const states: StateDefinition[] = [];
771
- const seenProps = new Set<string>();
772
- const seenStates = new Set<string>();
773
-
774
- const stateKeywords = new Set([
775
- 'hover', 'focus', 'disabled', 'pressed', 'active', 'selected',
776
- 'error', 'loading', 'incomplete', 'complete', 'current',
777
- ]);
778
-
779
- const raw = componentData as Record<string, unknown>;
780
- const children = raw.children as Array<Record<string, unknown>> | undefined;
781
- if (!children) return { properties, states };
782
-
783
- const walkNode = (node: Record<string, unknown>): void => {
784
- const cp = node.componentProperties as
785
- Record<string, { type: string; value: unknown; boundVariables?: unknown }> | undefined;
786
-
787
- if (cp) {
788
- for (const [rawName, def] of Object.entries(cp)) {
789
- // Strip Figma hash suffix (e.g. "Show Label#1231:0" → "Show Label")
790
- const cleanName = rawName.replace(/#[\d:]+$/, '').trim();
791
- if (seenProps.has(cleanName)) continue;
792
- seenProps.add(cleanName);
793
-
794
- if (def.type === 'VARIANT') {
795
- const value = String(def.value ?? '');
796
-
797
- // Check if this variant value is a visual state
798
- if (stateKeywords.has(value.toLowerCase()) && !seenStates.has(value.toLowerCase())) {
799
- states.push({ name: value.toLowerCase() });
800
- seenStates.add(value.toLowerCase());
801
- }
802
-
803
- properties.push({
804
- name: cleanName,
805
- type: 'variant',
806
- defaultValue: value,
807
- });
808
- } else if (def.type === 'BOOLEAN') {
809
- properties.push({
810
- name: cleanName,
811
- type: 'boolean',
812
- defaultValue: String(def.value ?? 'false'),
813
- });
814
- }
815
- }
816
- }
817
-
818
- // Recurse into children
819
- const nodeChildren = node.children as Array<Record<string, unknown>> | undefined;
820
- if (nodeChildren) {
821
- for (const child of nodeChildren) {
822
- walkNode(child);
823
- }
824
- }
825
- };
826
-
827
- for (const child of children) {
828
- walkNode(child);
829
- }
830
-
831
- return { properties, states };
832
- }
833
-
834
- // -------------------------------------------------------------------------
835
- // Hierarchical Node Tree Construction (Task 1.3)
836
- // -------------------------------------------------------------------------
837
-
838
- /**
839
- * Build a hierarchical node tree with per-node token classifications.
840
- *
841
- * Recursively walks the Figma node tree preserving parent-child
842
- * relationships. Each node carries its own token classifications
843
- * (semantic, primitive, unidentified) rather than flattening them.
844
- *
845
- * @param figmaNode - Raw Figma node object from API response
846
- * @param depth - Current depth in the tree (root = 0)
847
- * @param ancestors - Ancestor node types from root to parent
848
- * @returns NodeWithClassifications tree
849
- * @requirements Req 2 (Hierarchical Node Tree Preservation)
850
- */
851
- buildNodeTree(
852
- figmaNode: Record<string, unknown>,
853
- depth: number = 0,
854
- ancestors: string[] = [],
855
- ): NodeWithClassifications {
856
- const nodeType = (figmaNode.type as string) ?? 'FRAME';
857
- const validTypes = new Set<string>([
858
- 'COMPONENT_SET', 'COMPONENT', 'INSTANCE', 'FRAME', 'TEXT',
859
- ]);
860
- const type: FigmaNodeType = validTypes.has(nodeType)
861
- ? (nodeType as FigmaNodeType)
862
- : 'FRAME';
863
-
864
- const node: NodeWithClassifications = {
865
- id: String(figmaNode.id ?? ''),
866
- name: String(figmaNode.name ?? ''),
867
- type,
868
- depth,
869
- ancestorChain: ancestors,
870
- tokenClassifications: {
871
- semanticIdentified: [],
872
- primitiveIdentified: [],
873
- unidentified: [],
874
- },
875
- children: [],
876
- };
877
-
878
- // Extract layout properties
879
- node.layout = this.extractNodeLayout(figmaNode);
880
-
881
- // Extract text style for TEXT nodes
882
- if (type === 'TEXT') {
883
- node.textStyle = this.extractTextStyle(figmaNode);
884
- }
885
-
886
- // Extract stroke colors
887
- const strokes = figmaNode.strokes as Array<Record<string, unknown>> | undefined;
888
- if (strokes?.length) {
889
- const extracted: Array<{ color: string }> = [];
890
- for (const stroke of strokes) {
891
- const c = stroke.color as Record<string, number> | undefined;
892
- if (!c) continue;
893
- const r = Math.round((c.r ?? 0) * 255);
894
- const g = Math.round((c.g ?? 0) * 255);
895
- const b = Math.round((c.b ?? 0) * 255);
896
- const a = (c.a ?? 1) * ((stroke.opacity as number) ?? 1);
897
- extracted.push({ color: `rgba(${r}, ${g}, ${b}, ${a})` });
898
- }
899
- if (extracted.length) node.strokes = extracted;
900
- }
901
-
902
- // Extract componentProperties for INSTANCE nodes
903
- if (type === 'INSTANCE') {
904
- node.componentProperties = this.extractNodeComponentProperties(figmaNode);
905
- }
906
-
907
- // Classify tokens for this node
908
- this.classifyNodeTokens(figmaNode, node);
909
-
910
- // Recursively build children
911
- const children = figmaNode.children as
912
- Array<Record<string, unknown>> | undefined;
913
- if (children) {
914
- const newAncestors = [...ancestors, nodeType];
915
- node.children = children.map(child =>
916
- this.buildNodeTree(child, depth + 1, newAncestors),
917
- );
918
- }
919
-
920
- return node;
921
- }
922
-
923
- /**
924
- * Detect composition patterns in a node tree.
925
- *
926
- * Groups INSTANCE children by component name and identifies repeated
927
- * usage patterns with shared properties and property variations.
928
- * Applies recursively at every level of the node tree.
929
- *
930
- * @param nodeTree - Root of the classified node tree
931
- * @returns Array of detected composition patterns across all tree levels
932
- * @requirements Req 3 (Composition Pattern Detection)
933
- */
934
- detectCompositionPatterns(
935
- nodeTree: NodeWithClassifications,
936
- ): CompositionPattern[] {
937
- const patterns: CompositionPattern[] = [];
938
- this.detectPatternsAtLevel(nodeTree, patterns);
939
- return patterns;
940
- }
941
-
942
- /**
943
- * Detect composition patterns at a single level and recurse into children.
944
- */
945
- private detectPatternsAtLevel(
946
- node: NodeWithClassifications,
947
- patterns: CompositionPattern[],
948
- ): void {
949
- if (node.children.length > 0) {
950
- // Group INSTANCE children by component name
951
- const grouped = new Map<string, NodeWithClassifications[]>();
952
- for (const child of node.children) {
953
- if (child.type === 'INSTANCE') {
954
- const existing = grouped.get(child.name);
955
- if (existing) {
956
- existing.push(child);
957
- } else {
958
- grouped.set(child.name, [child]);
959
- }
960
- }
961
- }
962
-
963
- // Build patterns for groups with 2+ instances
964
- for (const [componentName, instances] of grouped) {
965
- if (instances.length < 2) continue;
966
-
967
- const shared = this.findSharedProperties(instances);
968
- const variations = this.groupByPropertyVariations(instances, shared);
969
-
970
- patterns.push({
971
- componentName,
972
- count: instances.length,
973
- sharedProperties: shared,
974
- propertyVariations: variations,
975
- depth: instances[0].depth,
976
- });
977
- }
978
-
979
- // Recurse into all children (not just INSTANCE)
980
- for (const child of node.children) {
981
- this.detectPatternsAtLevel(child, patterns);
982
- }
983
- }
984
- }
985
-
986
- /**
987
- * Find properties shared across all instances in a group.
988
- *
989
- * A property is "shared" when every instance has the same value for it.
990
- */
991
- private findSharedProperties(
992
- instances: NodeWithClassifications[],
993
- ): Record<string, unknown> {
994
- const first = instances[0].componentProperties;
995
- if (!first || instances.length === 0) return {};
996
-
997
- const shared: Record<string, unknown> = {};
998
- for (const [key, def] of Object.entries(first)) {
999
- const allSame = instances.every(inst => {
1000
- const cp = inst.componentProperties;
1001
- if (!cp || !(key in cp)) return false;
1002
- return this.valuesEqual(cp[key].value, def.value);
1003
- });
1004
- if (allSame) {
1005
- shared[key] = def.value;
1006
- }
1007
- }
1008
- return shared;
1009
- }
1010
-
1011
- /**
1012
- * Group instances by their non-shared property combinations.
1013
- *
1014
- * Returns distinct property value combinations with counts.
1015
- */
1016
- private groupByPropertyVariations(
1017
- instances: NodeWithClassifications[],
1018
- sharedProperties: Record<string, unknown>,
1019
- ): CompositionPattern['propertyVariations'] {
1020
- const variationMap = new Map<string, { properties: Record<string, unknown>; count: number }>();
1021
-
1022
- for (const inst of instances) {
1023
- const cp = inst.componentProperties;
1024
- const varying: Record<string, unknown> = {};
1025
- if (cp) {
1026
- for (const [key, def] of Object.entries(cp)) {
1027
- if (!(key in sharedProperties)) {
1028
- varying[key] = def.value;
1029
- }
1030
- }
1031
- }
1032
-
1033
- const key = JSON.stringify(varying, Object.keys(varying).sort());
1034
- const existing = variationMap.get(key);
1035
- if (existing) {
1036
- existing.count++;
1037
- } else {
1038
- variationMap.set(key, { properties: varying, count: 1 });
1039
- }
1040
- }
1041
-
1042
- return Array.from(variationMap.values());
1043
- }
1044
-
1045
- // -----------------------------------------------------------------------
1046
- // Screenshot Capture (Task 2.3)
1047
- // -----------------------------------------------------------------------
1048
-
1049
- /**
1050
- * Capture a component screenshot via figma-console-mcp.
1051
- *
1052
- * Calls `figma_get_component_image` at 2x scale in PNG format.
1053
- * On failure, logs a warning and returns null so extraction can
1054
- * continue without a screenshot.
1055
- *
1056
- * @param fileKey - The Figma file key.
1057
- * @param nodeId - The node ID of the component to capture.
1058
- * @param outputDir - Directory for storing screenshot images.
1059
- * @param componentName - Component name for the filename.
1060
- * @param variant - Optional variant identifier for the filename.
1061
- * @returns ScreenshotMetadata or null if capture failed.
1062
- * @requirements Req 5 (Component Screenshots)
1063
- */
1064
- async captureComponentScreenshot(
1065
- fileUrl: string,
1066
- nodeId: string,
1067
- outputDir: string,
1068
- componentName: string,
1069
- variant?: string,
1070
- ): Promise<ScreenshotMetadata | null> {
1071
- try {
1072
- const result = await this.consoleMcp.getComponentImage(fileUrl, nodeId, {
1073
- scale: 2,
1074
- format: 'png',
1075
- });
1076
-
1077
- if (!result.imageUrl) {
1078
- console.warn(`[DesignExtractor] Screenshot capture returned no image URL for "${componentName}"`);
1079
- return null;
1080
- }
1081
-
1082
- // Build filename
1083
- const safeName = componentName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
1084
- const safeVariant = variant
1085
- ? '-' + variant.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
1086
- : '';
1087
- const filename = `${safeName}${safeVariant}.png`;
1088
- const relativePath = `./images/${filename}`;
1089
-
1090
- // Download image to disk
1091
- const absPath = path.join(outputDir, 'images', filename);
1092
- try {
1093
- await this.downloadFile(result.imageUrl, absPath);
1094
- } catch (dlErr) {
1095
- const msg = dlErr instanceof Error ? dlErr.message : String(dlErr);
1096
- console.warn(`[DesignExtractor] Image download failed for "${componentName}": ${msg}`);
1097
- }
1098
-
1099
- return {
1100
- filePath: relativePath,
1101
- url: result.imageUrl,
1102
- format: 'png',
1103
- scale: 2,
1104
- variant,
1105
- capturedAt: new Date().toISOString(),
1106
- };
1107
- } catch (error) {
1108
- const msg = error instanceof Error ? error.message : String(error);
1109
- console.warn(`[DesignExtractor] Screenshot capture failed for "${componentName}": ${msg}`);
1110
- return null;
1111
- }
1112
- }
1113
-
1114
- /** Download a file from a URL to a local path. */
1115
- private downloadFile(url: string, dest: string): Promise<void> {
1116
- return new Promise((resolve, reject) => {
1117
- const mod = url.startsWith('https') ? https : http;
1118
- const file = fs.createWriteStream(dest);
1119
- mod.get(url, (res) => {
1120
- if (res.statusCode === 301 || res.statusCode === 302) {
1121
- file.close();
1122
- fs.unlinkSync(dest);
1123
- this.downloadFile(res.headers.location!, dest).then(resolve, reject);
1124
- return;
1125
- }
1126
- if (res.statusCode !== 200) {
1127
- file.close();
1128
- fs.unlinkSync(dest);
1129
- reject(new Error(`HTTP ${res.statusCode}`));
1130
- return;
1131
- }
1132
- res.pipe(file);
1133
- file.on('finish', () => { file.close(); resolve(); });
1134
- }).on('error', (err) => {
1135
- file.close();
1136
- fs.unlinkSync(dest);
1137
- reject(err);
1138
- });
1139
- });
1140
- }
1141
-
1142
- /**
1143
- * Deep equality check for property values.
1144
- */
1145
- private valuesEqual(a: unknown, b: unknown): boolean {
1146
- if (a === b) return true;
1147
- if (a === null || b === null) return false;
1148
- if (typeof a !== typeof b) return false;
1149
- if (typeof a === 'object') {
1150
- return JSON.stringify(a) === JSON.stringify(b);
1151
- }
1152
- return false;
1153
- }
1154
-
1155
- /**
1156
- * Extract layout properties from a single Figma node.
1157
- *
1158
- * Returns undefined when the node has no layout-related properties,
1159
- * keeping the node tree compact.
1160
- */
1161
- private extractNodeLayout(
1162
- node: Record<string, unknown>,
1163
- ): NodeWithClassifications['layout'] | undefined {
1164
- const layoutMode = node.layoutMode as string | undefined;
1165
- const pTop = node.paddingTop as number | undefined;
1166
- const pRight = node.paddingRight as number | undefined;
1167
- const pBottom = node.paddingBottom as number | undefined;
1168
- const pLeft = node.paddingLeft as number | undefined;
1169
- const itemSpacing = node.itemSpacing as number | undefined;
1170
- const counterAxisSpacing = node.counterAxisSpacing as number | undefined;
1171
- const cornerRadius = node.cornerRadius as number | undefined;
1172
- const width = node.width as number | undefined;
1173
- const height = node.height as number | undefined;
1174
- const layoutSizingH = node.layoutSizingHorizontal as string | undefined;
1175
- const layoutSizingV = node.layoutSizingVertical as string | undefined;
1176
- const primaryAlign = node.primaryAxisAlignItems as string | undefined;
1177
- const counterAlign = node.counterAxisAlignItems as string | undefined;
1178
- const layoutAlign = node.layoutAlign as string | undefined;
1179
- const layoutGrow = node.layoutGrow as number | undefined;
1180
- const opacity = node.opacity as number | undefined;
1181
- const strokeWeight = node.strokeWeight as number | undefined;
1182
- const strokeAlign = node.strokeAlign as string | undefined;
1183
-
1184
- const hasLayout =
1185
- layoutMode != null ||
1186
- pTop != null || pRight != null || pBottom != null || pLeft != null ||
1187
- itemSpacing != null || counterAxisSpacing != null || cornerRadius != null ||
1188
- width != null || height != null || opacity != null || strokeWeight != null;
1189
-
1190
- if (!hasLayout) return undefined;
1191
-
1192
- const layout: NonNullable<NodeWithClassifications['layout']> = {};
1193
-
1194
- if (layoutMode === 'HORIZONTAL' || layoutMode === 'VERTICAL') {
1195
- layout.layoutMode = layoutMode;
1196
- } else if (layoutMode) {
1197
- layout.layoutMode = 'NONE';
1198
- }
1199
-
1200
- if (pTop != null || pRight != null || pBottom != null || pLeft != null) {
1201
- layout.padding = {
1202
- top: pTop ?? 0,
1203
- right: pRight ?? 0,
1204
- bottom: pBottom ?? 0,
1205
- left: pLeft ?? 0,
1206
- };
1207
- }
1208
-
1209
- if (itemSpacing != null) layout.itemSpacing = itemSpacing;
1210
- if (counterAxisSpacing != null) layout.counterAxisSpacing = counterAxisSpacing;
1211
- if (cornerRadius != null) layout.cornerRadius = cornerRadius;
1212
- if (width != null) layout.width = width;
1213
- if (height != null) layout.height = height;
1214
- if (layoutSizingH === 'FIXED' || layoutSizingH === 'HUG' || layoutSizingH === 'FILL') {
1215
- layout.layoutSizingHorizontal = layoutSizingH;
1216
- }
1217
- if (layoutSizingV === 'FIXED' || layoutSizingV === 'HUG' || layoutSizingV === 'FILL') {
1218
- layout.layoutSizingVertical = layoutSizingV;
1219
- }
1220
- if (primaryAlign) layout.primaryAxisAlignItems = primaryAlign;
1221
- if (counterAlign) layout.counterAxisAlignItems = counterAlign;
1222
- if (layoutAlign) layout.layoutAlign = layoutAlign;
1223
- if (layoutGrow != null) layout.layoutGrow = layoutGrow;
1224
- if (opacity != null && opacity !== 1) layout.opacity = opacity;
1225
- if (strokeWeight != null && strokeWeight > 0) layout.strokeWeight = strokeWeight;
1226
- if (strokeAlign) layout.strokeAlign = strokeAlign;
1227
-
1228
- return layout;
1229
- }
1230
-
1231
- /**
1232
- * Extract text style properties from a TEXT node.
1233
- */
1234
- private extractTextStyle(
1235
- node: Record<string, unknown>,
1236
- ): NodeWithClassifications['textStyle'] | undefined {
1237
- const style: NonNullable<NodeWithClassifications['textStyle']> = {};
1238
- let hasData = false;
1239
-
1240
- const chars = node.characters as string | undefined;
1241
- if (chars != null) { style.characters = chars; hasData = true; }
1242
-
1243
- const fontSize = node.fontSize as number | undefined;
1244
- if (fontSize != null) { style.fontSize = fontSize; hasData = true; }
1245
-
1246
- const fontName = node.fontName as { family?: string; style?: string } | undefined;
1247
- if (fontName?.family) { style.fontFamily = fontName.family; hasData = true; }
1248
- if (fontName?.style) { style.fontStyle = fontName.style; hasData = true; }
1249
-
1250
- const fontWeight = node.fontWeight as number | undefined;
1251
- if (fontWeight != null) { style.fontWeight = fontWeight; hasData = true; }
1252
-
1253
- const lh = node.lineHeight as { value?: number; unit?: string } | undefined;
1254
- if (lh?.value != null && lh.unit !== 'AUTO') { style.lineHeight = lh.value; hasData = true; }
1255
-
1256
- const ls = node.letterSpacing as { value?: number } | undefined;
1257
- if (ls?.value != null && ls.value !== 0) { style.letterSpacing = ls.value; hasData = true; }
1258
-
1259
- const tah = node.textAlignHorizontal as string | undefined;
1260
- if (tah) { style.textAlignHorizontal = tah; hasData = true; }
1261
-
1262
- const tav = node.textAlignVertical as string | undefined;
1263
- if (tav) { style.textAlignVertical = tav; hasData = true; }
1264
-
1265
- return hasData ? style : undefined;
1266
- }
1267
-
1268
- /**
1269
- * Extract componentProperties from an INSTANCE node.
1270
- *
1271
- * Strips Figma hash suffixes (e.g. "Show Label#1231:0" → "Show Label")
1272
- * and returns undefined when no properties exist.
1273
- */
1274
- private extractNodeComponentProperties(
1275
- node: Record<string, unknown>,
1276
- ): NodeWithClassifications['componentProperties'] | undefined {
1277
- const cp = node.componentProperties as
1278
- Record<string, { type: string; value: unknown }> | undefined;
1279
- if (!cp || Object.keys(cp).length === 0) return undefined;
1280
-
1281
- const result: NonNullable<NodeWithClassifications['componentProperties']> = {};
1282
- for (const [rawName, def] of Object.entries(cp)) {
1283
- const cleanName = rawName.replace(/#[\d:]+$/, '').trim();
1284
- const type = def.type as 'VARIANT' | 'BOOLEAN' | 'TEXT' | 'INSTANCE_SWAP';
1285
- result[cleanName] = { type, value: def.value };
1286
- }
1287
- return result;
1288
- }
1289
-
1290
- /**
1291
- * Classify tokens for a single Figma node using TokenTranslator.
1292
- *
1293
- * Collects spacing, radius, and fill-color properties from the node,
1294
- * translates each via the translator, and sorts results into the
1295
- * three-tier classification buckets on the node.
1296
- */
1297
- private classifyNodeTokens(
1298
- figmaNode: Record<string, unknown>,
1299
- node: NodeWithClassifications,
1300
- ): void {
1301
- const propertiesToClassify: Array<{
1302
- property: string;
1303
- figmaVarName?: string;
1304
- rawValue: number | string;
1305
- category: TokenCategory;
1306
- }> = [];
1307
-
1308
- // Spacing properties
1309
- const spacingProps: Array<[string, string]> = [
1310
- ['paddingTop', 'padding-top'],
1311
- ['paddingRight', 'padding-right'],
1312
- ['paddingBottom', 'padding-bottom'],
1313
- ['paddingLeft', 'padding-left'],
1314
- ['itemSpacing', 'item-spacing'],
1315
- ['counterAxisSpacing', 'counter-axis-spacing'],
1316
- ];
1317
-
1318
- const boundVars = figmaNode.boundVariables as
1319
- Record<string, unknown> | undefined;
1320
- const layoutMode = figmaNode.layoutMode as string | undefined;
1321
- const nodeType = figmaNode.type as string | undefined;
1322
- const isLeaf = nodeType === 'TEXT' || nodeType === 'VECTOR'
1323
- || nodeType === 'ELLIPSE' || nodeType === 'LINE'
1324
- || nodeType === 'STAR' || nodeType === 'POLYGON';
1325
-
1326
- for (const [figmaProp, cssProp] of spacingProps) {
1327
- const value = figmaNode[figmaProp] as number | undefined;
1328
- if (value == null) continue;
1329
-
1330
- // Skip irrelevant zero-value defaults
1331
- if (cssProp === 'counter-axis-spacing' && value === 0) continue;
1332
- if (cssProp === 'item-spacing' && layoutMode === 'NONE') continue;
1333
- if (isLeaf && cssProp.startsWith('padding-') && value === 0) continue;
1334
-
1335
- const varName = this.getBoundVariableName(boundVars, figmaProp);
1336
- propertiesToClassify.push({
1337
- property: cssProp,
1338
- figmaVarName: varName,
1339
- rawValue: value,
1340
- category: 'spacing',
1341
- });
1342
- }
1343
-
1344
- // Corner radius
1345
- const cornerRadius = figmaNode.cornerRadius as number | undefined;
1346
- if (cornerRadius != null && cornerRadius !== 0) {
1347
- const varName = this.getBoundVariableName(boundVars, 'cornerRadius');
1348
- propertiesToClassify.push({
1349
- property: 'border-radius',
1350
- figmaVarName: varName,
1351
- rawValue: cornerRadius,
1352
- category: 'radius',
1353
- });
1354
- }
1355
-
1356
- // Fill colors
1357
- const fills = figmaNode.fills as
1358
- Array<Record<string, unknown>> | undefined;
1359
- if (fills) {
1360
- for (const fill of fills) {
1361
- const color = fill.color as Record<string, number> | undefined;
1362
- if (!color) continue;
1363
- const r = Math.round((color.r ?? 0) * 255);
1364
- const g = Math.round((color.g ?? 0) * 255);
1365
- const b = Math.round((color.b ?? 0) * 255);
1366
- const a = (color.a ?? 1) * ((fill.opacity as number) ?? 1);
1367
- const rgba = `rgba(${r}, ${g}, ${b}, ${a})`;
1368
-
1369
- const fillBv = fill.boundVariables as
1370
- Record<string, unknown> | undefined;
1371
- const varName = this.getBoundVariableName(fillBv, 'color');
1372
- propertiesToClassify.push({
1373
- property: 'fill',
1374
- figmaVarName: varName,
1375
- rawValue: rgba,
1376
- category: 'color',
1377
- });
1378
- }
1379
- }
1380
-
1381
- // Opacity
1382
- const opacity = figmaNode.opacity as number | undefined;
1383
- if (opacity != null && opacity !== 1) {
1384
- const varName = this.getBoundVariableName(boundVars, 'opacity');
1385
- propertiesToClassify.push({
1386
- property: 'opacity',
1387
- figmaVarName: varName,
1388
- rawValue: opacity,
1389
- category: 'opacity',
1390
- });
1391
- }
1392
-
1393
- // Stroke weight
1394
- const strokeWeight = figmaNode.strokeWeight as number | undefined;
1395
- if (strokeWeight != null && strokeWeight > 0) {
1396
- const varName = this.getBoundVariableName(boundVars, 'strokeWeight');
1397
- propertiesToClassify.push({
1398
- property: 'border-width',
1399
- figmaVarName: varName,
1400
- rawValue: strokeWeight,
1401
- category: 'borderWidth',
1402
- });
1403
- }
1404
-
1405
- // Stroke colors
1406
- const strokes = figmaNode.strokes as Array<Record<string, unknown>> | undefined;
1407
- if (strokes) {
1408
- for (const stroke of strokes) {
1409
- const c = stroke.color as Record<string, number> | undefined;
1410
- if (!c) continue;
1411
- const r = Math.round((c.r ?? 0) * 255);
1412
- const g = Math.round((c.g ?? 0) * 255);
1413
- const b = Math.round((c.b ?? 0) * 255);
1414
- const a = (c.a ?? 1) * ((stroke.opacity as number) ?? 1);
1415
- const strokeBv = stroke.boundVariables as Record<string, unknown> | undefined;
1416
- const varName = this.getBoundVariableName(strokeBv, 'color');
1417
- propertiesToClassify.push({
1418
- property: 'stroke',
1419
- figmaVarName: varName,
1420
- rawValue: `rgba(${r}, ${g}, ${b}, ${a})`,
1421
- category: 'color',
1422
- });
1423
- }
1424
- }
1425
-
1426
- // Typography properties (TEXT nodes only)
1427
- if (nodeType === 'TEXT') {
1428
- const fontSize = figmaNode.fontSize as number | undefined;
1429
- if (fontSize != null) {
1430
- const varName = this.getBoundVariableName(boundVars, 'fontSize');
1431
- propertiesToClassify.push({
1432
- property: 'font-size',
1433
- figmaVarName: varName,
1434
- rawValue: fontSize,
1435
- category: 'fontSize',
1436
- });
1437
- }
1438
-
1439
- const fontWeight = figmaNode.fontWeight as number | undefined;
1440
- if (fontWeight != null) {
1441
- const varName = this.getBoundVariableName(boundVars, 'fontWeight');
1442
- propertiesToClassify.push({
1443
- property: 'font-weight',
1444
- figmaVarName: varName,
1445
- rawValue: fontWeight,
1446
- category: 'fontWeight',
1447
- });
1448
- }
1449
-
1450
- const lh = figmaNode.lineHeight as { value?: number; unit?: string } | undefined;
1451
- if (lh?.value != null && lh.unit !== 'AUTO') {
1452
- const varName = this.getBoundVariableName(boundVars, 'lineHeight');
1453
- propertiesToClassify.push({
1454
- property: 'line-height',
1455
- figmaVarName: varName,
1456
- rawValue: lh.value,
1457
- category: 'lineHeight',
1458
- });
1459
- }
1460
-
1461
- const ls = figmaNode.letterSpacing as { value?: number } | undefined;
1462
- if (ls?.value != null && ls.value !== 0) {
1463
- const varName = this.getBoundVariableName(boundVars, 'letterSpacing');
1464
- propertiesToClassify.push({
1465
- property: 'letter-spacing',
1466
- figmaVarName: varName,
1467
- rawValue: ls.value,
1468
- category: 'letterSpacing',
1469
- });
1470
- }
1471
- }
1472
-
1473
- // Classify each property
1474
- for (const { property, figmaVarName, rawValue, category } of propertiesToClassify) {
1475
- const result = this.translator.translate(figmaVarName, rawValue, category);
1476
- const tier = this.translator.classifyTokenMatch(result);
1477
-
1478
- // Value-based matches → Unidentified with suggestion (only bindings earn Identified)
1479
- if (result.matchMethod === 'value' && tier !== 'unidentified') {
1480
- node.tokenClassifications.unidentified.push({
1481
- property,
1482
- rawValue: result.rawValue,
1483
- reason: figmaVarName ? 'unresolved-binding' : 'value-match',
1484
- suggestedToken: result.semantic ?? result.primitive ?? result.token,
1485
- boundVariableId: figmaVarName,
1486
- });
1487
- } else if (tier === 'semantic') {
1488
- node.tokenClassifications.semanticIdentified.push(
1489
- this.translator.toClassifiedToken(result, property),
1490
- );
1491
- } else if (tier === 'primitive') {
1492
- node.tokenClassifications.primitiveIdentified.push(
1493
- this.translator.toClassifiedToken(result, property),
1494
- );
1495
- } else {
1496
- node.tokenClassifications.unidentified.push(
1497
- this.translator.toUnidentifiedValue(result, property),
1498
- );
1499
- }
1500
- }
1501
- }
1502
-
1503
- /**
1504
- * Extract a Figma variable name from a node's boundVariables for a
1505
- * given property.
1506
- *
1507
- * Handles both single-binding objects and array-of-bindings.
1508
- */
1509
- private getBoundVariableName(
1510
- boundVars: Record<string, unknown> | undefined,
1511
- property: string,
1512
- ): string | undefined {
1513
- if (!boundVars) return undefined;
1514
- const binding = boundVars[property];
1515
- if (!binding || typeof binding !== 'object') return undefined;
1516
- const bindingObj = binding as Record<string, unknown>;
1517
- const entry = Array.isArray(bindingObj) ? bindingObj[0] : bindingObj;
1518
- if (!entry || typeof entry !== 'object') return undefined;
1519
- const entryObj = entry as Record<string, unknown>;
1520
- return entryObj.id as string | undefined;
1521
- }
1522
-
1523
- /**
1524
- * Extract boundVariables from a node's boundVariables object into the map.
1525
- */
1526
- private extractBoundVariables(
1527
- boundVars: Record<string, unknown>,
1528
- boundVariableMap: Map<string, string>,
1529
- ): void {
1530
- for (const [prop, binding] of Object.entries(boundVars)) {
1531
- if (!binding || typeof binding !== 'object') continue;
1532
-
1533
- const bindingObj = binding as Record<string, unknown>;
1534
- const bindingEntries = Array.isArray(bindingObj) ? bindingObj : [bindingObj];
1535
-
1536
- for (const entry of bindingEntries) {
1537
- const entryObj = entry as Record<string, unknown>;
1538
- const varId = entryObj.id as string | undefined;
1539
- if (varId && !boundVariableMap.has(prop)) {
1540
- boundVariableMap.set(prop, varId);
1541
- }
1542
- }
1543
- }
1544
- }
1545
-
1546
- /**
1547
- * Recursively walk a node tree to collect all boundVariables.
1548
- *
1549
- * Collects from node-level boundVariables and fill-level boundVariables
1550
- * on all descendants up to maxDepth.
1551
- */
1552
- private collectBoundVariablesRecursive(
1553
- node: Record<string, unknown>,
1554
- boundVariableMap: Map<string, string>,
1555
- depth: number,
1556
- maxDepth: number,
1557
- ): void {
1558
- if (depth > maxDepth) return;
1559
-
1560
- // Node-level boundVariables
1561
- const boundVars = node.boundVariables as Record<string, unknown> | undefined;
1562
- if (boundVars) {
1563
- this.extractBoundVariables(boundVars, boundVariableMap);
1564
- }
1565
-
1566
- // Fill-level boundVariables (color bindings inside fills array)
1567
- const nodeFills = node.fills as Array<Record<string, unknown>> | undefined;
1568
- if (nodeFills) {
1569
- for (const fill of nodeFills) {
1570
- const fillBoundVars = fill.boundVariables as Record<string, unknown> | undefined;
1571
- if (fillBoundVars) {
1572
- this.extractBoundVariables(fillBoundVars, boundVariableMap);
1573
- }
1574
- }
1575
- }
1576
-
1577
- // Recurse into children
1578
- const children = node.children as Array<Record<string, unknown>> | undefined;
1579
- if (children) {
1580
- for (const child of children) {
1581
- this.collectBoundVariablesRecursive(child, boundVariableMap, depth + 1, maxDepth);
1582
- }
1583
- }
1584
- }
1585
-
1586
- // -----------------------------------------------------------------------
1587
- // Bound Variable Batch Resolution (Task 1.5)
1588
- // -----------------------------------------------------------------------
1589
-
1590
- /**
1591
- * Walk a raw Figma node tree and collect all bound variable entries
1592
- * with full node context.
1593
- *
1594
- * Checks spacing properties, cornerRadius, and fill colors for
1595
- * boundVariables. Returns all entries (not deduplicated) — dedup
1596
- * happens in batchResolveBoundVariables.
1597
- *
1598
- * @param figmaNode - Raw Figma node object from API response
1599
- * @param depth - Current depth in the tree (root = 0)
1600
- * @param ancestors - Ancestor node types from root to parent
1601
- * @returns Array of BoundVariableEntry with full node context
1602
- * @requirements Req 4 (Bound Variable Batch Resolution)
1603
- */
1604
- collectBoundVariableIds(
1605
- figmaNode: Record<string, unknown>,
1606
- depth: number = 0,
1607
- ancestors: string[] = [],
1608
- ): BoundVariableEntry[] {
1609
- const entries: BoundVariableEntry[] = [];
1610
- const nodeId = String(figmaNode.id ?? '');
1611
- const nodeName = String(figmaNode.name ?? '');
1612
- const nodeType = String(figmaNode.type ?? 'FRAME');
1613
-
1614
- const boundVars = figmaNode.boundVariables as
1615
- Record<string, unknown> | undefined;
1616
-
1617
- // Spacing properties
1618
- const spacingProps: Array<[string, string]> = [
1619
- ['paddingTop', 'padding-top'],
1620
- ['paddingRight', 'padding-right'],
1621
- ['paddingBottom', 'padding-bottom'],
1622
- ['paddingLeft', 'padding-left'],
1623
- ['itemSpacing', 'item-spacing'],
1624
- ['counterAxisSpacing', 'counter-axis-spacing'],
1625
- ];
1626
-
1627
- for (const [figmaProp, cssProp] of spacingProps) {
1628
- const value = figmaNode[figmaProp] as number | undefined;
1629
- if (value == null) continue;
1630
- const varId = this.getBoundVariableName(boundVars, figmaProp);
1631
- if (varId) {
1632
- entries.push({
1633
- variableId: varId,
1634
- property: cssProp,
1635
- nodeId,
1636
- nodeName,
1637
- ancestorChain: ancestors,
1638
- rawValue: value,
1639
- category: 'spacing',
1640
- });
1641
- }
1642
- }
1643
-
1644
- // Corner radius
1645
- const cornerRadius = figmaNode.cornerRadius as number | undefined;
1646
- if (cornerRadius != null) {
1647
- const varId = this.getBoundVariableName(boundVars, 'cornerRadius');
1648
- if (varId) {
1649
- entries.push({
1650
- variableId: varId,
1651
- property: 'border-radius',
1652
- nodeId,
1653
- nodeName,
1654
- ancestorChain: ancestors,
1655
- rawValue: cornerRadius,
1656
- category: 'radius',
1657
- });
1658
- }
1659
- }
1660
-
1661
- // Fill colors
1662
- const fills = figmaNode.fills as
1663
- Array<Record<string, unknown>> | undefined;
1664
- if (fills) {
1665
- for (const fill of fills) {
1666
- const color = fill.color as Record<string, number> | undefined;
1667
- if (!color) continue;
1668
- const r = Math.round((color.r ?? 0) * 255);
1669
- const g = Math.round((color.g ?? 0) * 255);
1670
- const b = Math.round((color.b ?? 0) * 255);
1671
- const a = (color.a ?? 1) * ((fill.opacity as number) ?? 1);
1672
- const rgba = `rgba(${r}, ${g}, ${b}, ${a})`;
1673
-
1674
- const fillBv = fill.boundVariables as
1675
- Record<string, unknown> | undefined;
1676
- const varId = this.getBoundVariableName(fillBv, 'color');
1677
- if (varId) {
1678
- entries.push({
1679
- variableId: varId,
1680
- property: 'fill',
1681
- nodeId,
1682
- nodeName,
1683
- ancestorChain: ancestors,
1684
- rawValue: rgba,
1685
- category: 'color',
1686
- });
1687
- }
1688
- }
1689
- }
1690
-
1691
- // Opacity
1692
- const opacity = figmaNode.opacity as number | undefined;
1693
- if (opacity != null && opacity !== 1) {
1694
- const varId = this.getBoundVariableName(boundVars, 'opacity');
1695
- if (varId) {
1696
- entries.push({
1697
- variableId: varId, property: 'opacity', nodeId, nodeName,
1698
- ancestorChain: ancestors, rawValue: opacity, category: 'opacity',
1699
- });
1700
- }
1701
- }
1702
-
1703
- // Stroke weight
1704
- const strokeWeight = figmaNode.strokeWeight as number | undefined;
1705
- if (strokeWeight != null && strokeWeight > 0) {
1706
- const varId = this.getBoundVariableName(boundVars, 'strokeWeight');
1707
- if (varId) {
1708
- entries.push({
1709
- variableId: varId, property: 'border-width', nodeId, nodeName,
1710
- ancestorChain: ancestors, rawValue: strokeWeight, category: 'borderWidth',
1711
- });
1712
- }
1713
- }
1714
-
1715
- // Stroke colors
1716
- const strokes = figmaNode.strokes as Array<Record<string, unknown>> | undefined;
1717
- if (strokes) {
1718
- for (const stroke of strokes) {
1719
- const sc = stroke.color as Record<string, number> | undefined;
1720
- if (!sc) continue;
1721
- const sr = Math.round((sc.r ?? 0) * 255);
1722
- const sg = Math.round((sc.g ?? 0) * 255);
1723
- const sb = Math.round((sc.b ?? 0) * 255);
1724
- const sa = (sc.a ?? 1) * ((stroke.opacity as number) ?? 1);
1725
- const strokeBv = stroke.boundVariables as Record<string, unknown> | undefined;
1726
- const varId = this.getBoundVariableName(strokeBv, 'color');
1727
- if (varId) {
1728
- entries.push({
1729
- variableId: varId, property: 'stroke', nodeId, nodeName,
1730
- ancestorChain: ancestors, rawValue: `rgba(${sr}, ${sg}, ${sb}, ${sa})`, category: 'color',
1731
- });
1732
- }
1733
- }
1734
- }
1735
-
1736
- // Typography bindings (TEXT nodes only)
1737
- if (nodeType === 'TEXT') {
1738
- const typoProps: Array<[string, string, TokenCategory]> = [
1739
- ['fontSize', 'font-size', 'fontSize'],
1740
- ['fontWeight', 'font-weight', 'fontWeight'],
1741
- ['lineHeight', 'line-height', 'lineHeight'],
1742
- ['letterSpacing', 'letter-spacing', 'letterSpacing'],
1743
- ];
1744
- for (const [figmaProp, cssProp, cat] of typoProps) {
1745
- const varId = this.getBoundVariableName(boundVars, figmaProp);
1746
- if (varId) {
1747
- const raw = figmaNode[figmaProp];
1748
- const rawVal = typeof raw === 'object' && raw !== null
1749
- ? (raw as Record<string, unknown>).value ?? 0
1750
- : raw ?? 0;
1751
- entries.push({
1752
- variableId: varId, property: cssProp, nodeId, nodeName,
1753
- ancestorChain: ancestors, rawValue: rawVal as number, category: cat,
1754
- });
1755
- }
1756
- }
1757
- }
1758
-
1759
- // Recurse into children
1760
- const children = figmaNode.children as
1761
- Array<Record<string, unknown>> | undefined;
1762
- if (children) {
1763
- const newAncestors = [...ancestors, nodeType];
1764
- for (const child of children) {
1765
- entries.push(
1766
- ...this.collectBoundVariableIds(child, depth + 1, newAncestors),
1767
- );
1768
- }
1769
- }
1770
-
1771
- return entries;
1772
- }
1773
-
1774
- /**
1775
- * Batch-resolve bound variable IDs via the Figma Plugin API.
1776
- *
1777
- * Deduplicates variable IDs, calls figma_execute to resolve names,
1778
- * and returns a map of resolved names plus an array of unresolved
1779
- * bindings with full node context.
1780
- *
1781
- * @param fileKey - The Figma file key
1782
- * @param entries - BoundVariableEntry[] collected from the node tree
1783
- * @returns Object with resolved map and unresolvedBindings array
1784
- * @requirements Req 4 (Bound Variable Batch Resolution)
1785
- */
1786
- async batchResolveBoundVariables(
1787
- fileKey: string,
1788
- entries: BoundVariableEntry[],
1789
- ): Promise<{
1790
- resolved: Map<string, string>;
1791
- unresolvedBindings: UnresolvedBinding[];
1792
- }> {
1793
- const resolved = new Map<string, string>();
1794
- const unresolvedBindings: UnresolvedBinding[] = [];
1795
-
1796
- if (entries.length === 0) {
1797
- return { resolved, unresolvedBindings };
1798
- }
1799
-
1800
- // Deduplicate variable IDs
1801
- const uniqueIds = [...new Set(entries.map(e => e.variableId))];
1802
-
1803
- // Build Plugin API code
1804
- const code = `
1805
- const results = {};
1806
- const collections = {};
1807
- for (const id of ${JSON.stringify(uniqueIds)}) {
1808
- try {
1809
- const v = await figma.variables.getVariableByIdAsync(id);
1810
- if (v) {
1811
- let collectionName = collections[v.variableCollectionId];
1812
- if (!collectionName) {
1813
- try {
1814
- const c = await figma.variables.getVariableCollectionByIdAsync(v.variableCollectionId);
1815
- collectionName = c ? c.name : '';
1816
- } catch(e) { collectionName = ''; }
1817
- collections[v.variableCollectionId] = collectionName;
1818
- }
1819
- results[id] = { name: v.name, collection: collectionName };
1820
- }
1821
- } catch (e) {
1822
- // Variable not found — skip
1823
- }
1824
- }
1825
- return results;
1826
- `.trim();
1827
-
1828
- try {
1829
- const result = await this.consoleMcp.execute(fileKey, code);
1830
-
1831
- // Parse the result — may be wrapped in { result: { ... } } or { result: "..." }
1832
- let resolvedData: Record<string, { name: string; collection?: string }> = {};
1833
- if (result && typeof result === 'object') {
1834
- const raw = result as Record<string, unknown>;
1835
- let inner = raw.result ?? raw;
1836
- if (typeof inner === 'string') {
1837
- try { inner = JSON.parse(inner); } catch { /* not JSON */ }
1838
- }
1839
- if (inner && typeof inner === 'object') {
1840
- resolvedData = inner as typeof resolvedData;
1841
- }
1842
- }
1843
-
1844
- // Populate resolved map
1845
- for (const [varId, info] of Object.entries(resolvedData)) {
1846
- if (info?.name) {
1847
- resolved.set(varId, info.name);
1848
- }
1849
- }
1850
-
1851
- // Build unresolvedBindings for IDs that failed
1852
- for (const entry of entries) {
1853
- if (!resolved.has(entry.variableId)) {
1854
- unresolvedBindings.push({
1855
- variableId: entry.variableId,
1856
- property: entry.property,
1857
- nodeId: entry.nodeId,
1858
- nodeName: entry.nodeName,
1859
- ancestorChain: entry.ancestorChain,
1860
- reason: 'api-resolution-failed' as UnresolvedBindingReason,
1861
- });
1862
- }
1863
- }
1864
- } catch {
1865
- // API call failed entirely — all entries are unresolved
1866
- for (const entry of entries) {
1867
- unresolvedBindings.push({
1868
- variableId: entry.variableId,
1869
- property: entry.property,
1870
- nodeId: entry.nodeId,
1871
- nodeName: entry.nodeName,
1872
- ancestorChain: entry.ancestorChain,
1873
- reason: 'api-resolution-failed' as UnresolvedBindingReason,
1874
- });
1875
- }
1876
- }
1877
-
1878
- return { resolved, unresolvedBindings };
1879
- }
1880
-
1881
- /**
1882
- * Walk a NodeWithClassifications tree and reclassify unidentified values
1883
- * that have a boundVariableId using resolved variable names.
1884
- *
1885
- * For each unidentified value with a boundVariableId found in the
1886
- * resolvedMap, re-translates using the resolved name and moves
1887
- * successfully classified tokens from unidentified to semantic or
1888
- * primitive. Mutates the tree in place.
1889
- *
1890
- * @param nodeTree - Root of the classified node tree
1891
- * @param resolvedMap - Map of variableId → resolved variable name
1892
- * @requirements Req 4 (Bound Variable Batch Resolution)
1893
- */
1894
- reclassifyWithResolvedBindings(
1895
- nodeTree: NodeWithClassifications,
1896
- resolvedMap: Map<string, string>,
1897
- ): void {
1898
- const { unidentified } = nodeTree.tokenClassifications;
1899
- const remaining: typeof unidentified = [];
1900
-
1901
- for (const entry of unidentified) {
1902
- if (entry.boundVariableId && resolvedMap.has(entry.boundVariableId)) {
1903
- const resolvedName = resolvedMap.get(entry.boundVariableId)!;
1904
-
1905
- // Use translateByBinding directly — no enrichResponse promotion.
1906
- // The designer bound to THIS variable; honour the tier it lives at.
1907
- const bindingResult = this.translator.translateByBinding(resolvedName);
1908
- if (bindingResult.confidence === 'no-match') {
1909
- // Binding resolved to a name but no matching token in DTCG —
1910
- // likely a component-level variable that needs to be created.
1911
- entry.reason = 'no-token-match';
1912
- entry.suggestedToken = resolvedName;
1913
- remaining.push(entry);
1914
- continue;
1915
- }
1916
-
1917
- // Determine tier from the token itself (alias = semantic, raw = primitive)
1918
- const tokenObj = this.translator.lookupToken(bindingResult.token);
1919
- const isAlias = tokenObj && typeof tokenObj.$value === 'string'
1920
- && tokenObj.$value.startsWith('{') && tokenObj.$value.endsWith('}');
1921
-
1922
- const classified: ClassifiedToken = {
1923
- property: entry.property,
1924
- semanticToken: isAlias ? bindingResult.token : undefined,
1925
- primitiveToken: isAlias
1926
- ? (tokenObj!.$value as string).slice(1, -1)
1927
- : bindingResult.token,
1928
- rawValue: bindingResult.rawValue,
1929
- matchMethod: 'binding',
1930
- confidence: 'exact',
1931
- };
1932
-
1933
- if (isAlias) {
1934
- nodeTree.tokenClassifications.semanticIdentified.push(classified);
1935
- } else {
1936
- nodeTree.tokenClassifications.primitiveIdentified.push(classified);
1937
- }
1938
- } else {
1939
- remaining.push(entry);
1940
- }
1941
- }
1942
-
1943
- nodeTree.tokenClassifications.unidentified = remaining;
1944
-
1945
- // Recurse into children
1946
- for (const child of nodeTree.children) {
1947
- this.reclassifyWithResolvedBindings(child, resolvedMap);
1948
- }
1949
- }
1950
-
1951
- /**
1952
- * Collect fills from deep children that have boundVariables on their fills.
1953
- *
1954
- * These represent designer-intentional color assignments (variables bound
1955
- * to fill colors) that may differ from the parent component's fills.
1956
- * Returns deduplicated fills with their hex color values.
1957
- */
1958
- private collectDeepFills(
1959
- nodes: Array<Record<string, unknown>>,
1960
- ): Array<{ type: string; color?: string; opacity?: number }> {
1961
- const result: Array<{ type: string; color?: string; opacity?: number }> = [];
1962
- const seenColors = new Set<string>();
1963
-
1964
- const walk = (node: Record<string, unknown>, depth: number): void => {
1965
- if (depth > 4) return;
1966
-
1967
- const nodeFills = node.fills as Array<Record<string, unknown>> | undefined;
1968
- if (nodeFills) {
1969
- for (const fill of nodeFills) {
1970
- // Only collect fills that have boundVariables (designer intent)
1971
- const fillBv = fill.boundVariables as Record<string, unknown> | undefined;
1972
- if (!fillBv || Object.keys(fillBv).length === 0) continue;
1973
-
1974
- const color = fill.color as Record<string, number> | undefined;
1975
- if (!color) continue;
1976
-
1977
- const r = Math.round((color.r ?? 0) * 255);
1978
- const g = Math.round((color.g ?? 0) * 255);
1979
- const b = Math.round((color.b ?? 0) * 255);
1980
- const hex = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
1981
-
1982
- if (!seenColors.has(hex)) {
1983
- seenColors.add(hex);
1984
- result.push({
1985
- type: String(fill.type ?? 'SOLID'),
1986
- color: hex,
1987
- opacity: fill.opacity as number | undefined,
1988
- });
1989
- }
1990
- }
1991
- }
1992
-
1993
- const children = node.children as Array<Record<string, unknown>> | undefined;
1994
- if (children) {
1995
- for (const child of children) {
1996
- walk(child, depth + 1);
1997
- }
1998
- }
1999
- };
2000
-
2001
- for (const node of nodes) {
2002
- walk(node, 0);
2003
- }
2004
-
2005
- return result;
2006
- }
2007
-
2008
-
2009
-
2010
-
2011
- // -------------------------------------------------------------------------
2012
- // Design context parsing helpers
2013
- // -------------------------------------------------------------------------
2014
-
2015
- /** Extract component name from generated code. */
2016
- private extractComponentName(code: string): string {
2017
- // Match class/component name patterns
2018
- const classMatch = code.match(/class\s+(\w+)/);
2019
- if (classMatch) return classMatch[1];
2020
-
2021
- const componentMatch = code.match(/(?:export\s+)?(?:default\s+)?(?:function|const)\s+(\w+)/);
2022
- if (componentMatch) return componentMatch[1];
2023
-
2024
- // Try HTML custom element tag
2025
- const tagMatch = code.match(/<([a-z][\w-]*)/);
2026
- if (tagMatch) return tagMatch[1];
2027
-
2028
- return '';
2029
- }
2030
-
2031
- /** Extract description from code comments or JSDoc. */
2032
- private extractDescription(code: string): string {
2033
- const jsdocMatch = code.match(/\/\*\*\s*\n?\s*\*?\s*(.+?)(?:\n|\*\/)/);
2034
- if (jsdocMatch) return jsdocMatch[1].trim();
2035
-
2036
- const commentMatch = code.match(/\/\/\s*(.+)/);
2037
- if (commentMatch) return commentMatch[1].trim();
2038
-
2039
- return '';
2040
- }
2041
-
2042
- /** Extract variant definitions from code. */
2043
- private extractVariants(code: string): VariantDefinition[] {
2044
- const variants: VariantDefinition[] = [];
2045
-
2046
- // Match variant property patterns (e.g. variant="primary", size="large")
2047
- const variantPattern = /(?:variant|type|size|state)\s*[=:]\s*["'](\w+)["']/gi;
2048
- const seen = new Set<string>();
2049
- let match: RegExpExecArray | null;
2050
-
2051
- while ((match = variantPattern.exec(code)) !== null) {
2052
- const propName = match[0].split(/[=:]/)[0].trim().toLowerCase();
2053
- const value = match[1];
2054
- const key = `${propName}=${value}`;
2055
- if (!seen.has(key)) {
2056
- seen.add(key);
2057
- variants.push({ name: key, properties: { [propName]: value } });
2058
- }
2059
- }
2060
-
2061
- return variants;
2062
- }
2063
-
2064
- /** Extract visual states from code (hover, focus, disabled, pressed). */
2065
- private extractStates(code: string): StateDefinition[] {
2066
- const stateKeywords = ['hover', 'focus', 'disabled', 'pressed', 'active', 'selected'];
2067
- const states: StateDefinition[] = [];
2068
- const codeLower = code.toLowerCase();
2069
-
2070
- for (const keyword of stateKeywords) {
2071
- if (codeLower.includes(keyword)) {
2072
- states.push({ name: keyword });
2073
- }
2074
- }
2075
-
2076
- return states;
2077
- }
2078
-
2079
- /** Extract component properties from code. */
2080
- private extractProperties(code: string): PropertyDefinition[] {
2081
- const properties: PropertyDefinition[] = [];
2082
-
2083
- // Match TypeScript interface/type property patterns
2084
- const propPattern = /(\w+)\s*[?]?\s*:\s*(string|number|boolean|'[^']*'(?:\s*\|\s*'[^']*')*)/g;
2085
- const seen = new Set<string>();
2086
- let match: RegExpExecArray | null;
2087
-
2088
- while ((match = propPattern.exec(code)) !== null) {
2089
- const name = match[1];
2090
- const type = match[2];
2091
- if (!seen.has(name)) {
2092
- seen.add(name);
2093
- properties.push({ name, type });
2094
- }
2095
- }
2096
-
2097
- return properties;
2098
- }
2099
-
2100
- /** Extract layout information from code. */
2101
- private extractLayout(code: string): ExtractedLayout {
2102
- const codeLower = code.toLowerCase();
2103
-
2104
- let mode: ExtractedLayout['mode'] = 'none';
2105
- if (codeLower.includes('flex-direction: row') || codeLower.includes('flexdirection: row') || codeLower.includes('display: flex')) {
2106
- mode = 'horizontal';
2107
- }
2108
- if (codeLower.includes('flex-direction: column') || codeLower.includes('flexdirection: column')) {
2109
- mode = 'vertical';
2110
- }
2111
-
2112
- const layout: ExtractedLayout = { mode };
2113
-
2114
- // Extract gap/spacing
2115
- const gapMatch = code.match(/gap:\s*(\d+)/);
2116
- if (gapMatch) {
2117
- layout.itemSpacing = parseInt(gapMatch[1], 10);
2118
- }
2119
-
2120
- // Extract padding
2121
- const paddingMatch = code.match(/padding:\s*(\d+)(?:px)?(?:\s+(\d+)(?:px)?)?(?:\s+(\d+)(?:px)?)?(?:\s+(\d+)(?:px)?)?/);
2122
- if (paddingMatch) {
2123
- const values = [paddingMatch[1], paddingMatch[2], paddingMatch[3], paddingMatch[4]]
2124
- .filter(Boolean)
2125
- .map(Number);
2126
-
2127
- if (values.length === 1) {
2128
- layout.padding = { top: values[0], right: values[0], bottom: values[0], left: values[0] };
2129
- } else if (values.length === 2) {
2130
- layout.padding = { top: values[0], right: values[1], bottom: values[0], left: values[1] };
2131
- } else if (values.length === 4) {
2132
- layout.padding = { top: values[0], right: values[1], bottom: values[2], left: values[3] };
2133
- }
2134
- }
2135
-
2136
- return layout;
2137
- }
2138
-
2139
- /** Extract states from metadata XML. */
2140
- private extractStatesFromMetadata(xml: string): StateDefinition[] {
2141
- const stateKeywords = ['hover', 'focus', 'disabled', 'pressed', 'active', 'selected'];
2142
- const states: StateDefinition[] = [];
2143
- const xmlLower = xml.toLowerCase();
2144
-
2145
- for (const keyword of stateKeywords) {
2146
- if (xmlLower.includes(keyword)) {
2147
- states.push({ name: keyword });
2148
- }
2149
- }
2150
-
2151
- return states;
2152
- }
2153
-
2154
- // -------------------------------------------------------------------------
2155
- // readTokenBindings (Task 3.3)
2156
- // -------------------------------------------------------------------------
2157
-
2158
- /**
2159
- * Read all token bindings (Figma variables) from a file.
2160
- *
2161
- * Uses figma-console-mcp via `consoleMcp.getVariables()` which calls
2162
- * `figma_get_token_values`. Maps results to `TokenBinding[]` with alias
2163
- * detection based on `valuesByMode` containing `{ aliasOf: string }`.
2164
- *
2165
- * @param fileKey - The Figma file key.
2166
- * @returns Array of token bindings with alias relationships detected.
2167
- */
2168
- async readTokenBindings(fileKey: string): Promise<TokenBinding[]> {
2169
- const variables = await this.consoleMcp.getVariables(fileKey);
2170
-
2171
- if (!variables || variables.length === 0) {
2172
- return [];
2173
- }
2174
-
2175
- // Build a lookup of variable names for alias target resolution
2176
- const nameById = new Map<string, string>();
2177
- for (const v of variables) {
2178
- if (v.id) {
2179
- nameById.set(v.id, v.name);
2180
- }
2181
- }
2182
-
2183
- return variables.map((v) => {
2184
- // Detect alias: valuesByMode values shaped { aliasOf: string }
2185
- const { isAlias, aliasTarget } = this.detectAlias(v.valuesByMode, nameById);
2186
-
2187
- // collectionName is available at runtime from figma_get_token_values
2188
- // even though the FigmaVariable type doesn't declare it
2189
- const raw = v as unknown as Record<string, unknown>;
2190
- const collectionName = typeof raw.collectionName === 'string'
2191
- ? raw.collectionName
2192
- : this.inferCollectionFromName(v.name, isAlias);
2193
-
2194
- return {
2195
- variableName: v.name,
2196
- variableId: v.id ?? '',
2197
- collectionName,
2198
- resolvedType: v.resolvedType,
2199
- valuesByMode: v.valuesByMode,
2200
- isAlias,
2201
- aliasTarget,
2202
- };
2203
- });
2204
- }
2205
-
2206
- /**
2207
- * Detect whether a variable is an alias by inspecting its mode values.
2208
- *
2209
- * Figma aliases are represented as `{ aliasOf: string }` in valuesByMode.
2210
- * Returns the first alias target found (semantic tokens typically alias
2211
- * the same primitive across all modes).
2212
- */
2213
- private detectAlias(
2214
- valuesByMode: Record<string, unknown>,
2215
- nameById: Map<string, string>,
2216
- ): { isAlias: boolean; aliasTarget?: string } {
2217
- for (const modeValue of Object.values(valuesByMode)) {
2218
- if (
2219
- modeValue &&
2220
- typeof modeValue === 'object' &&
2221
- 'aliasOf' in (modeValue as Record<string, unknown>)
2222
- ) {
2223
- const aliasRef = (modeValue as { aliasOf: string }).aliasOf;
2224
- // aliasOf may be a variable name or an ID — resolve via lookup
2225
- const resolved = nameById.get(aliasRef) ?? aliasRef;
2226
- return { isAlias: true, aliasTarget: resolved };
2227
- }
2228
- }
2229
- return { isAlias: false };
2230
- }
2231
-
2232
- /**
2233
- * Infer collection name from variable name when not provided by MCP.
2234
- *
2235
- * Heuristic: variables with dot-separated semantic paths (e.g.
2236
- * "color.primary", "color.feedback.success.text") are Semantics;
2237
- * simple group/value names (e.g. "space/100", "color/purple/300")
2238
- * are Primitives.
2239
- */
2240
- private inferCollectionFromName(name: string, isAlias: boolean): string {
2241
- if (isAlias) return 'Semantics';
2242
- // Semantic tokens use dot notation in their Figma names (pushed via 054a)
2243
- // e.g. "color.primary", "color.feedback.success.text"
2244
- if (name.includes('.')) return 'Semantics';
2245
- // Primitive tokens use slash notation: "space/100", "color/purple/300"
2246
- return 'Primitives';
2247
- }
2248
-
2249
- /**
2250
- * Read Figma styles (effect and text) from a file via figma-console-mcp.
2251
- *
2252
- * Calls `consoleMcp.getStyles(fileKey)` which invokes `figma_get_styles`,
2253
- * then maps results to `FigmaStyle[]`. Effect styles represent shadows/blurs;
2254
- * text styles represent typography.
2255
- *
2256
- * @param fileKey - The Figma file key.
2257
- * @returns Array of FigmaStyle objects separated by type.
2258
- * @requirements Req 3 (Composite Token Reconstruction)
2259
- */
2260
- async readStyles(fileKey: string): Promise<FigmaStyle[]> {
2261
- const rawStyles = await this.consoleMcp.getStyles(fileKey);
2262
-
2263
- if (!rawStyles || rawStyles.length === 0) {
2264
- return [];
2265
- }
2266
-
2267
- return rawStyles.map((s) => ({
2268
- name: s.name,
2269
- type: s.type,
2270
- properties: s.properties,
2271
- }));
2272
- }
2273
-
2274
- // -------------------------------------------------------------------------
2275
- // queryContext (Task 3.5)
2276
- // -------------------------------------------------------------------------
2277
-
2278
- /**
2279
- * Determine the component family from a component name and query
2280
- * DesignerPunk MCP for family pattern and existing component status.
2281
- *
2282
- * Family extraction uses PascalCase heuristics:
2283
- * "ButtonCTA" → "Button"
2284
- * "InputTextBase" → "Input"
2285
- * "IconBase" → "Icon"
2286
- * "ContainerBase" → "Container"
2287
- *
2288
- * Delegates to VariantAnalyzer's `queryFamilyPattern()` and
2289
- * `queryExistingComponents()` for the actual MCP queries.
2290
- *
2291
- * @param componentName - The Figma component name (e.g. "ButtonCTA").
2292
- * @returns ExtractionContext with family pattern and existing components.
2293
- * @requirements Req 1 (DesignExtractor), Req 4 (Context-Aware Variant Mapping)
2294
- */
2295
- async queryContext(componentName: string): Promise<ExtractionContext> {
2296
- const familyName = this.extractFamilyName(componentName);
2297
-
2298
- const [familyPattern, existingComponents] = await Promise.all([
2299
- this.analyzer.queryFamilyPattern(familyName),
2300
- this.analyzer.queryExistingComponents(familyName),
2301
- ]);
2302
-
2303
- return { familyPattern, existingComponents };
2304
- }
2305
-
2306
- /**
2307
- * Extract the family name from a PascalCase component name.
2308
- *
2309
- * Splits on uppercase boundaries and returns the first segment.
2310
- * Handles common suffixes like "Base", "CTA", etc.
2311
- *
2312
- * Examples:
2313
- * "ButtonCTA" → "Button"
2314
- * "InputTextBase" → "Input"
2315
- * "IconBase" → "Icon"
2316
- * "container-base" → "Container" (kebab-case fallback)
2317
- * "Button" → "Button"
2318
- */
2319
- private extractFamilyName(componentName: string): string {
2320
- // Handle kebab-case (e.g. "button-cta", "input-text-base")
2321
- if (componentName.includes('-')) {
2322
- const first = componentName.split('-')[0];
2323
- return first.charAt(0).toUpperCase() + first.slice(1).toLowerCase();
2324
- }
2325
-
2326
- // PascalCase: split on uppercase boundaries
2327
- const segments = componentName.replace(/([a-z])([A-Z])/g, '$1 $2').split(' ');
2328
- return segments[0];
2329
- }
2330
-
2331
- // -------------------------------------------------------------------------
2332
- // translateTokens (Task 3.6)
2333
- // -------------------------------------------------------------------------
2334
-
2335
- /**
2336
- * Translate all component properties to DesignerPunk token references.
2337
- *
2338
- * Builds a binding lookup map from the token bindings, then iterates
2339
- * over the component's layout, color, typography, radius, and shadow
2340
- * properties. For each property, checks if a variable binding exists
2341
- * and delegates to `translator.translate()` with binding-first strategy.
2342
- *
2343
- * Tracks no-match values for pause reporting in the extraction confidence.
2344
- *
2345
- * @param component - The extracted Figma component with layout and raw data.
2346
- * @param bindings - Token bindings read from figma-console-mcp.
2347
- * @returns Aggregated TokenUsage with all translated references.
2348
- * @requirements Req 2 (TokenTranslator Implementation)
2349
- */
2350
- translateTokens(
2351
- component: ExtractedComponent,
2352
- bindings: TokenBinding[],
2353
- ): TokenUsage {
2354
- // Build binding lookup: variableName → TokenBinding
2355
- const bindingMap = new Map<string, TokenBinding>();
2356
- for (const binding of bindings) {
2357
- bindingMap.set(binding.variableName, binding);
2358
- }
2359
-
2360
- // Build variable ID → variable name lookup for resolving boundVariables
2361
- const nameById = new Map<string, string>();
2362
- for (const binding of bindings) {
2363
- if (binding.variableId) {
2364
- nameById.set(binding.variableId, binding.variableName);
2365
- }
2366
- }
2367
-
2368
- const usage: TokenUsage = {
2369
- spacing: [],
2370
- colors: [],
2371
- typography: [],
2372
- radius: [],
2373
- shadows: [],
2374
- };
2375
-
2376
- // --- Direct boundVariable translation (highest confidence path) ---
2377
- // When Console MCP provides boundVariables from component children,
2378
- // we can resolve variable IDs directly to token names without value scanning.
2379
- const bvMap = component.boundVariableMap;
2380
- // Track which layout properties were resolved via boundVariables so we
2381
- // can fall through to value-based matching for the rest.
2382
- const resolvedByBinding = new Set<string>();
2383
-
2384
- if (bvMap && bvMap.size > 0) {
2385
- // Mapping of Figma boundVariable property names to our categories
2386
- const spacingProps: Record<string, string> = {
2387
- paddingLeft: 'padding-left',
2388
- paddingRight: 'padding-right',
2389
- paddingTop: 'padding-top',
2390
- paddingBottom: 'padding-bottom',
2391
- itemSpacing: 'item-spacing',
2392
- };
2393
- const radiusProps: Record<string, string> = {
2394
- topLeftRadius: 'border-radius-top-left',
2395
- topRightRadius: 'border-radius-top-right',
2396
- bottomLeftRadius: 'border-radius-bottom-left',
2397
- bottomRightRadius: 'border-radius-bottom-right',
2398
- cornerRadius: 'border-radius',
2399
- };
2400
- const colorProps: Record<string, string> = {
2401
- color: 'fill',
2402
- };
2403
-
2404
- for (const [figmaProp, varId] of bvMap) {
2405
- const varName = nameById.get(varId);
2406
- if (!varName) continue; // Variable ID not found in bindings
2407
-
2408
- const cssProperty = spacingProps[figmaProp] ?? radiusProps[figmaProp] ?? colorProps[figmaProp];
2409
- if (!cssProperty) continue; // Unknown property — skip
2410
-
2411
- let category: TokenCategory;
2412
- if (spacingProps[figmaProp]) category = 'spacing';
2413
- else if (radiusProps[figmaProp]) category = 'radius';
2414
- else category = 'color';
2415
-
2416
- const result = this.translator.translate(varName, 0, category);
2417
-
2418
- const ref: TokenReference = {
2419
- property: cssProperty,
2420
- token: result.token,
2421
- confidence: result.confidence,
2422
- matchMethod: 'binding',
2423
- primitive: result.primitive,
2424
- semantic: result.semantic,
2425
- delta: result.delta,
2426
- rawValue: result.rawValue,
2427
- suggestion: result.suggestion,
2428
- };
2429
-
2430
- if (category === 'spacing') {
2431
- usage.spacing.push(ref);
2432
- resolvedByBinding.add(cssProperty);
2433
- } else if (category === 'radius') {
2434
- usage.radius.push(ref);
2435
- resolvedByBinding.add(cssProperty);
2436
- } else {
2437
- usage.colors.push(ref);
2438
- }
2439
- }
2440
- }
2441
-
2442
- // --- Layout-based spacing (fills gaps not covered by boundVariables) ---
2443
- // Always attempt layout-based translation for properties that weren't
2444
- // resolved via direct boundVariable binding above.
2445
- {
2446
- const layout = component.layout;
2447
-
2448
- if (layout.itemSpacing != null && !resolvedByBinding.has('item-spacing')) {
2449
- const ref = this.translateProperty(
2450
- 'item-spacing', layout.itemSpacing, 'spacing', bindingMap,
2451
- );
2452
- usage.spacing.push(ref);
2453
- }
2454
-
2455
- if (layout.padding) {
2456
- const sides: Array<[string, number | undefined]> = [
2457
- ['padding-top', layout.padding.top],
2458
- ['padding-right', layout.padding.right],
2459
- ['padding-bottom', layout.padding.bottom],
2460
- ['padding-left', layout.padding.left],
2461
- ];
2462
- for (const [prop, value] of sides) {
2463
- if (value != null && !resolvedByBinding.has(prop)) {
2464
- usage.spacing.push(
2465
- this.translateProperty(prop, value, 'spacing', bindingMap),
2466
- );
2467
- }
2468
- }
2469
- }
2470
-
2471
- // Corner radius from structured data (when not resolved via boundVariable)
2472
- if (component.cornerRadius != null && usage.radius.length === 0) {
2473
- usage.radius.push(
2474
- this.translateProperty('border-radius', component.cornerRadius, 'radius', bindingMap),
2475
- );
2476
- }
2477
- }
2478
-
2479
- // --- Fills from structured data (when no rawDesignContext) ---
2480
- if (component.fills && component.fills.length > 0 && !component.rawDesignContext) {
2481
- for (const fill of component.fills) {
2482
- if (fill.color) {
2483
- usage.colors.push(
2484
- this.translateProperty('fill', fill.color, 'color', bindingMap),
2485
- );
2486
- }
2487
- }
2488
- }
2489
-
2490
- // --- Parse raw design context for colors, typography, radius, shadows ---
2491
- const raw = component.rawDesignContext ?? '';
2492
-
2493
- // Colors: match CSS color properties
2494
- const colorPatterns = [
2495
- { pattern: /(?:background|background-color)\s*:\s*([^;}\n]+)/gi, prop: 'background' },
2496
- { pattern: /(?:^|[^-])color\s*:\s*([^;}\n]+)/gim, prop: 'color' },
2497
- { pattern: /border-color\s*:\s*([^;}\n]+)/gi, prop: 'border-color' },
2498
- { pattern: /fill\s*:\s*([^;}\n]+)/gi, prop: 'fill' },
2499
- { pattern: /stroke\s*:\s*([^;}\n]+)/gi, prop: 'stroke' },
2500
- ];
2501
- for (const { pattern, prop } of colorPatterns) {
2502
- let match: RegExpExecArray | null;
2503
- while ((match = pattern.exec(raw)) !== null) {
2504
- const value = match[1].trim();
2505
- if (this.isColorValue(value)) {
2506
- usage.colors.push(
2507
- this.translateProperty(prop, value, 'color', bindingMap),
2508
- );
2509
- }
2510
- }
2511
- }
2512
-
2513
- // Typography: font-size, font-family, font-weight, line-height
2514
- const typographyPatterns = [
2515
- { pattern: /font-size\s*:\s*([^;}\n]+)/gi, prop: 'font-size' },
2516
- { pattern: /font-weight\s*:\s*([^;}\n]+)/gi, prop: 'font-weight' },
2517
- { pattern: /line-height\s*:\s*([^;}\n]+)/gi, prop: 'line-height' },
2518
- ];
2519
- for (const { pattern, prop } of typographyPatterns) {
2520
- let match: RegExpExecArray | null;
2521
- while ((match = pattern.exec(raw)) !== null) {
2522
- const value = match[1].trim();
2523
- usage.typography.push(
2524
- this.translateProperty(prop, value, 'typography', bindingMap),
2525
- );
2526
- }
2527
- }
2528
-
2529
- // Radius: border-radius
2530
- const radiusPattern = /border-radius\s*:\s*([^;}\n]+)/gi;
2531
- let radiusMatch: RegExpExecArray | null;
2532
- while ((radiusMatch = radiusPattern.exec(raw)) !== null) {
2533
- const value = radiusMatch[1].trim();
2534
- usage.radius.push(
2535
- this.translateProperty('border-radius', value, 'radius', bindingMap),
2536
- );
2537
- }
2538
-
2539
- // Shadows: box-shadow
2540
- const shadowPattern = /box-shadow\s*:\s*([^;}\n]+)/gi;
2541
- let shadowMatch: RegExpExecArray | null;
2542
- while ((shadowMatch = shadowPattern.exec(raw)) !== null) {
2543
- const value = shadowMatch[1].trim();
2544
- usage.shadows.push(
2545
- this.translateProperty('box-shadow', value, 'shadow', bindingMap),
2546
- );
2547
- }
2548
-
2549
- return usage;
2550
- }
2551
-
2552
- /**
2553
- * Translate a single property value to a token reference.
2554
- *
2555
- * Checks the binding map for a variable whose resolved value matches
2556
- * the raw value, then delegates to `translator.translate()`.
2557
- */
2558
- private translateProperty(
2559
- property: string,
2560
- rawValue: number | string,
2561
- category: TokenCategory,
2562
- bindingMap: Map<string, TokenBinding>,
2563
- ): TokenReference {
2564
- // Try to find a binding whose value matches this raw value
2565
- const bindingName = this.findBindingForValue(rawValue, category, bindingMap);
2566
-
2567
- const result: TranslationResult = this.translator.translate(
2568
- bindingName, rawValue, category,
2569
- );
2570
-
2571
- return {
2572
- property,
2573
- token: result.token,
2574
- confidence: result.confidence,
2575
- matchMethod: result.matchMethod,
2576
- primitive: result.primitive,
2577
- semantic: result.semantic,
2578
- delta: result.delta,
2579
- rawValue: result.rawValue,
2580
- suggestion: result.suggestion,
2581
- };
2582
- }
2583
-
2584
- /**
2585
- * Find a binding variable name whose resolved value matches the given raw value.
2586
- *
2587
- * Searches the binding map for a variable of the matching type whose
2588
- * first mode value equals the raw value. Returns the variable name
2589
- * (for binding-first translation) or undefined if no binding found.
2590
- */
2591
- private findBindingForValue(
2592
- rawValue: number | string,
2593
- category: TokenCategory,
2594
- bindingMap: Map<string, TokenBinding>,
2595
- ): string | undefined {
2596
- const expectedType = category === 'color' ? 'COLOR' : 'FLOAT';
2597
-
2598
- for (const [name, binding] of bindingMap) {
2599
- if (binding.resolvedType !== expectedType) continue;
2600
-
2601
- // Check first mode value
2602
- const modeValues = Object.values(binding.valuesByMode);
2603
- if (modeValues.length === 0) continue;
2604
-
2605
- const firstValue = modeValues[0];
2606
-
2607
- // Skip alias objects — they don't carry resolved values
2608
- if (firstValue != null && typeof firstValue === 'object') continue;
2609
-
2610
- if (typeof rawValue === 'number' && firstValue === rawValue) {
2611
- return name;
2612
- }
2613
- if (String(rawValue) === String(firstValue)) {
2614
- return name;
2615
- }
2616
- }
2617
-
2618
- return undefined;
2619
- }
2620
-
2621
- /**
2622
- * Check if a CSS value looks like a color (hex, rgb, rgba, hsl, named).
2623
- */
2624
- /**
2625
- * Check if a CSS value looks like a color (hex, rgb, rgba, hsl, named).
2626
- */
2627
- private isColorValue(value: string): boolean {
2628
- const v = value.toLowerCase().trim();
2629
-
2630
- // Exclude CSS keywords and non-color values
2631
- const nonColorKeywords = new Set([
2632
- 'inherit', 'initial', 'unset', 'revert', 'none', 'transparent',
2633
- 'currentcolor', 'auto', 'normal',
2634
- ]);
2635
- if (nonColorKeywords.has(v)) return false;
2636
-
2637
- // Exclude url(), var() (non-color), calc(), etc.
2638
- if (v.startsWith('url(') || v.startsWith('calc(')) return false;
2639
-
2640
- return (
2641
- v.startsWith('#') ||
2642
- v.startsWith('rgb') ||
2643
- v.startsWith('hsl') ||
2644
- v.startsWith('var(--color')
2645
- );
2646
- }
2647
-
2648
- // -------------------------------------------------------------------------
2649
- // reconstructCompositeTokens (Task 3.7)
2650
- // -------------------------------------------------------------------------
2651
-
2652
- /**
2653
- * Reconstruct composite token references from Figma styles.
2654
- *
2655
- * Primary path: match style names directly to DTCG composite tokens
2656
- * (names match because 054a pushed them with known names).
2657
- *
2658
- * Fallback path: if style name doesn't match, attempt property-by-property
2659
- * reconstruction by searching the DTCG token tree for tokens whose
2660
- * composite sub-values match the style's raw properties.
2661
- *
2662
- * Unmatched composites are flagged with ⚠️ confidence for Ada's review.
2663
- *
2664
- * @param styles - Figma styles read via figma-console-mcp.
2665
- * @param dtcgTokens - The loaded DTCG token file for lookup.
2666
- * @returns TokenReference[] with matched composite tokens.
2667
- * @requirements Req 3 (Composite Token Reconstruction)
2668
- */
2669
- reconstructCompositeTokens(
2670
- styles: FigmaStyle[],
2671
- dtcgTokens: DTCGTokenFile,
2672
- ): TokenReference[] {
2673
- const results: TokenReference[] = [];
2674
-
2675
- for (const style of styles) {
2676
- const category = style.type === 'EFFECT' ? 'shadow' : 'typography';
2677
-
2678
- // Primary path: direct name match against DTCG token tree
2679
- const directMatch = this.lookupCompositeToken(style.name, category, dtcgTokens);
2680
- if (directMatch) {
2681
- results.push({
2682
- property: category,
2683
- token: directMatch.path,
2684
- confidence: 'exact',
2685
- matchMethod: 'binding',
2686
- primitive: directMatch.path,
2687
- });
2688
- continue;
2689
- }
2690
-
2691
- // Fallback path: property-by-property reconstruction
2692
- const reconstructed = this.reconstructFromProperties(style, category, dtcgTokens);
2693
- if (reconstructed) {
2694
- results.push(reconstructed);
2695
- continue;
2696
- }
2697
-
2698
- // No match — flag for Ada's review
2699
- results.push({
2700
- property: category,
2701
- token: '',
2702
- confidence: 'no-match',
2703
- matchMethod: 'value',
2704
- delta: `Unmatched ${category} style "${style.name}" — requires Ada review`,
2705
- });
2706
- }
2707
-
2708
- return results;
2709
- }
2710
-
2711
- /**
2712
- * Look up a composite token by name in the DTCG token tree.
2713
- *
2714
- * Tries multiple name resolution strategies:
2715
- * 1. Direct path: `{category}.{styleName}` (e.g. `shadow.elevation200`)
2716
- * 2. Full style name as path (e.g. `shadow.elevation200` already dot-separated)
2717
- * 3. Style name with dots converted from slashes
2718
- *
2719
- * @returns The token path and token object if found, or null.
2720
- */
2721
- private lookupCompositeToken(
2722
- styleName: string,
2723
- category: 'shadow' | 'typography',
2724
- dtcgTokens: DTCGTokenFile,
2725
- ): { path: string; token: object } | null {
2726
- // Strategy 1: style name already includes category prefix (e.g. "shadow.elevation200")
2727
- if (styleName.startsWith(`${category}.`)) {
2728
- const token = this.resolveTokenPath(styleName, dtcgTokens);
2729
- if (token) return { path: styleName, token };
2730
- }
2731
-
2732
- // Strategy 2: prepend category (e.g. "elevation200" → "shadow.elevation200")
2733
- const prefixedPath = `${category}.${styleName}`;
2734
- const prefixedToken = this.resolveTokenPath(prefixedPath, dtcgTokens);
2735
- if (prefixedToken) return { path: prefixedPath, token: prefixedToken };
2736
-
2737
- // Strategy 3: convert slashes to dots and try both with and without prefix
2738
- const dotName = styleName.replace(/\//g, '.');
2739
- if (dotName !== styleName) {
2740
- if (dotName.startsWith(`${category}.`)) {
2741
- const token = this.resolveTokenPath(dotName, dtcgTokens);
2742
- if (token) return { path: dotName, token };
2743
- }
2744
- const prefixedDot = `${category}.${dotName}`;
2745
- const token = this.resolveTokenPath(prefixedDot, dtcgTokens);
2746
- if (token) return { path: prefixedDot, token };
2747
- }
2748
-
2749
- return null;
2750
- }
2751
-
2752
- /**
2753
- * Resolve a dot-separated token path in the DTCG token tree.
2754
- *
2755
- * Walks the tree following each path segment and returns the node
2756
- * if it has a `$value` (i.e. is a token, not just a group).
2757
- */
2758
- private resolveTokenPath(
2759
- path: string,
2760
- dtcgTokens: DTCGTokenFile,
2761
- ): object | null {
2762
- const parts = path.split('.');
2763
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2764
- let current: any = dtcgTokens;
2765
-
2766
- for (const part of parts) {
2767
- if (current == null || typeof current !== 'object') return null;
2768
- current = current[part];
2769
- }
2770
-
2771
- if (current != null && typeof current === 'object' && '$value' in current) {
2772
- return current;
2773
- }
2774
-
2775
- return null;
2776
- }
2777
-
2778
- /**
2779
- * Attempt to reconstruct a composite token from raw style properties.
2780
- *
2781
- * For shadow styles: compares offsetX, offsetY, blur, spread, color
2782
- * against all shadow tokens in the DTCG tree.
2783
- *
2784
- * For typography styles: compares fontFamily, fontSize, fontWeight,
2785
- * lineHeight against all typography tokens in the DTCG tree.
2786
- *
2787
- * Returns an approximate-confidence match if a token's sub-values
2788
- * match the style properties, or null if no reconstruction possible.
2789
- */
2790
- private reconstructFromProperties(
2791
- style: FigmaStyle,
2792
- category: 'shadow' | 'typography',
2793
- dtcgTokens: DTCGTokenFile,
2794
- ): TokenReference | null {
2795
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2796
- const group = (dtcgTokens as any)[category];
2797
- if (!group || typeof group !== 'object') return null;
2798
-
2799
- const props = style.properties;
2800
- let bestMatch: { path: string; score: number } | null = null;
2801
-
2802
- for (const [key, entry] of Object.entries(group)) {
2803
- if (key.startsWith('$')) continue;
2804
- if (entry == null || typeof entry !== 'object' || !('$value' in entry)) continue;
2805
-
2806
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2807
- const tokenValue = (entry as any).$value;
2808
- if (tokenValue == null || typeof tokenValue !== 'object') continue;
2809
-
2810
- const score = category === 'shadow'
2811
- ? this.scoreShadowMatch(props, tokenValue)
2812
- : this.scoreTypographyMatch(props, tokenValue);
2813
-
2814
- if (score > 0 && (bestMatch === null || score > bestMatch.score)) {
2815
- bestMatch = { path: `${category}.${key}`, score };
2816
- }
2817
- }
2818
-
2819
- if (bestMatch) {
2820
- return {
2821
- property: category,
2822
- token: bestMatch.path,
2823
- confidence: 'approximate',
2824
- matchMethod: 'value',
2825
- primitive: bestMatch.path,
2826
- delta: `Reconstructed from properties (score: ${bestMatch.score}/4)`,
2827
- };
2828
- }
2829
-
2830
- return null;
2831
- }
2832
-
2833
- /**
2834
- * Score how well a Figma effect style's properties match a DTCG shadow token value.
2835
- *
2836
- * Compares offsetX, offsetY, blur, and spread. Each matching property
2837
- * adds 1 to the score (max 4). Returns 0 if no properties match.
2838
- */
2839
- private scoreShadowMatch(
2840
- styleProps: Record<string, unknown>,
2841
- tokenValue: Record<string, unknown>,
2842
- ): number {
2843
- let score = 0;
2844
- const fields = ['offsetX', 'offsetY', 'blur', 'spread'];
2845
-
2846
- for (const field of fields) {
2847
- const styleProp = styleProps[field];
2848
- const tokenProp = tokenValue[field];
2849
- if (styleProp == null || tokenProp == null) continue;
2850
- if (this.dimensionValuesMatch(styleProp, tokenProp)) score++;
2851
- }
2852
-
2853
- return score;
2854
- }
2855
-
2856
- /**
2857
- * Score how well a Figma text style's properties match a DTCG typography token value.
2858
- *
2859
- * Compares fontFamily, fontSize, fontWeight, and lineHeight. Each matching
2860
- * property adds 1 to the score (max 4). Returns 0 if no properties match.
2861
- */
2862
- private scoreTypographyMatch(
2863
- styleProps: Record<string, unknown>,
2864
- tokenValue: Record<string, unknown>,
2865
- ): number {
2866
- let score = 0;
2867
-
2868
- // fontFamily: string comparison
2869
- if (styleProps.fontFamily != null && tokenValue.fontFamily != null) {
2870
- if (String(styleProps.fontFamily) === String(tokenValue.fontFamily)) score++;
2871
- }
2872
-
2873
- // fontSize: dimension comparison
2874
- if (styleProps.fontSize != null && tokenValue.fontSize != null) {
2875
- if (this.dimensionValuesMatch(styleProps.fontSize, tokenValue.fontSize)) score++;
2876
- }
2877
-
2878
- // fontWeight: numeric comparison
2879
- if (styleProps.fontWeight != null && tokenValue.fontWeight != null) {
2880
- if (Number(styleProps.fontWeight) === Number(tokenValue.fontWeight)) score++;
2881
- }
2882
-
2883
- // lineHeight: numeric comparison (may be unitless ratio or px)
2884
- if (styleProps.lineHeight != null && tokenValue.lineHeight != null) {
2885
- if (this.dimensionValuesMatch(styleProps.lineHeight, tokenValue.lineHeight)) score++;
2886
- }
2887
-
2888
- return score;
2889
- }
2890
-
2891
- /**
2892
- * Compare two dimension values that may be numbers or strings with units.
2893
- *
2894
- * Handles: `24` vs `"24px"`, `"16px"` vs `"16px"`, `1.5` vs `1.5`.
2895
- */
2896
- private dimensionValuesMatch(a: unknown, b: unknown): boolean {
2897
- // Both numeric
2898
- const numA = typeof a === 'number' ? a : parseFloat(String(a));
2899
- const numB = typeof b === 'number' ? b : parseFloat(String(b));
2900
-
2901
- if (!isNaN(numA) && !isNaN(numB)) {
2902
- return numA === numB;
2903
- }
2904
-
2905
- // String comparison as fallback
2906
- return String(a) === String(b);
2907
- }
2908
-
2909
- // ---------------------------------------------------------------------------
2910
- // Behavioral contract detection (Task 3.8)
2911
- // ---------------------------------------------------------------------------
2912
-
2913
- /**
2914
- * Keywords that indicate an interactive component requiring behavioral contracts.
2915
- * Matched case-insensitively against the component name.
2916
- */
2917
- private static readonly INTERACTIVE_KEYWORDS = [
2918
- 'button', 'input', 'toggle', 'switch', 'checkbox', 'radio',
2919
- 'select', 'dropdown', 'slider', 'tab', 'link', 'menu',
2920
- 'dialog', 'modal', 'tooltip', 'popover', 'accordion',
2921
- ];
2922
-
2923
- /**
2924
- * Keywords that indicate a static (non-interactive) component.
2925
- * Matched case-insensitively against the component name.
2926
- */
2927
- private static readonly STATIC_KEYWORDS = [
2928
- 'badge', 'divider', 'icon', 'avatar', 'label', 'tag',
2929
- 'separator', 'spacer', 'image', 'logo', 'progress',
2930
- ];
2931
-
2932
- /**
2933
- * Classify a component as interactive or static based on keyword heuristics.
2934
- *
2935
- * Checks the component name against known interactive and static keywords.
2936
- * If both match (unlikely but possible), interactive takes precedence because
2937
- * missing behavioral contracts on an interactive component is a higher risk
2938
- * than unnecessary contracts on a static one.
2939
- *
2940
- * @param componentName - The Figma component name.
2941
- * @returns 'interactive' or 'static'.
2942
- */
2943
- private classifyComponent(componentName: string): 'interactive' | 'static' {
2944
- const lower = componentName.toLowerCase();
2945
-
2946
- const isInteractive = DesignExtractor.INTERACTIVE_KEYWORDS.some(
2947
- (kw) => lower.includes(kw),
2948
- );
2949
- if (isInteractive) return 'interactive';
2950
-
2951
- const isStatic = DesignExtractor.STATIC_KEYWORDS.some(
2952
- (kw) => lower.includes(kw),
2953
- );
2954
- if (isStatic) return 'static';
2955
-
2956
- // Default: treat unknown components as interactive (safer — forces review)
2957
- return 'interactive';
2958
- }
2959
-
2960
- /**
2961
- * Extract visual state names from a component's detected states.
2962
- *
2963
- * Filters for well-known interaction states: hover, focus, disabled, pressed,
2964
- * active, selected, error, loading.
2965
- */
2966
- private extractVisualStates(states: StateDefinition[]): string[] {
2967
- const knownStates = new Set([
2968
- 'hover', 'focus', 'disabled', 'pressed',
2969
- 'active', 'selected', 'error', 'loading',
2970
- 'long-press',
2971
- ]);
2972
- return states
2973
- .map((s) => s.name.toLowerCase())
2974
- .filter((name) => knownStates.has(name));
2975
- }
2976
-
2977
- /**
2978
- * Detect behavioral contract status for a component.
2979
- *
2980
- * Classifies the component as interactive or static using keyword heuristics,
2981
- * extracts visual states from the Figma component, and flags missing
2982
- * behavioral contracts for interactive components.
2983
- *
2984
- * For static components, auto-generates a "no interaction" contract.
2985
- *
2986
- * @param component - The extracted Figma component.
2987
- * @returns BehavioralContractStatus with classification, states, and confidence.
2988
- */
2989
- detectBehavioralContracts(component: ExtractedComponent): BehavioralContractStatus {
2990
- const classification = this.classifyComponent(component.name);
2991
- const detectedStates = this.extractVisualStates(component.states);
2992
-
2993
- if (classification === 'static') {
2994
- return {
2995
- classification: 'static',
2996
- detectedStates,
2997
- contractsDefined: true,
2998
- autoContract: 'No interaction — static display component',
2999
- confidence: '✅',
3000
- };
3001
- }
3002
-
3003
- // Interactive component: flag missing behavioral contracts
3004
- // Behavioral contracts are considered missing because Figma designs
3005
- // don't encode interaction behavior — only visual states.
3006
- // The actual contracts must be defined during spec review.
3007
- const hasStates = detectedStates.length > 0;
3008
-
3009
- return {
3010
- classification: 'interactive',
3011
- detectedStates,
3012
- contractsDefined: false,
3013
- confidence: '❌',
3014
- };
3015
- }
3016
-
3017
- // -------------------------------------------------------------------------
3018
- // detectPlatformParity (Task 3.9)
3019
- // -------------------------------------------------------------------------
3020
-
3021
- /**
3022
- * Detect platform-specific interactions and flag parity concerns.
3023
- *
3024
- * Applies heuristics to classify each detected visual state by platform
3025
- * support (hover = web-only, focus = all platforms, long-press = mobile).
3026
- * Optionally queries platform-implementation-guidelines.md via
3027
- * DesignerPunk MCP for cross-reference validation.
3028
- *
3029
- * Provides decision options for platform-specific interactions:
3030
- * omit on unsupported platform, map to alternative interaction, or
3031
- * defer to human review.
3032
- *
3033
- * @param component - The extracted Figma component.
3034
- * @returns PlatformParityCheck with interactions and concern status.
3035
- * @requirements Req 7 (Platform Parity Detection)
3036
- */
3037
- async detectPlatformParity(component: ExtractedComponent): Promise<PlatformParityCheck> {
3038
- const detectedStates = this.extractVisualStates(component.states);
3039
-
3040
- // Query platform guidelines for cross-reference (best-effort)
3041
- let guidelinesContent: string | null = null;
3042
- if (this.mcpDocs) {
3043
- try {
3044
- guidelinesContent = await this.mcpDocs.getSection(
3045
- 'governance/platform-implementation-guidelines.md',
3046
- 'State Management Consistency',
3047
- );
3048
- } catch {
3049
- // MCP unavailable — proceed with heuristics only
3050
- }
3051
- }
3052
-
3053
- const interactions: PlatformInteraction[] = [];
3054
-
3055
- for (const state of detectedStates) {
3056
- const platforms = DesignExtractor.PLATFORM_HEURISTICS[state];
3057
- if (!platforms) continue;
3058
-
3059
- const allPlatforms: ('web' | 'ios' | 'android')[] = ['web', 'ios', 'android'];
3060
- const missingPlatforms = allPlatforms.filter((p) => !platforms.includes(p));
3061
-
3062
- // Only flag interactions that are NOT available on all platforms
3063
- if (missingPlatforms.length === 0) continue;
3064
-
3065
- const recommendation = this.buildPlatformRecommendation(
3066
- state,
3067
- platforms,
3068
- missingPlatforms,
3069
- guidelinesContent,
3070
- );
3071
-
3072
- interactions.push({
3073
- interaction: state,
3074
- platforms,
3075
- recommendation,
3076
- });
3077
- }
3078
-
3079
- return {
3080
- interactions,
3081
- hasConcerns: interactions.length > 0,
3082
- };
3083
- }
3084
-
3085
- /**
3086
- * Build a recommendation string for a platform-specific interaction.
3087
- *
3088
- * Includes decision options for the human reviewer: omit on unsupported
3089
- * platforms, map to an alternative interaction, or provide a custom
3090
- * approach.
3091
- */
3092
- private buildPlatformRecommendation(
3093
- state: string,
3094
- supportedPlatforms: ('web' | 'ios' | 'android')[],
3095
- missingPlatforms: ('web' | 'ios' | 'android')[],
3096
- guidelinesContent: string | null,
3097
- ): string {
3098
- const supported = supportedPlatforms.join(', ');
3099
- const missing = missingPlatforms.join(', ');
3100
-
3101
- // State-specific recommendations
3102
- if (state === 'hover') {
3103
- return (
3104
- `"${state}" is ${supported}-only (not available on ${missing}). ` +
3105
- 'Decision options: (a) omit hover feedback on mobile, ' +
3106
- '(b) map to press/active state on mobile, ' +
3107
- '(c) provide alternative visual feedback.' +
3108
- (guidelinesContent ? ' Cross-referenced with platform-implementation-guidelines.md.' : '')
3109
- );
3110
- }
3111
-
3112
- if (state === 'long-press') {
3113
- return (
3114
- `"${state}" is ${supported}-only (not available on ${missing}). ` +
3115
- 'Decision options: (a) omit on web, ' +
3116
- '(b) map to right-click/context menu on web, ' +
3117
- '(c) provide alternative trigger.' +
3118
- (guidelinesContent ? ' Cross-referenced with platform-implementation-guidelines.md.' : '')
3119
- );
3120
- }
3121
-
3122
- // Generic recommendation for other platform-limited states
3123
- return (
3124
- `"${state}" is available on ${supported} but not on ${missing}. ` +
3125
- `Decision options: (a) omit on ${missing}, ` +
3126
- '(b) map to equivalent interaction, ' +
3127
- '(c) defer to human review.' +
3128
- (guidelinesContent ? ' Cross-referenced with platform-implementation-guidelines.md.' : '')
3129
- );
3130
- }
3131
-
3132
-
3133
- // -------------------------------------------------------------------------
3134
- // detectComponentTokenDecisions (Task 3.10)
3135
- // -------------------------------------------------------------------------
3136
-
3137
- /**
3138
- * Detect repeated primitive token usage and surface component token
3139
- * decision points for Ada's review.
3140
- *
3141
- * Scans all token categories in the usage map, groups references by
3142
- * their resolved primitive token, and generates illustrative component
3143
- * token suggestions for any primitive used two or more times.
3144
- *
3145
- * All suggestions are explicitly labeled as pending human review —
3146
- * no autonomous token creation per governance.
3147
- *
3148
- * @param tokenUsage - Aggregated token usage from translateTokens().
3149
- * @param componentName - Component name for illustrative naming.
3150
- * @returns Array of decision points for Ada's review.
3151
- */
3152
- detectComponentTokenDecisions(
3153
- tokenUsage: TokenUsage,
3154
- componentName: string = 'component',
3155
- ): ComponentTokenDecision[] {
3156
- // Build a map of primitiveToken → list of property locations
3157
- const usageMap = new Map<string, string[]>();
3158
-
3159
- const categories: Array<[keyof TokenUsage, string]> = [
3160
- ['spacing', 'spacing'],
3161
- ['colors', 'color'],
3162
- ['typography', 'typography'],
3163
- ['radius', 'radius'],
3164
- ['shadows', 'shadow'],
3165
- ];
3166
-
3167
- for (const [category] of categories) {
3168
- const refs = tokenUsage[category];
3169
- for (const ref of refs) {
3170
- // Only consider matched tokens (not no-match)
3171
- if (ref.confidence === 'no-match') continue;
3172
-
3173
- // Use the primitive token if available, otherwise the main token
3174
- const primitiveKey = ref.primitive ?? ref.token;
3175
- if (!primitiveKey) continue;
3176
-
3177
- const location = ref.property;
3178
- const existing = usageMap.get(primitiveKey) ?? [];
3179
- existing.push(location);
3180
- usageMap.set(primitiveKey, existing);
3181
- }
3182
- }
3183
-
3184
- // Generate decisions for tokens used 2+ times
3185
- const decisions: ComponentTokenDecision[] = [];
3186
- const baseName = this.extractComponentBaseName(componentName);
3187
-
3188
- for (const [primitiveToken, locations] of usageMap) {
3189
- if (locations.length < 2) continue;
3190
-
3191
- const propertyGroup = this.inferPropertyGroup(locations);
3192
- const suggestion = `${baseName}.${propertyGroup} = ${primitiveToken}`;
3193
-
3194
- decisions.push({
3195
- primitiveToken,
3196
- usageCount: locations.length,
3197
- locations,
3198
- illustrativeSuggestion: suggestion,
3199
- rationale:
3200
- `${primitiveToken} is used across ${locations.length} properties ` +
3201
- `(${locations.join(', ')}). Consistent usage suggests semantic ` +
3202
- `intent that could be encoded as a component token.`,
3203
- });
3204
- }
3205
-
3206
- // Sort by usage count descending for prioritized review
3207
- decisions.sort((a, b) => b.usageCount - a.usageCount);
3208
-
3209
- return decisions;
3210
- }
3211
-
3212
- /**
3213
- * Extract a short base name from a component name for illustrative
3214
- * token naming.
3215
- *
3216
- * "ButtonCTA" → "button", "InputTextBase" → "input", "ContainerBase" → "container"
3217
- */
3218
- private extractComponentBaseName(componentName: string): string {
3219
- // Split PascalCase into words, take the first word, lowercase it
3220
- const words = componentName.replace(/([a-z])([A-Z])/g, '$1 $2').split(/[\s_-]+/);
3221
- return (words[0] ?? 'component').toLowerCase();
3222
- }
3223
-
3224
- /**
3225
- * Infer a property group name from a list of CSS property locations.
3226
- *
3227
- * Groups related properties into semantic names:
3228
- * - padding-left, padding-right → "padding.horizontal"
3229
- * - padding-top, padding-bottom → "padding.vertical"
3230
- * - mixed padding → "padding"
3231
- * - color, fill, background → "fill"
3232
- * - border-radius → "radius"
3233
- * - Otherwise uses the first property name.
3234
- */
3235
- private inferPropertyGroup(locations: string[]): string {
3236
- const normalized = locations.map(l => l.toLowerCase());
3237
-
3238
- // Check for padding patterns
3239
- const hasPaddingLeft = normalized.some(l => l.includes('padding-left') || l.includes('padding-inline-start'));
3240
- const hasPaddingRight = normalized.some(l => l.includes('padding-right') || l.includes('padding-inline-end'));
3241
- const hasPaddingTop = normalized.some(l => l.includes('padding-top') || l.includes('padding-block-start'));
3242
- const hasPaddingBottom = normalized.some(l => l.includes('padding-bottom') || l.includes('padding-block-end'));
3243
- const allPadding = normalized.every(l => l.includes('padding'));
3244
-
3245
- if (allPadding) {
3246
- if ((hasPaddingLeft || hasPaddingRight) && !hasPaddingTop && !hasPaddingBottom) {
3247
- return 'padding.horizontal';
3248
- }
3249
- if ((hasPaddingTop || hasPaddingBottom) && !hasPaddingLeft && !hasPaddingRight) {
3250
- return 'padding.vertical';
3251
- }
3252
- return 'padding';
3253
- }
3254
-
3255
- // Check for spacing patterns (item-spacing, gap, margin)
3256
- if (normalized.every(l => l.includes('spacing') || l.includes('gap') || l.includes('margin'))) {
3257
- return 'spacing';
3258
- }
3259
-
3260
- // Check for color patterns
3261
- if (normalized.every(l =>
3262
- l.includes('color') || l.includes('fill') || l.includes('background') || l.includes('stroke'),
3263
- )) {
3264
- return 'fill';
3265
- }
3266
-
3267
- // Check for radius
3268
- if (normalized.every(l => l.includes('radius'))) {
3269
- return 'radius';
3270
- }
3271
-
3272
- // Check for shadow
3273
- if (normalized.every(l => l.includes('shadow'))) {
3274
- return 'shadow';
3275
- }
3276
-
3277
- // Check for typography
3278
- if (normalized.every(l =>
3279
- l.includes('font') || l.includes('line-height') || l.includes('letter-spacing'),
3280
- )) {
3281
- return 'typography';
3282
- }
3283
-
3284
- // Fallback: use the first property, cleaned up
3285
- return normalized[0]?.replace(/[^a-z0-9.]/g, '-') ?? 'token';
3286
- }
3287
-
3288
- /**
3289
- * Validate mode consistency across token bindings.
3290
- *
3291
- * For each binding with multiple mode values, checks whether light and
3292
- * dark mode values are identical. Discrepancies are categorized:
3293
- *
3294
- * - **expected**: Color tokens differ by mode (light/dark theme variations).
3295
- * - **unexpected**: Spacing, radius, or typography tokens differ by mode
3296
- * (structural tokens should be mode-agnostic).
3297
- *
3298
- * @param bindings - Token bindings read from Figma.
3299
- * @returns ModeValidationResult with discrepancies and a flag for unexpected ones.
3300
- * @requirements Req 9 (Mode Consistency Validation)
3301
- */
3302
- validateModes(bindings: TokenBinding[]): ModeValidationResult {
3303
- const discrepancies: ModeDiscrepancy[] = [];
3304
-
3305
- for (const binding of bindings) {
3306
- const modeEntries = Object.entries(binding.valuesByMode);
3307
-
3308
- // Need at least two modes to compare
3309
- if (modeEntries.length < 2) continue;
3310
-
3311
- // Identify light and dark mode entries by key name heuristic
3312
- const lightKey = modeEntries.find(([k]) => /light/i.test(k));
3313
- const darkKey = modeEntries.find(([k]) => /dark/i.test(k));
3314
-
3315
- // If we can't identify light/dark by name, compare first two modes
3316
- const [modeA, modeB] = lightKey && darkKey
3317
- ? [lightKey, darkKey]
3318
- : [modeEntries[0], modeEntries[1]];
3319
-
3320
- const valueA = modeA[1];
3321
- const valueB = modeB[1];
3322
-
3323
- // Skip alias objects — they reference other variables, not resolved values
3324
- if (this.isAliasValue(valueA) || this.isAliasValue(valueB)) continue;
3325
-
3326
- // Compare values — use JSON.stringify for deep equality of objects
3327
- if (this.modeValuesEqual(valueA, valueB)) continue;
3328
-
3329
- // Values differ — categorize the discrepancy
3330
- const category = binding.resolvedType === 'COLOR' ? 'expected' : 'unexpected';
3331
-
3332
- discrepancies.push({
3333
- variableName: binding.variableName,
3334
- lightValue: valueA,
3335
- darkValue: valueB,
3336
- category,
3337
- });
3338
- }
3339
-
3340
- return {
3341
- discrepancies,
3342
- hasUnexpectedDiscrepancies: discrepancies.some(d => d.category === 'unexpected'),
3343
- };
3344
- }
3345
-
3346
- /**
3347
- * Resolve variable IDs from boundVariableMap that aren't in the bindings.
3348
- *
3349
- * When `figma_get_token_values` (limit: 500) doesn't return all variables,
3350
- * some boundVariable IDs from the component tree won't resolve in the
3351
- * `nameById` lookup during `translateTokens`. This method uses
3352
- * `figma_execute` with Plugin API to batch-resolve those missing IDs,
3353
- * returning synthetic TokenBinding entries that can be appended to the
3354
- * bindings array.
3355
- *
3356
- * @param fileKey - The Figma file key.
3357
- * @param boundVariableMap - Property→variableId map from component extraction.
3358
- * @param existingBindings - Bindings already loaded from figma_get_token_values.
3359
- * @returns Additional TokenBinding entries for previously unresolved IDs.
3360
- */
3361
- async resolveUnknownVariableIds(
3362
- fileKey: string,
3363
- boundVariableMap: Map<string, string>,
3364
- existingBindings: TokenBinding[],
3365
- ): Promise<TokenBinding[]> {
3366
- if (!boundVariableMap || boundVariableMap.size === 0) return [];
3367
-
3368
- // Build set of known variable IDs
3369
- const knownIds = new Set<string>();
3370
- for (const binding of existingBindings) {
3371
- if (binding.variableId) knownIds.add(binding.variableId);
3372
- }
3373
-
3374
- // Collect unresolved IDs (deduplicated)
3375
- const unresolvedIds = new Set<string>();
3376
- for (const varId of boundVariableMap.values()) {
3377
- if (!knownIds.has(varId)) unresolvedIds.add(varId);
3378
- }
3379
-
3380
- if (unresolvedIds.size === 0) return [];
3381
-
3382
- // Batch-resolve via Plugin API
3383
- const idsArray = [...unresolvedIds];
3384
- const code = `
3385
- const results = {};
3386
- for (const id of ${JSON.stringify(idsArray)}) {
3387
- try {
3388
- const v = figma.variables.getVariableById(id);
3389
- if (v) {
3390
- results[id] = {
3391
- name: v.name,
3392
- resolvedType: v.resolvedType,
3393
- id: v.id,
3394
- };
3395
- }
3396
- } catch (e) {
3397
- // Variable not found — skip
3398
- }
3399
- }
3400
- return results;
3401
- `.trim();
3402
-
3403
- try {
3404
- const result = await this.consoleMcp.execute(fileKey, code);
3405
-
3406
- // Parse the result — may be wrapped in various formats
3407
- let resolved: Record<string, { name: string; resolvedType: string; id: string }> = {};
3408
- if (result && typeof result === 'object') {
3409
- // Handle { result: { ... } } wrapper from figma_execute
3410
- const raw = result as Record<string, unknown>;
3411
- const inner = raw.result ?? raw;
3412
- if (inner && typeof inner === 'object') {
3413
- resolved = inner as typeof resolved;
3414
- }
3415
- }
3416
-
3417
- const additionalBindings: TokenBinding[] = [];
3418
- for (const [varId, info] of Object.entries(resolved)) {
3419
- if (!info?.name) continue;
3420
- additionalBindings.push({
3421
- variableName: info.name,
3422
- variableId: varId,
3423
- collectionName: this.inferCollectionFromName(info.name, false),
3424
- resolvedType: (info.resolvedType ?? 'FLOAT') as TokenBinding['resolvedType'],
3425
- valuesByMode: {},
3426
- isAlias: false,
3427
- });
3428
- }
3429
-
3430
- return additionalBindings;
3431
- } catch {
3432
- // Plugin API resolution failed — return empty (value-based fallback still works)
3433
- return [];
3434
- }
3435
- }
3436
-
3437
-
3438
-
3439
- /**
3440
- * Check whether a mode value is an alias reference (not a resolved value).
3441
- */
3442
- private isAliasValue(value: unknown): boolean {
3443
- return (
3444
- value != null &&
3445
- typeof value === 'object' &&
3446
- 'aliasOf' in (value as Record<string, unknown>)
3447
- );
3448
- }
3449
-
3450
- /**
3451
- * Compare two mode values for equality.
3452
- *
3453
- * Handles primitives (number, string) directly and falls back to
3454
- * JSON.stringify for object values (e.g. color objects).
3455
- */
3456
- private modeValuesEqual(a: unknown, b: unknown): boolean {
3457
- if (a === b) return true;
3458
- if (typeof a !== typeof b) return false;
3459
- if (typeof a === 'object' && a !== null && b !== null) {
3460
- return JSON.stringify(a) === JSON.stringify(b);
3461
- }
3462
- return false;
3463
- }
3464
-
3465
-
3466
- /**
3467
- * Extract a Figma component and produce a ComponentAnalysis.
3468
- *
3469
- * Orchestrates: read component → build node tree → collect/resolve
3470
- * bound variables → reclassify → detect composition patterns →
3471
- * capture screenshot → gather recommendations.
3472
- */
3473
- async extractComponentAnalysis(
3474
- fileKey: string,
3475
- nodeId: string,
3476
- outputDir: string,
3477
- fileUrl?: string,
3478
- ): Promise<ComponentAnalysis> {
3479
- // 1. Read component structure, token bindings, and styles in parallel
3480
- const [component, bindings, styles] = await Promise.all([
3481
- this.readFigmaComponent(fileKey, nodeId),
3482
- this.readTokenBindings(fileKey),
3483
- this.readStyles(fileKey),
3484
- ]);
3485
-
3486
- // 2. Resolve unknown variable IDs
3487
- if (component.boundVariableMap && component.boundVariableMap.size > 0) {
3488
- const additional = await this.resolveUnknownVariableIds(
3489
- fileKey, component.boundVariableMap, bindings,
3490
- );
3491
- if (additional.length > 0) bindings.push(...additional);
3492
- }
3493
-
3494
- // 3. Get raw component data for node tree building
3495
- const rawComponent = await this.consoleMcp.getComponent(fileKey, nodeId);
3496
-
3497
- // 4. Build hierarchical node tree with per-node classification
3498
- const nodeTree = this.buildNodeTree(rawComponent as Record<string, unknown>);
3499
-
3500
- // 5. Collect and resolve bound variable IDs
3501
- const boundEntries = this.collectBoundVariableIds(rawComponent as Record<string, unknown>);
3502
- const { resolved, unresolvedBindings } = await this.batchResolveBoundVariables(fileKey, boundEntries);
3503
-
3504
- // 6. Reclassify unidentified values using resolved bindings
3505
- this.reclassifyWithResolvedBindings(nodeTree, resolved);
3506
-
3507
- // 7. Aggregate classification counts
3508
- const classificationSummary = this.aggregateClassifications(nodeTree);
3509
-
3510
- // 8. Detect composition patterns
3511
- const compositionPatterns = this.detectCompositionPatterns(nodeTree);
3512
-
3513
- // 9. Capture screenshots (variants for COMPONENT_SET, single for others)
3514
- const screenshots: ScreenshotMetadata[] = [];
3515
- const screenshotUrl = fileUrl ?? `https://www.figma.com/design/${fileKey}`;
3516
- if (nodeTree.type === 'COMPONENT_SET' && nodeTree.children.length > 0) {
3517
- for (const child of nodeTree.children) {
3518
- const shot = await this.captureComponentScreenshot(
3519
- screenshotUrl, child.id, outputDir, component.name, child.name,
3520
- );
3521
- if (shot) screenshots.push(shot);
3522
- }
3523
- } else {
3524
- const shot = await this.captureComponentScreenshot(
3525
- screenshotUrl, nodeId, outputDir, component.name,
3526
- );
3527
- if (shot) screenshots.push(shot);
3528
- }
3529
-
3530
- // 10. Gather recommendations (reuse existing methods)
3531
- const tokenUsage = this.translateTokens(component, bindings);
3532
- const compositeTokens = this.reconstructCompositeTokens(styles, this.translator.getDtcgTokens());
3533
- for (const ref of compositeTokens) {
3534
- if (ref.property === 'shadow') tokenUsage.shadows.push(ref);
3535
- else if (ref.property === 'typography') tokenUsage.typography.push(ref);
3536
- }
3537
- const context = await this.queryContext(component.name);
3538
- const analyzerComponent = {
3539
- name: component.name,
3540
- description: component.description,
3541
- variants: component.variants.map(v => ({ name: v.name, properties: v.properties })),
3542
- states: component.states.map(s => s.name),
3543
- };
3544
- const variantMapping = await this.analyzer.analyzeVariants(analyzerComponent, context);
3545
- const componentTokens = this.detectComponentTokenDecisions(tokenUsage, component.name);
3546
- const modeValidation = this.validateModes(bindings);
3547
- const platformParity = await this.detectPlatformParity(component);
3548
-
3549
- // 11. Build variant definitions from raw response
3550
- const variantDefinitions = this.buildVariantDefinitions(rawComponent);
3551
-
3552
- // 12. Determine component type
3553
- const componentType = this.resolveComponentType(rawComponent);
3554
-
3555
- return {
3556
- componentName: component.name,
3557
- componentType,
3558
- figmaId: nodeId,
3559
- fileKey,
3560
- variantDefinitions: Object.keys(variantDefinitions).length > 0 ? variantDefinitions : undefined,
3561
- nodeTree,
3562
- classificationSummary,
3563
- compositionPatterns,
3564
- unresolvedBindings,
3565
- recommendations: {
3566
- variantMapping: variantMapping.recommendations.length > 0 || variantMapping.conflicts.length > 0 ? variantMapping : undefined,
3567
- componentTokens: componentTokens.length > 0 ? componentTokens : undefined,
3568
- modeValidation: modeValidation.hasUnexpectedDiscrepancies ? modeValidation : undefined,
3569
- platformParity: platformParity.hasConcerns ? platformParity : undefined,
3570
- },
3571
- screenshots,
3572
- extractedAt: new Date().toISOString(),
3573
- extractorVersion: '6.3.0',
3574
- };
3575
- }
3576
-
3577
- /** Aggregate classification counts across all nodes in a tree. */
3578
- private aggregateClassifications(node: NodeWithClassifications): {
3579
- semanticIdentified: number;
3580
- primitiveIdentified: number;
3581
- unidentified: number;
3582
- } {
3583
- let semantic = node.tokenClassifications.semanticIdentified.length;
3584
- let primitive = node.tokenClassifications.primitiveIdentified.length;
3585
- let unidentified = node.tokenClassifications.unidentified.length;
3586
- for (const child of node.children) {
3587
- const c = this.aggregateClassifications(child);
3588
- semantic += c.semanticIdentified;
3589
- primitive += c.primitiveIdentified;
3590
- unidentified += c.unidentified;
3591
- }
3592
- return { semanticIdentified: semantic, primitiveIdentified: primitive, unidentified };
3593
- }
3594
-
3595
- /** Build variantDefinitions from raw Figma component response. */
3596
- private buildVariantDefinitions(raw: Record<string, unknown>): Record<string, {
3597
- type: 'VARIANT' | 'BOOLEAN' | 'TEXT' | 'INSTANCE_SWAP';
3598
- defaultValue: unknown;
3599
- variantOptions?: string[];
3600
- }> {
3601
- const defs: Record<string, { type: 'VARIANT' | 'BOOLEAN' | 'TEXT' | 'INSTANCE_SWAP'; defaultValue: unknown; variantOptions?: string[] }> = {};
3602
- const vp = raw.variantProperties as Record<string, string[]> | undefined;
3603
- if (vp) {
3604
- for (const [name, options] of Object.entries(vp)) {
3605
- defs[name] = { type: 'VARIANT', defaultValue: options[0] ?? '', variantOptions: options };
3606
- }
3607
- }
3608
- return defs;
3609
- }
3610
-
3611
- /** Resolve component type from raw Figma response. */
3612
- private resolveComponentType(raw: Record<string, unknown>): 'COMPONENT_SET' | 'COMPONENT' | 'INSTANCE' {
3613
- const t = raw.type as string | undefined;
3614
- if (t === 'COMPONENT_SET' || t === 'COMPONENT' || t === 'INSTANCE') return t;
3615
- // If it has variantProperties, it's a COMPONENT_SET
3616
- if (raw.variantProperties) return 'COMPONENT_SET';
3617
- return 'COMPONENT';
3618
- }
3619
-
3620
- }