@astryxdesign/cli 0.6.3-canary.98a2e4e → 0.6.3-canary.9dbb6c1

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 (466) hide show
  1. package/README.md +106 -73
  2. package/api/blog/blog.doc.mjs +1 -0
  3. package/api/build/build.doc.mjs +4 -3
  4. package/api/build/build.test.mjs +14 -3
  5. package/api/build/build.type.d.mts +36 -2
  6. package/api/build/build.type.mjs +25 -4
  7. package/api/build/help/help.d.mts +8 -5
  8. package/api/build/help/help.mjs +56 -6
  9. package/api/component/component.doc.mjs +13 -3
  10. package/api/component/component.mjs +31 -2
  11. package/api/component/component.test.mjs +38 -0
  12. package/api/component/component.type.d.mts +22 -11
  13. package/api/component/component.type.mjs +32 -24
  14. package/api/component/detail/blocks/blocks.d.mts +2 -1
  15. package/api/component/detail/blocks/blocks.mjs +4 -3
  16. package/api/component/list/list.d.mts +0 -5
  17. package/api/component/list/list.mjs +37 -9
  18. package/api/discover/discover.doc.mjs +2 -1
  19. package/api/discover/discover.type.d.mts +4 -4
  20. package/api/discover/discover.type.mjs +10 -10
  21. package/api/docs/_adapter.d.mts +28 -30
  22. package/api/docs/_adapter.mjs +73 -135
  23. package/api/docs/compiled-topics.test.mjs +78 -0
  24. package/api/docs/detail/detail.d.mts +0 -15
  25. package/api/docs/detail/detail.mjs +14 -78
  26. package/api/docs/detail/section/section.mjs +22 -18
  27. package/api/docs/detail/section/section.test.mjs +4 -3
  28. package/api/docs/docs.doc.mjs +1 -0
  29. package/api/docs/docs.type.d.mts +4 -4
  30. package/api/docs/docs.type.mjs +10 -10
  31. package/api/docs/index/index.mjs +6 -5
  32. package/api/docs/list/list.mjs +3 -7
  33. package/api/doctor/doctor.d.mts +25 -3
  34. package/api/doctor/doctor.doc.mjs +1 -0
  35. package/api/doctor/doctor.mjs +186 -18
  36. package/api/doctor/doctor.test.mjs +326 -1
  37. package/api/gap-report/gap-report.doc.mjs +8 -4
  38. package/api/hook/_adapter.mjs +19 -5
  39. package/api/hook/hook.doc.mjs +1 -0
  40. package/api/hook/hook.type.d.mts +3 -3
  41. package/api/hook/hook.type.mjs +11 -11
  42. package/api/hook/list/list.d.mts +1 -1
  43. package/api/hook/list/list.mjs +69 -17
  44. package/api/init/init.doc.mjs +5 -0
  45. package/api/init/init.test.mjs +41 -1
  46. package/api/init/remove/remove.mjs +1 -1
  47. package/api/init/run/run.mjs +20 -10
  48. package/api/integration/add-contribution.component-names.test.mjs +120 -0
  49. package/api/integration/add-contribution.mjs +23 -10
  50. package/api/integration/add-contribution.test.mjs +121 -7
  51. package/api/integration/add-theme.mjs +34 -64
  52. package/api/integration/add-theme.test.mjs +105 -21
  53. package/api/integration/authoring-checks.test.mjs +8 -4
  54. package/api/integration/integration-block-exports.test.mjs +10 -6
  55. package/api/integration/integrationAdd.doc.mjs +8 -4
  56. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  57. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  58. package/api/integration/integrationAddComponent.doc.mjs +2 -1
  59. package/api/integration/integrationAddDoc.doc.mjs +1 -0
  60. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  61. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  62. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  63. package/api/integration/integrationDocConflicts.doc.mjs +1 -0
  64. package/api/integration/integrationPackCheck.doc.mjs +1 -0
  65. package/api/integration/integrationTemplateConflicts.doc.mjs +1 -0
  66. package/api/integration/pack-check.mjs +49 -7
  67. package/api/integration/pack-check.test.mjs +266 -47
  68. package/api/integration/summarizeIssues.doc.mjs +1 -0
  69. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  70. package/api/integration/validate-integration.mjs +52 -102
  71. package/api/integration/validate-integration.test.mjs +176 -23
  72. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  73. package/api/integration/validateIntegration.doc.mjs +2 -1
  74. package/api/json/assertResponse.doc.mjs +1 -0
  75. package/api/json/envelope-types.test.mjs +76 -0
  76. package/api/json/isError.doc.mjs +1 -0
  77. package/api/json/parseResponse.doc.mjs +3 -2
  78. package/api/layout/expand/expand.mjs +7 -5
  79. package/api/layout/expand/expand.path-safety.test.mjs +53 -0
  80. package/api/layout/grammar/grammar.mjs +2 -1
  81. package/api/layout/layoutCheck.doc.mjs +1 -0
  82. package/api/layout/layoutExpand.doc.mjs +2 -1
  83. package/api/layout/layoutGrammar.doc.mjs +1 -0
  84. package/api/search/search-return-type.test.mjs +54 -0
  85. package/api/search/search.d.mts +2 -9
  86. package/api/search/search.doc.mjs +6 -1
  87. package/api/search/search.mjs +31 -14
  88. package/api/search/search.test.mjs +34 -0
  89. package/api/search/search.type.d.mts +1 -1
  90. package/api/search/search.type.mjs +1 -1
  91. package/api/swizzle/copy/copy.mjs +28 -11
  92. package/api/swizzle/swizzle.doc.mjs +2 -1
  93. package/api/swizzle/swizzle.type.d.mts +2 -2
  94. package/api/swizzle/swizzle.type.mjs +2 -2
  95. package/api/template/copy/copy.mjs +17 -23
  96. package/api/template/copy/copy.test.mjs +17 -0
  97. package/api/template/template-suffix.test.mjs +41 -21
  98. package/api/template/template.doc.mjs +3 -1
  99. package/api/template/template.type.d.mts +5 -5
  100. package/api/template/template.type.mjs +12 -12
  101. package/api/theme/_adapter.d.mts +2 -3
  102. package/api/theme/_adapter.mjs +4 -5
  103. package/api/theme/add/add.binary.test.mjs +84 -0
  104. package/api/theme/add/add.mjs +20 -3
  105. package/api/theme/add/add.staging.test.mjs +66 -0
  106. package/api/theme/add/add.test.mjs +14 -1
  107. package/api/theme/build/build.mjs +133 -42
  108. package/api/theme/build/build.public-component-vars.test.mjs +1 -1
  109. package/api/theme/build/build.receipt-doc.test.mjs +111 -0
  110. package/api/theme/build/build.test.mjs +127 -0
  111. package/api/theme/build/font-warning.mjs +3 -3
  112. package/api/theme/build/font-warning.test.mjs +5 -2
  113. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  114. package/api/theme/integration-themes.test.mjs +39 -28
  115. package/api/theme/list/list.test.mjs +19 -20
  116. package/api/theme/listThemes.doc.mjs +6 -5
  117. package/api/theme/palette/generate/generate.mjs +8 -3
  118. package/api/theme/palette/generate/generate.test.mjs +96 -0
  119. package/api/theme/palette/generate/generator.d.mts +10 -13
  120. package/api/theme/palette/generate/generator.mjs +15 -4
  121. package/api/theme/palette/generate/generator.test.mjs +10 -0
  122. package/api/theme/template/template.mjs +11 -2
  123. package/api/theme/template/template.test.mjs +15 -0
  124. package/api/theme/theme.type.d.mts +170 -11
  125. package/api/theme/theme.type.mjs +94 -27
  126. package/api/theme/themeAdd.doc.mjs +4 -3
  127. package/api/theme/themeBuild.doc.mjs +8 -4
  128. package/api/theme/themeList.doc.mjs +6 -3
  129. package/api/theme/themeListAvailable.doc.mjs +5 -3
  130. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  131. package/api/theme/themeTargets.doc.mjs +1 -0
  132. package/api/theme/themeTemplate.doc.mjs +5 -1
  133. package/api/upgrade/_adapter.d.mts +12 -3
  134. package/api/upgrade/_adapter.mjs +108 -70
  135. package/api/upgrade/list/list.mjs +2 -1
  136. package/api/upgrade/list/list.test.mjs +73 -0
  137. package/api/upgrade/provider-agreement.test.mjs +152 -0
  138. package/api/upgrade/run/run.mjs +1 -0
  139. package/api/upgrade/status/status.mjs +2 -2
  140. package/api/upgrade/upgrade.doc.mjs +3 -1
  141. package/api/upgrade/upgrade.type.d.mts +8 -4
  142. package/api/upgrade/upgrade.type.mjs +11 -10
  143. package/assets/codemods/integration-discovery.mjs +48 -4
  144. package/assets/codemods/integration-discovery.test.mjs +73 -0
  145. package/assets/codemods/runner.mjs +115 -5
  146. package/assets/codemods/term-log.mjs +32 -8
  147. package/assets/codemods/term-log.test.mjs +19 -1
  148. package/assets/codemods/transform-prop.mjs +109 -0
  149. package/assets/codemods/transform-prop.test.mjs +95 -0
  150. package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +216 -0
  151. package/assets/codemods/transforms/next/index.mjs +11 -1
  152. package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
  153. package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
  154. package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
  155. package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
  156. package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
  157. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  158. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  159. package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
  160. package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
  161. package/assets/docs/cli-integrations.doc.mjs +26 -30
  162. package/assets/docs/cli.doc.mjs +15 -0
  163. package/assets/docs/styling-libraries.doc.mjs +1 -1
  164. package/assets/docs/theme.doc.mjs +1 -1
  165. package/assets/docs/working-with-ai.doc.mjs +1 -1
  166. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
  167. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
  168. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
  169. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
  170. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
  171. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
  172. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
  173. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
  174. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
  175. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
  176. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
  177. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
  178. package/assets/templates/pages/table-tree/page.tsx +1704 -0
  179. package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
  180. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  181. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  182. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  183. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  184. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  185. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  186. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  187. package/authoring/_shared/contract.ts +22 -0
  188. package/authoring/codemod/codemod.doc.mjs +7 -2
  189. package/authoring/codemod/parse.d.mts +8 -8
  190. package/authoring/codemod/parse.mjs +8 -6
  191. package/authoring/config/config.doc.mjs +2 -2
  192. package/authoring/config/debug-composition.test.mjs +92 -0
  193. package/authoring/config/parse.d.mts +13 -13
  194. package/authoring/config/parse.mjs +8 -8
  195. package/authoring/config/type.ts +18 -6
  196. package/authoring/debug/debug.doc.d.mts +11 -0
  197. package/authoring/debug/debug.doc.mjs +182 -0
  198. package/authoring/debug/parse.d.mts +4 -4
  199. package/authoring/debug/parse.mjs +3 -3
  200. package/authoring/doctypes/_schema.d.mts +121 -11
  201. package/authoring/doctypes/_schema.mjs +144 -13
  202. package/authoring/doctypes/base/graph-fields.doc.mjs +11 -4
  203. package/authoring/doctypes/base/type.ts +8 -4
  204. package/authoring/doctypes/command/command.doc.mjs +4 -3
  205. package/authoring/doctypes/command/parse.d.mts +2 -2
  206. package/authoring/doctypes/command/parse.mjs +1 -1
  207. package/authoring/doctypes/command/type.ts +3 -3
  208. package/authoring/doctypes/component/component.doc.mjs +5 -2
  209. package/authoring/doctypes/component/parse.d.mts +2 -2
  210. package/authoring/doctypes/component/parse.mjs +1 -1
  211. package/authoring/doctypes/component/type.ts +3 -3
  212. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  213. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  214. package/authoring/doctypes/enum/parse.d.mts +2 -2
  215. package/authoring/doctypes/enum/parse.mjs +1 -1
  216. package/authoring/doctypes/enum/type.ts +2 -2
  217. package/authoring/doctypes/function/function.doc.mjs +5 -1
  218. package/authoring/doctypes/function/parse.d.mts +2 -2
  219. package/authoring/doctypes/function/parse.mjs +1 -1
  220. package/authoring/doctypes/function/type.ts +2 -2
  221. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  222. package/authoring/doctypes/hook/parse.d.mts +2 -2
  223. package/authoring/doctypes/hook/parse.mjs +1 -1
  224. package/authoring/doctypes/hook/type.ts +3 -3
  225. package/authoring/doctypes/legacy.d.mts +6 -6
  226. package/authoring/doctypes/legacy.mjs +3 -3
  227. package/authoring/doctypes/load-contract.test.mjs +208 -0
  228. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -3
  229. package/authoring/doctypes/namespace/parse.d.mts +2 -2
  230. package/authoring/doctypes/namespace/parse.mjs +1 -1
  231. package/authoring/doctypes/namespace/type.ts +2 -2
  232. package/authoring/doctypes/parse.d.mts +22 -20
  233. package/authoring/doctypes/parse.mjs +16 -12
  234. package/authoring/doctypes/reference/parse.d.mts +2 -2
  235. package/authoring/doctypes/reference/parse.mjs +1 -1
  236. package/authoring/doctypes/reference/reference.doc.mjs +7 -3
  237. package/authoring/doctypes/reference/type.ts +3 -3
  238. package/authoring/doctypes/schema/parse.d.mts +2 -2
  239. package/authoring/doctypes/schema/parse.mjs +1 -1
  240. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  241. package/authoring/doctypes/schema/type.ts +3 -4
  242. package/authoring/doctypes/template/parse.d.mts +92 -1
  243. package/authoring/doctypes/template/parse.mjs +33 -1
  244. package/authoring/doctypes/template/template.doc.mjs +7 -3
  245. package/authoring/doctypes/template/type.ts +4 -1
  246. package/authoring/doctypes/theme/parse.d.mts +35 -0
  247. package/authoring/doctypes/theme/parse.mjs +76 -0
  248. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  249. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  250. package/authoring/doctypes/theme/type.ts +42 -0
  251. package/authoring/doctypes/types.ts +12 -11
  252. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  253. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  254. package/authoring/gap-report/parse.d.mts +9 -9
  255. package/authoring/gap-report/parse.mjs +6 -6
  256. package/authoring/gap-report/type.ts +1 -1
  257. package/authoring/identity/identity.doc.mjs +3 -2
  258. package/authoring/identity/type.ts +10 -10
  259. package/authoring/index.d.mts +1 -0
  260. package/authoring/index.d.ts +21 -19
  261. package/authoring/index.mjs +2 -1
  262. package/authoring/integration/integration.doc.mjs +2 -2
  263. package/authoring/integration/parse.d.mts +2 -2
  264. package/authoring/integration/parse.mjs +1 -1
  265. package/authoring/integration/schema.d.mts +4 -4
  266. package/authoring/integration/schema.mjs +3 -3
  267. package/authoring/integration/type.ts +4 -10
  268. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  269. package/clients/cli/command-load-failure.test.mjs +83 -0
  270. package/clients/cli/commands/blog.doc.mjs +1 -1
  271. package/clients/cli/commands/blog.mjs +23 -8
  272. package/clients/cli/commands/blog.test.mjs +42 -1
  273. package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
  274. package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
  275. package/clients/cli/commands/build-theme.mjs +5 -5
  276. package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
  277. package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
  278. package/clients/cli/commands/build.doc.mjs +5 -2
  279. package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
  280. package/clients/cli/commands/build.mjs +32 -47
  281. package/clients/cli/commands/build.playbook.test.mjs +75 -0
  282. package/clients/cli/commands/build.text-fields.test.mjs +40 -0
  283. package/clients/cli/commands/component/index.mjs +2 -7
  284. package/clients/cli/commands/component-package.test.mjs +46 -0
  285. package/clients/cli/commands/component-resolution.test.mjs +21 -0
  286. package/clients/cli/commands/component.doc.mjs +1 -1
  287. package/clients/cli/commands/component.test.mjs +19 -0
  288. package/clients/cli/commands/detail-levels.test.mjs +2 -2
  289. package/clients/cli/commands/discover.broken-integration.test.mjs +48 -0
  290. package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
  291. package/clients/cli/commands/discover.doc.mjs +5 -3
  292. package/clients/cli/commands/discover.mjs +3 -3
  293. package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
  294. package/clients/cli/commands/docs.doc.mjs +1 -1
  295. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  296. package/clients/cli/commands/doctor-integration-docs.doc.mjs +1 -1
  297. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -1
  298. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  299. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  300. package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
  301. package/clients/cli/commands/doctor-integration.test.mjs +15 -7
  302. package/clients/cli/commands/doctor.doc.mjs +1 -1
  303. package/clients/cli/commands/doctor.mjs +6 -16
  304. package/clients/cli/commands/doctor.test.mjs +42 -0
  305. package/clients/cli/commands/gap-report.doc.mjs +17 -6
  306. package/clients/cli/commands/gap-report.test.mjs +72 -0
  307. package/clients/cli/commands/hook/index.mjs +7 -17
  308. package/clients/cli/commands/hook.doc.mjs +1 -1
  309. package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
  310. package/clients/cli/commands/init.doc.mjs +20 -9
  311. package/clients/cli/commands/init.flag-help.test.mjs +153 -0
  312. package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
  313. package/clients/cli/commands/integration-add.doc.mjs +22 -6
  314. package/clients/cli/commands/integration-authoring.test.mjs +13 -9
  315. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  316. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  317. package/clients/cli/commands/integration.doc.mjs +1 -1
  318. package/clients/cli/commands/interactive-guard.test.mjs +101 -24
  319. package/clients/cli/commands/json-contract.test.mjs +33 -0
  320. package/clients/cli/commands/layout-check.doc.mjs +15 -4
  321. package/clients/cli/commands/layout-expand.doc.mjs +22 -5
  322. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  323. package/clients/cli/commands/layout.doc.mjs +3 -3
  324. package/clients/cli/commands/layout.mjs +21 -9
  325. package/clients/cli/commands/layout.path-help.test.mjs +33 -0
  326. package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
  327. package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
  328. package/clients/cli/commands/manifest.doc.mjs +1 -1
  329. package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
  330. package/clients/cli/commands/search.doc.mjs +7 -4
  331. package/clients/cli/commands/search.mjs +17 -7
  332. package/clients/cli/commands/search.test.mjs +75 -0
  333. package/clients/cli/commands/swizzle.doc.mjs +3 -2
  334. package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
  335. package/clients/cli/commands/template.doc.mjs +29 -7
  336. package/clients/cli/commands/template.flag-help.test.mjs +117 -0
  337. package/clients/cli/commands/template.path-help.test.mjs +40 -0
  338. package/clients/cli/commands/theme-add.doc.mjs +4 -3
  339. package/clients/cli/commands/theme-build.doc.mjs +8 -7
  340. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  341. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -3
  342. package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
  343. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  344. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  345. package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
  346. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  347. package/clients/cli/commands/theme.doc.mjs +1 -1
  348. package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
  349. package/clients/cli/commands/upgrade.doc.mjs +18 -7
  350. package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
  351. package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
  352. package/clients/cli/index.mjs +13 -30
  353. package/clients/cli/latest-version-env.test.mjs +50 -0
  354. package/clients/cli/lib/cli-error.test.mjs +7 -0
  355. package/clients/cli/lib/component-format.mjs +9 -9
  356. package/clients/cli/lib/component-format.test.mjs +1 -1
  357. package/clients/cli/lib/define-command.mjs +32 -6
  358. package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
  359. package/clients/cli/lib/exit-codes.test.mjs +97 -0
  360. package/clients/cli/lib/hook-format.mjs +19 -10
  361. package/clients/cli/lib/json-shim.mjs +38 -2
  362. package/clients/cli/lib/json-shim.test.mjs +83 -0
  363. package/clients/cli/lib/manifest.d.ts +2 -0
  364. package/clients/cli/lib/manifest.mjs +22 -0
  365. package/clients/cli/lib/manifest.test.mjs +17 -0
  366. package/foundation/agent-docs/agent-docs.d.mts +4 -0
  367. package/foundation/agent-docs/agent-docs.mjs +69 -3
  368. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
  369. package/foundation/config/integration-debug.test.mjs +28 -3
  370. package/foundation/config/project-themes.test.mjs +11 -19
  371. package/foundation/config/project.d.mts +8 -0
  372. package/foundation/config/project.mjs +173 -30
  373. package/foundation/config/project.test.mjs +129 -16
  374. package/foundation/discovery/authoring-self-docs.d.mts +6 -0
  375. package/foundation/discovery/authoring-self-docs.mjs +17 -7
  376. package/foundation/discovery/authoring-self-docs.test.mjs +71 -12
  377. package/foundation/discovery/authoring-surface.d.mts +74 -0
  378. package/foundation/discovery/authoring-surface.mjs +525 -0
  379. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  380. package/foundation/discovery/cli-self-docs.d.mts +113 -0
  381. package/foundation/discovery/cli-self-docs.mjs +514 -0
  382. package/foundation/discovery/cli-self-docs.test.mjs +437 -0
  383. package/foundation/discovery/component-loader.d.mts +35 -38
  384. package/foundation/discovery/component-loader.mjs +53 -222
  385. package/foundation/discovery/docs-discovery.d.mts +7 -2
  386. package/foundation/discovery/docs-discovery.mjs +24 -14
  387. package/foundation/discovery/docs-discovery.test.mjs +55 -16
  388. package/foundation/discovery/template-adapter.d.mts +21 -5
  389. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
  390. package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
  391. package/foundation/discovery/template-adapter.mjs +319 -65
  392. package/foundation/discovery/template-adapter.test.mjs +15 -0
  393. package/foundation/discovery/theme-discovery.d.mts +67 -7
  394. package/foundation/discovery/theme-discovery.mjs +916 -186
  395. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  396. package/foundation/discovery/theming-targets.test.mjs +4 -0
  397. package/foundation/doc-compiler/bundle.d.mts +47 -0
  398. package/foundation/doc-compiler/bundle.mjs +218 -0
  399. package/foundation/doc-compiler/bundle.test.mjs +255 -0
  400. package/foundation/doc-compiler/compile.d.mts +362 -0
  401. package/foundation/doc-compiler/compile.mjs +511 -0
  402. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  403. package/foundation/doc-compiler/diagnostics.mjs +277 -0
  404. package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
  405. package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
  406. package/foundation/doc-compiler/import.d.mts +24 -0
  407. package/foundation/doc-compiler/import.mjs +59 -0
  408. package/foundation/doc-compiler/inputs.d.mts +102 -0
  409. package/foundation/doc-compiler/inputs.mjs +286 -0
  410. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  411. package/foundation/doc-compiler/ir.d.mts +22 -0
  412. package/foundation/doc-compiler/ir.mjs +464 -0
  413. package/foundation/doc-compiler/lenses.d.mts +33 -0
  414. package/foundation/doc-compiler/lenses.mjs +127 -0
  415. package/foundation/doc-compiler/lower-doc.test.mjs +492 -0
  416. package/foundation/doc-compiler/overlays.d.mts +37 -0
  417. package/foundation/doc-compiler/overlays.mjs +206 -0
  418. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  419. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  420. package/foundation/doc-compiler/read.d.mts +126 -0
  421. package/foundation/doc-compiler/read.mjs +320 -0
  422. package/foundation/doc-compiler/read.test.mjs +313 -0
  423. package/foundation/doc-compiler/source.d.mts +33 -0
  424. package/foundation/doc-compiler/source.mjs +128 -0
  425. package/foundation/fs/module-loader.d.mts +1 -0
  426. package/foundation/fs/module-loader.mjs +50 -1
  427. package/foundation/fs/module-loader.stdout.test.mjs +332 -0
  428. package/foundation/fs/path-safety.d.mts +3 -2
  429. package/foundation/fs/path-safety.mjs +49 -19
  430. package/foundation/fs/path-safety.test.mjs +50 -0
  431. package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
  432. package/foundation/integrations/autolink.d.mts +58 -1
  433. package/foundation/integrations/autolink.mjs +143 -52
  434. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  435. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  436. package/foundation/integrations/contribution-inventory.d.mts +1 -1
  437. package/foundation/integrations/contribution-inventory.mjs +17 -20
  438. package/foundation/integrations/contribution-inventory.test.mjs +67 -27
  439. package/foundation/integrations/integrations.d.mts +3 -0
  440. package/foundation/integrations/integrations.mjs +11 -97
  441. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  442. package/foundation/integrations/provider-resolution.d.mts +152 -0
  443. package/foundation/integrations/provider-resolution.mjs +576 -0
  444. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  445. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  446. package/foundation/integrations/theme-descriptor.mjs +44 -0
  447. package/foundation/integrations/validate-contributions.mjs +104 -10
  448. package/foundation/response/base.d.ts +8 -4
  449. package/foundation/response/error-codes.doc.mjs +3 -4
  450. package/foundation/response/error-codes.mjs +2 -2
  451. package/foundation/response/error-codes.test.mjs +83 -0
  452. package/foundation/response/json-contract.test.mjs +11 -0
  453. package/foundation/response/json.d.mts +4 -2
  454. package/foundation/response/json.mjs +8 -10
  455. package/foundation/response/response-types.doc.mjs +11 -11
  456. package/foundation/response/response-types.doc.test.mjs +158 -0
  457. package/foundation/response/response.doc.mjs +1 -1
  458. package/foundation/text/string-utils.mjs +22 -10
  459. package/foundation/xle/expand.d.mts +2 -0
  460. package/foundation/xle/expand.mjs +3 -2
  461. package/foundation/xle/expand.test.mjs +54 -0
  462. package/package.json +9 -11
  463. package/assets/templates/themes/manifest.json +0 -95
  464. package/clients/cli/lib/update-check.mjs +0 -83
  465. package/clients/cli/lib/update-check.test.mjs +0 -137
  466. package/clients/cli/update-hint-commands.test.mjs +0 -54
