@astryxdesign/cli 0.6.3 → 0.6.4-canary.10dd683

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 (643) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/README.md +117 -78
  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 +16 -9
  7. package/api/build/build.test.mjs +197 -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 +165 -49
  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 +6 -12
  18. package/api/component/_adapter.mjs +20 -10
  19. package/api/component/component.doc.mjs +13 -3
  20. package/api/component/component.mjs +91 -14
  21. package/api/component/component.test.mjs +38 -0
  22. package/api/component/component.type.d.mts +22 -11
  23. package/api/component/component.type.mjs +32 -24
  24. package/api/component/detail/blocks/blocks.d.mts +2 -1
  25. package/api/component/detail/blocks/blocks.mjs +4 -3
  26. package/api/component/list/list.d.mts +0 -5
  27. package/api/component/list/list.mjs +40 -11
  28. package/api/discover/_adapter.d.mts +114 -6
  29. package/api/discover/_adapter.mjs +372 -17
  30. package/api/discover/_adapter.test.mjs +215 -0
  31. package/api/discover/_catalog-view.d.mts +115 -0
  32. package/api/discover/_catalog-view.mjs +203 -0
  33. package/api/discover/_catalog-view.test.mjs +128 -0
  34. package/api/discover/detail/detail.d.mts +18 -6
  35. package/api/discover/detail/detail.mjs +67 -13
  36. package/api/discover/detail/detail.test.mjs +85 -0
  37. package/api/discover/detail/item/item.d.mts +26 -0
  38. package/api/discover/detail/item/item.mjs +78 -0
  39. package/api/discover/detail/item/item.test.mjs +73 -0
  40. package/api/discover/discover.d.mts +3 -9
  41. package/api/discover/discover.doc.mjs +62 -18
  42. package/api/discover/discover.mjs +220 -36
  43. package/api/discover/discover.test.mjs +11 -2
  44. package/api/discover/discover.type.d.mts +150 -11
  45. package/api/discover/discover.type.mjs +107 -17
  46. package/api/discover/list/list.d.mts +20 -6
  47. package/api/discover/list/list.mjs +45 -12
  48. package/api/discover/list/list.test.mjs +46 -0
  49. package/api/discover/search/search.d.mts +18 -16
  50. package/api/discover/search/search.mjs +102 -56
  51. package/api/discover/search/search.test.mjs +144 -10
  52. package/api/docs/_adapter.d.mts +272 -41
  53. package/api/docs/_adapter.mjs +985 -108
  54. package/api/docs/compiled-topics.test.mjs +78 -0
  55. package/api/docs/detail/detail.mjs +22 -63
  56. package/api/docs/detail/section/section.d.mts +1 -1
  57. package/api/docs/detail/section/section.mjs +54 -19
  58. package/api/docs/detail/section/section.test.mjs +50 -0
  59. package/api/docs/docs.d.mts +10 -3
  60. package/api/docs/docs.doc.mjs +55 -16
  61. package/api/docs/docs.mjs +53 -10
  62. package/api/docs/docs.test.mjs +164 -4
  63. package/api/docs/docs.type.d.mts +221 -5
  64. package/api/docs/docs.type.mjs +153 -11
  65. package/api/docs/index/index.d.mts +18 -0
  66. package/api/docs/index/index.mjs +40 -0
  67. package/api/docs/index/index.test.mjs +62 -0
  68. package/api/docs/integration-tree.test.mjs +555 -0
  69. package/api/docs/integrationDocs.test.mjs +114 -8
  70. package/api/docs/list/list.mjs +28 -12
  71. package/api/docs/node/node.d.mts +43 -0
  72. package/api/docs/node/node.mjs +192 -0
  73. package/api/docs/reference-blocks.test.mjs +406 -0
  74. package/api/doctor/doctor.d.mts +99 -1
  75. package/api/doctor/doctor.doc.mjs +1 -0
  76. package/api/doctor/doctor.mjs +548 -1
  77. package/api/doctor/doctor.test.mjs +610 -1
  78. package/api/gap-report/gap-report.doc.mjs +8 -4
  79. package/api/hook/_adapter.mjs +19 -5
  80. package/api/hook/hook.doc.mjs +1 -0
  81. package/api/hook/hook.type.d.mts +3 -3
  82. package/api/hook/hook.type.mjs +11 -11
  83. package/api/hook/list/list.d.mts +2 -2
  84. package/api/hook/list/list.mjs +69 -17
  85. package/api/index.d.mts +1 -1
  86. package/api/index.mjs +1 -0
  87. package/api/init/init.doc.mjs +6 -1
  88. package/api/init/init.test.mjs +41 -1
  89. package/api/init/remove/remove.mjs +1 -1
  90. package/api/init/run/run.mjs +20 -10
  91. package/api/integration/add-contribution.component-names.test.mjs +120 -0
  92. package/api/integration/add-contribution.d.mts +2 -1
  93. package/api/integration/add-contribution.mjs +130 -15
  94. package/api/integration/add-contribution.test.mjs +258 -7
  95. package/api/integration/add-helpers.d.mts +5 -2
  96. package/api/integration/add-helpers.mjs +36 -9
  97. package/api/integration/add-theme.mjs +34 -64
  98. package/api/integration/add-theme.test.mjs +105 -21
  99. package/api/integration/authoring-checks.mjs +138 -28
  100. package/api/integration/authoring-checks.test.mjs +179 -7
  101. package/api/integration/authoring-checks.type.mjs +6 -1
  102. package/api/integration/integration-authoring.type.d.mts +3 -1
  103. package/api/integration/integration-authoring.type.mjs +2 -0
  104. package/api/integration/integration-block-exports.test.mjs +10 -6
  105. package/api/integration/integrationAdd.doc.mjs +14 -4
  106. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  107. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  108. package/api/integration/integrationAddComponent.doc.mjs +2 -1
  109. package/api/integration/integrationAddDoc.doc.mjs +8 -1
  110. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  111. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  112. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  113. package/api/integration/integrationDocConflicts.doc.mjs +2 -1
  114. package/api/integration/integrationPackCheck.doc.mjs +2 -1
  115. package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
  116. package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
  117. package/api/integration/pack-check.mjs +83 -7
  118. package/api/integration/pack-check.test.mjs +387 -47
  119. package/api/integration/pack-check.type.d.mts +26 -2
  120. package/api/integration/pack-check.type.mjs +14 -1
  121. package/api/integration/summarizeIssues.doc.mjs +1 -0
  122. package/api/integration/template-conflict-compatibility.test.mjs +73 -0
  123. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  124. package/api/integration/validate-integration.mjs +52 -102
  125. package/api/integration/validate-integration.test.mjs +179 -26
  126. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  127. package/api/integration/validateIntegration.doc.mjs +3 -2
  128. package/api/json/assertResponse.doc.mjs +1 -0
  129. package/api/json/envelope-types.test.mjs +76 -0
  130. package/api/json/index.ts +2 -0
  131. package/api/json/isError.doc.mjs +1 -0
  132. package/api/json/parseResponse.doc.mjs +3 -2
  133. package/api/layout/_adapter.mjs +20 -5
  134. package/api/layout/expand/expand.mjs +7 -5
  135. package/api/layout/expand/expand.path-safety.test.mjs +53 -0
  136. package/api/layout/grammar/grammar.mjs +2 -1
  137. package/api/layout/layoutCheck.doc.mjs +1 -0
  138. package/api/layout/layoutExpand.doc.mjs +2 -1
  139. package/api/layout/layoutGrammar.doc.mjs +1 -0
  140. package/api/search/search-return-type.test.mjs +54 -0
  141. package/api/search/search.d.mts +62 -11
  142. package/api/search/search.doc.mjs +8 -2
  143. package/api/search/search.mjs +471 -83
  144. package/api/search/search.test.mjs +124 -1
  145. package/api/search/search.type.d.mts +15 -3
  146. package/api/search/search.type.mjs +5 -2
  147. package/api/swizzle/copy/copy.mjs +28 -11
  148. package/api/swizzle/swizzle.doc.mjs +2 -1
  149. package/api/swizzle/swizzle.type.d.mts +2 -2
  150. package/api/swizzle/swizzle.type.mjs +2 -2
  151. package/api/template/copy/copy.mjs +17 -23
  152. package/api/template/copy/copy.test.mjs +17 -0
  153. package/api/template/list/list.mjs +1 -0
  154. package/api/template/table-floating-bulk-actions.test.mjs +66 -0
  155. package/api/template/template-integration.test.mjs +1072 -3
  156. package/api/template/template-suffix.test.mjs +41 -21
  157. package/api/template/template.d.mts +1 -1
  158. package/api/template/template.doc.mjs +30 -8
  159. package/api/template/template.mjs +45 -8
  160. package/api/template/template.type.d.mts +12 -14
  161. package/api/template/template.type.mjs +15 -14
  162. package/api/theme/_adapter.d.mts +2 -3
  163. package/api/theme/_adapter.mjs +4 -5
  164. package/api/theme/add/add.binary.test.mjs +84 -0
  165. package/api/theme/add/add.mjs +31 -22
  166. package/api/theme/add/add.rollback.test.mjs +158 -0
  167. package/api/theme/add/add.staging.test.mjs +83 -0
  168. package/api/theme/add/add.test.mjs +14 -1
  169. package/api/theme/build/build.family.test.mjs +7 -12
  170. package/api/theme/build/build.mjs +140 -59
  171. package/api/theme/build/build.public-component-vars.test.mjs +1 -1
  172. package/api/theme/build/build.receipt-doc.test.mjs +111 -0
  173. package/api/theme/build/build.rollback.test.mjs +148 -0
  174. package/api/theme/build/build.test.mjs +127 -0
  175. package/api/theme/build/font-warning.mjs +3 -3
  176. package/api/theme/build/font-warning.test.mjs +5 -2
  177. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  178. package/api/theme/integration-themes.test.mjs +39 -28
  179. package/api/theme/list/list.test.mjs +19 -20
  180. package/api/theme/listThemes.doc.mjs +6 -5
  181. package/api/theme/palette/generate/generate.mjs +8 -3
  182. package/api/theme/palette/generate/generate.test.mjs +96 -0
  183. package/api/theme/palette/generate/generator.d.mts +10 -13
  184. package/api/theme/palette/generate/generator.mjs +15 -4
  185. package/api/theme/palette/generate/generator.test.mjs +10 -0
  186. package/api/theme/template/template.mjs +11 -2
  187. package/api/theme/template/template.test.mjs +20 -0
  188. package/api/theme/theme.type.d.mts +170 -11
  189. package/api/theme/theme.type.mjs +94 -27
  190. package/api/theme/themeAdd.doc.mjs +4 -3
  191. package/api/theme/themeBuild.doc.mjs +8 -4
  192. package/api/theme/themeList.doc.mjs +6 -3
  193. package/api/theme/themeListAvailable.doc.mjs +5 -3
  194. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  195. package/api/theme/themeTargets.doc.mjs +1 -0
  196. package/api/theme/themeTemplate.doc.mjs +6 -2
  197. package/api/upgrade/_adapter.d.mts +32 -5
  198. package/api/upgrade/_adapter.mjs +139 -22
  199. package/api/upgrade/list/list.mjs +2 -1
  200. package/api/upgrade/list/list.test.mjs +73 -0
  201. package/api/upgrade/project-context.test.mjs +272 -0
  202. package/api/upgrade/provider-agreement.test.mjs +152 -0
  203. package/api/upgrade/run/run.mjs +356 -59
  204. package/api/upgrade/status/status.mjs +2 -2
  205. package/api/upgrade/upgrade.doc.mjs +12 -5
  206. package/api/upgrade/upgrade.type.d.mts +43 -5
  207. package/api/upgrade/upgrade.type.mjs +27 -11
  208. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  209. package/assets/codemods/__tests__/runner.test.mjs +330 -8
  210. package/assets/codemods/integration-discovery.mjs +48 -4
  211. package/assets/codemods/integration-discovery.test.mjs +73 -0
  212. package/assets/codemods/integration-runner.mjs +56 -4
  213. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  214. package/assets/codemods/registry.mjs +1 -0
  215. package/assets/codemods/run-codemod.mjs +177 -34
  216. package/assets/codemods/runner.mjs +350 -102
  217. package/assets/codemods/term-log.mjs +32 -8
  218. package/assets/codemods/term-log.test.mjs +19 -1
  219. package/assets/codemods/transform-prop.mjs +109 -0
  220. package/assets/codemods/transform-prop.test.mjs +95 -0
  221. package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
  222. package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
  223. package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
  224. package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
  225. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  226. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  227. package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
  228. package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
  229. package/assets/codemods/transforms/v0.6.4/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  230. package/assets/codemods/transforms/v0.6.4/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  231. package/assets/codemods/transforms/v0.6.4/index.mjs +31 -0
  232. package/assets/codemods/transforms/v0.6.4/migrate-native-picker-to-presentation.mjs +148 -0
  233. package/assets/codemods/transforms/v0.6.4/migrate-theme-catalog-to-descriptors.mjs +141 -0
  234. package/assets/docs/README.md +9 -0
  235. package/assets/docs/authoring.doc.mjs +14 -0
  236. package/assets/docs/getting-started.doc.mjs +2 -2
  237. package/assets/docs/internationalization.doc.mjs +7 -5
  238. package/assets/docs/layout.doc.dense.mjs +2 -2
  239. package/assets/docs/layout.doc.mjs +1 -1
  240. package/assets/docs/principles.doc.mjs +6 -6
  241. package/assets/docs/styling-libraries.doc.mjs +4 -4
  242. package/assets/docs/styling.doc.mjs +4 -4
  243. package/assets/docs/theme.doc.mjs +5 -5
  244. package/assets/docs/tokens.doc.mjs +1 -1
  245. package/assets/docs/tree/api.doc.mjs +30 -0
  246. package/assets/docs/tree/cli.doc.mjs +23 -0
  247. package/assets/docs/tree/commands.doc.mjs +25 -0
  248. package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +144 -26
  249. package/assets/docs/tree/integrations.test.mjs +62 -0
  250. package/assets/docs/tree/writing-docs.doc.mjs +286 -0
  251. package/assets/docs/working-with-ai.doc.mjs +4 -4
  252. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
  253. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
  254. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  255. package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
  256. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  257. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  258. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
  259. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
  260. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
  261. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
  262. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
  263. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
  264. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
  265. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
  266. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
  267. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
  268. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
  269. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
  270. package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
  271. package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
  272. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
  273. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
  274. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  275. package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +14 -0
  276. package/assets/templates/blocks/components/Timer/TimerFormats.tsx +34 -0
  277. package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +14 -0
  278. package/assets/templates/blocks/components/Timer/TimerInline.tsx +14 -0
  279. package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +13 -0
  280. package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +47 -0
  281. package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +14 -0
  282. package/assets/templates/blocks/components/Timer/TimerTypography.tsx +31 -0
  283. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +19 -3
  284. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +383 -65
  285. package/assets/templates/pages/table-tree/page.tsx +1704 -0
  286. package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
  287. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  288. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  289. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  290. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  291. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  292. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  293. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  294. package/authoring/_shared/contract.ts +22 -0
  295. package/authoring/codemod/codemod.doc.mjs +7 -2
  296. package/authoring/codemod/parse.d.mts +8 -8
  297. package/authoring/codemod/parse.mjs +8 -6
  298. package/authoring/codemod/type.ts +12 -0
  299. package/authoring/config/config.doc.mjs +10 -2
  300. package/authoring/config/debug-composition.test.mjs +92 -0
  301. package/authoring/config/parse.d.mts +15 -13
  302. package/authoring/config/parse.mjs +27 -8
  303. package/authoring/config/parse.test.mjs +8 -0
  304. package/authoring/config/type.ts +29 -6
  305. package/authoring/debug/debug.doc.d.mts +11 -0
  306. package/authoring/debug/debug.doc.mjs +182 -0
  307. package/authoring/debug/parse.d.mts +8 -8
  308. package/authoring/debug/parse.mjs +3 -3
  309. package/authoring/discover/discover.doc.d.mts +13 -0
  310. package/authoring/discover/discover.doc.mjs +138 -0
  311. package/authoring/discover/parse.d.mts +24 -0
  312. package/authoring/discover/parse.mjs +128 -0
  313. package/authoring/discover/parse.test.mjs +124 -0
  314. package/authoring/discover/type.ts +87 -0
  315. package/authoring/doctypes/_schema.d.mts +790 -23
  316. package/authoring/doctypes/_schema.mjs +543 -39
  317. package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
  318. package/authoring/doctypes/base/graph-fields.doc.mjs +64 -0
  319. package/authoring/doctypes/base/type.ts +41 -0
  320. package/authoring/doctypes/command/command.doc.mjs +4 -3
  321. package/authoring/doctypes/command/parse.d.mts +2 -2
  322. package/authoring/doctypes/command/parse.mjs +1 -1
  323. package/authoring/doctypes/command/type.ts +5 -4
  324. package/authoring/doctypes/component/component.doc.mjs +6 -3
  325. package/authoring/doctypes/component/parse.d.mts +2 -2
  326. package/authoring/doctypes/component/parse.mjs +1 -1
  327. package/authoring/doctypes/component/type.ts +6 -5
  328. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  329. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  330. package/authoring/doctypes/enum/parse.d.mts +2 -2
  331. package/authoring/doctypes/enum/parse.mjs +1 -1
  332. package/authoring/doctypes/enum/type.ts +4 -2
  333. package/authoring/doctypes/function/function.doc.mjs +7 -2
  334. package/authoring/doctypes/function/parse.d.mts +2 -2
  335. package/authoring/doctypes/function/parse.mjs +1 -1
  336. package/authoring/doctypes/function/type.ts +9 -4
  337. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  338. package/authoring/doctypes/hook/parse.d.mts +2 -2
  339. package/authoring/doctypes/hook/parse.mjs +1 -1
  340. package/authoring/doctypes/hook/type.ts +5 -4
  341. package/authoring/doctypes/legacy.d.mts +8 -6
  342. package/authoring/doctypes/legacy.mjs +5 -4
  343. package/authoring/doctypes/load-contract.test.mjs +233 -0
  344. package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
  345. package/authoring/doctypes/namespace/namespace.doc.mjs +128 -0
  346. package/authoring/doctypes/namespace/parse.d.mts +12 -0
  347. package/authoring/doctypes/namespace/parse.mjs +25 -0
  348. package/authoring/doctypes/namespace/parse.test.mjs +163 -0
  349. package/authoring/doctypes/namespace/type.ts +74 -0
  350. package/authoring/doctypes/parse.d.mts +22 -18
  351. package/authoring/doctypes/parse.mjs +22 -11
  352. package/authoring/doctypes/parse.test.mjs +77 -3
  353. package/authoring/doctypes/reference/parse.d.mts +2 -2
  354. package/authoring/doctypes/reference/parse.mjs +8 -5
  355. package/authoring/doctypes/reference/reference.doc.mjs +48 -6
  356. package/authoring/doctypes/reference/type.ts +70 -7
  357. package/authoring/doctypes/schema/parse.d.mts +2 -2
  358. package/authoring/doctypes/schema/parse.mjs +1 -1
  359. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  360. package/authoring/doctypes/schema/type.ts +4 -4
  361. package/authoring/doctypes/template/parse.d.mts +94 -1
  362. package/authoring/doctypes/template/parse.mjs +40 -2
  363. package/authoring/doctypes/template/parse.test.mjs +26 -2
  364. package/authoring/doctypes/template/template.doc.mjs +13 -3
  365. package/authoring/doctypes/template/type.ts +13 -2
  366. package/authoring/doctypes/theme/parse.d.mts +35 -0
  367. package/authoring/doctypes/theme/parse.mjs +76 -0
  368. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  369. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  370. package/authoring/doctypes/theme/type.ts +42 -0
  371. package/authoring/doctypes/types.ts +12 -10
  372. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  373. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  374. package/authoring/gap-report/parse.d.mts +10 -10
  375. package/authoring/gap-report/parse.mjs +6 -6
  376. package/authoring/gap-report/type.ts +1 -1
  377. package/authoring/identity/identity.doc.d.mts +9 -0
  378. package/authoring/identity/identity.doc.mjs +61 -0
  379. package/authoring/identity/type.ts +132 -0
  380. package/authoring/index.d.mts +3 -0
  381. package/authoring/index.d.ts +62 -17
  382. package/authoring/index.mjs +4 -1
  383. package/authoring/integration/integration.doc.mjs +15 -8
  384. package/authoring/integration/parse.d.mts +2 -2
  385. package/authoring/integration/parse.mjs +1 -1
  386. package/authoring/integration/parse.test.mjs +10 -1
  387. package/authoring/integration/schema.d.mts +6 -4
  388. package/authoring/integration/schema.mjs +9 -3
  389. package/authoring/integration/type.ts +19 -8
  390. package/authoring/shadcn/receipt.d.mts +6 -6
  391. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  392. package/clients/cli/command-load-failure.test.mjs +83 -0
  393. package/clients/cli/commands/blog.doc.mjs +1 -1
  394. package/clients/cli/commands/blog.mjs +23 -8
  395. package/clients/cli/commands/blog.test.mjs +42 -1
  396. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  397. package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
  398. package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
  399. package/clients/cli/commands/build-theme.mjs +16 -50
  400. package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
  401. package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
  402. package/clients/cli/commands/build.doc.mjs +16 -8
  403. package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
  404. package/clients/cli/commands/build.mjs +137 -114
  405. package/clients/cli/commands/build.playbook.test.mjs +75 -0
  406. package/clients/cli/commands/build.text-fields.test.mjs +81 -0
  407. package/clients/cli/commands/component/index.mjs +3 -8
  408. package/clients/cli/commands/component-ownership.test.mjs +3 -3
  409. package/clients/cli/commands/component-package.test.mjs +46 -0
  410. package/clients/cli/commands/component-resolution.test.mjs +21 -0
  411. package/clients/cli/commands/component.doc.mjs +1 -1
  412. package/clients/cli/commands/component.test.mjs +19 -0
  413. package/clients/cli/commands/detail-levels.test.mjs +2 -2
  414. package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
  415. package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
  416. package/clients/cli/commands/discover.doc.mjs +55 -9
  417. package/clients/cli/commands/discover.mjs +393 -118
  418. package/clients/cli/commands/discover.sources.test.mjs +267 -0
  419. package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
  420. package/clients/cli/commands/docs.doc.mjs +28 -6
  421. package/clients/cli/commands/docs.mjs +240 -26
  422. package/clients/cli/commands/docs.test.mjs +193 -1
  423. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  424. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
  425. package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
  426. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  427. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  428. package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
  429. package/clients/cli/commands/doctor-integration.test.mjs +90 -8
  430. package/clients/cli/commands/doctor.doc.mjs +1 -1
  431. package/clients/cli/commands/doctor.mjs +59 -32
  432. package/clients/cli/commands/doctor.test.mjs +42 -0
  433. package/clients/cli/commands/gap-report.doc.mjs +17 -6
  434. package/clients/cli/commands/gap-report.test.mjs +72 -0
  435. package/clients/cli/commands/hook/index.mjs +7 -17
  436. package/clients/cli/commands/hook.doc.mjs +1 -1
  437. package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
  438. package/clients/cli/commands/init.doc.mjs +20 -9
  439. package/clients/cli/commands/init.flag-help.test.mjs +153 -0
  440. package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
  441. package/clients/cli/commands/integration-add.doc.mjs +32 -6
  442. package/clients/cli/commands/integration-authoring.test.mjs +13 -9
  443. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  444. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  445. package/clients/cli/commands/integration.doc.mjs +1 -1
  446. package/clients/cli/commands/integration.mjs +1 -0
  447. package/clients/cli/commands/interactive-guard.test.mjs +101 -24
  448. package/clients/cli/commands/json-contract.test.mjs +33 -0
  449. package/clients/cli/commands/layout-check.doc.mjs +15 -4
  450. package/clients/cli/commands/layout-expand.doc.mjs +22 -5
  451. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  452. package/clients/cli/commands/layout.doc.mjs +3 -3
  453. package/clients/cli/commands/layout.mjs +21 -9
  454. package/clients/cli/commands/layout.path-help.test.mjs +33 -0
  455. package/clients/cli/commands/layout.stdin-cap.test.mjs +47 -0
  456. package/clients/cli/commands/layout.text-fields.test.mjs +39 -0
  457. package/clients/cli/commands/manifest.doc.mjs +1 -1
  458. package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
  459. package/clients/cli/commands/search.doc.mjs +7 -4
  460. package/clients/cli/commands/search.mjs +28 -9
  461. package/clients/cli/commands/search.test.mjs +75 -0
  462. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  463. package/clients/cli/commands/swizzle.doc.mjs +3 -2
  464. package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
  465. package/clients/cli/commands/template.doc.mjs +52 -13
  466. package/clients/cli/commands/template.flag-help.test.mjs +117 -0
  467. package/clients/cli/commands/template.mjs +4 -91
  468. package/clients/cli/commands/template.path-help.test.mjs +40 -0
  469. package/clients/cli/commands/text-json-parity.test.mjs +719 -0
  470. package/clients/cli/commands/theme-add.doc.mjs +4 -3
  471. package/clients/cli/commands/theme-build.doc.mjs +8 -7
  472. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  473. package/clients/cli/commands/theme-palette-generate.doc.mjs +9 -5
  474. package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
  475. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  476. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  477. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  478. package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
  479. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  480. package/clients/cli/commands/theme.doc.mjs +1 -1
  481. package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
  482. package/clients/cli/commands/upgrade.doc.mjs +22 -10
  483. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  484. package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
  485. package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
  486. package/clients/cli/commands/upgrade.mjs +29 -7
  487. package/clients/cli/formatters/index.mjs +164 -1
  488. package/clients/cli/formatters/index.test.mjs +97 -0
  489. package/clients/cli/index.mjs +21 -30
  490. package/clients/cli/latest-version-env.test.mjs +50 -0
  491. package/clients/cli/lib/cli-error.test.mjs +7 -0
  492. package/clients/cli/lib/component-format.mjs +9 -9
  493. package/clients/cli/lib/component-format.test.mjs +1 -1
  494. package/clients/cli/lib/define-command.mjs +32 -6
  495. package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
  496. package/clients/cli/lib/exit-codes.test.mjs +97 -0
  497. package/clients/cli/lib/hook-format.mjs +19 -10
  498. package/clients/cli/lib/json-shim.mjs +38 -2
  499. package/clients/cli/lib/json-shim.test.mjs +83 -0
  500. package/clients/cli/lib/manifest.d.ts +2 -0
  501. package/clients/cli/lib/manifest.mjs +37 -2
  502. package/clients/cli/lib/manifest.test.mjs +17 -0
  503. package/foundation/agent-docs/agent-docs.d.mts +7 -2
  504. package/foundation/agent-docs/agent-docs.mjs +82 -12
  505. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
  506. package/foundation/agent-docs/agent-docs.test.mjs +19 -1
  507. package/foundation/config/integration-debug.test.mjs +28 -3
  508. package/foundation/config/project-themes.test.mjs +11 -19
  509. package/foundation/config/project.d.mts +20 -11
  510. package/foundation/config/project.mjs +263 -91
  511. package/foundation/config/project.test.mjs +270 -21
  512. package/foundation/discovery/authoring-self-docs.d.mts +87 -0
  513. package/foundation/discovery/authoring-self-docs.mjs +237 -0
  514. package/foundation/discovery/authoring-self-docs.test.mjs +170 -0
  515. package/foundation/discovery/authoring-surface.d.mts +74 -0
  516. package/foundation/discovery/authoring-surface.mjs +525 -0
  517. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  518. package/foundation/discovery/cli-self-docs.d.mts +119 -0
  519. package/foundation/discovery/cli-self-docs.mjs +490 -0
  520. package/foundation/discovery/cli-self-docs.test.mjs +375 -0
  521. package/foundation/discovery/component-discovery.d.mts +39 -1
  522. package/foundation/discovery/component-discovery.mjs +50 -1
  523. package/foundation/discovery/component-loader.d.mts +35 -38
  524. package/foundation/discovery/component-loader.mjs +53 -222
  525. package/foundation/discovery/docs-discovery.d.mts +119 -11
  526. package/foundation/discovery/docs-discovery.mjs +423 -108
  527. package/foundation/discovery/docs-discovery.test.mjs +365 -20
  528. package/foundation/discovery/docs-output-budget.d.mts +28 -0
  529. package/foundation/discovery/docs-output-budget.mjs +50 -0
  530. package/foundation/discovery/docs-section-key.d.mts +116 -0
  531. package/foundation/discovery/docs-section-key.mjs +322 -0
  532. package/foundation/discovery/docs-section-key.test.mjs +246 -0
  533. package/foundation/discovery/template-adapter.d.mts +113 -11
  534. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
  535. package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
  536. package/foundation/discovery/template-adapter.mjs +774 -83
  537. package/foundation/discovery/template-adapter.test.mjs +57 -0
  538. package/foundation/discovery/template-conflict-release.d.mts +13 -0
  539. package/foundation/discovery/template-conflict-release.mjs +40 -0
  540. package/foundation/discovery/template-conflict-release.test.mjs +40 -0
  541. package/foundation/discovery/theme-discovery.d.mts +67 -7
  542. package/foundation/discovery/theme-discovery.mjs +916 -186
  543. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  544. package/foundation/discovery/theming-targets.test.mjs +4 -0
  545. package/foundation/doc-compiler/bundle.d.mts +47 -0
  546. package/foundation/doc-compiler/bundle.mjs +278 -0
  547. package/foundation/doc-compiler/bundle.test.mjs +266 -0
  548. package/foundation/doc-compiler/compile.d.mts +343 -0
  549. package/foundation/doc-compiler/compile.mjs +558 -0
  550. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  551. package/foundation/doc-compiler/diagnostics.mjs +305 -0
  552. package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
  553. package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
  554. package/foundation/doc-compiler/import.d.mts +24 -0
  555. package/foundation/doc-compiler/import.mjs +59 -0
  556. package/foundation/doc-compiler/inputs.d.mts +102 -0
  557. package/foundation/doc-compiler/inputs.mjs +291 -0
  558. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  559. package/foundation/doc-compiler/ir.d.mts +22 -0
  560. package/foundation/doc-compiler/ir.mjs +471 -0
  561. package/foundation/doc-compiler/lenses.d.mts +36 -0
  562. package/foundation/doc-compiler/lenses.mjs +173 -0
  563. package/foundation/doc-compiler/links.d.mts +162 -0
  564. package/foundation/doc-compiler/links.mjs +294 -0
  565. package/foundation/doc-compiler/links.test.mjs +192 -0
  566. package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
  567. package/foundation/doc-compiler/overlays.d.mts +37 -0
  568. package/foundation/doc-compiler/overlays.mjs +206 -0
  569. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  570. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  571. package/foundation/doc-compiler/read.d.mts +127 -0
  572. package/foundation/doc-compiler/read.mjs +325 -0
  573. package/foundation/doc-compiler/read.test.mjs +313 -0
  574. package/foundation/doc-compiler/source.d.mts +33 -0
  575. package/foundation/doc-compiler/source.mjs +128 -0
  576. package/foundation/doc-compiler/tree.d.mts +288 -0
  577. package/foundation/doc-compiler/tree.mjs +876 -0
  578. package/foundation/doc-compiler/tree.test.mjs +598 -0
  579. package/foundation/fs/file-protection.d.mts +33 -0
  580. package/foundation/fs/file-protection.mjs +825 -0
  581. package/foundation/fs/file-protection.test.mjs +250 -0
  582. package/foundation/fs/module-loader.d.mts +1 -0
  583. package/foundation/fs/module-loader.mjs +50 -1
  584. package/foundation/fs/module-loader.stdout.test.mjs +332 -0
  585. package/foundation/fs/path-safety.d.mts +3 -2
  586. package/foundation/fs/path-safety.mjs +49 -19
  587. package/foundation/fs/path-safety.test.mjs +50 -0
  588. package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
  589. package/foundation/identity/provider-identity.d.mts +90 -0
  590. package/foundation/identity/provider-identity.mjs +320 -0
  591. package/foundation/identity/provider-identity.test.mjs +254 -0
  592. package/foundation/identity/providers.d.mts +7 -0
  593. package/foundation/identity/providers.mjs +16 -0
  594. package/foundation/integrations/autolink.d.mts +58 -1
  595. package/foundation/integrations/autolink.mjs +143 -45
  596. package/foundation/integrations/autolink.test.mjs +1 -1
  597. package/foundation/integrations/cli-requirement.d.mts +45 -0
  598. package/foundation/integrations/cli-requirement.mjs +154 -0
  599. package/foundation/integrations/cli-requirement.test.mjs +84 -0
  600. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  601. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  602. package/foundation/integrations/contribution-inventory.d.mts +3 -2
  603. package/foundation/integrations/contribution-inventory.mjs +27 -24
  604. package/foundation/integrations/contribution-inventory.test.mjs +86 -27
  605. package/foundation/integrations/integration-warnings.d.mts +9 -2
  606. package/foundation/integrations/integration-warnings.mjs +52 -21
  607. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  608. package/foundation/integrations/integrations.d.mts +63 -3
  609. package/foundation/integrations/integrations.mjs +122 -9
  610. package/foundation/integrations/integrations.test.mjs +415 -1
  611. package/foundation/integrations/provider-conflicts.test.mjs +125 -0
  612. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  613. package/foundation/integrations/provider-resolution.d.mts +152 -0
  614. package/foundation/integrations/provider-resolution.mjs +576 -0
  615. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  616. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  617. package/foundation/integrations/theme-descriptor.mjs +44 -0
  618. package/foundation/integrations/validate-contributions.d.mts +2 -0
  619. package/foundation/integrations/validate-contributions.mjs +131 -29
  620. package/foundation/response/base.d.ts +8 -4
  621. package/foundation/response/error-codes.d.mts +3 -1
  622. package/foundation/response/error-codes.d.ts +2 -0
  623. package/foundation/response/error-codes.doc.mjs +13 -4
  624. package/foundation/response/error-codes.mjs +8 -2
  625. package/foundation/response/error-codes.test.mjs +137 -10
  626. package/foundation/response/json-contract.test.mjs +57 -17
  627. package/foundation/response/json.d.mts +4 -2
  628. package/foundation/response/json.mjs +8 -10
  629. package/foundation/response/response-types.doc.d.mts +5 -1
  630. package/foundation/response/response-types.doc.mjs +41 -21
  631. package/foundation/response/response-types.doc.test.mjs +158 -0
  632. package/foundation/response/response.doc.mjs +1 -1
  633. package/foundation/text/string-utils.d.mts +8 -0
  634. package/foundation/text/string-utils.mjs +40 -10
  635. package/foundation/xle/expand.d.mts +2 -0
  636. package/foundation/xle/expand.mjs +4 -3
  637. package/foundation/xle/expand.test.mjs +54 -0
  638. package/foundation/xle/xle.test.mjs +13 -0
  639. package/package.json +10 -11
  640. package/assets/templates/themes/manifest.json +0 -95
  641. package/clients/cli/lib/update-check.mjs +0 -83
  642. package/clients/cli/lib/update-check.test.mjs +0 -137
  643. package/clients/cli/update-hint-commands.test.mjs +0 -54
