@astryxdesign/cli 0.1.7 → 0.1.8-canary.07362a9

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 (389) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +115 -19
  3. package/{src/api → api/blog}/blog.mjs +42 -6
  4. package/{src/api → api/blog}/blog.test.mjs +2 -2
  5. package/api/build/build.mjs +92 -0
  6. package/api/build/build.test.mjs +92 -0
  7. package/{src/api → api/component}/component.mjs +49 -26
  8. package/{src/api → api/discover}/discover.mjs +55 -18
  9. package/{src/api → api/docs}/docs.mjs +47 -21
  10. package/{src/api → api/doctor}/doctor.mjs +13 -10
  11. package/{src/api → api}/error.mjs +2 -2
  12. package/{src/api → api/hook}/hook.mjs +11 -11
  13. package/{src/api → api}/index.mjs +16 -9
  14. package/{src/api → api/integration}/validate-integration.mjs +48 -15
  15. package/{src/api → api/integration}/validate-integration.test.mjs +1 -1
  16. package/{src/api → api/layout}/layout.mjs +66 -17
  17. package/{src/api → api/layout}/layout.test.mjs +1 -1
  18. package/{src/api → api/search}/search.mjs +71 -12
  19. package/api/swizzle/swizzle.mjs +283 -0
  20. package/{src/commands → api/swizzle}/swizzle.test.mjs +26 -1
  21. package/{src/api → api/template}/template-integration.test.mjs +2 -2
  22. package/{src/api → api/template}/template-suffix.test.mjs +3 -3
  23. package/{src/api → api/template}/template.mjs +96 -19
  24. package/{src/api → api/theme}/theme-add.mjs +35 -7
  25. package/{src → authoring}/codemod.mjs +6 -6
  26. package/{src → authoring}/config.test.mjs +1 -1
  27. package/{src → authoring}/doc.mjs +1 -1
  28. package/{src → authoring}/doc.test.mjs +1 -1
  29. package/{src → authoring}/template.mjs +1 -1
  30. package/bin/astryx.mjs +12 -10
  31. package/{src → cli}/commands/blog.mjs +48 -7
  32. package/{src → cli}/commands/build-theme.mjs +133 -115
  33. package/cli/commands/build.mjs +172 -0
  34. package/cli/commands/cli-postinstall.test.mjs +42 -0
  35. package/{src → cli}/commands/component/index.mjs +52 -25
  36. package/{src → cli}/commands/component-ownership.test.mjs +3 -3
  37. package/{src → cli}/commands/component-package.test.mjs +1 -1
  38. package/{src → cli}/commands/component-resolution.test.mjs +2 -2
  39. package/{src → cli}/commands/discover.mjs +23 -12
  40. package/{src → cli}/commands/docs.mjs +42 -10
  41. package/{src → cli}/commands/docs.test.mjs +1 -1
  42. package/{src → cli}/commands/doctor.mjs +3 -3
  43. package/{src → cli}/commands/doctor.test.mjs +2 -2
  44. package/{src → cli}/commands/ensure-core-built.mjs +3 -2
  45. package/{src → cli}/commands/external-showcase.test.mjs +1 -1
  46. package/{src → cli}/commands/hook/index.mjs +40 -17
  47. package/{src → cli}/commands/import-hint-correctness.test.mjs +1 -1
  48. package/cli/commands/init.mjs +195 -0
  49. package/{src → cli}/commands/init.next-steps.test.mjs +1 -1
  50. package/cli/commands/interactive-guard.test.mjs +66 -0
  51. package/{src → cli}/commands/json-contract.test.mjs +2 -2
  52. package/{src → cli}/commands/layout.mjs +59 -19
  53. package/{src → cli}/commands/search.mjs +22 -15
  54. package/{src → cli}/commands/search.test.mjs +1 -1
  55. package/cli/commands/setup-nudge.test.mjs +108 -0
  56. package/cli/commands/swizzle.mjs +103 -0
  57. package/{src → cli}/commands/template.mjs +84 -53
  58. package/{src → cli}/commands/template.path-safety.test.mjs +2 -2
  59. package/{src → cli}/commands/upgrade.integration-policy.test.mjs +1 -1
  60. package/{src → cli}/commands/upgrade.mjs +291 -77
  61. package/cli/commands/upgrade.test.mjs +314 -0
  62. package/{src → cli}/commands/validate-integration.mjs +17 -37
  63. package/{src → cli}/index.mjs +55 -19
  64. package/{src/codemods → codemods}/__tests__/registry.test.mjs +1 -0
  65. package/{src/codemods → codemods}/ensure-jscodeshift.mjs +12 -28
  66. package/{src/codemods → codemods}/integration-discovery.mjs +6 -3
  67. package/{src/codemods → codemods}/integration-discovery.test.mjs +1 -1
  68. package/{src/codemods → codemods}/integration-runner.mjs +8 -3
  69. package/{src/codemods → codemods}/registry.mjs +4 -1
  70. package/{src/codemods → codemods}/run-codemod.mjs +18 -11
  71. package/{src/codemods → codemods}/runner.mjs +24 -14
  72. package/{src/codemods → codemods}/transforms/v0.0.10/remove-size-props.mjs +9 -4
  73. package/{src/codemods → codemods}/transforms/v0.0.12/add-is-icon-only.mjs +27 -22
  74. package/{src/codemods → codemods}/transforms/v0.0.13/icon-name-deprecations.mjs +12 -5
  75. package/{src/codemods → codemods}/transforms/v0.0.13/rename-attachments-to-drawer.mjs +15 -8
  76. package/{src/codemods → codemods}/transforms/v0.0.13/toolbar-density-to-size.mjs +10 -4
  77. package/{src/codemods → codemods}/transforms/v0.0.14/rename-action-props.mjs +11 -5
  78. package/{src/codemods → codemods}/transforms/v0.0.14/rename-section-wash-to-muted.mjs +11 -6
  79. package/{src/codemods → codemods}/transforms/v0.0.14/rename-status-variants.mjs +15 -10
  80. package/{src/codemods → codemods}/transforms/v0.0.15/migrate-item-children-to-endcontent.mjs +13 -8
  81. package/{src/codemods → codemods}/transforms/v0.0.15/migrate-selector-children-to-render-option.mjs +18 -13
  82. package/{src/codemods → codemods}/transforms/v0.0.15/migrate-theme-selectors-to-data-attrs.mjs +8 -4
  83. package/{src/codemods → codemods}/transforms/v0.0.15/rename-date-picker-to-input.mjs +11 -6
  84. package/{src/codemods → codemods}/transforms/v0.0.15/rename-imperative-ref-to-handleRef.mjs +6 -1
  85. package/{src/codemods → codemods}/transforms/v0.0.15/rename-isStreaming-to-isStopShown.mjs +6 -1
  86. package/{src/codemods → codemods}/transforms/v0.0.15/rename-stack-element-to-as.mjs +8 -3
  87. package/{src/codemods → codemods}/transforms/v0.0.2/migrate-badge-dot-to-statusdot.mjs +17 -10
  88. package/{src/codemods → codemods}/transforms/v0.0.2/migrate-gap-to-numeric.mjs +7 -1
  89. package/{src/codemods → codemods}/transforms/v0.0.2/migrate-isFullBleed-to-padding.mjs +9 -4
  90. package/{src/codemods → codemods}/transforms/v0.0.2/migrate-useXDSIcon-to-getIcon.mjs +12 -7
  91. package/{src/codemods → codemods}/transforms/v0.0.2/rename-banner-endButton-to-endContent.mjs +7 -2
  92. package/{src/codemods → codemods}/transforms/v0.0.2/rename-form-tooltip-startIcon.mjs +8 -2
  93. package/{src/codemods → codemods}/transforms/v0.0.2/rename-isShown-to-isOpen.mjs +7 -2
  94. package/{src/codemods → codemods}/transforms/v0.0.2/rename-selector-items-to-options.mjs +7 -2
  95. package/{src/codemods → codemods}/transforms/v0.0.2/rename-sidenav-header-to-heading.mjs +11 -4
  96. package/{src/codemods → codemods}/transforms/v0.0.2/rename-topnav-title-to-heading.mjs +10 -4
  97. package/{src/codemods → codemods}/transforms/v0.0.2/unify-uncontrolled-to-defaultX.mjs +7 -2
  98. package/{src/codemods → codemods}/transforms/v0.0.2/unify-visibility-to-onOpenChange.mjs +10 -5
  99. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-badge-children-to-label.mjs +7 -2
  100. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-collapse-to-collapsible.mjs +9 -3
  101. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-radius-tokens.mjs +11 -5
  102. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-shadow-tokens.mjs +13 -6
  103. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-skeleton-radius.mjs +7 -1
  104. package/{src/codemods → codemods}/transforms/v0.0.6/migrate-token-names.mjs +11 -5
  105. package/{src/codemods → codemods}/transforms/v0.0.7/rename-banner-variant-to-container.mjs +8 -3
  106. package/{src/codemods → codemods}/transforms/v0.0.8/migrate-token-renames.mjs +15 -8
  107. package/{src/codemods → codemods}/transforms/v0.0.8/rename-endslot-to-endcontent.mjs +7 -2
  108. package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/drop-xds-prefix-imports.test.mjs +42 -7
  109. package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-module-specifiers.test.mjs +43 -0
  110. package/{src/codemods → codemods}/transforms/v0.1.0/drop-xds-prefix-imports.mjs +117 -13
  111. package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-css-surfaces.mjs +21 -17
  112. package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-declare-module.mjs +7 -2
  113. package/{src/codemods → codemods}/transforms/v0.1.0/migrate-xds-module-specifiers.mjs +86 -15
  114. package/{src/codemods → codemods}/transforms/v0.1.2/rename-text-color-active-to-accent.mjs +15 -9
  115. package/{src/codemods → codemods}/transforms/v0.1.3/migrate-layout-components-to-experimental.mjs +17 -12
  116. package/{src/codemods → codemods}/transforms/v0.1.5/rename-switch-label-spacing-default-to-hug.mjs +15 -9
  117. package/{src/codemods → codemods}/transforms/v0.1.7/migrate-table-tableprops-to-direct-props.mjs +17 -10
  118. package/{src/codemods → codemods}/transforms/v0.1.7/rename-table-renderprops-styles-to-xstyle.mjs +18 -13
  119. package/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +161 -0
  120. package/codemods/transforms/v0.1.8/index.mjs +19 -0
  121. package/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +239 -0
  122. package/docs/cli-integrations.doc.mjs +150 -0
  123. package/docs/elevation.doc.mjs +79 -1
  124. package/docs/getting-started.doc.mjs +9 -9
  125. package/docs/internationalization.doc.mjs +92 -46
  126. package/docs/migration.doc.mjs +18 -18
  127. package/docs/principles.doc.dense.mjs +1 -1
  128. package/docs/principles.doc.mjs +6 -6
  129. package/docs/principles.doc.zh.mjs +1 -1
  130. package/docs/styling-libraries.doc.mjs +3 -3
  131. package/docs/styling.doc.mjs +4 -4
  132. package/docs/theme.doc.dense.mjs +2 -2
  133. package/docs/theme.doc.mjs +7 -7
  134. package/docs/theme.doc.zh.mjs +1 -1
  135. package/docs/tokens.doc.mjs +1 -1
  136. package/docs/working-with-ai.doc.mjs +19 -19
  137. package/{src/commands → lib/agent-docs}/agent-docs.mjs +164 -29
  138. package/{src/commands → lib/agent-docs}/agent-docs.path-safety.test.mjs +1 -1
  139. package/{src/commands → lib/agent-docs}/agent-docs.test.mjs +123 -10
  140. package/{src/lib → lib}/cli-error.mjs +2 -2
  141. package/{src/lib → lib}/component-discovery.mjs +44 -2
  142. package/{src/lib → lib}/component-format.mjs +67 -25
  143. package/{src/lib → lib}/component-loader.mjs +27 -13
  144. package/{src/lib → lib}/componentDocOverlay.test.mjs +0 -1
  145. package/{src/lib → lib}/error-codes.test.mjs +1 -1
  146. package/{src/lib → lib}/hook-discovery.mjs +14 -1
  147. package/{src/lib → lib}/hook-format.mjs +29 -5
  148. package/{src/lib → lib}/integration-warnings.mjs +2 -2
  149. package/{src/lib → lib}/integrations.mjs +20 -0
  150. package/{src/lib → lib}/integrations.test.mjs +1 -1
  151. package/{src/lib → lib}/json-contract.test.mjs +1 -1
  152. package/{src/lib → lib}/json-shim.mjs +11 -6
  153. package/{src/lib → lib}/json-shim.test.mjs +1 -1
  154. package/{src/lib → lib}/json.mjs +3 -3
  155. package/{src/lib → lib}/levenshtein.mjs +6 -0
  156. package/{src/lib → lib}/manifest.mjs +7 -5
  157. package/{src/lib → lib}/manifest.test.mjs +2 -2
  158. package/{src/lib → lib}/module-loader.mjs +1 -0
  159. package/{src/lib → lib}/package-scanner.mjs +47 -0
  160. package/{src/lib → lib}/project.mjs +48 -18
  161. package/{src/lib → lib}/project.test.mjs +1 -1
  162. package/{src/lib → lib}/resolve-theme.mjs +5 -0
  163. package/{src/lib → lib}/string-utils.mjs +15 -0
  164. package/lib/term-log.mjs +57 -0
  165. package/{src/lib → lib}/xle/browser.mjs +18 -8
  166. package/{src/lib → lib}/xle/expand.mjs +155 -22
  167. package/{src/lib → lib}/xle/parse.mjs +119 -13
  168. package/{src/lib → lib}/xle/print.mjs +54 -14
  169. package/{src/lib → lib}/xle/registry-core.mjs +28 -3
  170. package/{src/lib → lib}/xle/registry.mjs +9 -4
  171. package/{src/lib → lib}/xle/splice.mjs +13 -2
  172. package/{src/lib → lib}/xle/validate.mjs +95 -14
  173. package/lib/xle/xle-ast.d.ts +214 -0
  174. package/package.json +37 -28
  175. package/scripts/postinstall.mjs +74 -0
  176. package/templates/blocks/components/Avatar/AvatarFallbackChain.tsx +4 -4
  177. package/templates/blocks/components/Avatar/AvatarGroup.tsx +2 -2
  178. package/templates/blocks/components/Avatar/AvatarInitialsFallback.tsx +1 -1
  179. package/templates/blocks/components/Avatar/AvatarShowcase.tsx +5 -5
  180. package/templates/blocks/components/Avatar/AvatarUserCard.tsx +1 -1
  181. package/templates/blocks/components/Avatar/AvatarWithImage.tsx +4 -4
  182. package/templates/blocks/components/Avatar/AvatarWithStatus.tsx +3 -3
  183. package/templates/blocks/components/AvatarGroup/AvatarGroupShowcase.tsx +2 -2
  184. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowCustomText.tsx +1 -1
  185. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowDefault.tsx +1 -1
  186. package/templates/blocks/components/AvatarGroupOverflow/AvatarGroupOverflowShowcase.tsx +2 -2
  187. package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotShowcase.tsx +3 -3
  188. package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotVariants.tsx +3 -3
  189. package/templates/blocks/components/Banner/BannerFloating.doc.mjs +14 -0
  190. package/templates/blocks/components/Banner/BannerFloating.tsx +16 -0
  191. package/templates/blocks/components/Button/ButtonFloating.doc.mjs +14 -0
  192. package/templates/blocks/components/Button/ButtonFloating.tsx +37 -0
  193. package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.doc.mjs +14 -0
  194. package/templates/blocks/components/ButtonGroup/ButtonGroupFloating.tsx +23 -0
  195. package/templates/blocks/components/Card/CardElevations.doc.mjs +14 -0
  196. package/templates/blocks/components/Card/CardElevations.tsx +32 -0
  197. package/templates/blocks/components/Card/ClickableCardElevated.doc.mjs +14 -0
  198. package/templates/blocks/components/Card/ClickableCardElevated.tsx +21 -0
  199. package/templates/blocks/components/Card/SelectableCardElevated.doc.mjs +14 -0
  200. package/templates/blocks/components/Card/SelectableCardElevated.tsx +37 -0
  201. package/templates/blocks/components/Carousel/CarouselSnap.tsx +1 -1
  202. package/templates/blocks/components/ChatComposer/ChatComposerFlat.doc.mjs +14 -0
  203. package/templates/blocks/components/ChatComposer/ChatComposerFlat.tsx +75 -0
  204. package/templates/blocks/components/ChatMessage/ChatMessageAvatarName.tsx +2 -2
  205. package/templates/blocks/components/ChatMessage/ChatMessageMultiBubble.tsx +1 -1
  206. package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleGrouping.tsx +1 -1
  207. package/templates/blocks/components/ChatMessageBubble/ChatMessageBubbleMetadata.tsx +1 -1
  208. package/templates/blocks/components/ChatMessageList/ChatMessageListDensity.tsx +5 -9
  209. package/templates/blocks/components/ChatMessageList/ChatMessageListFullFeatured.tsx +1 -1
  210. package/templates/blocks/components/CodeBlock/CodeBlockTerminal.tsx +1 -1
  211. package/templates/blocks/components/HoverCard/HoverCardShowcase.tsx +1 -1
  212. package/templates/blocks/components/IconButton/IconButtonFloating.doc.mjs +14 -0
  213. package/templates/blocks/components/IconButton/IconButtonFloating.tsx +37 -0
  214. package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.doc.mjs +19 -0
  215. package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +46 -0
  216. package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider02Overrides.doc.mjs +14 -0
  217. package/templates/blocks/components/InternationalizationProvider/InternationalizationProvider02Overrides.tsx +33 -0
  218. package/templates/blocks/components/Item/ItemWithMedia.tsx +2 -2
  219. package/templates/blocks/components/ListItem/ListItemWithMedia.tsx +2 -2
  220. package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.doc.mjs +14 -0
  221. package/templates/blocks/components/OverflowList/OverflowListCappedToolbar.tsx +39 -0
  222. package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.doc.mjs +14 -0
  223. package/templates/blocks/components/OverflowList/OverflowListMultiRowTags.tsx +44 -0
  224. package/templates/blocks/components/Pagination/PaginationDotsCarousel.tsx +2 -6
  225. package/templates/blocks/components/Stack/StackFillItem.tsx +2 -6
  226. package/templates/blocks/components/TabList/TabListTabsWithActions.doc.mjs +1 -1
  227. package/templates/blocks/components/TabList/TabListTabsWithActions.tsx +2 -7
  228. package/templates/blocks/components/Table/TableRowStatusTable.doc.mjs +14 -0
  229. package/templates/blocks/components/Table/TableRowStatusTable.tsx +59 -0
  230. package/templates/blocks/components/Thumbnail/ThumbnailDisabled.tsx +6 -1
  231. package/templates/blocks/components/Thumbnail/ThumbnailGallery.tsx +1 -0
  232. package/templates/blocks/components/Thumbnail/ThumbnailRemovable.tsx +1 -0
  233. package/templates/blocks/components/TypeaheadItem/TypeaheadItemShowcase.tsx +1 -1
  234. package/templates/pages/ai-chat/page.tsx +4 -4
  235. package/templates/pages/dashboard-portfolio/page.tsx +3 -11
  236. package/templates/pages/detail-page/page.tsx +5 -12
  237. package/templates/pages/documentation-design/page.tsx +1 -1
  238. package/templates/pages/messaging-shell/page.tsx +6 -8
  239. package/templates/pages/table-grouped/page.tsx +9 -14
  240. package/templates/pages/table-page/page.tsx +7 -9
  241. package/templates/pages/table-page-heatmap-status/page.tsx +5 -13
  242. package/{src/types → types}/api.contract.assert.ts +17 -8
  243. package/{src/types → types}/api.d.ts +110 -9
  244. package/{src/types → types}/base.d.ts +40 -4
  245. package/types/build.d.ts +53 -0
  246. package/types/codemod.d.ts +166 -0
  247. package/{src/types → types}/component.d.ts +1 -1
  248. package/{src/types → types}/discover.d.ts +1 -1
  249. package/{src/types → types}/docs.d.ts +1 -4
  250. package/{src/types → types}/hook.d.ts +1 -1
  251. package/{src/types → types}/index.d.ts +1 -0
  252. package/types/jscodeshift.d.ts +19 -0
  253. package/types/layout.d.ts +74 -0
  254. package/{src/types → types}/swizzle.d.ts +4 -0
  255. package/{src/types → types}/template-api.d.ts +4 -1
  256. package/types/theme.d.ts +53 -0
  257. package/types/upgrade.d.ts +108 -0
  258. package/utils/package-manager.mjs +178 -0
  259. package/utils/package-manager.test.mjs +220 -0
  260. package/{src/utils → utils}/path-safety.mjs +0 -18
  261. package/{src/utils → utils}/paths.mjs +4 -1
  262. package/{src/utils → utils}/update-check.mjs +5 -4
  263. package/{src/utils → utils}/update-check.test.mjs +3 -3
  264. package/docs/integration-authoring.md +0 -105
  265. package/src/commands/build.mjs +0 -196
  266. package/src/commands/init.mjs +0 -288
  267. package/src/commands/interactive-guard.test.mjs +0 -69
  268. package/src/commands/swizzle.mjs +0 -440
  269. package/src/commands/upgrade.test.mjs +0 -160
  270. package/src/types/codemod.d.ts +0 -81
  271. package/src/types/theme.d.ts +0 -23
  272. package/src/types/upgrade.d.ts +0 -64
  273. package/src/utils/interactive.mjs +0 -76
  274. package/src/utils/interactive.test.mjs +0 -70
  275. package/src/utils/package-manager.mjs +0 -74
  276. package/src/utils/package-manager.test.mjs +0 -113
  277. /package/{src/api → api/docs}/docOverlays.test.mjs +0 -0
  278. /package/{src/api → api/integration}/integration-block-exports.test.mjs +0 -0
  279. /package/{src/api → api/template}/template.test.mjs +0 -0
  280. /package/{src → authoring}/codemod.test.mjs +0 -0
  281. /package/{src → authoring}/config.mjs +0 -0
  282. /package/{src → authoring}/integration.mjs +0 -0
  283. /package/{src → authoring}/template.test.mjs +0 -0
  284. /package/{src → cli}/cli-exit-codes.test.mjs +0 -0
  285. /package/{src → cli}/commands/build-theme.color-scheme.test.mjs +0 -0
  286. /package/{src → cli}/commands/build-theme.import-path.test.mjs +0 -0
  287. /package/{src → cli}/commands/build-theme.path-safety.test.mjs +0 -0
  288. /package/{src → cli}/commands/build-theme.prose.test.mjs +0 -0
  289. /package/{src → cli}/commands/build-theme.variants.test.mjs +0 -0
  290. /package/{src → cli}/commands/build-theme.watch.test.mjs +0 -0
  291. /package/{src → cli}/commands/component.test.mjs +0 -0
  292. /package/{src → cli}/commands/detail-levels.test.mjs +0 -0
  293. /package/{src → cli}/commands/swizzle.path-safety.test.mjs +0 -0
  294. /package/{src → cli}/commands/swizzle.routing.test.mjs +0 -0
  295. /package/{src → cli}/commands/template.test.mjs +0 -0
  296. /package/{src → cli}/commands/upgrade.config-ordering.test.mjs +0 -0
  297. /package/{src → cli}/commands/validate-integration.test.mjs +0 -0
  298. /package/{src → cli}/update-hint-commands.test.mjs +0 -0
  299. /package/{src/codemods → codemods}/__tests__/rename-imperative-ref-to-handleRef.test.mjs +0 -0
  300. /package/{src/codemods → codemods}/__tests__/rename-isStreaming-to-isStopShown.test.mjs +0 -0
  301. /package/{src/codemods → codemods}/__tests__/rename-section-wash-to-muted.test.mjs +0 -0
  302. /package/{src/codemods → codemods}/__tests__/runner.test.mjs +0 -0
  303. /package/{src/codemods → codemods}/__tests__/toolbar-density-to-size.test.mjs +0 -0
  304. /package/{src/codemods → codemods}/__tests__/validation.test.mjs +0 -0
  305. /package/{src/codemods → codemods}/transforms/v0.0.10/__tests__/remove-size-props.test.mjs +0 -0
  306. /package/{src/codemods → codemods}/transforms/v0.0.10/index.mjs +0 -0
  307. /package/{src/codemods → codemods}/transforms/v0.0.12/__tests__/add-is-icon-only.test.mjs +0 -0
  308. /package/{src/codemods → codemods}/transforms/v0.0.12/index.mjs +0 -0
  309. /package/{src/codemods → codemods}/transforms/v0.0.13/__tests__/icon-name-deprecations.test.mjs +0 -0
  310. /package/{src/codemods → codemods}/transforms/v0.0.13/__tests__/rename-attachments-to-drawer.test.mjs +0 -0
  311. /package/{src/codemods → codemods}/transforms/v0.0.13/index.mjs +0 -0
  312. /package/{src/codemods → codemods}/transforms/v0.0.14/__tests__/rename-action-props.test.mjs +0 -0
  313. /package/{src/codemods → codemods}/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +0 -0
  314. /package/{src/codemods → codemods}/transforms/v0.0.14/index.mjs +0 -0
  315. /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-item-children-to-endcontent.test.mjs +0 -0
  316. /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-selector-children-to-render-option.test.mjs +0 -0
  317. /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/migrate-theme-selectors-to-data-attrs.test.mjs +0 -0
  318. /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/rename-date-picker-to-input.test.mjs +0 -0
  319. /package/{src/codemods → codemods}/transforms/v0.0.15/__tests__/rename-stack-element-to-as.test.mjs +0 -0
  320. /package/{src/codemods → codemods}/transforms/v0.0.15/index.mjs +0 -0
  321. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-badge-dot-to-statusdot.test.mjs +0 -0
  322. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-gap-to-numeric.test.mjs +0 -0
  323. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-isFullBleed-to-padding.test.mjs +0 -0
  324. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/migrate-useXDSIcon-to-getIcon.test.mjs +0 -0
  325. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-banner-endButton-to-endContent.test.mjs +0 -0
  326. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-form-tooltip-startIcon.test.mjs +0 -0
  327. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-isShown-to-isOpen.test.mjs +0 -0
  328. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-selector-items-to-options.test.mjs +0 -0
  329. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-sidenav-header-to-heading.test.mjs +0 -0
  330. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/rename-topnav-title-to-heading.test.mjs +0 -0
  331. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/unify-uncontrolled-to-defaultX.test.mjs +0 -0
  332. /package/{src/codemods → codemods}/transforms/v0.0.2/__tests__/unify-visibility-to-onOpenChange.test.mjs +0 -0
  333. /package/{src/codemods → codemods}/transforms/v0.0.2/index.mjs +0 -0
  334. /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-collapse-to-collapsible.test.mjs +0 -0
  335. /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-radius-tokens.test.mjs +0 -0
  336. /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-shadow-tokens.test.mjs +0 -0
  337. /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-skeleton-radius.test.mjs +0 -0
  338. /package/{src/codemods → codemods}/transforms/v0.0.6/__tests__/migrate-token-names.test.mjs +0 -0
  339. /package/{src/codemods → codemods}/transforms/v0.0.6/index.mjs +0 -0
  340. /package/{src/codemods → codemods}/transforms/v0.0.7/__tests__/rename-banner-variant-to-container.test.mjs +0 -0
  341. /package/{src/codemods → codemods}/transforms/v0.0.7/index.mjs +0 -0
  342. /package/{src/codemods → codemods}/transforms/v0.0.8/__tests__/migrate-token-renames.test.mjs +0 -0
  343. /package/{src/codemods → codemods}/transforms/v0.0.8/__tests__/rename-endslot-to-endcontent.test.mjs +0 -0
  344. /package/{src/codemods → codemods}/transforms/v0.0.8/index.mjs +0 -0
  345. /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-css-surfaces.test.mjs +0 -0
  346. /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/migrate-xds-declare-module.test.mjs +0 -0
  347. /package/{src/codemods → codemods}/transforms/v0.1.0/__tests__/v0.1.0-ordering.test.mjs +0 -0
  348. /package/{src/codemods → codemods}/transforms/v0.1.0/index.mjs +0 -0
  349. /package/{src/codemods → codemods}/transforms/v0.1.2/__tests__/rename-text-color-active-to-accent.test.mjs +0 -0
  350. /package/{src/codemods → codemods}/transforms/v0.1.2/index.mjs +0 -0
  351. /package/{src/codemods → codemods}/transforms/v0.1.3/__tests__/migrate-layout-components-to-experimental.test.mjs +0 -0
  352. /package/{src/codemods → codemods}/transforms/v0.1.3/index.mjs +0 -0
  353. /package/{src/codemods → codemods}/transforms/v0.1.5/__tests__/rename-switch-label-spacing-default-to-hug.test.mjs +0 -0
  354. /package/{src/codemods → codemods}/transforms/v0.1.5/index.mjs +0 -0
  355. /package/{src/codemods → codemods}/transforms/v0.1.7/__tests__/migrate-table-tableprops-to-direct-props.test.mjs +0 -0
  356. /package/{src/codemods → codemods}/transforms/v0.1.7/__tests__/rename-table-renderprops-styles-to-xstyle.test.mjs +0 -0
  357. /package/{src/codemods → codemods}/transforms/v0.1.7/index.mjs +0 -0
  358. /package/{src/lib → lib}/cli-error.test.mjs +0 -0
  359. /package/{src/lib → lib}/component-discovery.importpath.test.mjs +0 -0
  360. /package/{src/lib → lib}/component-format.test.mjs +0 -0
  361. /package/{src/lib → lib}/component-loader.test.mjs +0 -0
  362. /package/{src/lib → lib}/config-cache.mjs +0 -0
  363. /package/{src/lib → lib}/config-cache.test.mjs +0 -0
  364. /package/{src/lib → lib}/config-schema.mjs +0 -0
  365. /package/{src/lib → lib}/error-codes.mjs +0 -0
  366. /package/{src/lib → lib}/integration-warnings.test.mjs +0 -0
  367. /package/{src/lib → lib}/module-loader.test.mjs +0 -0
  368. /package/{src/lib → lib}/node-version.mjs +0 -0
  369. /package/{src/lib → lib}/node-version.test.mjs +0 -0
  370. /package/{src/lib → lib}/parse.mjs +0 -0
  371. /package/{src/lib → lib}/site.mjs +0 -0
  372. /package/{src/lib → lib}/xle/browser.d.ts +0 -0
  373. /package/{src/lib → lib}/xle/xle.test.mjs +0 -0
  374. /package/{src/schemas → schemas}/doc-schema.mjs +0 -0
  375. /package/{src/schemas → schemas}/template-schema.mjs +0 -0
  376. /package/{src/types → types}/config.d.ts +0 -0
  377. /package/{src/types → types}/doc.d.ts +0 -0
  378. /package/{src/types → types}/doctor.d.ts +0 -0
  379. /package/{src/types → types}/error-codes.d.ts +0 -0
  380. /package/{src/types → types}/integration.d.ts +0 -0
  381. /package/{src/types → types}/manifest.d.ts +0 -0
  382. /package/{src/types → types}/search.d.ts +0 -0
  383. /package/{src/types → types}/template.d.ts +0 -0
  384. /package/{src/types → types}/validate-integration.d.ts +0 -0
  385. /package/{src/utils → utils}/github.mjs +0 -0
  386. /package/{src/utils → utils}/path-safety.test.mjs +0 -0
  387. /package/{src/utils → utils}/paths.test.mjs +0 -0
  388. /package/{src/utils → utils}/semver.mjs +0 -0
  389. /package/{src/utils → utils}/semver.test.mjs +0 -0
