@astryxdesign/cli 0.6.3 → 0.6.4-canary.078fd25

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 (728) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/README.md +152 -107
  3. package/api/blog/blog.doc.mjs +1 -0
  4. package/api/build/_adapter.d.mts +50 -0
  5. package/api/build/_adapter.mjs +60 -0
  6. package/api/build/build.doc.mjs +22 -10
  7. package/api/build/build.test.mjs +219 -8
  8. package/api/build/build.type.d.mts +91 -2
  9. package/api/build/build.type.mjs +52 -8
  10. package/api/build/help/help.d.mts +12 -5
  11. package/api/build/help/help.mjs +69 -6
  12. package/api/build/kit/kit.d.mts +4 -1
  13. package/api/build/kit/kit.mjs +208 -53
  14. package/api/build/kit/rank.d.mts +44 -0
  15. package/api/build/kit/rank.mjs +432 -0
  16. package/api/build/kit/rank.test.mjs +196 -0
  17. package/api/component/_adapter.d.mts +31 -12
  18. package/api/component/_adapter.mjs +79 -15
  19. package/api/component/component.d.mts +6 -3
  20. package/api/component/component.doc.mjs +49 -19
  21. package/api/component/component.mjs +339 -22
  22. package/api/component/component.test.mjs +38 -0
  23. package/api/component/component.type.d.mts +47 -11
  24. package/api/component/component.type.mjs +76 -24
  25. package/api/component/detail/blocks/blocks.d.mts +2 -1
  26. package/api/component/detail/blocks/blocks.mjs +4 -3
  27. package/api/component/list/list.d.mts +0 -5
  28. package/api/component/list/list.mjs +40 -11
  29. package/api/discover/_adapter.d.mts +114 -6
  30. package/api/discover/_adapter.mjs +372 -17
  31. package/api/discover/_adapter.test.mjs +215 -0
  32. package/api/discover/_catalog-view.d.mts +115 -0
  33. package/api/discover/_catalog-view.mjs +203 -0
  34. package/api/discover/_catalog-view.test.mjs +128 -0
  35. package/api/discover/detail/detail.d.mts +18 -6
  36. package/api/discover/detail/detail.mjs +67 -13
  37. package/api/discover/detail/detail.test.mjs +85 -0
  38. package/api/discover/detail/item/item.d.mts +26 -0
  39. package/api/discover/detail/item/item.mjs +78 -0
  40. package/api/discover/detail/item/item.test.mjs +73 -0
  41. package/api/discover/discover.d.mts +3 -9
  42. package/api/discover/discover.doc.mjs +62 -18
  43. package/api/discover/discover.mjs +220 -36
  44. package/api/discover/discover.test.mjs +11 -2
  45. package/api/discover/discover.type.d.mts +150 -11
  46. package/api/discover/discover.type.mjs +107 -17
  47. package/api/discover/list/list.d.mts +20 -6
  48. package/api/discover/list/list.mjs +45 -12
  49. package/api/discover/list/list.test.mjs +46 -0
  50. package/api/discover/search/search.d.mts +18 -16
  51. package/api/discover/search/search.mjs +102 -56
  52. package/api/discover/search/search.test.mjs +144 -10
  53. package/api/docs/_adapter.d.mts +277 -41
  54. package/api/docs/_adapter.mjs +993 -108
  55. package/api/docs/compiled-topics.test.mjs +78 -0
  56. package/api/docs/detail/detail.mjs +22 -63
  57. package/api/docs/detail/section/section.d.mts +1 -1
  58. package/api/docs/detail/section/section.mjs +54 -19
  59. package/api/docs/detail/section/section.test.mjs +50 -0
  60. package/api/docs/docOverlays.test.mjs +27 -1
  61. package/api/docs/docs.d.mts +10 -3
  62. package/api/docs/docs.doc.mjs +55 -16
  63. package/api/docs/docs.mjs +53 -10
  64. package/api/docs/docs.type.d.mts +221 -5
  65. package/api/docs/docs.type.mjs +153 -11
  66. package/api/docs/index/index.d.mts +18 -0
  67. package/api/docs/index/index.mjs +40 -0
  68. package/api/docs/index/index.test.mjs +62 -0
  69. package/api/docs/list/list.mjs +28 -12
  70. package/api/docs/node/node.d.mts +43 -0
  71. package/api/docs/node/node.mjs +192 -0
  72. package/api/docs/reference-blocks.test.mjs +406 -0
  73. package/api/doctor/doctor.d.mts +104 -1
  74. package/api/doctor/doctor.doc.mjs +18 -8
  75. package/api/doctor/doctor.mjs +635 -7
  76. package/api/doctor/doctor.test.mjs +732 -11
  77. package/api/doctor/doctor.type.d.mts +1 -1
  78. package/api/doctor/doctor.type.mjs +1 -1
  79. package/api/gap-report/gap-report.doc.mjs +27 -14
  80. package/api/hook/_adapter.mjs +19 -5
  81. package/api/hook/hook.doc.mjs +7 -3
  82. package/api/hook/hook.type.d.mts +3 -3
  83. package/api/hook/hook.type.mjs +11 -11
  84. package/api/hook/list/list.d.mts +2 -2
  85. package/api/hook/list/list.mjs +69 -17
  86. package/api/index.d.mts +2 -1
  87. package/api/index.mjs +6 -3
  88. package/api/init/init.doc.mjs +22 -12
  89. package/api/init/init.test.mjs +41 -1
  90. package/api/init/remove/remove.mjs +1 -1
  91. package/api/init/run/run.mjs +20 -10
  92. package/api/integration/add-contribution.component-names.test.mjs +120 -0
  93. package/api/integration/add-contribution.d.mts +2 -1
  94. package/api/integration/add-contribution.mjs +130 -15
  95. package/api/integration/add-contribution.test.mjs +258 -7
  96. package/api/integration/add-helpers.d.mts +5 -2
  97. package/api/integration/add-helpers.mjs +36 -9
  98. package/api/integration/add-theme.mjs +56 -65
  99. package/api/integration/add-theme.test.mjs +139 -21
  100. package/api/integration/authoring-checks.mjs +138 -28
  101. package/api/integration/authoring-checks.test.mjs +179 -7
  102. package/api/integration/authoring-checks.type.mjs +6 -1
  103. package/api/integration/integration-authoring.type.d.mts +3 -1
  104. package/api/integration/integration-authoring.type.mjs +2 -0
  105. package/api/integration/integration-block-exports.test.mjs +10 -6
  106. package/api/integration/integrationAdd.doc.mjs +14 -4
  107. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  108. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  109. package/api/integration/integrationAddComponent.doc.mjs +2 -1
  110. package/api/integration/integrationAddDoc.doc.mjs +8 -1
  111. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  112. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  113. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  114. package/api/integration/integrationDocConflicts.doc.mjs +2 -1
  115. package/api/integration/integrationPackCheck.doc.mjs +5 -4
  116. package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
  117. package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
  118. package/api/integration/pack-check.lifecycle-output.test.mjs +107 -0
  119. package/api/integration/pack-check.mjs +160 -11
  120. package/api/integration/pack-check.test.mjs +477 -47
  121. package/api/integration/pack-check.type.d.mts +26 -2
  122. package/api/integration/pack-check.type.mjs +15 -2
  123. package/api/integration/summarizeIssues.doc.mjs +1 -0
  124. package/api/integration/template-conflict-compatibility.test.mjs +73 -0
  125. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  126. package/api/integration/validate-integration.mjs +52 -102
  127. package/api/integration/validate-integration.test.mjs +179 -26
  128. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  129. package/api/integration/validateIntegration.doc.mjs +3 -2
  130. package/api/json/assertResponse.doc.mjs +2 -1
  131. package/api/json/envelope-types.test.mjs +76 -0
  132. package/api/json/index.ts +2 -0
  133. package/api/json/isError.doc.mjs +2 -1
  134. package/api/json/parseResponse.doc.mjs +3 -2
  135. package/api/layout/_adapter.mjs +20 -5
  136. package/api/layout/expand/expand.mjs +7 -5
  137. package/api/layout/expand/expand.path-safety.test.mjs +53 -0
  138. package/api/layout/grammar/grammar.mjs +2 -1
  139. package/api/layout/layoutCheck.doc.mjs +1 -0
  140. package/api/layout/layoutExpand.doc.mjs +2 -1
  141. package/api/layout/layoutGrammar.doc.mjs +1 -0
  142. package/api/search/search-return-type.test.mjs +54 -0
  143. package/api/search/search.d.mts +89 -12
  144. package/api/search/search.doc.mjs +8 -2
  145. package/api/search/search.mjs +697 -97
  146. package/api/search/search.type.d.mts +15 -3
  147. package/api/search/search.type.mjs +5 -2
  148. package/api/swizzle/copy/copy.mjs +28 -11
  149. package/api/swizzle/swizzle.doc.mjs +8 -5
  150. package/api/swizzle/swizzle.type.d.mts +2 -2
  151. package/api/swizzle/swizzle.type.mjs +2 -2
  152. package/api/template/copy/copy.mjs +18 -24
  153. package/api/template/copy/copy.test.mjs +26 -0
  154. package/api/template/list/list.mjs +1 -0
  155. package/api/template/table-floating-bulk-actions.test.mjs +66 -0
  156. package/api/template/template-integration.test.mjs +1072 -3
  157. package/api/template/template-suffix.test.mjs +41 -21
  158. package/api/template/template.d.mts +1 -1
  159. package/api/template/template.doc.mjs +32 -9
  160. package/api/template/template.mjs +45 -8
  161. package/api/template/template.type.d.mts +12 -14
  162. package/api/template/template.type.mjs +15 -14
  163. package/api/theme/_adapter.d.mts +2 -3
  164. package/api/theme/_adapter.mjs +4 -5
  165. package/api/theme/add/add.binary.test.mjs +84 -0
  166. package/api/theme/add/add.mjs +31 -22
  167. package/api/theme/add/add.rollback.test.mjs +158 -0
  168. package/api/theme/add/add.staging.test.mjs +83 -0
  169. package/api/theme/add/add.test.mjs +14 -1
  170. package/api/theme/build/build.family.test.mjs +7 -12
  171. package/api/theme/build/build.mjs +140 -59
  172. package/api/theme/build/build.public-component-vars.test.mjs +1 -1
  173. package/api/theme/build/build.receipt-doc.test.mjs +111 -0
  174. package/api/theme/build/build.rollback.test.mjs +148 -0
  175. package/api/theme/build/build.test.mjs +127 -0
  176. package/api/theme/build/font-warning.mjs +3 -3
  177. package/api/theme/build/font-warning.test.mjs +5 -2
  178. package/api/theme/generateTonalPalette.doc.mjs +2 -2
  179. package/api/theme/integration-themes.test.mjs +39 -28
  180. package/api/theme/list/list.test.mjs +19 -20
  181. package/api/theme/listThemes.doc.mjs +6 -5
  182. package/api/theme/palette/generate/generate.mjs +8 -3
  183. package/api/theme/palette/generate/generate.test.mjs +96 -0
  184. package/api/theme/palette/generate/generator.d.mts +10 -13
  185. package/api/theme/palette/generate/generator.mjs +15 -4
  186. package/api/theme/palette/generate/generator.test.mjs +10 -0
  187. package/api/theme/template/template.mjs +11 -2
  188. package/api/theme/template/template.test.mjs +20 -0
  189. package/api/theme/theme.type.d.mts +170 -11
  190. package/api/theme/theme.type.mjs +94 -27
  191. package/api/theme/themeAdd.doc.mjs +12 -12
  192. package/api/theme/themeBuild.doc.mjs +21 -17
  193. package/api/theme/themeList.doc.mjs +6 -3
  194. package/api/theme/themeListAvailable.doc.mjs +6 -3
  195. package/api/theme/themePaletteGenerate.doc.mjs +16 -8
  196. package/api/theme/themeTargets.doc.mjs +4 -2
  197. package/api/theme/themeTemplate.doc.mjs +8 -3
  198. package/api/upgrade/_adapter.d.mts +32 -5
  199. package/api/upgrade/_adapter.mjs +139 -22
  200. package/api/upgrade/list/list.mjs +2 -1
  201. package/api/upgrade/list/list.test.mjs +73 -0
  202. package/api/upgrade/project-context.test.mjs +272 -0
  203. package/api/upgrade/provider-agreement.test.mjs +152 -0
  204. package/api/upgrade/run/files-changed.test.mjs +111 -0
  205. package/api/upgrade/run/run.mjs +358 -59
  206. package/api/upgrade/status/status.mjs +2 -2
  207. package/api/upgrade/upgrade.doc.mjs +32 -23
  208. package/api/upgrade/upgrade.type.d.mts +43 -5
  209. package/api/upgrade/upgrade.type.mjs +29 -13
  210. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  211. package/assets/codemods/__tests__/runner.test.mjs +332 -8
  212. package/assets/codemods/file-count.test.mjs +163 -0
  213. package/assets/codemods/integration-discovery.mjs +48 -4
  214. package/assets/codemods/integration-discovery.test.mjs +73 -0
  215. package/assets/codemods/integration-runner.mjs +59 -7
  216. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  217. package/assets/codemods/registry.mjs +1 -0
  218. package/assets/codemods/run-codemod.mjs +177 -34
  219. package/assets/codemods/runner.mjs +353 -104
  220. package/assets/codemods/term-log.mjs +32 -8
  221. package/assets/codemods/term-log.test.mjs +19 -1
  222. package/assets/codemods/transform-prop.mjs +109 -0
  223. package/assets/codemods/transform-prop.test.mjs +95 -0
  224. package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
  225. package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
  226. package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
  227. package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
  228. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  229. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  230. package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
  231. package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
  232. package/assets/codemods/transforms/v0.6.4/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  233. package/assets/codemods/transforms/v0.6.4/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  234. package/assets/codemods/transforms/v0.6.4/index.mjs +31 -0
  235. package/assets/codemods/transforms/v0.6.4/migrate-native-picker-to-presentation.mjs +148 -0
  236. package/assets/codemods/transforms/v0.6.4/migrate-theme-catalog-to-descriptors.mjs +141 -0
  237. package/assets/docs/README.md +12 -1
  238. package/assets/docs/authoring.doc.mjs +14 -0
  239. package/assets/docs/browser-support.doc.mjs +11 -11
  240. package/assets/docs/color.doc.mjs +8 -2
  241. package/assets/docs/elevation.doc.mjs +6 -4
  242. package/assets/docs/getting-started.doc.mjs +6 -17
  243. package/assets/docs/icons.doc.mjs +2 -21
  244. package/assets/docs/illustrations.doc.mjs +7 -15
  245. package/assets/docs/internationalization.doc.mjs +7 -5
  246. package/assets/docs/layout.doc.dense.mjs +132 -84
  247. package/assets/docs/layout.doc.mjs +134 -78
  248. package/assets/docs/migration.doc.mjs +19 -21
  249. package/assets/docs/motion.doc.mjs +16 -3
  250. package/assets/docs/principles.doc.dense.mjs +5 -5
  251. package/assets/docs/principles.doc.mjs +14 -6
  252. package/assets/docs/principles.doc.zh.mjs +6 -6
  253. package/assets/docs/shape.doc.mjs +8 -3
  254. package/assets/docs/spacing.doc.mjs +7 -2
  255. package/assets/docs/styling-libraries.doc.mjs +10 -6
  256. package/assets/docs/styling.doc.mjs +22 -26
  257. package/assets/docs/theme.doc.dense.mjs +58 -18
  258. package/assets/docs/theme.doc.mjs +60 -50
  259. package/assets/docs/theme.doc.zh.mjs +9 -8
  260. package/assets/docs/tokens.doc.dense.mjs +2 -2
  261. package/assets/docs/tokens.doc.mjs +390 -9
  262. package/assets/docs/tokens.doc.zh.mjs +2 -2
  263. package/assets/docs/tree/add-a-component.doc.mjs +75 -0
  264. package/assets/docs/tree/add-a-theme.doc.mjs +85 -0
  265. package/assets/docs/tree/add-a-topic.doc.mjs +144 -0
  266. package/assets/docs/tree/agent-guidance.doc.mjs +138 -0
  267. package/assets/docs/tree/api.doc.mjs +30 -0
  268. package/assets/docs/tree/block-template.doc.mjs +130 -0
  269. package/assets/docs/tree/build-the-template.doc.mjs +28 -0
  270. package/assets/docs/tree/building-blocks.doc.mjs +46 -0
  271. package/assets/docs/tree/check-your-docs.doc.mjs +137 -0
  272. package/assets/docs/tree/checks.doc.mjs +119 -0
  273. package/assets/docs/tree/cli.doc.mjs +23 -0
  274. package/assets/docs/tree/codemods.doc.mjs +147 -0
  275. package/assets/docs/tree/commands.doc.mjs +25 -0
  276. package/assets/docs/tree/component-family.doc.mjs +113 -0
  277. package/assets/docs/tree/component-imports.doc.mjs +69 -0
  278. package/assets/docs/tree/component-lookups.doc.mjs +149 -0
  279. package/assets/docs/tree/components.doc.mjs +23 -0
  280. package/assets/docs/tree/configuration.doc.mjs +23 -0
  281. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +182 -0
  282. package/assets/docs/tree/define-the-theme.doc.mjs +118 -0
  283. package/assets/docs/tree/describe-the-component.doc.mjs +57 -0
  284. package/assets/docs/tree/docs.doc.mjs +21 -0
  285. package/assets/docs/tree/document-the-template.doc.mjs +28 -0
  286. package/assets/docs/tree/document-the-theme.doc.mjs +68 -0
  287. package/assets/docs/tree/export-template-assets.doc.mjs +147 -0
  288. package/assets/docs/tree/extend-or-replace.doc.mjs +103 -0
  289. package/assets/docs/tree/fonts-and-assets.doc.mjs +106 -0
  290. package/assets/docs/tree/generate-a-palette.doc.mjs +66 -0
  291. package/assets/docs/tree/grade-template-with-agent.doc.mjs +105 -0
  292. package/assets/docs/tree/help.doc.mjs +16 -0
  293. package/assets/docs/tree/integrations.doc.mjs +40 -0
  294. package/assets/docs/tree/links.doc.mjs +98 -0
  295. package/assets/docs/tree/package-and-test.doc.mjs +32 -0
  296. package/assets/docs/tree/page-template.doc.mjs +71 -0
  297. package/assets/docs/tree/publishing.doc.mjs +111 -0
  298. package/assets/docs/tree/quick-start.doc.mjs +272 -0
  299. package/assets/docs/tree/replace-a-core-component.doc.mjs +104 -0
  300. package/assets/docs/tree/replace-a-core-template.doc.mjs +172 -0
  301. package/assets/docs/tree/sections-and-placement.doc.mjs +108 -0
  302. package/assets/docs/tree/see-it-in-an-app.doc.mjs +59 -0
  303. package/assets/docs/tree/ship.doc.mjs +16 -0
  304. package/assets/docs/tree/short-and-findable.doc.mjs +108 -0
  305. package/assets/docs/tree/single-component.doc.mjs +165 -0
  306. package/assets/docs/tree/start-a-template.doc.mjs +143 -0
  307. package/assets/docs/tree/subcomponent.doc.mjs +115 -0
  308. package/assets/docs/tree/template-assets.doc.mjs +64 -0
  309. package/assets/docs/tree/template-doc-overview.doc.mjs +109 -0
  310. package/assets/docs/tree/template-fonts.doc.mjs +102 -0
  311. package/assets/docs/tree/template-grading-rubric.doc.mjs +452 -0
  312. package/assets/docs/tree/template-icons.doc.mjs +97 -0
  313. package/assets/docs/tree/template-images-media.doc.mjs +127 -0
  314. package/assets/docs/tree/template-styles.doc.mjs +93 -0
  315. package/assets/docs/tree/templates.doc.mjs +34 -0
  316. package/assets/docs/tree/test-in-an-app.doc.mjs +115 -0
  317. package/assets/docs/tree/test-template-in-app.doc.mjs +128 -0
  318. package/assets/docs/tree/themes.doc.mjs +39 -0
  319. package/assets/docs/tree/troubleshooting.doc.mjs +149 -0
  320. package/assets/docs/tree/upgrading.doc.mjs +103 -0
  321. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +51 -0
  322. package/assets/docs/tree/verify-packed-template.doc.mjs +77 -0
  323. package/assets/docs/tree/versioning.doc.mjs +161 -0
  324. package/assets/docs/tree/write-good-templates.doc.mjs +64 -0
  325. package/assets/docs/tree/write-the-template-file.doc.mjs +154 -0
  326. package/assets/docs/typography.doc.mjs +24 -4
  327. package/assets/docs/working-with-ai.doc.mjs +34 -26
  328. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
  329. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
  330. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  331. package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
  332. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  333. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  334. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
  335. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
  336. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
  337. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
  338. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
  339. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
  340. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
  341. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
  342. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
  343. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
  344. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
  345. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
  346. package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
  347. package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
  348. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
  349. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
  350. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  351. package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +14 -0
  352. package/assets/templates/blocks/components/Timer/TimerFormats.tsx +34 -0
  353. package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +14 -0
  354. package/assets/templates/blocks/components/Timer/TimerInline.tsx +14 -0
  355. package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +13 -0
  356. package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +47 -0
  357. package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +14 -0
  358. package/assets/templates/blocks/components/Timer/TimerTypography.tsx +31 -0
  359. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +19 -3
  360. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +383 -65
  361. package/assets/templates/pages/table-tree/page.tsx +1704 -0
  362. package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
  363. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  364. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  365. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  366. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  367. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  368. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  369. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  370. package/authoring/_shared/contract.ts +22 -0
  371. package/authoring/codemod/codemod.doc.mjs +7 -2
  372. package/authoring/codemod/parse.d.mts +8 -8
  373. package/authoring/codemod/parse.mjs +8 -6
  374. package/authoring/codemod/type.ts +12 -0
  375. package/authoring/config/config.doc.mjs +11 -3
  376. package/authoring/config/debug-composition.test.mjs +92 -0
  377. package/authoring/config/parse.d.mts +15 -13
  378. package/authoring/config/parse.mjs +27 -8
  379. package/authoring/config/parse.test.mjs +8 -0
  380. package/authoring/config/type.ts +29 -6
  381. package/authoring/debug/debug.doc.d.mts +11 -0
  382. package/authoring/debug/debug.doc.mjs +182 -0
  383. package/authoring/debug/parse.d.mts +8 -8
  384. package/authoring/debug/parse.mjs +3 -3
  385. package/authoring/discover/discover.doc.d.mts +13 -0
  386. package/authoring/discover/discover.doc.mjs +138 -0
  387. package/authoring/discover/parse.d.mts +24 -0
  388. package/authoring/discover/parse.mjs +128 -0
  389. package/authoring/discover/parse.test.mjs +124 -0
  390. package/authoring/discover/type.ts +87 -0
  391. package/authoring/doctypes/_schema.d.mts +792 -24
  392. package/authoring/doctypes/_schema.mjs +549 -39
  393. package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
  394. package/authoring/doctypes/base/graph-fields.doc.mjs +64 -0
  395. package/authoring/doctypes/base/type.ts +43 -0
  396. package/authoring/doctypes/command/command.doc.mjs +4 -3
  397. package/authoring/doctypes/command/parse.d.mts +2 -2
  398. package/authoring/doctypes/command/parse.mjs +1 -1
  399. package/authoring/doctypes/command/type.ts +5 -4
  400. package/authoring/doctypes/component/component.doc.mjs +12 -3
  401. package/authoring/doctypes/component/parse.d.mts +2 -2
  402. package/authoring/doctypes/component/parse.mjs +1 -1
  403. package/authoring/doctypes/component/type.ts +14 -5
  404. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  405. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  406. package/authoring/doctypes/enum/parse.d.mts +2 -2
  407. package/authoring/doctypes/enum/parse.mjs +1 -1
  408. package/authoring/doctypes/enum/type.ts +4 -2
  409. package/authoring/doctypes/function/function.doc.mjs +7 -2
  410. package/authoring/doctypes/function/parse.d.mts +2 -2
  411. package/authoring/doctypes/function/parse.mjs +1 -1
  412. package/authoring/doctypes/function/type.ts +9 -4
  413. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  414. package/authoring/doctypes/hook/parse.d.mts +2 -2
  415. package/authoring/doctypes/hook/parse.mjs +1 -1
  416. package/authoring/doctypes/hook/type.ts +5 -4
  417. package/authoring/doctypes/legacy.d.mts +8 -6
  418. package/authoring/doctypes/legacy.mjs +5 -4
  419. package/authoring/doctypes/load-contract.test.mjs +233 -0
  420. package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
  421. package/authoring/doctypes/namespace/namespace.doc.mjs +128 -0
  422. package/authoring/doctypes/namespace/parse.d.mts +12 -0
  423. package/authoring/doctypes/namespace/parse.mjs +25 -0
  424. package/authoring/doctypes/namespace/parse.test.mjs +163 -0
  425. package/authoring/doctypes/namespace/type.ts +74 -0
  426. package/authoring/doctypes/parse.d.mts +22 -18
  427. package/authoring/doctypes/parse.mjs +22 -11
  428. package/authoring/doctypes/parse.test.mjs +77 -3
  429. package/authoring/doctypes/reference/parse.d.mts +2 -2
  430. package/authoring/doctypes/reference/parse.mjs +8 -5
  431. package/authoring/doctypes/reference/reference.doc.mjs +55 -6
  432. package/authoring/doctypes/reference/type.ts +75 -7
  433. package/authoring/doctypes/schema/parse.d.mts +2 -2
  434. package/authoring/doctypes/schema/parse.mjs +1 -1
  435. package/authoring/doctypes/schema/schema.doc.mjs +2 -2
  436. package/authoring/doctypes/schema/type.ts +4 -4
  437. package/authoring/doctypes/template/parse.d.mts +94 -1
  438. package/authoring/doctypes/template/parse.mjs +40 -2
  439. package/authoring/doctypes/template/parse.test.mjs +26 -2
  440. package/authoring/doctypes/template/template.doc.mjs +13 -3
  441. package/authoring/doctypes/template/type.ts +13 -2
  442. package/authoring/doctypes/theme/parse.d.mts +35 -0
  443. package/authoring/doctypes/theme/parse.mjs +76 -0
  444. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  445. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  446. package/authoring/doctypes/theme/type.ts +42 -0
  447. package/authoring/doctypes/types.ts +12 -10
  448. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  449. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  450. package/authoring/gap-report/parse.d.mts +10 -10
  451. package/authoring/gap-report/parse.mjs +6 -6
  452. package/authoring/gap-report/type.ts +1 -1
  453. package/authoring/identity/identity.doc.d.mts +9 -0
  454. package/authoring/identity/identity.doc.mjs +61 -0
  455. package/authoring/identity/type.ts +132 -0
  456. package/authoring/index.d.mts +3 -0
  457. package/authoring/index.d.ts +62 -17
  458. package/authoring/index.mjs +4 -1
  459. package/authoring/integration/integration.doc.mjs +22 -13
  460. package/authoring/integration/parse.d.mts +2 -2
  461. package/authoring/integration/parse.mjs +1 -1
  462. package/authoring/integration/parse.test.mjs +10 -1
  463. package/authoring/integration/schema.d.mts +6 -4
  464. package/authoring/integration/schema.mjs +9 -3
  465. package/authoring/integration/type.ts +19 -8
  466. package/authoring/shadcn/receipt.d.mts +6 -6
  467. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  468. package/clients/cli/command-load-failure.test.mjs +83 -0
  469. package/clients/cli/commands/blog.doc.mjs +1 -1
  470. package/clients/cli/commands/blog.mjs +23 -8
  471. package/clients/cli/commands/blog.test.mjs +42 -1
  472. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  473. package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
  474. package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
  475. package/clients/cli/commands/build-theme.mjs +16 -50
  476. package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
  477. package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
  478. package/clients/cli/commands/build.doc.mjs +16 -8
  479. package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
  480. package/clients/cli/commands/build.mjs +137 -114
  481. package/clients/cli/commands/build.playbook.test.mjs +75 -0
  482. package/clients/cli/commands/build.text-fields.test.mjs +81 -0
  483. package/clients/cli/commands/component/index.mjs +153 -61
  484. package/clients/cli/commands/component-batch.test.mjs +341 -0
  485. package/clients/cli/commands/component-ownership.test.mjs +92 -3
  486. package/clients/cli/commands/component-package.test.mjs +46 -0
  487. package/clients/cli/commands/component-resolution.test.mjs +21 -0
  488. package/clients/cli/commands/component.doc.mjs +28 -10
  489. package/clients/cli/commands/component.test.mjs +19 -0
  490. package/clients/cli/commands/detail-levels.test.mjs +2 -2
  491. package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
  492. package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
  493. package/clients/cli/commands/discover.doc.mjs +55 -9
  494. package/clients/cli/commands/discover.mjs +393 -118
  495. package/clients/cli/commands/discover.sources.test.mjs +267 -0
  496. package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
  497. package/clients/cli/commands/docs.doc.mjs +28 -6
  498. package/clients/cli/commands/docs.mjs +295 -38
  499. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  500. package/clients/cli/commands/doctor-integration-docs.doc.mjs +6 -5
  501. package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
  502. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  503. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  504. package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
  505. package/clients/cli/commands/doctor-integration.test.mjs +143 -8
  506. package/clients/cli/commands/doctor.doc.mjs +4 -2
  507. package/clients/cli/commands/doctor.mjs +108 -37
  508. package/clients/cli/commands/doctor.test.mjs +42 -0
  509. package/clients/cli/commands/gap-report.doc.mjs +27 -15
  510. package/clients/cli/commands/gap-report.test.mjs +72 -0
  511. package/clients/cli/commands/hook/index.mjs +7 -17
  512. package/clients/cli/commands/hook.doc.mjs +1 -1
  513. package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
  514. package/clients/cli/commands/init.doc.mjs +24 -10
  515. package/clients/cli/commands/init.flag-help.test.mjs +153 -0
  516. package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
  517. package/clients/cli/commands/integration-add.doc.mjs +39 -13
  518. package/clients/cli/commands/integration-authoring.test.mjs +74 -19
  519. package/clients/cli/commands/integration-pack.doc.mjs +6 -10
  520. package/clients/cli/commands/integration-real-world.test.mjs +4 -10
  521. package/clients/cli/commands/integration-verify.doc.mjs +22 -0
  522. package/clients/cli/commands/integration.doc.mjs +5 -5
  523. package/clients/cli/commands/integration.mjs +75 -43
  524. package/clients/cli/commands/interactive-guard.test.mjs +101 -24
  525. package/clients/cli/commands/json-contract.test.mjs +33 -0
  526. package/clients/cli/commands/layout-check.doc.mjs +15 -4
  527. package/clients/cli/commands/layout-expand.doc.mjs +22 -5
  528. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  529. package/clients/cli/commands/layout.doc.mjs +3 -3
  530. package/clients/cli/commands/layout.mjs +21 -9
  531. package/clients/cli/commands/layout.path-help.test.mjs +33 -0
  532. package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
  533. package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
  534. package/clients/cli/commands/manifest.doc.mjs +2 -2
  535. package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
  536. package/clients/cli/commands/search.doc.mjs +16 -6
  537. package/clients/cli/commands/search.mjs +49 -11
  538. package/clients/cli/commands/search.test.mjs +92 -0
  539. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  540. package/clients/cli/commands/swizzle.doc.mjs +4 -3
  541. package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
  542. package/clients/cli/commands/template.doc.mjs +53 -14
  543. package/clients/cli/commands/template.flag-help.test.mjs +117 -0
  544. package/clients/cli/commands/template.mjs +4 -91
  545. package/clients/cli/commands/template.path-help.test.mjs +40 -0
  546. package/clients/cli/commands/text-json-parity.test.mjs +725 -0
  547. package/clients/cli/commands/theme-add.doc.mjs +5 -4
  548. package/clients/cli/commands/theme-build.doc.mjs +8 -7
  549. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  550. package/clients/cli/commands/theme-palette-generate.doc.mjs +12 -7
  551. package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
  552. package/clients/cli/commands/theme-palette.doc.mjs +2 -3
  553. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  554. package/clients/cli/commands/theme-targets.doc.mjs +3 -3
  555. package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
  556. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  557. package/clients/cli/commands/theme.doc.mjs +3 -2
  558. package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
  559. package/clients/cli/commands/upgrade.doc.mjs +83 -12
  560. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  561. package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
  562. package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
  563. package/clients/cli/commands/upgrade.mjs +29 -7
  564. package/clients/cli/formatters/index.mjs +164 -1
  565. package/clients/cli/formatters/index.test.mjs +97 -0
  566. package/clients/cli/index.mjs +47 -34
  567. package/clients/cli/latest-version-env.test.mjs +50 -0
  568. package/clients/cli/lib/cli-error.test.mjs +7 -0
  569. package/clients/cli/lib/component-format.mjs +9 -9
  570. package/clients/cli/lib/component-format.test.mjs +1 -1
  571. package/clients/cli/lib/define-command.mjs +56 -6
  572. package/clients/cli/lib/define-command.test.mjs +54 -0
  573. package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
  574. package/clients/cli/lib/exit-codes.test.mjs +113 -0
  575. package/clients/cli/lib/hook-format.mjs +19 -10
  576. package/clients/cli/lib/json-shim.mjs +62 -16
  577. package/clients/cli/lib/json-shim.test.mjs +83 -0
  578. package/clients/cli/lib/manifest.d.ts +2 -0
  579. package/clients/cli/lib/manifest.mjs +53 -6
  580. package/clients/cli/lib/manifest.test.mjs +22 -2
  581. package/clients/cli/lib/parse-error-format.test.mjs +81 -0
  582. package/foundation/agent-docs/agent-docs.d.mts +7 -2
  583. package/foundation/agent-docs/agent-docs.mjs +83 -13
  584. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
  585. package/foundation/config/integration-debug.test.mjs +28 -3
  586. package/foundation/config/project-themes.test.mjs +11 -19
  587. package/foundation/config/project.d.mts +20 -11
  588. package/foundation/config/project.mjs +263 -91
  589. package/foundation/config/project.test.mjs +270 -21
  590. package/foundation/discovery/authoring-self-docs.d.mts +87 -0
  591. package/foundation/discovery/authoring-self-docs.mjs +237 -0
  592. package/foundation/discovery/authoring-self-docs.test.mjs +174 -0
  593. package/foundation/discovery/authoring-surface.d.mts +74 -0
  594. package/foundation/discovery/authoring-surface.mjs +525 -0
  595. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  596. package/foundation/discovery/cli-self-docs.d.mts +119 -0
  597. package/foundation/discovery/cli-self-docs.mjs +504 -0
  598. package/foundation/discovery/cli-self-docs.test.mjs +395 -0
  599. package/foundation/discovery/component-discovery.d.mts +39 -1
  600. package/foundation/discovery/component-discovery.mjs +50 -1
  601. package/foundation/discovery/component-loader.d.mts +35 -38
  602. package/foundation/discovery/component-loader.mjs +53 -222
  603. package/foundation/discovery/docs-discovery.d.mts +119 -11
  604. package/foundation/discovery/docs-discovery.mjs +427 -108
  605. package/foundation/discovery/docs-discovery.test.mjs +386 -20
  606. package/foundation/discovery/docs-output-budget.d.mts +28 -0
  607. package/foundation/discovery/docs-output-budget.mjs +50 -0
  608. package/foundation/discovery/docs-section-key.d.mts +116 -0
  609. package/foundation/discovery/docs-section-key.mjs +322 -0
  610. package/foundation/discovery/docs-section-key.test.mjs +246 -0
  611. package/foundation/discovery/template-adapter.d.mts +113 -11
  612. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
  613. package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
  614. package/foundation/discovery/template-adapter.mjs +774 -83
  615. package/foundation/discovery/template-adapter.test.mjs +57 -0
  616. package/foundation/discovery/template-conflict-release.d.mts +13 -0
  617. package/foundation/discovery/template-conflict-release.mjs +40 -0
  618. package/foundation/discovery/template-conflict-release.test.mjs +40 -0
  619. package/foundation/discovery/theme-discovery.d.mts +67 -7
  620. package/foundation/discovery/theme-discovery.mjs +916 -186
  621. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  622. package/foundation/discovery/theming-targets.test.mjs +4 -0
  623. package/foundation/doc-compiler/bundle.d.mts +47 -0
  624. package/foundation/doc-compiler/bundle.mjs +278 -0
  625. package/foundation/doc-compiler/bundle.test.mjs +266 -0
  626. package/foundation/doc-compiler/compile.d.mts +343 -0
  627. package/foundation/doc-compiler/compile.mjs +558 -0
  628. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  629. package/foundation/doc-compiler/diagnostics.mjs +305 -0
  630. package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
  631. package/foundation/doc-compiler/doc-loads.test.mjs +1643 -0
  632. package/foundation/doc-compiler/import.d.mts +24 -0
  633. package/foundation/doc-compiler/import.mjs +59 -0
  634. package/foundation/doc-compiler/inputs.d.mts +102 -0
  635. package/foundation/doc-compiler/inputs.mjs +291 -0
  636. package/foundation/doc-compiler/inputs.test.mjs +298 -0
  637. package/foundation/doc-compiler/ir.d.mts +22 -0
  638. package/foundation/doc-compiler/ir.mjs +471 -0
  639. package/foundation/doc-compiler/lenses.d.mts +36 -0
  640. package/foundation/doc-compiler/lenses.mjs +173 -0
  641. package/foundation/doc-compiler/links.d.mts +162 -0
  642. package/foundation/doc-compiler/links.mjs +294 -0
  643. package/foundation/doc-compiler/links.test.mjs +192 -0
  644. package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
  645. package/foundation/doc-compiler/overlays.d.mts +37 -0
  646. package/foundation/doc-compiler/overlays.mjs +206 -0
  647. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  648. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  649. package/foundation/doc-compiler/read.d.mts +127 -0
  650. package/foundation/doc-compiler/read.mjs +325 -0
  651. package/foundation/doc-compiler/read.test.mjs +313 -0
  652. package/foundation/doc-compiler/source.d.mts +33 -0
  653. package/foundation/doc-compiler/source.mjs +128 -0
  654. package/foundation/doc-compiler/tree.d.mts +292 -0
  655. package/foundation/doc-compiler/tree.mjs +881 -0
  656. package/foundation/fs/file-protection.d.mts +33 -0
  657. package/foundation/fs/file-protection.mjs +825 -0
  658. package/foundation/fs/file-protection.test.mjs +250 -0
  659. package/foundation/fs/module-loader.d.mts +1 -0
  660. package/foundation/fs/module-loader.mjs +50 -1
  661. package/foundation/fs/module-loader.stdout.test.mjs +332 -0
  662. package/foundation/fs/path-safety.d.mts +3 -2
  663. package/foundation/fs/path-safety.mjs +49 -19
  664. package/foundation/fs/path-safety.test.mjs +50 -0
  665. package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
  666. package/foundation/identity/provider-identity.d.mts +90 -0
  667. package/foundation/identity/provider-identity.mjs +320 -0
  668. package/foundation/identity/provider-identity.test.mjs +254 -0
  669. package/foundation/identity/providers.d.mts +7 -0
  670. package/foundation/identity/providers.mjs +16 -0
  671. package/foundation/integrations/autolink.d.mts +58 -1
  672. package/foundation/integrations/autolink.mjs +143 -45
  673. package/foundation/integrations/autolink.test.mjs +1 -1
  674. package/foundation/integrations/cli-requirement.d.mts +65 -0
  675. package/foundation/integrations/cli-requirement.mjs +189 -0
  676. package/foundation/integrations/cli-requirement.test.mjs +89 -0
  677. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  678. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  679. package/foundation/integrations/contribution-inventory.d.mts +3 -2
  680. package/foundation/integrations/contribution-inventory.mjs +28 -25
  681. package/foundation/integrations/contribution-inventory.test.mjs +86 -27
  682. package/foundation/integrations/integration-warnings.d.mts +9 -2
  683. package/foundation/integrations/integration-warnings.mjs +52 -21
  684. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  685. package/foundation/integrations/integrations.d.mts +63 -3
  686. package/foundation/integrations/integrations.mjs +122 -9
  687. package/foundation/integrations/integrations.test.mjs +415 -1
  688. package/foundation/integrations/provider-conflicts.test.mjs +125 -0
  689. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  690. package/foundation/integrations/provider-resolution.d.mts +152 -0
  691. package/foundation/integrations/provider-resolution.mjs +576 -0
  692. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  693. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  694. package/foundation/integrations/theme-descriptor.mjs +44 -0
  695. package/foundation/integrations/validate-contributions.d.mts +2 -0
  696. package/foundation/integrations/validate-contributions.mjs +131 -29
  697. package/foundation/response/base.d.ts +8 -4
  698. package/foundation/response/batch.type.d.mts +33 -0
  699. package/foundation/response/batch.type.mjs +34 -0
  700. package/foundation/response/error-codes.d.mts +3 -1
  701. package/foundation/response/error-codes.d.ts +2 -0
  702. package/foundation/response/error-codes.doc.mjs +19 -12
  703. package/foundation/response/error-codes.mjs +8 -2
  704. package/foundation/response/error-codes.test.mjs +166 -14
  705. package/foundation/response/json-contract.test.mjs +57 -17
  706. package/foundation/response/json.d.mts +4 -2
  707. package/foundation/response/json.mjs +8 -10
  708. package/foundation/response/response-types.doc.d.mts +7 -2
  709. package/foundation/response/response-types.doc.mjs +69 -25
  710. package/foundation/response/response-types.doc.test.mjs +181 -0
  711. package/foundation/response/response.doc.mjs +12 -11
  712. package/foundation/text/string-utils.d.mts +8 -0
  713. package/foundation/text/string-utils.mjs +40 -10
  714. package/foundation/xle/expand.d.mts +2 -0
  715. package/foundation/xle/expand.mjs +4 -3
  716. package/foundation/xle/expand.test.mjs +54 -0
  717. package/foundation/xle/xle.test.mjs +13 -0
  718. package/package.json +10 -11
  719. package/api/docs/docs.test.mjs +0 -83
  720. package/api/docs/integrationDocs.test.mjs +0 -208
  721. package/api/search/search.test.mjs +0 -389
  722. package/assets/docs/cli-integrations.doc.mjs +0 -367
  723. package/assets/templates/themes/manifest.json +0 -95
  724. package/clients/cli/commands/docs.test.mjs +0 -102
  725. package/clients/cli/lib/update-check.mjs +0 -83
  726. package/clients/cli/lib/update-check.test.mjs +0 -137
  727. package/clients/cli/update-hint-commands.test.mjs +0 -54
  728. package/foundation/agent-docs/agent-docs.test.mjs +0 -1141