@@ -0,0 +1,40 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file docs.index leaf — the section index of one topic.
5
+ *
6
+ * @input A topic name plus optional {lang, zh, dense, cwd}. Resolves the topic
7
+ * via the shared adapter and reads its lowered compiled node; nothing is
8
+ * linked, since the index never inlines a token reference.
9
+ * @output { type: 'docs.index', data: DocsIndex } — the topic's name, title and
10
+ * description and, for each section, the key it is read by, its title, and a
11
+ * one-line summary. Matches `astryx --json docs <topic> --index`.
12
+ * @position Leaf under api/docs: a topic's opt-in progressive read. One section
13
+ * is the section leaf (`docs <topic> <key>`); the whole topic, a plain topic
14
+ * read, is the detail leaf.
15
+ */
16
+
17
+ import {indexView} from '../../../foundation/doc-compiler/lenses.mjs';
18
+ import {resolveTopicDocs, topicLinks} from '../_adapter.mjs';
19
+
20
+ /**
21
+ * @param {string} topic
22
+ * @param {object} [options]
23
+ * @param {string} [options.lang]
24
+ * @param {boolean} [options.zh]
25
+ * @param {boolean} [options.dense]
26
+ * @param {string} [options.cwd]
27
+ * @returns {Promise<import('../docs.type.mjs').DocsIndexResponse>}
28
+ */
29
+ export async function index(topic, options = {}) {
30
+ const {node, entry, catalog} = await resolveTopicDocs(topic, options);
31
+ const view = indexView(node);
32
+ /** @type {import('../docs.type.mjs').DocsIndex} */
33
+ const data = {
34
+ ...view,
35
+ // A guide the docs tree places is read by its route, not its doc name.
36
+ name: entry.tree ? entry.name : view.name,
37
+ links: await topicLinks(catalog, entry),
38
+ };
39
+ return {type: 'docs.index', data};
40
+ }
@@ -0,0 +1,62 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {describe, expect, it} from 'vitest';
4
+ import {docs} from '../docs.mjs';
5
+ import {index} from './index.mjs';
6
+ import {loadDocsCatalog} from '../_adapter.mjs';
7
+
8
+ const SLOW = 60_000;
9
+
10
+ describe('docs.index leaf', () => {
11
+ it('lists each section by key, title, and summary', async () => {
12
+ const res = await index('theme');
13
+ expect(res.type).toBe('docs.index');
14
+ expect(res.data).toMatchObject({name: 'theme', title: expect.any(String)});
15
+ const keys = res.data.sections.map(s => s.id);
16
+ expect(new Set(keys).size).toBe(keys.length);
17
+ for (const entry of res.data.sections) {
18
+ expect(Object.keys(entry)).toEqual(['id', 'title', 'summary']);
19
+ expect(entry.summary.length).toBeLessThanOrEqual(240);
20
+ }
21
+ }, SLOW);
22
+
23
+ it('names the sections the full topic has, with the same keys', async () => {
24
+ const full = await docs('theme');
25
+ const {data} = await index('theme');
26
+ expect(data.sections.map(s => [s.id, s.title])).toEqual(
27
+ full.data.sections.map(s => [s.id, s.title]),
28
+ );
29
+ }, SLOW);
30
+
31
+ it('keeps every key the same in every language', async () => {
32
+ const english = (await index('theme')).data.sections.map(s => s.id);
33
+ for (const lang of ['zh', 'dense']) {
34
+ const localized = await index('theme', {lang});
35
+ expect(localized.data.sections.map(s => s.id)).toEqual(english);
36
+ }
37
+ }, SLOW);
38
+
39
+ it('lists keys every section can be read by', async () => {
40
+ const catalog = await loadDocsCatalog();
41
+ for (const entry of catalog.entries()) {
42
+ const {data} = await index(entry.name);
43
+ for (const {id, title} of data.sections) {
44
+ const read = await docs(entry.name, id);
45
+ expect(read.data.title).toBe(title);
46
+ }
47
+ }
48
+ }, SLOW);
49
+ });
50
+
51
+ describe('docs() topic reads', () => {
52
+ it('returns the whole topic by default', async () => {
53
+ const res = await docs('theme');
54
+ expect(res.type).toBe('docs.detail');
55
+ expect(res.data.sections[0].content.length).toBeGreaterThan(0);
56
+ }, SLOW);
57
+
58
+ it('returns the section index on request', async () => {
59
+ const res = await docs('theme', undefined, {index: true});
60
+ expect(res.type).toBe('docs.index');
61
+ }, SLOW);
62
+ });
@@ -0,0 +1,555 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Integration docs in the docs tree (spec:AST-046, spec:AST-047): an
5
+ * integration's namespace docs and placed guides join the CLI's tree with the
6
+ * same moves, links, search, and doctor checks, named by its provider id.
7
+ */
8
+
9
+ import * as fs from 'node:fs';
10
+ import * as path from 'node:path';
11
+ import {afterEach, beforeEach, describe, expect, it} from 'vitest';
12
+ import {docs} from './docs.mjs';
13
+ import {loadDocsCatalog} from './_adapter.mjs';
14
+ import {search} from '../search/search.mjs';
15
+ import {checkDocsTree} from '../doctor/doctor.mjs';
16
+ import {integrationDocConflicts} from '../integration/authoring-checks.mjs';
17
+
18
+ const SLOW = 60_000;
19
+
20
+ /** @type {string} */
21
+ let tmpDir;
22
+
23
+ const NAMESPACE = {
24
+ type: 'namespace',
25
+ name: 'acme',
26
+ title: 'Acme',
27
+ summary: 'Everything about the Acme kit.',
28
+ slots: {guides: {title: 'Guides', accepts: {kinds: ['generic']}}},
29
+ };
30
+
31
+ /**
32
+ * A guide placed in the acme namespace.
33
+ * @param {string} name
34
+ * @param {object} [fields]
35
+ */
36
+ function guide(name, fields = {}) {
37
+ return {
38
+ type: 'generic',
39
+ name,
40
+ title: `Acme ${name}`,
41
+ description: `How to ${name} the Acme kit.`,
42
+ placement: {parent: 'namespace:acme', slot: 'guides'},
43
+ sections: [
44
+ {title: 'Overview', content: [{type: 'prose', text: `Do ${name}.`}]},
45
+ ],
46
+ ...fields,
47
+ };
48
+ }
49
+
50
+ /** The docs of a small integration: a namespace, two guides, and a topic. */
51
+ function kit() {
52
+ return {
53
+ 'acme.doc.mjs': NAMESPACE,
54
+ 'setup.doc.mjs': guide('setup', {
55
+ placement: {parent: 'namespace:acme', slot: 'guides', order: 1},
56
+ sections: [
57
+ {
58
+ title: 'Install',
59
+ content: [
60
+ {
61
+ type: 'prose',
62
+ text: 'Frobnicate the kit, then check it with {@link @astryxdesign/cli:command:doctor}.',
63
+ },
64
+ {type: 'prose', text: 'Next: {@link generic:deploy}.'},
65
+ ],
66
+ },
67
+ {
68
+ title: 'Configure',
69
+ content: [{type: 'prose', text: 'Add it to astryx.config.'}],
70
+ },
71
+ ],
72
+ }),
73
+ 'deploy.doc.mjs': guide('deploy', {
74
+ placement: {parent: 'namespace:acme', slot: 'guides', order: 2},
75
+ }),
76
+ 'notes.doc.mjs': {
77
+ type: 'generic',
78
+ name: 'acme-notes',
79
+ title: 'Acme notes',
80
+ description: 'Notes about the kit.',
81
+ sections: [
82
+ {
83
+ title: 'Start',
84
+ content: [{type: 'prose', text: 'Start at {@link generic:setup}.'}],
85
+ },
86
+ ],
87
+ },
88
+ };
89
+ }
90
+
91
+ /** A guide whose only link names no doc. */
92
+ const broken = () =>
93
+ guide('broken', {
94
+ sections: [
95
+ {
96
+ title: 'Overview',
97
+ content: [{type: 'prose', text: 'See {@link generic:nope}.'}],
98
+ },
99
+ ],
100
+ });
101
+
102
+ /**
103
+ * A consumer project that configures `@acme/kit`, whose manifest names a
104
+ * provider id that differs from its package name.
105
+ * @param {Record<string, object>} files
106
+ */
107
+ function scaffold(files) {
108
+ fs.writeFileSync(
109
+ path.join(tmpDir, 'package.json'),
110
+ JSON.stringify({name: 'consumer'}),
111
+ );
112
+ fs.writeFileSync(
113
+ path.join(tmpDir, 'astryx.config.mjs'),
114
+ "export default {integrations: ['@acme/kit']};\n",
115
+ );
116
+ const pkgDir = path.join(tmpDir, 'node_modules', '@acme', 'kit');
117
+ fs.mkdirSync(path.join(pkgDir, 'docs'), {recursive: true});
118
+ fs.writeFileSync(
119
+ path.join(pkgDir, 'package.json'),
120
+ JSON.stringify({name: '@acme/kit', version: '1.0.0'}),
121
+ );
122
+ fs.writeFileSync(
123
+ path.join(pkgDir, 'astryx.integration.mjs'),
124
+ "export default {docs: './docs', providerId: '@acme/tree-provider'};\n",
125
+ );
126
+ for (const [file, doc] of Object.entries(files)) {
127
+ fs.writeFileSync(
128
+ path.join(pkgDir, 'docs', file),
129
+ `export const docs = ${JSON.stringify(doc, null, 2)};\n`,
130
+ );
131
+ }
132
+ }
133
+
134
+ beforeEach(() => {
135
+ tmpDir = fs.mkdtempSync(
136
+ path.join(process.cwd(), '.astryx-integration-tree-test-'),
137
+ );
138
+ });
139
+
140
+ afterEach(() => {
141
+ fs.rmSync(tmpDir, {recursive: true, force: true});
142
+ });
143
+
144
+ describe('integration docs in the docs tree', () => {
145
+ it('names a package whose docs did not load, instead of dropping them silently', async () => {
146
+ scaffold({
147
+ ...kit(),
148
+ 'broken.doc.mjs': {
149
+ type: 'generic',
150
+ name: 'broken',
151
+ title: 'Broken',
152
+ description: 'A topic whose block no topic may hold.',
153
+ sections: [
154
+ {
155
+ title: 'Only',
156
+ content: [
157
+ {
158
+ type: 'workflow',
159
+ steps: [{title: 'Set up', references: ['generic:setup']}],
160
+ },
161
+ ],
162
+ },
163
+ ],
164
+ },
165
+ });
166
+ const listed = await docs(undefined, undefined, {cwd: tmpDir});
167
+ expect(listed.meta?.notLoaded).toEqual([
168
+ expect.objectContaining({package: '@acme/kit', message: expect.any(String)}),
169
+ ]);
170
+ }, 60_000);
171
+
172
+ it('lists an integration namespace beside the CLI, named by its provider id', async () => {
173
+ scaffold(kit());
174
+ const listed = await docs(undefined, undefined, {cwd: tmpDir});
175
+ expect(listed.meta.namespaces).toContainEqual({
176
+ topic: 'acme',
177
+ description: 'Everything about the Acme kit.',
178
+ package: '@acme/kit',
179
+ });
180
+ const top = await docs('acme', undefined, {cwd: tmpDir});
181
+ expect(top.type).toBe('docs.node');
182
+ expect(top.data).toMatchObject({
183
+ id: 'astryx:artifact:v1/%40acme%2Ftree-provider/namespace/acme',
184
+ package: '@acme/kit',
185
+ links: {up: 'astryx docs'},
186
+ });
187
+ expect(
188
+ top.data.slots[0].children.map((/** @type {any} */ c) => c.route),
189
+ ).toEqual(['acme/setup', 'acme/deploy']);
190
+ }, SLOW);
191
+
192
+ it('reads a placed guide one level at a time, with its links resolved', async () => {
193
+ scaffold(kit());
194
+ const index = await docs('acme/setup', undefined, {cwd: tmpDir, index: true});
195
+ expect(index.type).toBe('docs.index');
196
+ expect(index.data.links.up).toBe('astryx docs acme');
197
+ const install = await docs('acme/setup', 'install', {cwd: tmpDir});
198
+ const [prose, next] = install.data.content;
199
+ expect(prose.text).toBe(
200
+ 'Frobnicate the kit, then check it with `astryx docs cli/commands/doctor`.',
201
+ );
202
+ expect(next.text).toBe('Next: `astryx docs acme/deploy`.');
203
+ const notes = await docs('acme-notes', undefined, {cwd: tmpDir});
204
+ expect(notes.data.sections[0].content[0].text).toBe(
205
+ 'Start at `astryx docs acme/setup`.',
206
+ );
207
+ }, SLOW);
208
+
209
+ it('finds a section of the guide by search, with its package and parent', async () => {
210
+ scaffold(kit());
211
+ const {data} = await search('frobnicate', {cwd: tmpDir, type: 'doc'});
212
+ expect(data.results[0]).toMatchObject({
213
+ name: 'acme/setup',
214
+ section: 'install',
215
+ command: 'astryx docs acme/setup install',
216
+ parent: 'astryx docs acme/setup --index',
217
+ package: '@acme/kit',
218
+ });
219
+ }, SLOW);
220
+
221
+ it('passes doctor, and warns on a link that names no doc', async () => {
222
+ scaffold(kit());
223
+ const ok = await checkDocsTree({
224
+ docsCatalog: await loadDocsCatalog(tmpDir),
225
+ });
226
+ expect(ok).toMatchObject({id: 'docs-tree', status: 'pass'});
227
+ scaffold({...kit(), 'broken.doc.mjs': broken()});
228
+ const bad = await checkDocsTree({
229
+ docsCatalog: await loadDocsCatalog(tmpDir),
230
+ });
231
+ expect(bad.status).toBe('warn');
232
+ expect(bad.message).toContain('acme/broken');
233
+ expect(bad.message).toContain('"generic:nope" names no doc');
234
+ }, SLOW);
235
+
236
+ it("keeps the CLI's routes: an integration namespace or topic that claims one is withdrawn, and both doctors say so", async () => {
237
+ const flat = (/** @type {string} */ name) => ({
238
+ type: 'generic',
239
+ name,
240
+ title: `Acme ${name}`,
241
+ description: `Acme's ${name} notes.`,
242
+ sections: [
243
+ {title: 'One', content: [{type: 'prose', text: 'One.'}]},
244
+ {title: 'Two', content: [{type: 'prose', text: 'Two.'}]},
245
+ ],
246
+ });
247
+ scaffold({
248
+ ...kit(),
249
+ 'unorganized.doc.mjs': {...NAMESPACE, name: 'unorganized', title: 'Mine', summary: 'Mine.'},
250
+ 'tokens.doc.mjs': {...NAMESPACE, name: 'tokens', title: 'Acme tokens', summary: 'Acme tokens.'},
251
+ 'cli.doc.mjs': flat('cli'),
252
+ });
253
+ const listed = await docs(undefined, undefined, {cwd: tmpDir});
254
+ expect(listed.meta.namespaces).toEqual(
255
+ expect.arrayContaining([
256
+ expect.objectContaining({topic: 'cli', package: '@astryxdesign/cli'}),
257
+ expect.objectContaining({topic: 'unorganized', package: '@astryxdesign/cli'}),
258
+ ]),
259
+ );
260
+ expect(listed.meta.namespaces.filter(n => ['tokens', 'unorganized'].includes(n.topic) && n.package === '@acme/kit')).toEqual([]);
261
+ expect(listed.data.map(entry => entry.topic)).not.toContain('cli');
262
+ // Each name opens the CLI's doc, and a CLI topic keeps its home.
263
+ expect((await docs('cli', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
264
+ expect((await docs('unorganized', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'unorganized', package: '@astryxdesign/cli'});
265
+ const tokens = await docs('tokens', undefined, {cwd: tmpDir});
266
+ expect(tokens.type).toBe('docs.detail');
267
+ expect(tokens.data.links.up).toBe('astryx docs unorganized');
268
+ // The project doctor and the package doctor both name the claims.
269
+ const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
270
+ expect(check.status).toBe('warn');
271
+ expect(check.message).toContain('takes the route "unorganized", which the CLI\'s own docs keep');
272
+ expect(check.message).toContain('takes the route "tokens"');
273
+ expect(check.message).toContain('both have the route "cli"');
274
+ const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
275
+ const graph = result.data.issues.filter(issue => issue.code === 'invalid_doc_graph').map(issue => issue.message).join('\n');
276
+ expect(graph).toContain('takes the route "unorganized"');
277
+ expect(graph).toContain('takes the route "tokens"');
278
+ expect(graph).toContain('route "cli"');
279
+ }, SLOW);
280
+
281
+ it("keeps the CLI's routes from a claim that differs only in case", async () => {
282
+ const flat = (/** @type {string} */ name) => ({
283
+ type: 'generic',
284
+ name,
285
+ title: `Acme ${name}`,
286
+ description: `Acme's ${name} notes.`,
287
+ sections: [
288
+ {title: 'One', content: [{type: 'prose', text: 'One.'}]},
289
+ {title: 'Two', content: [{type: 'prose', text: 'Two.'}]},
290
+ ],
291
+ });
292
+ scaffold({...kit(), 'caps-cli.doc.mjs': flat('CLI')});
293
+ // Another spelling, in a nested folder of the package's docs.
294
+ const nested = path.join(tmpDir, 'node_modules', '@acme', 'kit', 'docs', 'nested');
295
+ fs.mkdirSync(nested, {recursive: true});
296
+ fs.writeFileSync(
297
+ path.join(nested, 'caps-unorganized.doc.mjs'),
298
+ `export const docs = ${JSON.stringify(flat('Unorganized'), null, 2)};\n`,
299
+ );
300
+ fs.writeFileSync(
301
+ path.join(nested, 'caps-tokens.doc.mjs'),
302
+ `export const docs = ${JSON.stringify(flat('TOKENS'), null, 2)};\n`,
303
+ );
304
+ expect((await docs('cli', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
305
+ expect((await docs('unorganized', undefined, {cwd: tmpDir})).data).toMatchObject({route: 'unorganized', package: '@astryxdesign/cli'});
306
+ expect((await docs('theme', undefined, {cwd: tmpDir, index: true})).data.links.up).toBe('astryx docs unorganized');
307
+ const listed = await docs(undefined, undefined, {cwd: tmpDir});
308
+ expect(listed.data.map(entry => entry.topic.toLowerCase())).not.toContain('cli');
309
+ // Search does not offer a topic whose route another doc owns.
310
+ const found = await search("Acme's CLI notes", {cwd: tmpDir, type: 'doc', limit: 20});
311
+ expect(
312
+ found.data.results.filter(hit => hit.package === '@acme/kit' && /^cli$/i.test(hit.name)),
313
+ ).toEqual([]);
314
+ const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
315
+ expect(check.status).toBe('warn');
316
+ expect(check.message).toContain('route "CLI"');
317
+ expect(check.message).toContain('takes the route "Unorganized"');
318
+ // `TOKENS` is the CLI's topic `tokens` in another spelling: the CLI's wins.
319
+ const tokens = await docs('TOKENS', undefined, {cwd: tmpDir, index: true});
320
+ expect(tokens.data).toMatchObject({name: 'tokens', links: {up: 'astryx docs unorganized'}});
321
+ expect(tokens.data.title).not.toBe('Acme TOKENS');
322
+ const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
323
+ const graph = result.data.issues
324
+ .filter(issue => issue.code === 'invalid_doc_graph')
325
+ .map(issue => issue.message)
326
+ .join('\n');
327
+ expect(graph).toContain('route "CLI"');
328
+ expect(graph).toContain('takes the route "Unorganized"');
329
+ }, SLOW);
330
+
331
+ it("keeps a replaced name for the topic that replaces it, over another integration's namespace", async () => {
332
+ scaffold({...kit(), 'tokens-ns.doc.mjs': {...NAMESPACE, name: 'tokens', title: 'Kit tokens', summary: 'Kit tokens.'}});
333
+ const two = path.join(tmpDir, 'node_modules', '@acme', 'two');
334
+ fs.mkdirSync(path.join(two, 'docs'), {recursive: true});
335
+ fs.writeFileSync(path.join(two, 'package.json'), JSON.stringify({name: '@acme/two', version: '1.0.0'}));
336
+ fs.writeFileSync(path.join(two, 'astryx.integration.mjs'), "export default {docs: './docs'};\n");
337
+ fs.writeFileSync(
338
+ path.join(two, 'docs', 'acme-tokens.doc.mjs'),
339
+ `export const docs = ${JSON.stringify({
340
+ type: 'generic',
341
+ name: 'acme-tokens',
342
+ title: 'Acme tokens',
343
+ description: 'Acme tokens.',
344
+ replaces: 'tokens',
345
+ sections: [{title: 'One', content: [{type: 'prose', text: 'One.'}]}],
346
+ }, null, 2)};\n`,
347
+ );
348
+ fs.writeFileSync(
349
+ path.join(tmpDir, 'astryx.config.mjs'),
350
+ "export default {integrations: ['@acme/kit', '@acme/two']};\n",
351
+ );
352
+ const listed = await docs(undefined, undefined, {cwd: tmpDir});
353
+ expect(listed.meta.namespaces.map(entry => entry.topic)).not.toContain('tokens');
354
+ const read = await docs('tokens', undefined, {cwd: tmpDir, index: true});
355
+ expect(read.data.name).toBe('acme-tokens');
356
+ const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
357
+ expect(check.status).toBe('warn');
358
+ expect(check.message).toContain('which the topic "acme-tokens" also answers to');
359
+ }, SLOW);
360
+
361
+ it('keeps every name a topic replaced twice answers to, and the CLI\'s links to it still open', async () => {
362
+ scaffold({...kit(), 'tokens-ns.doc.mjs': {...NAMESPACE, name: 'tokens', title: 'Kit tokens', summary: 'Kit tokens.'}});
363
+ /** @param {string} pkg @param {string} name @param {string} replaces */
364
+ const replacement = (pkg, name, replaces) => {
365
+ const dir = path.join(tmpDir, 'node_modules', '@acme', pkg);
366
+ fs.mkdirSync(path.join(dir, 'docs'), {recursive: true});
367
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({name: `@acme/${pkg}`, version: '1.0.0'}));
368
+ fs.writeFileSync(path.join(dir, 'astryx.integration.mjs'), "export default {docs: './docs'};\n");
369
+ fs.writeFileSync(
370
+ path.join(dir, 'docs', `${name}.doc.mjs`),
371
+ `export const docs = ${JSON.stringify({
372
+ type: 'generic',
373
+ name,
374
+ title: `Tokens by ${pkg}`,
375
+ description: `Tokens by ${pkg}.`,
376
+ replaces,
377
+ sections: [{title: 'One', content: [{type: 'prose', text: 'One.'}]}],
378
+ }, null, 2)};\n`,
379
+ );
380
+ };
381
+ replacement('two', 'acme-tokens', 'tokens');
382
+ replacement('three', 'b-tokens', 'tokens');
383
+ replacement('four', 'super-tokens', 'b-tokens');
384
+ fs.writeFileSync(
385
+ path.join(tmpDir, 'astryx.config.mjs'),
386
+ "export default {integrations: ['@acme/kit', '@acme/two', '@acme/three', '@acme/four']};\n",
387
+ );
388
+ const listed = await docs(undefined, undefined, {cwd: tmpDir});
389
+ expect(listed.meta.namespaces.map(entry => entry.topic)).not.toContain('tokens');
390
+ for (const name of ['tokens', 'acme-tokens', 'b-tokens', 'super-tokens']) {
391
+ expect((await docs(name, undefined, {cwd: tmpDir, index: true})).data.name).toBe('super-tokens');
392
+ }
393
+ // A walk over every topic: the CLI's own links to `tokens` still open it.
394
+ /** @type {string[]} */
395
+ const raw = [];
396
+ for (const entry of listed.data) {
397
+ const read = await docs(entry.topic, undefined, {cwd: tmpDir});
398
+ if (/\{@link [^}]*tokens\}/.test(JSON.stringify(read.data))) raw.push(entry.topic);
399
+ }
400
+ expect(raw).toEqual([]);
401
+ const principles = await docs('principles', undefined, {cwd: tmpDir});
402
+ expect(JSON.stringify(principles.data)).toContain('astryx docs super-tokens');
403
+ const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
404
+ expect(check.message).toContain('takes the route "tokens", which the topic "super-tokens" also answers to');
405
+ expect(check.message).not.toContain('names no doc');
406
+ }, SLOW);
407
+
408
+ it("keeps the CLI's routes from a replacement that answers to one, in one package or across a chain", async () => {
409
+ const flat = (/** @type {string} */ name, /** @type {object} */ extra = {}) => ({
410
+ type: 'generic',
411
+ name,
412
+ title: `Acme ${name}`,
413
+ description: `Acme's ${name} notes.`,
414
+ sections: [
415
+ {title: 'One', content: [{type: 'prose', text: 'One.'}]},
416
+ {title: 'Two', content: [{type: 'prose', text: 'Two.'}]},
417
+ ],
418
+ ...extra,
419
+ });
420
+ scaffold({
421
+ ...kit(),
422
+ 'a-cli.doc.mjs': flat('cli'),
423
+ 'a-unorganized.doc.mjs': flat('Unorganized'),
424
+ 'z-b2.doc.mjs': flat('b2', {replaces: 'cli'}),
425
+ 'z-u2.doc.mjs': flat('u2', {replaces: 'Unorganized'}),
426
+ });
427
+ // Another package carries the chain on: c3 replaces b2, which replaced cli.
428
+ const three = path.join(tmpDir, 'node_modules', '@acme', 'three');
429
+ fs.mkdirSync(path.join(three, 'docs'), {recursive: true});
430
+ fs.writeFileSync(path.join(three, 'package.json'), JSON.stringify({name: '@acme/three', version: '1.0.0'}));
431
+ fs.writeFileSync(path.join(three, 'astryx.integration.mjs'), "export default {docs: './docs'};\n");
432
+ fs.writeFileSync(
433
+ path.join(three, 'docs', 'c3.doc.mjs'),
434
+ `export const docs = ${JSON.stringify(flat('c3', {replaces: 'b2'}), null, 2)};\n`,
435
+ );
436
+ fs.writeFileSync(
437
+ path.join(tmpDir, 'astryx.config.mjs'),
438
+ "export default {integrations: ['@acme/kit', '@acme/three']};\n",
439
+ );
440
+ for (const name of ['cli', 'CLI']) {
441
+ expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: 'cli', package: '@astryxdesign/cli'});
442
+ }
443
+ for (const name of ['unorganized', 'UNORGANIZED']) {
444
+ expect((await docs(name, undefined, {cwd: tmpDir})).data).toMatchObject({route: 'unorganized', package: '@astryxdesign/cli'});
445
+ }
446
+ // The replacement still answers to its own names.
447
+ for (const name of ['b2', 'c3']) {
448
+ expect((await docs(name, undefined, {cwd: tmpDir, index: true})).data.name).toBe('c3');
449
+ }
450
+ const listed = await docs(undefined, undefined, {cwd: tmpDir});
451
+ for (const entry of listed.data) {
452
+ const read = await docs(entry.topic, undefined, {cwd: tmpDir});
453
+ expect(read.type).toBe('docs.detail');
454
+ expect(read.data.name).toBe(entry.topic);
455
+ }
456
+ const check = await checkDocsTree({docsCatalog: await loadDocsCatalog(tmpDir)});
457
+ expect(check.status).toBe('warn');
458
+ expect(check.message).toContain('The topic "c3" answers to "cli" through replaces');
459
+ expect(check.message).toContain('The topic "u2" answers to "unorganized" through replaces');
460
+ const inPackage = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
461
+ const graph = inPackage.data.issues
462
+ .filter(issue => issue.code === 'invalid_doc_graph')
463
+ .map(issue => issue.message)
464
+ .join('\n');
465
+ expect(graph).toContain('answers to "cli" through replaces');
466
+ }, SLOW);
467
+
468
+ it('runs the same checks inside the package: doctor integration docs', async () => {
469
+ scaffold({...kit(), 'broken.doc.mjs': broken()});
470
+ const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
471
+ expect(result.data.issues).toContainEqual(
472
+ expect.objectContaining({
473
+ code: 'invalid_doc_graph',
474
+ severity: 'warning',
475
+ message: expect.stringContaining('"generic:nope" names no doc'),
476
+ }),
477
+ );
478
+ }, SLOW);
479
+
480
+ it("resolves an extension's links against the extension's provider, not the base topic's", async () => {
481
+ scaffold({
482
+ ...kit(),
483
+ 'integrations.doc.mjs': guide('integrations'),
484
+ 'theme-acme.doc.mjs': {
485
+ type: 'generic',
486
+ name: 'theme-acme',
487
+ title: 'Acme theming',
488
+ description: 'Acme notes on theming.',
489
+ extends: 'theme',
490
+ sections: [
491
+ {
492
+ title: 'Acme theming notes',
493
+ content: [
494
+ {
495
+ type: 'prose',
496
+ text: 'See {@link generic:integrations}, and {@link @astryxdesign/cli:generic:tokens} for the tokens.',
497
+ },
498
+ ],
499
+ },
500
+ ],
501
+ },
502
+ });
503
+ const {data} = await docs('theme', 'acme-theming-notes', {cwd: tmpDir});
504
+ // `generic:integrations` is the extension's own guide, never the CLI's
505
+ // `cli/integrations`; a provider-qualified link reaches the CLI's topic.
506
+ expect(data.content[0].text).toBe(
507
+ 'See `astryx docs acme/integrations`, and `astryx docs tokens` for the tokens.',
508
+ );
509
+ // The CLI's own sections of the topic still resolve against the CLI.
510
+ const full = await docs('theme', undefined, {cwd: tmpDir});
511
+ expect(JSON.stringify(full.data)).not.toContain('{@link');
512
+ }, SLOW);
513
+
514
+ it("warns, in the project and in the package, on an extension link that names no doc of its provider", async () => {
515
+ scaffold({
516
+ ...kit(),
517
+ 'theme-acme.doc.mjs': {
518
+ type: 'generic',
519
+ name: 'theme-acme',
520
+ title: 'Acme theming',
521
+ description: 'Acme notes on theming.',
522
+ extends: 'theme',
523
+ sections: [
524
+ {
525
+ title: 'Acme theming notes',
526
+ content: [{type: 'prose', text: 'See {@link generic:tokens}.'}],
527
+ },
528
+ ],
529
+ },
530
+ });
531
+ const check = await checkDocsTree({
532
+ docsCatalog: await loadDocsCatalog(tmpDir),
533
+ });
534
+ expect(check.status).toBe('warn');
535
+ expect(check.message).toContain('"generic:tokens" names no doc');
536
+ const result = await integrationDocConflicts('@acme/kit', {cwd: tmpDir});
537
+ expect(result.data.issues).toContainEqual(
538
+ expect.objectContaining({
539
+ code: 'invalid_doc_graph',
540
+ message: expect.stringContaining('"generic:tokens" names no doc'),
541
+ }),
542
+ );
543
+ }, SLOW);
544
+
545
+ it('keeps the CLI route when an integration claims it, and names the claim', async () => {
546
+ scaffold({'cli.doc.mjs': {...NAMESPACE, name: 'cli', title: 'Not the CLI'}});
547
+ const top = await docs('cli', undefined, {cwd: tmpDir});
548
+ expect(top.data.package).toBe('@astryxdesign/cli');
549
+ const check = await checkDocsTree({
550
+ docsCatalog: await loadDocsCatalog(tmpDir),
551
+ });
552
+ expect(check.status).toBe('warn');
553
+ expect(check.message).toContain('both have the route "cli"');
554
+ }, SLOW);
555
+ });