@@ -0,0 +1,57 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Minimal non-interactive terminal logger.
5
+ *
6
+ * @input message strings from CLI commands/codemods
7
+ * @output plain lines on stdout via humanLog (suppressed in --json mode)
8
+ * @position src/lib — shared output helper, no side effects on import
9
+ *
10
+ * The CLI is fully non-interactive: it never prompts, so it only needs plain,
11
+ * unbuffered output. This provides the *output-only* surface (`log.*`, `intro`,
12
+ * `outro`) the CLI needs, so it has no dependency on any prompt library.
13
+ *
14
+ * All output is routed through `humanLog`, the CLI's stdout-discipline
15
+ * primitive, which is a no-op in `--json` mode — so these human logs can never
16
+ * corrupt a JSON envelope.
17
+ *
18
+ * Call sites use it as `import * as p from './term-log.mjs'` and call
19
+ * `p.log.info(...)`, `p.intro(...)`, `p.outro(...)`.
20
+ */
21
+
22
+ import {humanLog} from './json.mjs';
23
+
24
+ /** @param {unknown} msg */
25
+ const toStr = (msg) => (msg === undefined || msg === null ? '' : String(msg));
26
+
27
+ /**
28
+ * Human-facing log surface (the small `log` API the CLI uses). All lines go to
29
+ * stdout via humanLog; the level prefixes are cosmetic. `--json` mode suppresses
30
+ * every one of these, keeping machine-readable stdout clean.
31
+ */
32
+ export const log = {
33
+ /** @param {unknown} msg */
34
+ message: (msg) => humanLog(toStr(msg)),
35
+ /** @param {unknown} msg */
36
+ info: (msg) => humanLog(toStr(msg)),
37
+ /** @param {unknown} msg */
38
+ step: (msg) => humanLog(toStr(msg)),
39
+ /** @param {unknown} msg */
40
+ success: (msg) => humanLog(`✓ ${toStr(msg)}`),
41
+ /** @param {unknown} msg */
42
+ warn: (msg) => humanLog(`⚠ ${toStr(msg)}`),
43
+ /** @param {unknown} msg */
44
+ error: (msg) => humanLog(`✗ ${toStr(msg)}`),
45
+ };
46
+
47
+ /** Banner printed at the start of a multi-step command.
48
+ * @param {unknown} title */
49
+ export function intro(title) {
50
+ humanLog(`\n${toStr(title)}`);
51
+ }
52
+
53
+ /** Footer printed at the end of a multi-step command.
54
+ * @param {unknown} message */
55
+ export function outro(message) {
56
+ humanLog(`${toStr(message)}\n`);
57
+ }
@@ -23,11 +23,21 @@ import {hydrateRegistry} from './registry-core.mjs';
23
23
  export {parse, detectForm, XLEParseError, validate, expand, toCompact, toOutline};