@@ -15,7 +15,9 @@
15
15
  * async). It does what loadConfig did — find the config sibling-of
16
16
  * package.json, import + validate it, load the configured integrations —
17
17
  * plus autolink the installed ones no config names, and self-resolve the
18
- * package being authored when it carries a manifest. Discovery is LAZY.
18
+ * package being authored when it carries a manifest. Provider identity is
19
+ * resolved once over all three (see integrations/provider-resolution), and
20
+ * the ledger is kept for {@link providerLedgerOf}. Discovery is LAZY.
19
21
  * - Discovery methods (components/templates/codemods/docs/themes) are MEMOIZED per
20
22
  * instance (via the pluggable cache) and orchestrate the EXISTING discovery
21
23
  * functions — Project never reimplements discovery.
@@ -38,9 +40,10 @@ import {parseConfig} from '../../authoring/config/parse.mjs';
38
40
  import {
39
41
  loadIntegrations,
40
42
  loadLocalIntegration,
41
- markProviderConflicts,
43
+ resolvePackageDir,
42
44
  } from '../integrations/integrations.mjs';
43
- import {autolinkIntegrations} from '../integrations/autolink.mjs';
45
+ import {loadAutolinkCandidates} from '../integrations/autolink.mjs';
46
+ import {resolveProviders} from '../integrations/provider-resolution.mjs';
44
47
  import {
45
48
  setProject as setDebugProject,
46
49
  setEventHandler as setDebugEventHandler,
@@ -95,6 +98,118 @@ function errorMessage(err) {
95
98
  return message == null ? String(err) : String(message);
96
99
  }
97
100
 
101
+ /**
102
+ * Load the configured integrations one at a time, so a package that cannot
103
+ * load at all (not installed, no manifest, more than one manifest, not a bare
104
+ * name) becomes that entry's load-error marker instead of failing the project.
105
+ * @param {string[]} specs
106
+ * @param {{cwd: string, fresh: boolean}} options
107
+ * @returns {Promise<import('../integrations/integrations.mjs').LoadedIntegration[]>}
108
+ */
109
+ async function loadConfiguredIntegrations(specs, {cwd, fresh}) {
110
+ /** @type {import('../integrations/integrations.mjs').LoadedIntegration[]} */
111
+ const loaded = [];
112
+ const seen = new Set();
113
+ for (const spec of specs) {
114
+ if (!spec || seen.has(spec)) continue;
115
+ seen.add(spec);
116
+ try {
117
+ loaded.push(
118
+ ...(await loadIntegrations([spec], {
119
+ cwd,
120
+ fresh,
121
+ resolveProviders: false,
122
+ })),
123
+ );
124
+ } catch (err) {
125
+ /** @type {string|undefined} */
126
+ let packageDir;
127
+ try {
128
+ packageDir = resolvePackageDir(spec, cwd);
129
+ } catch {
130
+ // Not a bare package name: there is no install location to record.
131
+ }
132
+ const pkg = packageDir ? readPackageJson(packageDir) : null;
133
+ loaded.push(
134
+ loadErrorMarker({
135
+ name: packageName(pkg) ?? spec,
136
+ version: pkg?.version,
137
+ spec,
138
+ packageDir,
139
+ err,
140
+ }),
141
+ );
142
+ }
143
+ }
144
+ return loaded;
145
+ }
146
+
147
+ /**
148
+ * Resolve the package being authored. Every failure, including an unreadable
149
+ * package.json or more than one manifest, becomes its load-error marker.
150
+ * @param {string} projectDir
151
+ * @param {boolean} fresh
152
+ * @returns {Promise<import('../integrations/integrations.mjs').LoadedIntegration|null>}
153
+ */
154
+ async function loadLocalIntegrationSafely(projectDir, fresh) {
155
+ try {
156
+ return await loadLocalIntegration(projectDir, {fresh});
157
+ } catch (err) {
158
+ const pkg = readPackageJson(projectDir);
159
+ const name = packageName(pkg) ?? '(local integration)';
160
+ return {
161
+ ...loadErrorMarker({
162
+ name,
163
+ version: pkg?.version,
164
+ spec: name,
165
+ packageDir: projectDir,
166
+ err,
167
+ }),
168
+ __local: true,
169
+ };
170
+ }
171
+ }
172
+
173
+ /**
174
+ * An inert entry for an integration that could not be loaded. It contributes
175
+ * nothing; Project reports its `__loadError` as the package's issue.
176
+ * @param {{name: string, version?: unknown, spec: string, packageDir?: string, err: unknown}} input
177
+ * @returns {import('../integrations/integrations.mjs').LoadedIntegration}
178
+ */
179
+ function loadErrorMarker({name, version, spec, packageDir, err}) {
180
+ return /** @type {import('../integrations/integrations.mjs').LoadedIntegration} */ ({
181
+ name,
182
+ ...(typeof version === 'string' ? {version} : {}),
183
+ __spec: spec,
184
+ ...(packageDir ? {__packageDir: packageDir} : {}),
185
+ __loadError: errorMessage(err),
186
+ });
187
+ }
188
+
189
+ /**
190
+ * @param {Record<string, unknown>|null} pkg
191
+ * @returns {string|undefined}
192
+ */
193
+ function packageName(pkg) {
194
+ const name = pkg?.name;
195
+ return typeof name === 'string' && name.length > 0 ? name : undefined;
196
+ }
197
+
198
+ /**
199
+ * @param {string} dir
200
+ * @returns {Record<string, unknown>|null}
201
+ */
202
+ function readPackageJson(dir) {
203
+ try {
204
+ const pkg = JSON.parse(
205
+ fs.readFileSync(path.join(dir, 'package.json'), 'utf-8'),
206
+ );
207
+ return pkg && typeof pkg === 'object' ? pkg : null;
208
+ } catch {
209
+ return null;
210
+ }
211
+ }
212
+
98
213
  /**
99
214
  * An integration issue tagged with the owner package. The base
100
215
  * {@link import('../integrations/issue').AstryxIntegrationIssue} fields plus the
@@ -147,13 +262,15 @@ function findPackageRoot(startDir) {
147
262
  *
148
263
  * This governs INHERITED handlers only. A project's own `debug` always runs.
149
264
  *
150
- * @param {string|null} configPath
265
+ * Read from the project root whether or not an astryx.config exists: an
266
+ * autolinked integration contributes a handler with no config at all.
267
+ *
268
+ * @param {string} projectDir directory holding the project's package.json
151
269
  * @returns {boolean}
152
270
  */
153
- function inheritsIntegrationDebug(configPath) {
154
- if (!configPath) return true;
271
+ function inheritsIntegrationDebug(projectDir) {
155
272
  try {
156
- const pkgPath = path.join(path.dirname(configPath), 'package.json');
273
+ const pkgPath = path.join(projectDir, 'package.json');
157
274
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
158
275
  return pkg?.astryx?.inheritDebug !== false;
159
276
  } catch {
@@ -182,6 +299,24 @@ export function findConfigPath(startDir = process.cwd()) {
182
299
  return present.length === 1 ? present[0] : null;
183
300
  }
184
301
 
302
+ /**
303
+ * The provider ledger each loaded Project resolved, kept off the class so it
304
+ * is not part of the Project API.
305
+ * @type {WeakMap<Project, import('../integrations/provider-resolution.mjs').ProviderLedger>}
306
+ */
307
+ const PROVIDER_LEDGERS = new WeakMap();
308
+
309
+ /**
310
+ * The provider ledger a Project resolved at load: one outcome for every
311
+ * package directory configured, autolinked, or authored. Internal: upgrade
312
+ * resolves on top of it, and tests account for every candidate with it.
313
+ * @param {Project} project
314
+ * @returns {import('../integrations/provider-resolution.mjs').ProviderLedger}
315
+ */
316
+ export function providerLedgerOf(project) {
317
+ return PROVIDER_LEDGERS.get(project) ?? new Map();
318
+ }
319
+
185
320
  /**
186
321
  * The single API for reading resolved project configuration. Construct via the
187
322
  * async {@link Project.load} factory.
@@ -276,11 +411,10 @@ export class Project {
276
411
  fresh,
277
412
  });
278
413
  integrations = config.integrations ?? [];
279
- loadedIntegrations = await loadIntegrations(integrations, {
414
+ // Provider identity is resolved once, below, over the final set.
415
+ loadedIntegrations = await loadConfiguredIntegrations(integrations, {
280
416
  cwd: projectDir,
281
417
  fresh,
282
- // Provider identity is resolved once, below, over the final set.
283
- resolveProviders: false,
284
418
  });
285
419
  }
286
420
 
@@ -288,35 +422,42 @@ export class Project {
288
422
  // This runs whether or not a config exists, because the projects it reaches
289
423
  // are overwhelmingly the ones with no astryx.config at all: a scaffold adds
290
424
  // the dependency and writes no config, and the integration then contributes
291
- // nothing for want of a line nobody knew to write. Appended AFTER the
425
+ // nothing for want of a line nobody knew to write. Resolved AFTER the
292
426
  // configured ones so an explicit entry keeps its position and its
293
427
  // precedence in every discovery order.
294
- loadedIntegrations = [
295
- ...loadedIntegrations,
296
- ...(await autolinkIntegrations({
297
- projectDir,
298
- loaded: loadedIntegrations,
299
- fresh,
300
- })),
301
- ];
428
+ const autolinked = await loadAutolinkCandidates({
429
+ projectDir,
430
+ loaded: loadedIntegrations,
431
+ fresh,
432
+ });
302
433
 
303
434
  // The package being authored is the one package that cannot install itself.
304
435
  // When it carries a manifest, resolve its working bytes directly so every
305
436
  // existing consumer command doubles as the author's preview. A local copy
306
437
  // replaces the same installed package in place, preserving configured
307
438
  // precedence while making the source being edited authoritative.
308
- const localIntegration = await loadLocalIntegration(projectDir, {fresh});
309
- if (localIntegration) {
310
- const existing = loadedIntegrations.findIndex(
311
- integration => integration.name === localIntegration.name,
312
- );
313
- if (existing === -1) loadedIntegrations.push(localIntegration);
314
- else loadedIntegrations[existing] = localIntegration;
315
- }
439
+ const localIntegration = await loadLocalIntegrationSafely(projectDir, fresh);
316
440
 
317
441
  // Autolinked and local packages can claim a provider ID that a configured
318
442
  // package already holds, so identity is resolved once over the final set.
319
- loadedIntegrations = markProviderConflicts(loadedIntegrations);
443
+ const resolution = resolveProviders([
444
+ ...loadedIntegrations.map(integration => ({
445
+ source: /** @type {const} */ ('configured'),
446
+ integration,
447
+ spec: integration.__spec,
448
+ })),
449
+ ...autolinked,
450
+ ...(localIntegration
451
+ ? [
452
+ {
453
+ source: /** @type {const} */ ('local'),
454
+ integration: localIntegration,
455
+ spec: localIntegration.__spec,
456
+ },
457
+ ]
458
+ : []),
459
+ ]);
460
+ loadedIntegrations = resolution.integrations;
320
461
 