@@ -1,6 +1,7 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  import {afterEach, beforeEach, describe, expect, it} from 'vitest';
4
+ import {execFileSync} from 'node:child_process';
4
5
  import * as fs from 'node:fs';
5
6
  import * as os from 'node:os';
6
7
  import * as path from 'node:path';
@@ -8,75 +9,98 @@ import {
8
9
  BUNDLED_THEME_PACKAGE,
9
10
  discoverBundledThemes,
10
11
  discoverIntegrationThemes,
11
- discoverThemeCatalog,
12
+ discoverThemeDirectory,
12
13
  } from './theme-discovery.mjs';
13
14
 
14
15
  let tmpDir;
15
16
 
16
- function writeCatalog(entries) {
17
- fs.mkdirSync(tmpDir, {recursive: true});
18
- for (const entry of entries) {
19
- const themeDir = path.join(tmpDir, entry.slug);
20
- fs.mkdirSync(themeDir, {recursive: true});
21
- for (const file of entry.files) {
22
- const target = path.join(themeDir, file);
23
- fs.mkdirSync(path.dirname(target), {recursive: true});
24
- fs.writeFileSync(target, `export const ${entry.exportName} = {};\n`);
25
- }
26
- }
17
+ /** @param {Record<string, unknown>} doc */
18
+ function descriptorSource(doc) {
19
+ return `/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */\nexport default ${JSON.stringify(doc, null, 2)};\n`;
20
+ }
21
+
22
+ /**
23
+ * @param {{slug?: string, stem?: string, extension?: string, source?: string,
24
+ * doc?: Record<string, unknown>, files?: Record<string, string>}} [options]
25
+ */
26
+ function writeTheme({
27
+ slug = 'ocean',
28
+ stem = 'oceanTheme',
29
+ extension = '.ts',
30
+ source = `export const ${stem} = {};\n`,
31
+ doc = {},
32
+ files = {},
33
+ } = {}) {
34
+ const themeDir = path.join(tmpDir, slug);
35
+ fs.mkdirSync(themeDir, {recursive: true});
36
+ fs.writeFileSync(path.join(themeDir, `${stem}${extension}`), source);
27
37
  fs.writeFileSync(
28
- path.join(tmpDir, 'manifest.json'),
29
- JSON.stringify({version: 1, themes: entries}),
38
+ path.join(themeDir, `${stem}.doc.mjs`),
39
+ descriptorSource({
40
+ type: 'theme',
41
+ name: slug,
42
+ displayName: 'Ocean',
43
+ description: 'Blue and calm.',
44
+ maintained: true,
45
+ ...doc,
46
+ }),
30
47
  );
48
+ for (const [file, contents] of Object.entries(files)) {
49
+ const target = path.join(themeDir, file);
50
+ fs.mkdirSync(path.dirname(target), {recursive: true});
51
+ fs.writeFileSync(target, contents);
52
+ }
53
+ return themeDir;
31
54
  }
32
55
 
33
- const ocean = {
34
- slug: 'ocean',
35
- displayName: 'Ocean',
36
- description: 'Blue and calm.',
37
- maintained: true,
38
- entry: 'oceanTheme.ts',
39
- exportName: 'oceanTheme',
40
- files: ['oceanTheme.ts'],
41
- };
42
-
43
56
  beforeEach(() => {
44
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-theme-catalog-'));
57
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-theme-descriptor-'));
45
58
  });
46
59
 
47
60
  afterEach(() => {
48
61
  fs.rmSync(tmpDir, {recursive: true, force: true});
49
62
  });
50
63
 
51
- describe('theme catalog discovery', () => {
52
- it('reads the existing bundled catalog with package ownership', () => {
64
+ describe('theme descriptor discovery', () => {
65
+ it('reads bundled descriptors with package ownership', () => {
53
66
  const themes = discoverBundledThemes();
54
67
  expect(themes.length).toBeGreaterThan(0);
55
68
  expect(themes.every(theme => theme.package === BUNDLED_THEME_PACKAGE)).toBe(
56
69
  true,
57
70
  );
58
71
  expect(themes.every(theme => theme.bundled)).toBe(true);
72
+ expect(
73
+ themes.filter(theme => theme.maintained).map(theme => theme.slug),
74
+ ).toEqual(['neutral']);
75
+ expect(themes.every(theme => theme.docPath.endsWith('.doc.mjs'))).toBe(
76
+ true,
77
+ );
59
78
  });
60
79
 
61
- it('reads the canonical manifest-plus-slug-directory shape', () => {
62
- writeCatalog([ocean]);
63
- expect(discoverThemeCatalog(tmpDir, '@acme/themes')).toEqual([
80
+ it('derives source entry and runtime export from the shared stem', () => {
81
+ writeTheme();
82
+ expect(discoverThemeDirectory(tmpDir, '@acme/themes')).toEqual([
64
83
  expect.objectContaining({
65
- ...ocean,
84
+ slug: 'ocean',
85
+ displayName: 'Ocean',
86
+ description: 'Blue and calm.',
87
+ maintained: true,
88
+ entry: 'oceanTheme.ts',
89
+ exportName: 'oceanTheme',
90
+ files: ['oceanTheme.ts', 'oceanTheme.doc.mjs'],
66
91
  package: '@acme/themes',
67
92
  sourceDir: path.join(tmpDir, 'ocean'),
93
+ docPath: path.join(tmpDir, 'ocean', 'oceanTheme.doc.mjs'),
68
94
  bundled: false,
69
95
  }),
70
96
  ]);
71
97
  });
72
98
 
73
- it('parses a named runtime export without executing the entry', async () => {
74
- writeCatalog([ocean]);
75
- fs.writeFileSync(
76
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
77
- "throw new Error('theme source executed');\nexport const oceanTheme = {};\n",
78
- );
79
-
99
+ it('parses source without executing it', async () => {
100
+ writeTheme({
101
+ source:
102
+ "throw new Error('theme source executed');\nexport const oceanTheme = {};\n",
103
+ });
80
104
  await expect(
81
105
  discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
82
106
  ).resolves.toEqual([
@@ -84,39 +108,50 @@ describe('theme catalog discovery', () => {
84
108
  ]);
85
109
  });
86
110
 
87
- it('rejects an entry that does not export the catalog name', async () => {
88
- writeCatalog([ocean]);
111
+ it('rejects an untyped descriptor', () => {
112
+ const themeDir = writeTheme();
89
113
  fs.writeFileSync(
90
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
91
- 'export const anotherTheme = {};\n',
114
+ path.join(themeDir, 'oceanTheme.doc.mjs'),
115
+ "export default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: '', maintained: true};\n",
92
116
  );
93
-
94
- await expect(
95
- discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
96
- ).rejects.toThrow(
97
- 'Theme catalog for @acme/themes entry "oceanTheme.ts" does not export "oceanTheme".',
117
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
118
+ /must declare its public ThemeDoc type/u,
98
119
  );
99
120
  });
100
121
 
101
- it('rejects a type-only export of the catalog name', async () => {
102
- writeCatalog([ocean]);
122
+ it('rejects a descriptor module with executable statements', () => {
123
+ const themeDir = writeTheme();
103
124
  fs.writeFileSync(
104
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
105
- 'export type oceanTheme = {};\n',
125
+ path.join(themeDir, 'oceanTheme.doc.mjs'),
126
+ `throw new Error('descriptor executed');\n${descriptorSource({
127
+ type: 'theme',
128
+ name: 'ocean',
129
+ displayName: 'Ocean',
130
+ description: 'Blue and calm.',
131
+ maintained: true,
132
+ })}`,
133
+ );
134
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
135
+ /only its static default-exported ThemeDoc object/u,
106
136
  );
137
+ });
107
138
 
139
+ it('rejects an entry that does not export its inferred runtime name', async () => {
140
+ writeTheme({source: 'export const anotherTheme = {};\n'});
108
141
  await expect(
109
142
  discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
110
143
  ).rejects.toThrow(/does not export "oceanTheme"/u);
111
144
  });
112
145
 
113
- it('rejects an unbound source-less export specifier', async () => {
114
- writeCatalog([ocean]);
115
- fs.writeFileSync(
116
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
117
- 'export {oceanTheme};\n',
118
- );
146
+ it('rejects a type-only export of its inferred runtime name', async () => {
147
+ writeTheme({source: 'export type oceanTheme = {};\n'});
148
+ await expect(
149
+ discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
150
+ ).rejects.toThrow(/does not export "oceanTheme"/u);
151
+ });
119
152
 
153
+ it('rejects an unbound source-less export specifier', async () => {
154
+ writeTheme({source: 'export {oceanTheme};\n'});
120
155
  await expect(
121
156
  discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
122
157
  ).rejects.toThrow(
@@ -125,251 +160,610 @@ describe('theme catalog discovery', () => {
125
160
  });
126
161
 
127
162
  it('accepts a source-less export backed by a local runtime declaration', async () => {
128
- writeCatalog([ocean]);
129
- fs.writeFileSync(
130
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
131
- 'const oceanTheme = {};\nexport {oceanTheme};\n',
132
- );
163
+ writeTheme({source: 'const oceanTheme = {};\nexport {oceanTheme};\n'});
164
+ await expect(
165
+ discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
166
+ ).resolves.toHaveLength(1);
167
+ });
133
168
 
169
+ it('follows imported aliases and local re-exports without execution', async () => {
170
+ writeTheme({
171
+ source:
172
+ "import {theme as oceanTheme} from './tokens/theme';\nexport {oceanTheme};\n",
173
+ files: {
174
+ 'tokens/theme.ts':
175
+ "throw new Error('nested source executed');\nexport const theme = {};\n",
176
+ },
177
+ });
134
178
  await expect(
135
179
  discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
136
180
  ).resolves.toEqual([
137
- expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
181
+ expect.objectContaining({
182
+ files: ['oceanTheme.ts', 'oceanTheme.doc.mjs', 'tokens/theme.ts'],
183
+ }),
138
184
  ]);
139
185
  });
140
186
 
141
- it('accepts a source-less export backed by a listed imported alias', async () => {
142
- writeCatalog([{...ocean, files: ['oceanTheme.ts', 'theme.ts']}]);
143
- fs.writeFileSync(
144
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
145
- "import {theme as oceanTheme} from './theme';\nexport {oceanTheme};\n",
146
- );
147
- fs.writeFileSync(
148
- path.join(tmpDir, 'ocean', 'theme.ts'),
149
- 'export const theme = {};\n',
150
- );
151
-
187
+ it('follows a default re-export', async () => {
188
+ writeTheme({
189
+ source: "export {default as oceanTheme} from './theme';\n",
190
+ files: {'theme.ts': 'export default {};\n'},
191
+ });
152
192
  await expect(
153
193
  discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
154
- ).resolves.toEqual([
155
- expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
156
- ]);
194
+ ).resolves.toHaveLength(1);
157
195
  });
158
196
 
159
- it('accepts a source-less export backed by a bare package import', async () => {
160
- writeCatalog([ocean]);
161
- fs.writeFileSync(
162
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
163
- "import {defineTheme as oceanTheme} from '@astryxdesign/core/theme';\nexport {oceanTheme};\n",
164
- );
197
+ it('follows an export-all barrel', async () => {
198
+ writeTheme({
199
+ source: "export * from './theme';\n",
200
+ files: {'theme.ts': 'export const oceanTheme = {};\n'},
201
+ });
202
+ await expect(
203
+ discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
204
+ ).resolves.toHaveLength(1);
205
+ });
165
206
 
207
+ it('accepts a runtime binding imported from a package', async () => {
208
+ writeTheme({
209
+ source:
210
+ "import {defineTheme as oceanTheme} from '@astryxdesign/core/theme';\nexport {oceanTheme};\n",
211
+ });
166
212
  await expect(
167
213
  discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
168
- ).resolves.toEqual([
169
- expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
170
- ]);
214
+ ).resolves.toHaveLength(1);
171
215
  });
172
216
 
173
- it('follows a listed default re-export', async () => {
174
- writeCatalog([{...ocean, files: ['oceanTheme.ts', 'theme.ts']}]);
175
- fs.writeFileSync(
176
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
177
- "export {default as oceanTheme} from './theme';\n",
178
- );
179
- fs.writeFileSync(
180
- path.join(tmpDir, 'ocean', 'theme.ts'),
181
- 'export default {};\n',
182
- );
217
+ it('copies unreferenced nested authoring artifacts as part of the directory', () => {
218
+ writeTheme({
219
+ files: {
220
+ 'tokens/ocean.palette.ts': 'export const palette = {};\n',
221
+ 'receipts/palette.json': '{"version":1}\n',
222
+ },
223
+ });
224
+ expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].files).toEqual([
225
+ 'oceanTheme.ts',
226
+ 'oceanTheme.doc.mjs',
227
+ 'receipts/palette.json',
228
+ 'tokens/ocean.palette.ts',
229
+ ]);
230
+ });
183
231
 
232
+ it('rejects a theme source that imports its descriptor', async () => {
233
+ writeTheme({
234
+ source:
235
+ "import metadata from './oceanTheme.doc.mjs';\nvoid metadata;\nexport const oceanTheme = {};\n",
236
+ });
184
237
  await expect(
185
238
  discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
186
- ).resolves.toEqual([
187
- expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
188
- ]);
239
+ ).rejects.toThrow(/must not import its descriptor "oceanTheme\.doc\.mjs"/u);
189
240
  });
190
241
 
191
- it('follows local export-all barrels without executing them', async () => {
192
- writeCatalog([{...ocean, files: ['oceanTheme.ts', 'theme.ts']}]);
193
- fs.writeFileSync(
194
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
195
- "export * from './theme';\n",
196
- );
242
+ it('rejects a local import outside the theme directory', async () => {
243
+ writeTheme({
244
+ source:
245
+ "import {palette} from '../outside';\nexport const oceanTheme = {palette};\n",
246
+ });
197
247
  fs.writeFileSync(
198
- path.join(tmpDir, 'ocean', 'theme.ts'),
199
- "throw new Error('theme source executed');\nexport const oceanTheme = {};\n",
248
+ path.join(tmpDir, 'outside.ts'),
249
+ 'export const palette = {};\n',
200
250
  );
201
-
202
251
  await expect(
203
252
  discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
204
- ).resolves.toEqual([
205
- expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
206
- ]);
253
+ ).rejects.toThrow(/must resolve to a file inside the theme directory/u);
207
254
  });
208
255
 
209
- it('accepts a listed nested palette import without executing it', async () => {
210
- writeCatalog([
211
- {...ocean, files: ['oceanTheme.ts', 'tokens/ocean.palette.ts']},
212
- ]);
213
- fs.writeFileSync(
214
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
215
- "import {oceanPalette} from './tokens/ocean.palette';\nexport const oceanTheme = {oceanPalette};\n",
216
- );
256
+ it('rejects a literal dynamic import outside the theme directory', async () => {
257
+ writeTheme({
258
+ extension: '.mjs',
259
+ source: "void import('../extra.mjs');\nexport const oceanTheme = {};\n",
260
+ });
217
261
  fs.writeFileSync(
218
- path.join(tmpDir, 'ocean', 'tokens', 'ocean.palette.ts'),
219
- "throw new Error('palette source executed');\nexport const oceanPalette = {};\n",
262
+ path.join(tmpDir, 'extra.mjs'),
263
+ 'export const extra = {};\n',
220
264
  );
221
-
222
265
  await expect(
223
266
  discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
224
- ).resolves.toEqual([
225
- expect.objectContaining({slug: 'ocean', exportName: 'oceanTheme'}),
226
- ]);
267
+ ).rejects.toThrow(/must resolve to a file inside the theme directory/u);
227
268
  });
228
269
 
229
- it('rejects a direct import from an unlisted theme file', async () => {
230
- writeCatalog([ocean]);
231
- fs.mkdirSync(path.join(tmpDir, 'ocean', 'tokens'), {recursive: true});
270
+ it('rejects a local re-export outside the theme directory', async () => {
271
+ writeTheme({source: "export * from '../outside';\n"});
232
272
  fs.writeFileSync(
233
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
234
- "import {oceanPalette} from './tokens/ocean.palette';\nexport const oceanTheme = {oceanPalette};\n",
235
- );
236
- fs.writeFileSync(
237
- path.join(tmpDir, 'ocean', 'tokens', 'ocean.palette.ts'),
238
- 'export const oceanPalette = {};\n',
273
+ path.join(tmpDir, 'outside.ts'),
274
+ 'export const oceanTheme = {};\n',
239
275
  );
240
-
241
276
  await expect(
242
277
  discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
243
- ).rejects.toThrow(
244
- /must resolve to a listed file inside the theme directory/u,
278
+ ).rejects.toThrow(/must resolve to a file inside the theme directory/u);
279
+ });
280
+
281
+ it('rejects the obsolete central manifest even when descriptors exist', () => {
282
+ writeTheme();
283
+ fs.writeFileSync(path.join(tmpDir, 'manifest.json'), '{"version":1}\n');
284
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
285
+ /the theme catalog Astryx 0\.6 wrote.*astryx upgrade --from 0\.6\.3 --path \. --apply/u,
245
286
  );
246
287
  });
247
288
 
248
- it('rejects a direct import outside the theme directory', async () => {
249
- writeCatalog([ocean]);
289
+ it('rejects a descriptor placed at the themes root', () => {
250
290
  fs.writeFileSync(
251
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
252
- "import {oceanPalette} from '../outside';\nexport const oceanTheme = {oceanPalette};\n",
291
+ path.join(tmpDir, 'oceanTheme.doc.mjs'),
292
+ descriptorSource({
293
+ type: 'theme',
294
+ name: 'ocean',
295
+ displayName: 'Ocean',
296
+ description: '',
297
+ maintained: true,
298
+ }),
253
299
  );
254
- fs.writeFileSync(
255
- path.join(tmpDir, 'outside.ts'),
256
- 'export const oceanPalette = {};\n',
300
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
301
+ /must be inside a lower-kebab theme directory/u,
257
302
  );
303
+ });
258
304
 
259
- await expect(
260
- discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
261
- ).rejects.toThrow(
262
- /must resolve to a listed file inside the theme directory/u,
305
+ it('rejects a missing descriptor', () => {
306
+ const dir = path.join(tmpDir, 'ocean');
307
+ fs.mkdirSync(dir);
308
+ fs.writeFileSync(
309
+ path.join(dir, 'oceanTheme.ts'),
310
+ 'export const oceanTheme = {};\n',
311
+ );
312
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
313
+ 'Theme "ocean" for @acme/themes must contain exactly one same-stem .doc.mjs descriptor; found 0 beside "oceanTheme.ts".',
263
314
  );
264
315
  });
265
316
 
266
- it('rejects a literal dynamic import from an unlisted file', async () => {
267
- const mjsTheme = {
268
- ...ocean,
269
- entry: 'oceanTheme.mjs',
270
- files: ['oceanTheme.mjs'],
271
- };
272
- writeCatalog([mjsTheme]);
317
+ it('rejects more than one descriptor', () => {
318
+ const dir = writeTheme();
273
319
  fs.writeFileSync(
274
- path.join(tmpDir, 'ocean', 'oceanTheme.mjs'),
275
- "void import('./extra.mjs');\nexport const oceanTheme = {};\n",
320
+ path.join(dir, 'other.doc.mjs'),
321
+ descriptorSource({
322
+ type: 'theme',
323
+ name: 'ocean',
324
+ displayName: 'Other',
325
+ description: '',
326
+ maintained: false,
327
+ }),
276
328
  );
277
- fs.writeFileSync(
278
- path.join(tmpDir, 'ocean', 'extra.mjs'),
279
- 'export const extra = {};\n',
329
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
330
+ 'Theme "ocean" for @acme/themes must contain exactly one same-stem .doc.mjs descriptor; found 2: "oceanTheme.doc.mjs", "other.doc.mjs".',
280
331
  );
332
+ });
281
333
 
282
- await expect(
283
- discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
284
- ).rejects.toThrow(
285
- /must resolve to a listed file inside the theme directory/u,
334
+ it('rejects missing and ambiguous same-stem source files', () => {
335
+ const dir = writeTheme();
336
+ fs.rmSync(path.join(dir, 'oceanTheme.ts'));
337
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
338
+ /exactly one same-stem source.*found 0/u,
286
339
  );
287
- });
288
340
 
289
- it('rejects a re-export outside the theme directory', async () => {
290
- writeCatalog([ocean]);
291
341
  fs.writeFileSync(
292
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
293
- "export * from '../outside';\n",
342
+ path.join(dir, 'oceanTheme.ts'),
343
+ 'export const oceanTheme = {};\n',
294
344
  );
295
345
  fs.writeFileSync(
296
- path.join(tmpDir, 'outside.ts'),
346
+ path.join(dir, 'oceanTheme.mjs'),
297
347
  'export const oceanTheme = {};\n',
298
348
  );
349
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
350
+ /exactly one same-stem source.*found 2/u,
351
+ );
352
+ });
299
353
 
300
- await expect(
301
- discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
302
- ).rejects.toThrow(
303
- /must resolve to a listed file inside the theme directory/u,
354
+ it('rejects descriptor identity that differs from its directory', () => {
355
+ writeTheme({doc: {name: 'sea'}});
356
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
357
+ 'Theme descriptor oceanTheme.doc.mjs for @acme/themes names "sea" but its directory is "ocean".',
304
358
  );
305
359
  });
306
360
 
307
- it('rejects a re-export from an unlisted theme file', async () => {
308
- writeCatalog([ocean]);
309
- fs.writeFileSync(
310
- path.join(tmpDir, 'ocean', 'oceanTheme.ts'),
311
- "export * from './theme';\n",
361
+ it('rejects malformed descriptor fields and unknown catalog-era fields', () => {
362
+ writeTheme({doc: {maintained: 'yes'}});
363
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
364
+ /maintained/u,
312
365
  );
313
- fs.writeFileSync(
314
- path.join(tmpDir, 'ocean', 'theme.ts'),
315
- 'export const oceanTheme = {};\n',
366
+
367
+ fs.rmSync(path.join(tmpDir, 'ocean'), {recursive: true});
368
+ writeTheme({doc: {entry: 'oceanTheme.ts'}});
369
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
370
+ /unrecognized key|entry/iu,
371
+ );
372
+ });
373
+
374
+ it('rejects invalid theme directory and source stem names', () => {
375
+ writeTheme({slug: 'Ocean'});
376
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
377
+ /invalid directory/u,
316
378
  );
317
379
 
318
- await expect(
319
- discoverIntegrationThemes({name: '@acme/themes', themes: tmpDir}),
320
- ).rejects.toThrow(
321
- /must resolve to a listed file inside the theme directory/u,
380
+ fs.rmSync(path.join(tmpDir, 'Ocean'), {recursive: true});
381
+ writeTheme({stem: 'ocean-theme'});
382
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
383
+ /not a valid runtime export name/u,
322
384
  );
323
385
  });
324
386
 
325
- it('rejects duplicate slugs case-insensitively', () => {
326
- writeCatalog([ocean, {...ocean, slug: 'OCEAN'}]);
327
- expect(() => discoverThemeCatalog(tmpDir, '@acme/themes')).toThrow(
328
- /invalid slug|duplicate slug/u,
387
+ it('rejects symlinks inside the copy boundary', () => {
388
+ const dir = writeTheme();
389
+ const outside = path.join(tmpDir, 'outside.json');
390
+ fs.writeFileSync(outside, '{}\n');
391
+ fs.symlinkSync(outside, path.join(dir, 'outside.json'));
392
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
393
+ 'Theme "ocean" for @acme/themes contains symlink "outside.json"; theme files must be regular files inside the theme directory.',
329
394
  );
330
395
  });
396
+ });
331
397
 
332
- it('rejects files that escape the theme directory', () => {
333
- fs.mkdirSync(path.join(tmpDir, 'ocean'), {recursive: true});
334
- fs.writeFileSync(
335
- path.join(tmpDir, 'outside.ts'),
336
- 'export const oceanTheme = {};\n',
398
+ const TYPE = "/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */";
399
+ const BODY =
400
+ "{type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Blue and calm.', maintained: true}";
401
+
402
+ /** @param {string} source the whole descriptor file */
403
+ function writeDescriptor(source) {
404
+ const dir = writeTheme();
405
+ fs.writeFileSync(path.join(dir, 'oceanTheme.doc.mjs'), source);
406
+ }
407
+
408
+ describe('theme descriptor type annotation', () => {
409
+ it.each([
410
+ ['the annotation on the export', `${TYPE}\nexport default ${BODY};\n`],
411
+ [
412
+ 'a header comment above the annotation',
413
+ `// Copyright (c) Meta Platforms, Inc. and affiliates.\n\n${TYPE}\nexport default ${BODY};\n`,
414
+ ],
415
+ [
416
+ 'a multi-line JSDoc block',
417
+ `/**\n * Ocean.\n *\n * @type {import("@astryxdesign/cli/authoring").ThemeDoc}\n */\nexport default ${BODY};\n`,
418
+ ],
419
+ [
420
+ 'a typedef alias',
421
+ `/** @typedef {import('@astryxdesign/cli/authoring').ThemeDoc} ThemeDoc */\n\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
422
+ ],
423
+ [
424
+ 'a typedef alias declared after the export',
425
+ `/** @type {Doc} */\nexport default ${BODY};\n/** @typedef {import('@astryxdesign/cli/authoring').ThemeDoc} Doc */\n`,
426
+ ],
427
+ [
428
+ 'an @import of the type',
429
+ `/** @import {ThemeDoc} from '@astryxdesign/cli/authoring' */\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
430
+ ],
431
+ [
432
+ 'a renamed @import',
433
+ `/** @import {ComponentDoc, ThemeDoc as Doc} from '@astryxdesign/cli/authoring' */\n/** @type {Doc} */\nexport default ${BODY};\n`,
434
+ ],
435
+ [
436
+ 'a namespace @import',
437
+ `/** @import * as authoring from '@astryxdesign/cli/authoring' */\n/** @type {authoring.ThemeDoc} */\nexport default ${BODY};\n`,
438
+ ],
439
+ ['a JSDoc cast of the object', `export default ${TYPE} (${BODY});\n`],
440
+ [
441
+ 'a JSDoc cast inside outer parentheses',
442
+ `export default (${TYPE} (${BODY}));\n`,
443
+ ],
444
+ [
445
+ 'a @satisfies cast',
446
+ `export default ${TYPE.replace('@type', '@satisfies')} (${BODY});\n`,
447
+ ],
448
+ ...['!T', '?T', 'T=', '(T)', 'T | null', 'undefined | T', 'T & {}'].map(
449
+ form => [
450
+ `the type written {${form}}`,
451
+ `/** @type {${form.replace('T', "import('@astryxdesign/cli/authoring').ThemeDoc")}} */\nexport default ${BODY};\n`,
452
+ ],
453
+ ),
454
+ [
455
+ 'an @import with a type modifier',
456
+ `/** @import {type ThemeDoc} from '@astryxdesign/cli/authoring' */\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
457
+ ],
458
+ [
459
+ 'a chain of typedef aliases',
460
+ `/** @typedef {import('@astryxdesign/cli/authoring').ThemeDoc} A */\n/** @typedef {A} B */\n/** @type {B} */\nexport default ${BODY};\n`,
461
+ ],
462
+ ])('accepts %s', (_, source) => {
463
+ writeDescriptor(source);
464
+ expect(discoverThemeDirectory(tmpDir, '@acme/themes')).toHaveLength(1);
465
+ });
466
+
467
+ it.each([
468
+ ['a line comment', `// ${TYPE.slice(4, -3)}\nexport default ${BODY};\n`],
469
+ [
470
+ 'a block comment that is not JSDoc',
471
+ `/* ${TYPE.slice(4, -3)} */\nexport default ${BODY};\n`,
472
+ ],
473
+ ['an annotation after the export', `export default ${BODY};\n${TYPE}\n`],
474
+ [
475
+ 'an annotation inside a string value',
476
+ `export default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: "${TYPE.slice(4, -3)}", maintained: true};\n`,
477
+ ],
478
+ [
479
+ 'an annotation on a property',
480
+ `export default {\n ${TYPE}\n type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Blue.', maintained: true};\n`,
481
+ ],
482
+ [
483
+ 'an unparenthesized inline annotation',
484
+ `export default ${TYPE} ${BODY};\n`,
485
+ ],
486
+ [
487
+ 'an annotation inside the parentheses',
488
+ `export default (${TYPE} ${BODY});\n`,
489
+ ],
490
+ [
491
+ 'a later JSDoc between the annotation and the export',
492
+ `${TYPE}\n/** Ocean. */\nexport default ${BODY};\n`,
493
+ ],
494
+ [
495
+ 'a typedef written as a line comment',
496
+ `// @typedef {import('@astryxdesign/cli/authoring').ThemeDoc} ThemeDoc\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
497
+ ],
498
+ [
499
+ 'an alias of another public type',
500
+ `/** @typedef {import('@astryxdesign/cli/authoring').ComponentDoc} ThemeDoc */\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
501
+ ],
502
+ [
503
+ 'a ThemeDoc from another module',
504
+ `/** @type {import('@astryxdesign/core').ThemeDoc} */\nexport default ${BODY};\n`,
505
+ ],
506
+ [
507
+ 'a type in a code span before the real @type {object}',
508
+ `/** Not \`${TYPE.slice(4, -3)}\` here. @type {object} */\nexport default ${BODY};\n`,
509
+ ],
510
+ [
511
+ 'a typedef in a code span',
512
+ `/** Declare \`@typedef {import('@astryxdesign/cli/authoring').ThemeDoc} TD\` first. */\n/** @type {TD} */\nexport default ${BODY};\n`,
513
+ ],
514
+ [
515
+ 'a type in a code span of a tag',
516
+ `/**\n * @see \` ${TYPE.slice(4, -3)}\` here\n */\nexport default ${BODY};\n`,
517
+ ],
518
+ [
519
+ '@import type {...}, which is not @import syntax',
520
+ `/** @import type {ThemeDoc} from '@astryxdesign/cli/authoring' */\n/** @type {ThemeDoc} */\nexport default ${BODY};\n`,
521
+ ],
522
+ [
523
+ '@satisfies on the export statement',
524
+ `${TYPE.replace('@type', '@satisfies')}\nexport default ${BODY};\n`,
525
+ ],
526
+ [
527
+ 'an annotation before default, not before the parenthesis',
528
+ `export ${TYPE} default (${BODY});\n`,
529
+ ],
530
+ [
531
+ 'a union with another type',
532
+ `/** @type {import('@astryxdesign/cli/authoring').ThemeDoc | string} */\nexport default ${BODY};\n`,
533
+ ],
534
+ ])('rejects %s', (_, source) => {
535
+ writeDescriptor(source);
536
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
537
+ 'Theme descriptor oceanTheme.doc.mjs for @acme/themes must declare its public ThemeDoc type from @astryxdesign/cli/authoring.',
538
+ );
539
+ });
540
+ });
541
+
542
+ describe('theme descriptor values', () => {
543
+ it.each([
544
+ ['displayName', {displayName: ' '}],
545
+ ['name', {name: ' '}],
546
+ ])('rejects a blank %s', (field, doc) => {
547
+ writeTheme({doc});
548
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
549
+ `Theme descriptor oceanTheme.doc.mjs for @acme/themes is invalid: ${field}: ${field} must not be blank`,
550
+ );
551
+ });
552
+
553
+ it.each(['', ' '])('accepts a blank description (%j)', description => {
554
+ writeTheme({doc: {description}});
555
+ expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].description).toBe(
556
+ description,
557
+ );
558
+ });
559
+
560
+ it.each(['__proto__', "'__proto__'", 'extra'])(
561
+ 'rejects the unknown key %s',
562
+ key => {
563
+ writeDescriptor(
564
+ `${TYPE}\nexport default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Blue.', maintained: true, ${key}: 'x'};\n`,
565
+ );
566
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
567
+ `Theme descriptor oceanTheme.doc.mjs for @acme/themes is invalid: (root): Unrecognized key: "${key.replaceAll("'", '')}"`,
568
+ );
569
+ },
570
+ );
571
+
572
+ it('rejects a BigInt where a string belongs', () => {
573
+ writeDescriptor(
574
+ `${TYPE}\nexport default {type: 'theme', name: 'ocean', displayName: 10n, description: 'Blue.', maintained: true};\n`,
575
+ );
576
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
577
+ /must use static string and boolean values/u,
337
578
  );
579
+ });
580
+
581
+ it('reuses a read while the file keeps its size and mtime', () => {
582
+ const dir = writeTheme();
583
+ const file = path.join(dir, 'oceanTheme.doc.mjs');
584
+ const pinned = new Date('2020-01-01T00:00:00Z');
585
+ fs.utimesSync(file, pinned, pinned);
586
+ expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].displayName).toBe(
587
+ 'Ocean',
588
+ );
589
+
338
590
  fs.writeFileSync(
339
- path.join(tmpDir, 'manifest.json'),
340
- JSON.stringify({
341
- version: 1,
342
- themes: [
343
- {
344
- ...ocean,
345
- entry: '../outside.ts',
346
- files: ['../outside.ts'],
347
- },
348
- ],
349
- }),
591
+ file,
592
+ fs.readFileSync(file, 'utf-8').replace('"Ocean"', '"Coral"'),
593
+ );
594
+ fs.utimesSync(file, pinned, pinned);
595
+ expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].displayName).toBe(
596
+ 'Ocean',
350
597
  );
351
- expect(() => discoverThemeCatalog(tmpDir, '@acme/themes')).toThrow(
352
- /must stay inside/u,
598
+
599
+ const later = new Date('2020-01-01T00:00:01Z');
600
+ fs.utimesSync(file, later, later);
601
+ expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].displayName).toBe(
602
+ 'Coral',
353
603
  );
354
604
  });
605
+ });
355
606
 
356
- it('rejects a missing catalog file and a missing listed source', () => {
357
- expect(() => discoverThemeCatalog(tmpDir, '@acme/themes')).toThrow(
358
- /must contain manifest\.json/u,
607
+ describe('theme folder messages', () => {
608
+ it('names the package and file of a symlinked descriptor', () => {
609
+ const dir = path.join(tmpDir, 'ocean');
610
+ fs.mkdirSync(dir);
611
+ fs.writeFileSync(
612
+ path.join(dir, 'oceanTheme.ts'),
613
+ 'export const oceanTheme = {};\n',
359
614
  );
615
+ const elsewhere = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-linked-'));
616
+ try {
617
+ const target = path.join(elsewhere, 'oceanTheme.doc.mjs');
618
+ fs.writeFileSync(target, `${TYPE}\nexport default ${BODY};\n`);
619
+ fs.symlinkSync(target, path.join(dir, 'oceanTheme.doc.mjs'));
620
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
621
+ 'Theme "ocean" for @acme/themes contains symlink "oceanTheme.doc.mjs"; theme files must be regular files inside the theme directory.',
622
+ );
623
+ } finally {
624
+ fs.rmSync(elsewhere, {recursive: true, force: true});
625
+ }
626
+ });
627
+
628
+ it('names the package and both files of a nested second descriptor', () => {
629
+ writeTheme({
630
+ files: {'extra/otherTheme.doc.mjs': `${TYPE}\nexport default ${BODY};\n`},
631
+ });
632
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
633
+ 'Theme "ocean" for @acme/themes contains more than one .doc.mjs descriptor: "oceanTheme.doc.mjs" and "extra/otherTheme.doc.mjs".',
634
+ );
635
+ });
636
+ });
637
+
638
+ const UNPUBLISHED = [
639
+ '.DS_Store',
640
+ '._oceanTheme.ts',
641
+ '.gitignore',
642
+ '.npmignore',
643
+ '.npmrc',
644
+ 'oceanTheme.ts.orig',
645
+ 'npm-debug.log',
646
+ 'palette/.DS_Store',
647
+ 'palette/npm-debug.log',
648
+ '.git/HEAD',
649
+ 'CVS/Entries',
650
+ 'node_modules/dep/index.js',
651
+ ];
652
+
653
+ describe('files a theme leaves out', () => {
654
+ it('leaves out dot entries and files npm never publishes, at any depth', () => {
655
+ const dir = writeTheme({files: {'palette/tokens.ts': 'export {};\n'}});
656
+ for (const file of UNPUBLISHED) {
657
+ fs.mkdirSync(path.dirname(path.join(dir, file)), {recursive: true});
658
+ fs.writeFileSync(path.join(dir, file), 'x\n');
659
+ }
660
+ fs.symlinkSync(path.join(dir, 'palette'), path.join(dir, '.linked'));
661
+ fs.mkdirSync(path.join(tmpDir, 'node_modules', 'dep'), {recursive: true});
662
+ fs.writeFileSync(path.join(tmpDir, 'npm-debug.log'), 'x\n');
663
+ expect(discoverThemeDirectory(tmpDir, '@acme/themes')[0].files).toEqual([
664
+ 'oceanTheme.ts',
665
+ 'oceanTheme.doc.mjs',
666
+ 'palette/tokens.ts',
667
+ ]);
668
+ });
669
+ });
670
+
671
+ describe('folders under a theme root that are not themes', () => {
672
+ it('skips dot-folders and folders with neither a descriptor nor a theme source', () => {
673
+ writeTheme();
674
+ const stray = {
675
+ 'shared/palette.ts': 'export const blue = "#00f";\n',
676
+ '.cache/state.json': '{}\n',
677
+ '.cache/stateTheme.ts': 'export const stateTheme = {};\n',
678
+ '__tests__/oceanTheme.test.ts': 'export {};\n',
679
+ 'Shared_Helpers/colors.ts': 'export const red = "#f00";\n',
680
+ };
681
+ for (const [file, contents] of Object.entries(stray)) {
682
+ fs.mkdirSync(path.dirname(path.join(tmpDir, file)), {recursive: true});
683
+ fs.writeFileSync(path.join(tmpDir, file), contents);
684
+ }
685
+ fs.mkdirSync(path.join(tmpDir, 'empty'));
686
+ fs.symlinkSync(path.join(tmpDir, 'shared'), path.join(tmpDir, '.linked'));
687
+ expect(
688
+ discoverThemeDirectory(tmpDir, '@acme/themes').map(theme => theme.slug),
689
+ ).toEqual(['ocean']);
690
+ });
691
+
692
+ it('still fails a folder with a theme source and no descriptor', () => {
693
+ writeTheme();
694
+ fs.mkdirSync(path.join(tmpDir, 'sand'));
360
695
  fs.writeFileSync(
361
- path.join(tmpDir, 'manifest.json'),
362
- JSON.stringify({version: 1, themes: [ocean]}),
696
+ path.join(tmpDir, 'sand', 'sandTheme.ts'),
697
+ 'export const sandTheme = {};\n',
363
698
  );
364
- expect(() => discoverThemeCatalog(tmpDir, '@acme/themes')).toThrow(
365
- /missing directory "ocean"/u,
699
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
700
+ 'Theme "sand" for @acme/themes must contain exactly one same-stem .doc.mjs descriptor; found 0 beside "sandTheme.ts".',
701
+ );
702
+ });
703
+
704
+ it('still fails a folder whose descriptor sits in a subfolder', () => {
705
+ writeTheme({slug: 'reef', stem: 'reefTheme', doc: {name: 'reef'}});
706
+ fs.mkdirSync(path.join(tmpDir, 'reef', 'src'));
707
+ for (const file of ['reefTheme.ts', 'reefTheme.doc.mjs']) {
708
+ fs.renameSync(
709
+ path.join(tmpDir, 'reef', file),
710
+ path.join(tmpDir, 'reef', 'src', file),
711
+ );
712
+ }
713
+ expect(() => discoverThemeDirectory(tmpDir, '@acme/themes')).toThrow(
714
+ 'Theme "reef" for @acme/themes must contain exactly one same-stem .doc.mjs descriptor; found 0; "src/reefTheme.doc.mjs" is in a subfolder.',
366
715
  );
367
716
  });
717
+ });
368
718
 
369
- it('requires the named entry to be one of the copied files', () => {
370
- writeCatalog([{...ocean, files: ['other.ts']}]);
371
- expect(() => discoverThemeCatalog(tmpDir, '@acme/themes')).toThrow(
372
- /must include entry/u,
719
+ describe('bundled theme files', () => {
720
+ it('copies what the bundle has always copied, entry first, without its descriptor', () => {
721
+ const themes = discoverBundledThemes();
722
+ expect(themes.find(theme => theme.slug === 'neutral')?.files).toEqual([
723
+ 'neutralTheme.ts',
724
+ 'icons.tsx',
725
+ 'neutralPalettes.ts',
726
+ 'neutralPalettes.generated.ts',
727
+ 'neutralPaletteRefs.generated.ts',
728
+ 'neutralPalettes.generated.receipt.json',
729
+ 'palette.config.json',
730
+ ]);
731
+ for (const theme of themes) {
732
+ expect(theme.files[0]).toBe(theme.entry);
733
+ expect(theme.files.some(file => file.endsWith('.doc.mjs'))).toBe(false);
734
+ }
735
+ });
736
+
737
+ it('passes the full source check it skips at runtime', () => {
738
+ const bundled = discoverBundledThemes();
739
+ const checked = discoverThemeDirectory(
740
+ path.dirname(bundled[0].sourceDir),
741
+ BUNDLED_THEME_PACKAGE,
742
+ );
743
+ expect(checked.map(theme => theme.slug)).toEqual(
744
+ bundled.map(theme => theme.slug),
373
745
  );
374
746
  });
747
+
748
+ it('loads no parser on import and only the descriptor parser for bundled themes', () => {
749
+ const script = `
750
+ import {createRequire} from 'node:module';
751
+ const cache = createRequire(import.meta.url).cache;
752
+ const loaded = name => Object.keys(cache).some(file => file.includes('/node_modules/' + name + '/'));
753
+ const state = () => ({babel: loaded('@babel/parser'), jscodeshift: loaded('jscodeshift')});
754
+ const discovery = await import(${JSON.stringify(new URL('./theme-discovery.mjs', import.meta.url).href)});
755
+ const imported = state();
756
+ discovery.discoverBundledThemes();
757
+ console.log(JSON.stringify({imported, bundled: state()}));
758
+ `;
759
+ const output = execFileSync(
760
+ process.execPath,
761
+ ['--input-type=module', '-e', script],
762
+ {encoding: 'utf-8'},
763
+ );
764
+ expect(JSON.parse(output)).toEqual({
765
+ imported: {babel: false, jscodeshift: false},
766
+ bundled: {babel: true, jscodeshift: false},
767
+ });
768
+ });
375
769
  });