24
24
  export {hydrateRegistry, serializeRegistry, ALIAS_TABLE, resolveComponent, SPACING_STEPS} from './registry-core.mjs';
25
25
 
26
- /** Accept either a hydrated registry (Map fields) or serialized JSON. */
26
+ /**
27
+ * Accept either a hydrated registry (Map fields) or serialized JSON.
28
+ * @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry
29
+ * @returns {import('./xle-ast').Registry}
30
+ */
27
31
  function asRegistry(registry) {
28
- return registry && registry.components instanceof Map ? registry : hydrateRegistry(registry);
32
+ return registry && /** @type {any} */ (registry).components instanceof Map
33
+ ? /** @type {import('./xle-ast').Registry} */ (registry)
34
+ : hydrateRegistry(/** @type {import('./browser').SerializedRegistry} */ (registry));
29
35
  }
30
36
 
37
+ /**
38
+ * @param {import('./xle-ast').RawIssue | {message: string, line?: number, col?: number}} issue
39
+ * @returns {string}
40
+ */
31
41
  function formatIssue(issue) {
32
42
  const where = issue.line != null ? `line ${issue.line}: ` : '';
33
43
  return `${where}${issue.message}`;
@@ -38,12 +48,12 @@ function formatIssue(issue) {
38
48
  * twin of `layout check`. Never throws on invalid input; returns the errors.
39
49
  *
40
50
  * @param {string} expression
41
- * @param {object} registry - serialized or hydrated
51
+ * @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry - serialized or hydrated
42
52
  * @param {object} [opts]
43
- * @param {Array} [opts.blocks] - block list for {hint} resolution (default [])
53
+ * @param {import('./browser').XLEBlock[]} [opts.blocks] - block list for {hint} resolution (default [])
44
54
  * @param {'compact'|'outline'|'auto'} [opts.form]
45
55
  * @param {boolean} [opts.loose]
46
- * @returns {{ok: boolean, valid?: boolean, form?: string, errors: Array, warnings: string[], compact?: string, outline?: string, parseError?: object}}
56
+ * @returns {import('./browser').CheckResult}
47
57
  */
48
58
  export function checkExpression(expression, registry, opts = {}) {
49
59
  const {blocks = [], form = 'auto', loose = false} = opts;
@@ -79,13 +89,13 @@ export function checkExpression(expression, registry, opts = {}) {
79
89
  * Returns either {code, ...} or {errors} (never writes files).
80
90
  *
81
91
  * @param {string} expression
82
- * @param {object} registry
92
+ * @param {import('./xle-ast').Registry | import('./browser').SerializedRegistry | object} registry
83
93
  * @param {object} [opts]
84
- * @param {Array} [opts.blocks]
94
+ * @param {import('./browser').XLEBlock[]} [opts.blocks]
85
95
  * @param {'compact'|'outline'|'auto'} [opts.form]
86
96
  * @param {boolean} [opts.loose]
87
97
  * @param {string} [opts.name] - generated component name (PascalCase)
88
- * @param {Map} [opts.blockModules] - prepared block sources/imports for splicing;
98
+ * @param {Map<string, import('./xle-ast').BlockModule>} [opts.blockModules] - prepared block sources/imports for splicing;
89
99
  * omit in the browser (hints stay as TODO markers without sources)
90
100
  */
91
101
  export function expandExpression(expression, registry, opts = {}) {
@@ -21,24 +21,31 @@ import {mergeImports, renderImport, prepareSpliceModule} from './splice.mjs';
21
21
 
22
22
  const INDENT = ' ';
23
23
 
24
+ /** @param {string | null | undefined} text */
24
25
  function slugify(text) {
25
26
  return String(text).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
26
27
  }
27
28
 
29
+ /** @param {string} text */
28
30
  function camelCase(text) {
29
31
  const parts = slugify(text).split('-').filter(Boolean);
30
32
  if (parts.length === 0) return 'item';
31
33
  return parts[0] + parts.slice(1).map(p => p[0].toUpperCase() + p.slice(1)).join('');
32
34
  }
33
35
 
36
+ /** @param {import('./xle-ast').XLEValue} value */
34
37
  function escapeAttr(value) {
35
38
  return String(value).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
36
39
  }
37
40
 
41
+ /**
42
+ * @param {import('./xle-ast').XLEItem} item
43
+ * @returns {import('./xle-ast').XLEItem}
44
+ */
38
45
  function cloneItem(item) {
39
46
  // .bound holds a registry reference (Map props) — rebuild it after the
40
47
  // JSON round-trip of the plain AST fields.
41
- const {bound, ...rest} = item;
48
+ const {bound, ...rest} = /** @type {import('./xle-ast').XLENode} */ (item);
42
49
  const copy = JSON.parse(JSON.stringify(rest, (key, value) => {
43
50
  if (key === 'bound') return undefined;
44
51
  return value;
@@ -58,16 +65,25 @@ function cloneItem(item) {
58
65
  /**
59
66
  * Substitute Emmet-style `$` counters in payloads and string props.
60
67
  * `\$` escapes a literal dollar sign (prices etc.).
68
+ * @param {string} text
69
+ * @param {number} index
61
70
  */
62
71
  function subCounterText(text, index) {
63
72
  return text.replace(/\\\$|\$/g, m => (m === '\\$' ? '$' : String(index)));
64
73
  }
65
74
 
66
- /** Strip `\$` escapes when a node is NOT repeated (single emission). */
75
+ /**
76
+ * Strip `\$` escapes when a node is NOT repeated (single emission).
77
+ * @param {string} text
78
+ */
67
79
  function unescapeCounterText(text) {
68
80
  return text.replace(/\\\$/g, '$');
69
81
  }
70
82
 
83
+ /**
84
+ * @param {import('./xle-ast').XLEItem} node
85
+ * @param {number} index
86
+ */
71
87
  function substituteCounter(node, index) {
72
88
  if (node.kind === 'group') {
73
89
  for (const child of node.children) substituteCounter(child, index);
@@ -86,44 +102,69 @@ function substituteCounter(node, index) {
86
102
  }
87
103
 
88
104
  class Emitter {
105
+ /**
106
+ * @param {import('./xle-ast').Registry} registry
107
+ * @param {{componentName?: string, blockModules?: Map<string, import('./xle-ast').BlockModule>}} [options]
108
+ */
89
109
  constructor(registry, options = {}) {
90
110
  this.registry = registry;
91
111
  // importPath → {named:Set, types:Set, default, namespace, sideEffect}
112
+ /** @type {Map<string, import('./xle-ast').ImportEntry>} */
92
113
  this.imports = new Map();
114
+ /** @type {import('./xle-ast').StateEntry[]} */
93
115
  this.states = [];
116
+ /** @type {Set<string>} */
94
117
  this.usedStateNames = new Set();
118
+ /** @type {string[]} */
95
119
  this.todos = [];
120
+ /** @type {Set<string>} */
96
121
  this.componentsUsed = new Set();
97
122
  this.componentName = options.componentName || 'GeneratedLayout';
98
123
  // canonical block key → prepared module ({mode, componentName, ...})
99
124
  this.blockModules = options.blockModules || new Map();
100
125
  // names of blocks already co-defined in this module (dedup)
126
+ /** @type {Map<string, string>} */
101
127
  this.splicedBlocks = new Map(); // key → componentName
128
+ /** @type {string[]} */
102
129
  this.blockDefs = []; // co-defined block source bodies, in first-use order
103
130
  }
104
131
 
132
+ /**
133
+ * @param {string} source
134
+ * @returns {import('./xle-ast').ImportEntry}
135
+ */
105
136
  importEntry(source) {
106
137
  if (!this.imports.has(source)) {
107
138
  this.imports.set(source, {named: new Set(), types: new Set(), default: null, namespace: null, sideEffect: false});
108
139
  }
109
- return this.imports.get(source);
140
+ return /** @type {import('./xle-ast').ImportEntry} */ (this.imports.get(source));
110
141
  }
111
142
 
143
+ /** @param {import('./xle-ast').RegistryComponent} component */
112
144
  addImport(component) {
113
145
  this.importEntry(component.importPath).named.add(component.exportName);
114
146
  this.componentsUsed.add(component.name);
115
147
  }
116
148
 
149
+ /**
150
+ * @param {string} source
151
+ * @param {string} name
152
+ */
117
153
  addNamedImport(source, name) {
118
154
  this.importEntry(source).named.add(name);
119
155
  }
120
156
 
157
+ /**
158
+ * @param {string} name
159
+ * @returns {import('./xle-ast').RegistryComponent | undefined}
160
+ */
121
161
  requireComponent(name) {
122
162
  const component = this.registry.components.get(name);
123
163
  if (component) this.addImport(component);
124
164
  return component;
125
165
  }
126
166
 
167
+ /** @param {string} base */
127
168
  stateName(base) {
128
169
  let name = camelCase(base);
129
170
  if (!/^[a-z]/.test(name)) name = 'v' + name;
@@ -134,6 +175,10 @@ class Emitter {
134
175
  return candidate;
135
176
  }
136
177
 
178
+ /**
179
+ * @param {string} base
180
+ * @param {string} initial
181
+ */
137
182
  addState(base, initial) {
138
183
  const name = this.stateName(base);
139
184
  const setter = 'set' + name[0].toUpperCase() + name.slice(1);
@@ -143,12 +188,16 @@ class Emitter {
143
188
 
144
189
  // ── value → JSX prop text ────────────────────────────────────────────
145
190
 
191
+ /**
192
+ * @param {import('./xle-ast').XLEValue} value
193
+ * @returns {string | null}
194
+ */
146
195
  jsxValue(value) {
147
196
  if (value === true) return null; // bare flag
148
197
  if (value === false) return '{false}';
149
198
  if (typeof value === 'number') return `{${value}}`;
150
199
  if (typeof value === 'string') return `"${escapeAttr(value)}"`;
151
- if (value && value.__expr) return `{${value.__expr}}`;
200
+ if (value && typeof value === 'object' && '__expr' in value) return `{${value.__expr}}`;
152
201
  if (Array.isArray(value)) {
153
202
  return `{[${value.map(v => (typeof v === 'string' ? `'${v}'` : String(v))).join(', ')}]}`;
154
203
  }
@@ -161,6 +210,10 @@ class Emitter {
161
210
  return `{${String(value)}}`;
162
211
  }
163
212
 
213
+ /**
214
+ * @param {string} key
215
+ * @param {import('./xle-ast').XLEValue} value
216
+ */
164
217
  propText(key, value) {
165
218
  const v = this.jsxValue(value);
166
219
  return v === null ? key : `${key}=${v}`;
@@ -168,10 +221,14 @@ class Emitter {
168
221
 
169
222
  // ── scaffolding ──────────────────────────────────────────────────────
170
223
 
224
+ /**
225
+ * @param {import('./xle-ast').RegistryProp} prop
226
+ * @param {import('./xle-ast').XLENode} node
227
+ */
171
228
  initialFor(prop, node) {
172
229
  const type = (prop.type || '').trim();
173
- if (node.bound.component.name === 'TabList') {
174
- const tabs = node.children.filter(c => c.kind === 'node');
230
+ if (node.bound?.component.name === 'TabList') {
231
+ const tabs = /** @type {import('./xle-ast').XLENode[]} */ (node.children.filter(c => c.kind === 'node'));
175
232
  const chosen = tabs.find(t => t.selected) || tabs[0];
176
233
  return chosen ? `'${slugify(chosen.payload || chosen.name)}'` : `''`;
177
234
  }
@@ -185,6 +242,11 @@ class Emitter {
185
242
  return 'undefined';
186
243
  }
187
244
 
245
+ /**
246
+ * @param {import('./xle-ast').XLENode} node
247
+ * @param {import('./xle-ast').RegistryComponent} component
248
+ * @param {Map<string, import('./xle-ast').XLEValue>} props
249
+ */
188
250
  scaffoldState(node, component, props) {
189
251
  for (const valueKey of ['value', 'page']) {
190
252
  const valueProp = component.props.get(valueKey);
@@ -199,6 +261,12 @@ class Emitter {
199
261
  }
200
262
  }
201
263
 
264
+ /**
265
+ * @param {import('./xle-ast').XLENode} node
266
+ * @param {import('./xle-ast').RegistryComponent} component
267
+ * @param {Map<string, import('./xle-ast').XLEValue>} props
268
+ * @param {Set<string>} slotKeys
269
+ */
202
270
  fillRequired(node, component, props, slotKeys) {
203
271
  for (const prop of component.props.values()) {
204
272
  if (!prop.required || props.has(prop.name) || slotKeys.has(prop.name)) continue;
@@ -221,7 +289,14 @@ class Emitter {
221
289
 
222
290
  // ── node emission ────────────────────────────────────────────────────
223
291
 
292
+ /**
293
+ * @param {import('./xle-ast').XLEItem[]} items
294
+ * @param {number} depth
295
+ * @param {import('./xle-ast').EmitContext} [context]
296
+ * @returns {string[]}
297
+ */
224
298
  emitItems(items, depth, context = {}) {
299
+ /** @type {string[]} */
225
300
  const lines = [];
226
301
  for (const item of items) {
227
302
  if (item.kind === 'group') {
@@ -237,7 +312,7 @@ class Emitter {
237
312
  }
238
313
  const count = item.repeat || 1;
239
314
  for (let i = 1; i <= count; i++) {
240
- const clone = count > 1 ? cloneItem(item) : item;
315
+ const clone = count > 1 ? /** @type {import('./xle-ast').XLENode} */ (cloneItem(item)) : item;
241
316
  if (count > 1) {
242
317
  clone.repeat = null;
243
318
  substituteCounter(clone, i);
@@ -248,6 +323,12 @@ class Emitter {
248
323
  return lines;
249
324
  }
250
325
 
326
+ /**
327
+ * @param {import('./xle-ast').XLENode} node
328
+ * @param {number} depth
329
+ * @param {import('./xle-ast').EmitContext} [context]
330
+ * @returns {string[]}
331
+ */
251
332
  emitNode(node, depth, context = {}) {
252
333
  if (!node.bound) {
253
334
  // Anonymous block reference — emit just the block, no wrapper element.
@@ -259,6 +340,7 @@ class Emitter {
259
340
  const pad = INDENT.repeat(depth);
260
341
 
261
342
  const props = new Map(node.bound.props);
343
+ /** @type {string | null} */
262
344
  let textChild = null;
263
345
 
264
346
  // Payload → primary text prop, else text child. Required props win
@@ -273,7 +355,7 @@ class Emitter {
273
355
  if (target && !props.has(target)) props.set(target, node.payload);
274
356
  else textChild = node.payload;
275
357
  }
276
- if (node.payload2 != null && component.props.has('value') && !component.props.get('value').required) {
358
+ if (node.payload2 != null && component.props.has('value') && !component.props.get('value')?.required) {
277
359
  props.set('value', node.payload2);
278
360
  }
279
361
 
@@ -292,9 +374,11 @@ class Emitter {
292
374
  props.delete('__opens');
293
375
  props.delete('__fill');
294
376
  if (opens) {
295
- const target = opens.idref || opens;
377
+ const opensRef = /** @type {import('./xle-ast').IdRef} */ (opens);
378
+ const target = opensRef.idref || opens;
296
379
  const handler = component.props.has('onClick') ? 'onClick' : 'clickAction';
297
- props.set(handler, {__expr: `() => {/* TODO(xle): open #${target.idref ?? target} */}`});
380
+ const targetId = typeof target === 'object' && target != null && 'idref' in target ? target.idref : target;
381
+ props.set(handler, {__expr: `() => {/* TODO(xle): open #${targetId} */}`});
298
382
  }
299
383
 
300
384
  // Slots → element-valued props (keys collected first so required-prop
@@ -302,12 +386,14 @@ class Emitter {
302
386
  const slotKeys = new Set(node.bound.slots.map(s => s.key));
303
387
  this.fillRequired(node, component, props, slotKeys);
304
388
 
389
+ /** @type {Array<[string, string[]]>} */
305
390
  const slotEntries = [];
306
391
  for (const slot of node.bound.slots) {
307
392
  slotEntries.push([slot.key, this.emitSlotValue(slot, depth + 1)]);
308
393
  }
309
394
 
310
395
  // Structural routing.
396
+ /** @type {import('./xle-ast').XLEItem[]} */
311
397
  let children = node.children;
312
398
  if (component.name === 'Layout') {
313
399
  const routed = this.routeLayoutChildren(node, props, slotEntries, depth);
@@ -356,12 +442,21 @@ class Emitter {
356
442
  return lines;
357
443
  }
358
444
 
445
+ /**
446
+ * @param {import('./xle-ast').RegistryComponent} component
447
+ * @param {Map<string, import('./xle-ast').XLEValue>} props
448
+ * @param {Array<[string, string[]]>} slotEntries
449
+ * @param {string[]} bodyLines
450
+ * @param {number} depth
451
+ * @returns {string[]}
452
+ */
359
453
  renderTag(component, props, slotEntries, bodyLines, depth) {
360
454
  const pad = INDENT.repeat(depth);
361
455
  const propTexts = [...props.entries()].map(([k, v]) => this.propText(k, v));
362
456
  const slotTexts = slotEntries.map(([key, valueLines]) => ({key, valueLines}));
363
457
  const tag = component.exportName;
364
458
 
459
+ /** @type {string[]} */
365
460
  const open = [];
366
461
  const simple = slotTexts.length === 0 && propTexts.join(' ').length <= 60;
367
462
  if (simple) {
@@ -385,6 +480,11 @@ class Emitter {
385
480
  return [...open, ...bodyLines, `${pad}</${tag}>`];
386
481
  }
387
482
 
483
+ /**
484
+ * @param {import('./xle-ast').Slot} slot
485
+ * @param {number} _depth
486
+ * @returns {string[]}
487
+ */
388
488
  emitSlotValue(slot, _depth) {
389
489
  const value = slot.value;
390
490
  if (value == null) {
@@ -394,17 +494,17 @@ class Emitter {
394
494
  const text = this.requireComponent('Text');
395
495
  return [text ? `<${text.exportName}>${value}</${text.exportName}>` : `<>${value}</>`];
396
496
  }
397
- if (value.hint) {
497
+ if ('hint' in value) {
398
498
  return [
399
499
  '<>',
400
500
  ...this.emitHint(value.hint, 1).map(l => l.trimStart()).map(l => INDENT + l),
401
501
  '</>',
402
502
  ];
403
503
  }
404
- if (value.idref) {
504
+ if ('idref' in value) {
405
505
  return [`null /* TODO(xle): reference #${value.idref} */`];
406
506
  }
407
- if (value.subexpr) {
507
+ if ('subexpr' in value) {
408
508
  const lines = this.emitItems(value.subexpr, 0, {});
409
509
  if (value.subexpr.length > 1) return ['<>', ...lines.map(l => INDENT + l), '</>'];
410
510
  return lines;
@@ -412,6 +512,11 @@ class Emitter {
412
512
  return ['null'];
413
513
  }
414
514
 
515
+ /**
516
+ * @param {import('./xle-ast').Hint} hint
517
+ * @param {number} depth
518
+ * @returns {string[]}
519
+ */
415
520
  emitHint(hint, depth) {
416
521
  const pad = INDENT.repeat(depth);
417
522
  if (hint.block) {
@@ -436,6 +541,9 @@ class Emitter {
436
541
  /**
437
542
  * Register a referenced block (import-mode app component, or splice-mode
438
543
  * template block co-defined once) and return the JSX component name to use.
544
+ * @param {string} key
545
+ * @param {import('./xle-ast').BlockModule} mod
546
+ * @returns {string | null | undefined}
439
547
  */
440
548
  referenceBlock(key, mod) {
441
549
  if (this.splicedBlocks.has(key)) return this.splicedBlocks.get(key);
@@ -468,18 +576,27 @@ class Emitter {
468
576
  return name;
469
577
  }
470
578
 
579
+ /**
580
+ * @param {import('./xle-ast').XLENode} node
581
+ * @param {Map<string, import('./xle-ast').XLEValue>} props
582
+ * @param {Array<[string, string[]]>} slotEntries
583
+ * @param {number} depth
584
+ * @returns {import('./xle-ast').XLEItem[]}
585
+ */
471
586
  routeLayoutChildren(node, props, slotEntries, depth) {
587
+ /** @type {Record<string, string>} */
472
588
  const family = {
473
589
  LayoutHeader: 'header',
474
590
  LayoutContent: 'content',
475
591
  LayoutFooter: 'footer',
476
592
  };
477
593
  const assigned = new Set(slotEntries.map(([k]) => k));
594
+ /** @type {import('./xle-ast').XLEItem[]} */
478
595
  const loose = [];
479
596
  let panelCount = 0;
480
597
  for (const child of node.children) {
481
- const childName = child.bound?.component?.name;
482
- let slotName = family[childName];
598
+ const childName = child.kind === 'node' ? child.bound?.component?.name : undefined;
599
+ let slotName = childName ? family[childName] : undefined;
483
600
  if (childName === 'LayoutPanel') {
484
601
  slotName = panelCount === 0 ? 'start' : 'end';
485
602
  panelCount++;
@@ -493,7 +610,7 @@ class Emitter {
493
610
  }
494
611
  // Loose children auto-wrap into an implicit LayoutContent slot.
495
612
  if (loose.length > 0 && !assigned.has('content')) {
496
- const lc = this.requireComponent('LayoutContent');
613
+ const lc = /** @type {import('./xle-ast').RegistryComponent} */ (this.requireComponent('LayoutContent'));
497
614
  const inner = this.emitItems(loose, 1, {});
498
615
  slotEntries.push(['content', [`<${lc.exportName}>`, ...inner, `</${lc.exportName}>`]]);
499
616
  } else if (loose.length > 0) {
@@ -503,8 +620,13 @@ class Emitter {
503
620
  return [];
504
621
  }
505
622
 
506
- /** Expand groups/repeats into a flat node list (clones carry repeat=null). */
623
+ /**
624
+ * Expand groups/repeats into a flat node list (clones carry repeat=null).
625
+ * @param {import('./xle-ast').XLEItem[]} items
626
+ * @returns {import('./xle-ast').XLENode[]}
627
+ */
507
628
  flattenItems(items) {
629
+ /** @type {import('./xle-ast').XLENode[]} */
508
630
  const out = [];
509
631
  for (const item of items) {
510
632
  const count = item.repeat || 1;
@@ -521,26 +643,37 @@ class Emitter {
521
643
  return out;
522
644
  }
523
645
 
646
+ /**
647
+ * @param {import('./xle-ast').XLENode} node
648
+ * @returns {import('./xle-ast').XLEItem[]}
649
+ */
524
650
  partitionTableChildren(node) {
525
651
  const flat = this.flattenItems(node.children);
526
652
  const rows = flat.filter(c => c.kind === 'node' && c.bound?.component?.name === 'TableRow');
527
653
  if (rows.length === 0 || rows.length !== flat.length) return node.children;
528
- const isHeaderRow = (row) => {
654
+ const isHeaderRow = (/** @type {import('./xle-ast').XLENode} */ row) => {
529
655
  const cells = this.flattenItems(row.children);
530
656
  return cells.length > 0 && cells.every(c => c.bound?.component?.name === 'TableHeaderCell');
531
657
  };
532
658
  const headerRows = rows.filter(isHeaderRow);
533
659
  const bodyRows = rows.filter(r => !isHeaderRow(r));
660
+ /**
661
+ * @param {string} name
662
+ * @param {import('./xle-ast').XLENode[]} rowNodes
663
+ * @returns {import('./xle-ast').XLENode}
664
+ */
534
665
  const wrap = (name, rowNodes) => {
535
666
  const comp = this.requireComponent(name);
667
+ /** @type {import('./xle-ast').XLENode} */
536
668
  const wrapper = {
537
669
  kind: 'node', name, id: null, enumMods: [], payload: null, payload2: null,
538
670
  attrs: [], slots: [], hint: null, repeat: null, selected: false,
539
671
  children: rowNodes, line: node.line, col: node.col,
540
- bound: {component: comp, props: new Map(), slots: [], stray: []},
672
+ bound: {component: /** @type {import('./xle-ast').RegistryComponent} */ (comp), props: new Map(), slots: [], stray: []},
541
673
  };
542
674
  return wrapper;
543
675
  };
676
+ /** @type {import('./xle-ast').XLEItem[]} */
544
677
  const out = [];
545
678
  if (headerRows.length > 0) out.push(wrap('TableHeader', headerRows));
546
679
  if (bodyRows.length > 0) out.push(wrap('TableBody', bodyRows));
@@ -551,9 +684,9 @@ class Emitter {
551
684
  /**
552
685
  * Expand a validated document into a complete TSX module.
553
686
  *
554
- * @param {{roots: any[], overlays: any[]}} doc
555
- * @param {object} registry
556
- * @param {{componentName?: string}} [options]
687
+ * @param {{roots: import('./xle-ast').XLEItem[], overlays: import('./xle-ast').XLEItem[]}} doc
688
+ * @param {import('./xle-ast').Registry} registry
689
+ * @param {{componentName?: string, blockModules?: Map<string, import('./xle-ast').BlockModule>}} [options]
557
690
  * @returns {{code: string, componentsUsed: string[], states: number, todos: string[]}}
558
691
  */
559
692
  export function expand(doc, registry, options = {}) {