321
462
  // The debug recorder resolves its settings synchronously, long before any
322
463
  // command gets here, so this is where a project's `debug` block gets a
@@ -335,7 +476,7 @@ export class Project {
335
476
  // because Project.load can run more than once in a process and appending
336
477
  // would deliver twice.
337
478
  setDebugIntegrationEventHandlers(
338
- inheritsIntegrationDebug(configPath)
479
+ inheritsIntegrationDebug(projectDir)
339
480
  ? loadedIntegrations.map(integration => integration.__debug)
340
481
  : [],
341
482
  );
@@ -347,7 +488,7 @@ export class Project {
347
488
  // Never let recording break config loading.
348
489
  }
349
490
 
350
- return new Project({
491
+ const project = new Project({
351
492
  cwd,
352
493
  configPath,
353
494
  config,
@@ -356,6 +497,8 @@ export class Project {
356
497
  cache: resolvedCache,
357
498
  hash,
358
499
  });
500
+ PROVIDER_LEDGERS.set(project, resolution.ledger);
501
+ return project;
359
502
  }
360
503
 
361
504
  /**
@@ -163,7 +163,7 @@ function scaffoldLocalPackage({name = '@acme/local'} = {}) {
163
163
 
164
164
  fs.mkdirSync(path.join(tmpDir, 'templates'));
165
165
  fs.writeFileSync(
166
- path.join(tmpDir, 'templates', 'local-page.template.mjs'),
166
+ path.join(tmpDir, 'templates', 'local-page.doc.mjs'),
167
167
  `export default {type: 'page', name: 'Local page', description: 'Local page.'};\n`,
168
168
  );
169
169
  fs.writeFileSync(
@@ -181,21 +181,8 @@ function scaffoldLocalPackage({name = '@acme/local'} = {}) {
181
181
 
182
182
  fs.mkdirSync(path.join(tmpDir, 'themes', 'ocean'), {recursive: true});
183
183
  fs.writeFileSync(
184
- path.join(tmpDir, 'themes', 'manifest.json'),
185
- JSON.stringify({
186
- version: 1,
187
- themes: [
188
- {
189
- slug: 'ocean',
190
- displayName: 'Ocean',
191
- description: 'Ocean theme.',
192
- maintained: true,
193
- entry: 'oceanTheme.ts',
194
- exportName: 'oceanTheme',
195
- files: ['oceanTheme.ts'],
196
- },
197
- ],
198
- }),
184
+ path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.doc.mjs'),
185
+ `/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */\nexport default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Ocean theme.', maintained: true};\n`,
199
186
  );
200
187
  fs.writeFileSync(
201
188
  path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.ts'),
@@ -515,6 +502,132 @@ describe('Project issues (skip + warn)', () => {
515
502
  });
516
503
  });
517
504
 
505
+ describe('Project loads each integration in isolation', () => {
506
+ /**
507
+ * Install a package under node_modules with the given root files.
508
+ * @param {string} name
509
+ * @param {string[]} manifests manifest basenames to write
510
+ */
511
+ function installPackage(name, manifests) {
512
+ const dir = path.join(tmpDir, 'node_modules', ...name.split('/'));
513
+ fs.mkdirSync(dir, {recursive: true});
514
+ fs.writeFileSync(
515
+ path.join(dir, 'package.json'),
516
+ JSON.stringify({name, version: '1.0.0'}),
517
+ );
518
+ for (const file of manifests) {
519
+ fs.writeFileSync(path.join(dir, file), 'export default {};\n');
520
+ }
521
+ }
522
+
523
+ /** @param {string[]} integrations */
524
+ function writeConfig(integrations) {
525
+ fs.writeFileSync(
526
+ path.join(tmpDir, 'astryx.config.mjs'),
527
+ `export default ${JSON.stringify({integrations})};\n`,
528
+ );
529
+ }
530
+
531
+ /** @param {Project} project */
532
+ async function widgetComponents(project) {
533
+ return (await project.components())
534
+ .filter(component => component.package === '@acme/widgets')
535
+ .map(component => component.name);
536
+ }
537
+
538
+ it.each([
539
+ ['is not installed', '@acme/broken', () => {}, /Install it first/],
540
+ [
541
+ 'has no root manifest',
542
+ '@acme/broken',
543
+ () => installPackage('@acme/broken', []),
544
+ /no conventional root manifest/,
545
+ ],
546
+ [
547
+ 'has two root manifests',
548
+ '@acme/broken',
549
+ () =>
550
+ installPackage('@acme/broken', [
551
+ 'astryx.integration.mjs',
552
+ 'astryx.integration.js',
553
+ ]),
554
+ /multiple root manifests/,
555
+ ],
556
+ [
557
+ 'is not a bare package name',
558
+ '../escape',
559
+ () => {},
560
+ /Invalid integration package name/,
561
+ ],
562
+ ])(
563
+ 'keeps the others when a configured package %s',
564
+ async (_label, spec, install, message) => {
565
+ scaffold();
566
+ install();
567
+ writeConfig([spec, '@acme/widgets']);
568
+
569
+ const project = await Project.load(tmpDir);
570
+
571
+ expect(await widgetComponents(project)).toEqual(['Widget']);
572
+ expect(await project.issues()).toContainEqual(
573
+ expect.objectContaining({
574
+ package: spec,
575
+ code: 'integration_error',
576
+ message: expect.stringMatching(message),
577
+ }),
578
+ );
579
+ },
580
+ );
581
+
582
+ it('keeps configured integrations when the package being authored has two root manifests', async () => {
583
+ scaffold();
584
+ fs.writeFileSync(
585
+ path.join(tmpDir, 'package.json'),
586
+ JSON.stringify({name: '@acme/local', version: '1.0.0'}),
587
+ );
588
+ fs.writeFileSync(
589
+ path.join(tmpDir, 'astryx.integration.mjs'),
590
+ 'export default {};\n',
591
+ );
592
+ fs.writeFileSync(
593
+ path.join(tmpDir, 'astryx.integration.js'),
594
+ 'export default {};\n',
595
+ );
596
+
597
+ const project = await Project.load(tmpDir);
598
+
599
+ expect(await widgetComponents(project)).toEqual(['Widget']);
600
+ expect(await project.issues()).toContainEqual(
601
+ expect.objectContaining({
602
+ package: '@acme/local',
603
+ code: 'integration_error',
604
+ message: expect.stringMatching(/multiple root manifests/),
605
+ }),
606
+ );
607
+ });
608
+
609
+ it('puts the package being authored at its configured position when the config names it', async () => {
610
+ scaffold();
611
+ scaffoldLocalPackage({name: '@acme/local'});
612
+ writeConfig(['@acme/local', '@acme/widgets']);
613
+
614
+ const project = await Project.load(tmpDir);
615
+
616
+ expect(
617
+ project.loadedIntegrations.map(integration => [
618
+ integration.name,
619
+ Boolean(integration.__local),
620
+ ]),
621
+ ).toEqual([
622
+ ['@acme/local', true],
623
+ ['@acme/widgets', false],
624
+ ]);
625
+ expect(await project.issues()).not.toContainEqual(
626
+ expect.objectContaining({package: '@acme/local', code: 'integration_error'}),
627
+ );
628
+ });
629
+ });
630
+
518
631
  describe('Project.issuesUrl routing', () => {
519
632
  it('routes core to config.issuesUrl, falling back to the default', async () => {
520
633
  scaffold({issuesUrl: 'https://example.com/core'});
@@ -24,6 +24,12 @@ export function loadAuthoringSelfDocs(sources?: string[], root?: string): Promis
24
24
  error: string;
25
25
  }[];
26
26
  }>;
27
+ /**
28
+ * One self-doc as a topic section, keyed by the doc's own name.
29
+ * @param {any} doc
30
+ * @returns {import('../../authoring/doctypes/reference/type').ReferenceSection}
31
+ */
32
+ export function selfDocSection(doc: any): import("../../authoring/doctypes/reference/type").ReferenceSection;
27
33
  /**
28
34
  * The `authoring` topic: one section per self-doc, in the order given.
29
35
  * @param {any[]} docs
@@ -17,8 +17,8 @@
17
17
 
18
18
  import * as fs from 'node:fs';
19
19
  import * as path from 'node:path';
20
- import {pathToFileURL} from 'node:url';
21
20
  import {CLI_ROOT} from '../fs/paths.mjs';
21
+ import {readDocView} from '../doc-compiler/read.mjs';
22
22
  import {
23
23
  DOC_OUTPUT_BUDGET_BYTES,
24
24
  oversizedDocSections,
@@ -31,6 +31,8 @@ export const AUTHORING_ROOT = path.join(CLI_ROOT, 'authoring');
31
31
  export const AUTHORING_SELF_DOCS = [
32
32
  'integration/integration.doc.mjs',
33
33
  'config/config.doc.mjs',
34
+ 'debug/debug.doc.mjs',
35
+ 'gap-report/gap-report.doc.mjs',
34
36
  'codemod/codemod.doc.mjs',
35
37
  'identity/identity.doc.mjs',
36
38
  'doctypes/base/graph-fields.doc.mjs',
@@ -43,6 +45,7 @@ export const AUTHORING_SELF_DOCS = [
43
45
  'doctypes/reference/reference.doc.mjs',
44
46
  'doctypes/schema/schema.doc.mjs',
45
47
  'doctypes/template/template.doc.mjs',
48
+ 'doctypes/theme/theme.doc.mjs',
46
49
  ];
47
50
 
48
51
  /** Blocks a self-doc note may carry that a topic section can render. */
@@ -59,7 +62,8 @@ export function discoverAuthoringSelfDocSources(root = AUTHORING_ROOT) {
59
62
  /** @param {string} dir */
60
63
  const walk = dir => {
61
64
  for (const entry of fs.readdirSync(dir, {withFileTypes: true})) {
62
- if (entry.name === 'node_modules' || entry.name.startsWith('__')) continue;
65
+ if (entry.name === 'node_modules' || entry.name.startsWith('__'))
66
+ continue;
63
67
  const full = path.join(dir, entry.name);
64
68
  if (entry.isDirectory()) walk(full);
65
69
  else if (entry.name.endsWith('.doc.mjs')) {
@@ -86,9 +90,14 @@ export async function loadAuthoringSelfDocs(
86
90
  const failed = [];
87
91
  for (const source of sources) {
88
92
  try {
89
- const mod = await import(pathToFileURL(path.join(root, source)).href);
90
- const doc = mod.doc ?? mod.docs ?? mod.default;
91
- if (typeof doc?.name !== 'string' || typeof doc?.description !== 'string') {
93
+ const doc = await readDocView(path.join(root, source), {
94
+ root: 'self-docs',
95
+ loader: 'native',
96
+ });
97
+ if (
98
+ typeof doc?.name !== 'string' ||
99
+ typeof doc?.description !== 'string'
100
+ ) {
92
101
  throw new Error('exports no doc with a name and a description');
93
102
  }
94
103
  loaded.push({source, doc});
@@ -129,7 +138,7 @@ function fieldRows(fields) {
129
138
  * @param {any} doc
130
139
  * @returns {import('../../authoring/doctypes/reference/type').ReferenceSection}
131
140
  */
132
- function selfDocSection(doc) {
141
+ export function selfDocSection(doc) {
133
142
  /** @type {any[]} */
134
143
  const content = [{type: 'prose', text: doc.description}];
135
144
  if (doc.appliesTo) {
@@ -144,7 +153,8 @@ function selfDocSection(doc) {
144
153
  });
145
154
  }
146
155
  for (const example of doc.examples ?? []) {
147
- if (typeof example?.code !== 'string' || example.code.trim() === '') continue;
156
+ if (typeof example?.code !== 'string' || example.code.trim() === '')
157
+ continue;
148
158
  content.push({
149
159
  type: 'code',
150
160
  lang: example.lang ?? 'js',
@@ -9,7 +9,14 @@ import {
9
9
  buildAuthoringTopic,
10
10
  discoverAuthoringSelfDocSources,
11
11
  } from './authoring-self-docs.mjs';
12
- import {problemsInTopic} from './docs-discovery.mjs';
12
+ import {
13
+ GRAPH_BLOCK_TYPES,
14
+ GRAPH_ONLY_FIELDS,
15
+ problemsInTopic,
16
+ } from './docs-discovery.mjs';
17
+ import {doc as graphFieldsDoc} from '../../authoring/doctypes/base/graph-fields.doc.mjs';
18
+ import {doc as namespaceDoc} from '../../authoring/doctypes/namespace/namespace.doc.mjs';
19
+ import {doc as referenceDoc} from '../../authoring/doctypes/reference/reference.doc.mjs';
13
20
  import {docs} from '../../api/docs/docs.mjs';
14
21
 
15
22
  const SLOW = 60_000;
@@ -37,14 +44,58 @@ describe('authoring self-docs', () => {
37
44
  expect(topic.sections).toHaveLength(AUTHORING_SELF_DOCS.length);
38
45
  });
39
46
 
40
- it('is readable progressively through the docs API', async () => {
41
- const index = await docs('authoring', undefined, {index: true});
42
- expect(index.type).toBe('docs.index');
43
- expect(index.data.sections.map(s => s.id)).toContain('integration');
44
- const section = await docs('authoring', 'integration');
45
- expect(section.data.title).toBe('Astryx Integration');
46
- expect(section.data.content.some(block => block.type === 'table')).toBe(true);
47
- }, SLOW);
47
+ it(
48
+ 'is readable progressively through the docs API',
49
+ async () => {
50
+ const index = await docs('authoring', undefined, {index: true});
51
+ expect(index.type).toBe('docs.index');
52
+ expect(index.data.sections.map(s => s.id)).toContain('integration');
53
+ const section = await docs('authoring', 'integration');
54
+ expect(section.data.title).toBe('Astryx Integration');
55
+ expect(section.data.content.some(block => block.type === 'table')).toBe(
56
+ true,
57
+ );
58
+ },
59
+ SLOW,
60
+ );
61
+ });
62
+
63
+ describe('what the authoring docs say about the unbuilt docs graph', () => {
64
+ it('marks exactly the fields topic loading rejects as not read yet', () => {
65
+ const notReadYet = graphFieldsDoc.fields
66
+ .filter(field => /Not read yet/.test(field.description))
67
+ .map(field => field.name);
68
+ expect(notReadYet.sort()).toEqual([...GRAPH_ONLY_FIELDS].sort());
69
+ for (const field of graphFieldsDoc.fields) {
70
+ if (notReadYet.includes(field.name)) {
71
+ expect(field.description).toMatch(/fails to load/);
72
+ }
73
+ }
74
+ expect(graphFieldsDoc.description).toMatch(/not built yet/);
75
+ });
76
+
77
+ it('says a topic using a graph block fails to load', () => {
78
+ const content = referenceDoc.fields
79
+ .flatMap(field => [field, ...(field.fields ?? [])])
80
+ .find(field => field.name === 'sections[].content');
81
+ for (const type of GRAPH_BLOCK_TYPES) {
82
+ expect(content.description).toContain(type);
83
+ }
84
+ expect(content.description).toMatch(/fails to load/);
85
+ });
86
+
87
+ it('says namespace docs are not loaded yet', () => {
88
+ expect(namespaceDoc.description).toMatch(/Not loaded yet/);
89
+ expect(
90
+ problemsInTopic({
91
+ ...namespaceDoc.examples?.[0],
92
+ type: 'namespace',
93
+ name: 'x',
94
+ }),
95
+ ).toEqual([
96
+ '"x" is a namespace doc. Only the docs graph reads namespace docs, and it is not built yet; remove this file from the docs directory.',
97
+ ]);
98
+ });
48
99
  });
49
100
 
50
101
  describe('auditAuthoringSelfDocs', () => {
@@ -68,17 +119,25 @@ describe('auditAuthoringSelfDocs', () => {
68
119
  path.join(root, 'kept', 'forgotten.doc.mjs'),
69
120
  "export const doc = {name: 'forgotten', description: 'Not listed.'};\n",
70
121
  );
71
- const audit = await auditAuthoringSelfDocs({root, sources: ['kept/kept.doc.mjs']});
122
+ const audit = await auditAuthoringSelfDocs({
123
+ root,
124
+ sources: ['kept/kept.doc.mjs'],
125
+ });
72
126
  expect(audit.unreachable).toEqual(['kept/forgotten.doc.mjs']);
73
127
  });
74
128
 
75
129
  it('reports a self-doc that fails to load instead of throwing', async () => {
76
- fs.writeFileSync(path.join(root, 'kept', 'broken.doc.mjs'), 'export const doc = {;\n');
130
+ fs.writeFileSync(
131
+ path.join(root, 'kept', 'broken.doc.mjs'),
132
+ 'export const doc = {;\n',
133
+ );
77
134
  const audit = await auditAuthoringSelfDocs({
78
135
  root,
79
136
  sources: ['kept/kept.doc.mjs', 'kept/broken.doc.mjs'],
80
137
  });
81
- expect(audit.failed.map(entry => entry.source)).toEqual(['kept/broken.doc.mjs']);
138
+ expect(audit.failed.map(entry => entry.source)).toEqual([
139
+ 'kept/broken.doc.mjs',
140
+ ]);
82
141
  expect(audit.sections).toBe(1);
83
142
  });
84
143