@astryxdesign/cli 0.7.2-canary.fe2c655 → 0.7.2

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 (509) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +175 -154
  3. package/api/build/_adapter.d.mts +8 -0
  4. package/api/build/_adapter.mjs +12 -1
  5. package/api/build/build.doc.mjs +4 -0
  6. package/api/build/help/help.mjs +1 -1
  7. package/api/build/kit/kit.mjs +3 -11
  8. package/api/component/_adapter.d.mts +72 -1
  9. package/api/component/_adapter.mjs +212 -18
  10. package/api/component/component.doc.mjs +6 -1
  11. package/api/component/component.mjs +82 -15
  12. package/api/component/component.test.mjs +80 -0
  13. package/api/component/doc-links.test.mjs +386 -0
  14. package/api/component/integration-export-name.test.mjs +644 -0
  15. package/api/component/list/list.mjs +42 -4
  16. package/api/discover/_adapter.d.mts +132 -12
  17. package/api/discover/_adapter.mjs +488 -27
  18. package/api/discover/_adapter.test.mjs +599 -17
  19. package/api/discover/_catalog-view.d.mts +16 -5
  20. package/api/discover/_catalog-view.mjs +32 -8
  21. package/api/discover/detail/doc/doc.mjs +9 -1
  22. package/api/discover/discover.d.mts +11 -0
  23. package/api/discover/discover.doc.mjs +9 -7
  24. package/api/discover/discover.mjs +121 -19
  25. package/api/discover/discover.type.d.mts +20 -7
  26. package/api/discover/discover.type.mjs +17 -7
  27. package/api/discover/list/list.d.mts +4 -3
  28. package/api/discover/list/list.mjs +17 -10
  29. package/api/docs/_adapter.d.mts +74 -0
  30. package/api/docs/_adapter.mjs +553 -16
  31. package/api/docs/docs.doc.mjs +2 -1
  32. package/api/docs/docs.mjs +2 -1
  33. package/api/docs/docs.test.mjs +5 -2
  34. package/api/docs/integration-tree.test.mjs +22 -0
  35. package/api/docs/integrationDocs.test.mjs +124 -0
  36. package/api/docs/list/list.mjs +12 -2
  37. package/api/docs/reference-blocks.test.mjs +1 -3
  38. package/api/doctor/_adapter.d.mts +108 -0
  39. package/api/doctor/_adapter.mjs +223 -4
  40. package/api/doctor/doctor.d.mts +199 -0
  41. package/api/doctor/doctor.doc.mjs +3 -2
  42. package/api/doctor/doctor.mjs +530 -34
  43. package/api/doctor/doctor.test.mjs +180 -14
  44. package/api/doctor/release-checks.test.mjs +156 -0
  45. package/api/doctor/theme-checks.mjs +17 -4
  46. package/api/doctor/theme-checks.test.mjs +223 -7
  47. package/api/error.d.mts +10 -0
  48. package/api/error.mjs +25 -0
  49. package/api/gap-report/gap-report.d.mts +3 -0
  50. package/api/gap-report/gap-report.doc.mjs +11 -3
  51. package/api/gap-report/gap-report.mjs +219 -52
  52. package/api/gap-report/gap-report.test.mjs +233 -0
  53. package/api/gap-report/gap-report.type.d.mts +41 -0
  54. package/api/gap-report/gap-report.type.mjs +18 -0
  55. package/api/hook/_adapter.mjs +3 -11
  56. package/api/hook/hook.doc.mjs +4 -0
  57. package/api/hook/list/list.d.mts +1 -1
  58. package/api/index.d.mts +2 -0
  59. package/api/index.mjs +2 -0
  60. package/api/init/_adapter.d.mts +22 -0
  61. package/api/init/_adapter.mjs +59 -0
  62. package/api/init/init.d.mts +7 -5
  63. package/api/init/init.doc.mjs +28 -7
  64. package/api/init/init.mjs +28 -4
  65. package/api/init/init.type.d.mts +48 -3
  66. package/api/init/init.type.mjs +37 -3
  67. package/api/init/run/run.d.mts +1 -1
  68. package/api/init/run/run.mjs +17 -6
  69. package/api/init/user/user.d.mts +14 -0
  70. package/api/init/user/user.mjs +87 -0
  71. package/api/init/user/user.test.mjs +232 -0
  72. package/api/integration/_adapter.d.mts +45 -0
  73. package/api/integration/_adapter.mjs +112 -0
  74. package/api/integration/add-contribution.component-names.test.mjs +66 -0
  75. package/api/integration/add-contribution.mjs +8 -4
  76. package/api/integration/add-contribution.test.mjs +4 -2
  77. package/api/integration/authoring-checks.mjs +110 -6
  78. package/api/integration/authoring-checks.test.mjs +808 -0
  79. package/api/integration/authoring-checks.type.d.mts +143 -0
  80. package/api/integration/authoring-checks.type.mjs +74 -2
  81. package/api/integration/check/check.d.mts +96 -0
  82. package/api/integration/check/check.mjs +357 -0
  83. package/api/integration/check/check.test.mjs +489 -0
  84. package/api/integration/integration-check.type.d.mts +118 -0
  85. package/api/integration/integration-check.type.mjs +84 -0
  86. package/api/integration/integrationCheck.doc.d.mts +10 -0
  87. package/api/integration/integrationCheck.doc.mjs +73 -0
  88. package/api/integration/integrationComponentConflicts.doc.mjs +45 -6
  89. package/api/integration/integrationDocConflicts.doc.mjs +22 -5
  90. package/api/integration/pack-check.mjs +364 -120
  91. package/api/integration/pack-check.test.mjs +730 -10
  92. package/api/integration/validate-integration-fixes.test.mjs +67 -0
  93. package/api/integration/validate-integration.d.mts +8 -0
  94. package/api/integration/validate-integration.mjs +63 -9
  95. package/api/integration/validate-integration.test.mjs +88 -8
  96. package/api/integration/validate-integration.type.d.mts +16 -0
  97. package/api/integration/validate-integration.type.mjs +14 -1
  98. package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
  99. package/api/integration/validateIntegration.doc.mjs +19 -3
  100. package/api/search/_adapter.d.mts +11 -0
  101. package/api/search/_adapter.mjs +25 -0
  102. package/api/search/search.d.mts +82 -13
  103. package/api/search/search.doc.mjs +8 -3
  104. package/api/search/search.domain-priority.test.mjs +108 -18
  105. package/api/search/search.integration-check.test.mjs +24 -0
  106. package/api/search/search.mjs +645 -64
  107. package/api/search/search.test.mjs +179 -1
  108. package/api/search/search.type.d.mts +14 -1
  109. package/api/search/search.type.mjs +6 -1
  110. package/api/swizzle/_adapter.mjs +2 -2
  111. package/api/swizzle/copy/copy.mjs +29 -15
  112. package/api/template/template-integration.test.mjs +1 -1
  113. package/api/template/template.test.mjs +120 -3
  114. package/api/theme/_adapter.d.mts +16 -0
  115. package/api/theme/_adapter.mjs +32 -5
  116. package/api/theme/build/build.d.mts +2 -1
  117. package/api/theme/build/build.family.test.mjs +64 -0
  118. package/api/theme/build/build.mjs +250 -38
  119. package/api/theme/build/build.packed-old-core.test.mjs +20 -3
  120. package/api/theme/build/font-warning.mjs +5 -3
  121. package/api/theme/build/font-warning.test.mjs +2 -1
  122. package/api/theme/remove/remove.test.mjs +2 -2
  123. package/api/theme/targets/targets.mjs +3 -10
  124. package/api/theme/themeBuild.doc.mjs +4 -4
  125. package/api/theme/themeTargets.doc.mjs +4 -0
  126. package/api/theme/use/use.test.mjs +1 -1
  127. package/api/upgrade/_adapter.d.mts +40 -2
  128. package/api/upgrade/_adapter.mjs +118 -5
  129. package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
  130. package/api/upgrade/run/run.mjs +35 -2
  131. package/api/upgrade/status/status.d.mts +21 -5
  132. package/api/upgrade/status/status.mjs +45 -8
  133. package/api/upgrade/upgrade.doc.mjs +6 -3
  134. package/api/upgrade/upgrade.mjs +5 -1
  135. package/api/upgrade/upgrade.type.d.mts +23 -0
  136. package/api/upgrade/upgrade.type.mjs +16 -1
  137. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  138. package/assets/codemods/registry.mjs +1 -0
  139. package/assets/codemods/runner.mjs +7 -1
  140. package/assets/codemods/transforms/v0.7.2/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
  141. package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
  142. package/assets/codemods/transforms/v0.7.2/migrate-list-edge-compensation-to-edge.mjs +198 -0
  143. package/assets/discover/official-packages.json +367 -0
  144. package/assets/docs/README.md +10 -0
  145. package/assets/docs/author-a-theme.doc.mjs +3 -3
  146. package/assets/docs/browser-support.doc.mjs +1 -1
  147. package/assets/docs/getting-started.doc.mjs +26 -6
  148. package/assets/docs/styling-overview.doc.mjs +1 -1
  149. package/assets/docs/theme.doc.dense.mjs +1 -1
  150. package/assets/docs/theme.doc.mjs +2 -2
  151. package/assets/docs/theme.doc.zh.mjs +1 -1
  152. package/assets/docs/tree/add-a-component.doc.mjs +22 -2
  153. package/assets/docs/tree/add-a-theme.doc.mjs +13 -3
  154. package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
  155. package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
  156. package/assets/docs/tree/block-template.doc.mjs +8 -20
  157. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  158. package/assets/docs/tree/building-blocks.doc.mjs +4 -0
  159. package/assets/docs/tree/check-the-props.doc.mjs +201 -0
  160. package/assets/docs/tree/check-your-docs.doc.mjs +69 -11
  161. package/assets/docs/tree/checks.doc.mjs +32 -24
  162. package/assets/docs/tree/ci-and-containers.doc.mjs +88 -0
  163. package/assets/docs/tree/cli-command.doc.mjs +142 -0
  164. package/assets/docs/tree/cli.doc.mjs +6 -0
  165. package/assets/docs/tree/codemods.doc.mjs +17 -7
  166. package/assets/docs/tree/commands.doc.mjs +7 -1
  167. package/assets/docs/tree/component-family.doc.mjs +8 -6
  168. package/assets/docs/tree/component-imports.doc.mjs +21 -3
  169. package/assets/docs/tree/components.doc.mjs +7 -1
  170. package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
  171. package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
  172. package/assets/docs/tree/configuration.doc.mjs +7 -3
  173. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
  174. package/assets/docs/tree/define-the-theme.doc.mjs +6 -5
  175. package/assets/docs/tree/describe-the-component.doc.mjs +3 -3
  176. package/assets/docs/tree/docs.doc.mjs +9 -3
  177. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  178. package/assets/docs/tree/document-the-theme.doc.mjs +3 -3
  179. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  180. package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
  181. package/assets/docs/tree/fonts-and-assets.doc.mjs +2 -2
  182. package/assets/docs/tree/generate-a-palette.doc.mjs +7 -5
  183. package/assets/docs/tree/global-integrations.doc.mjs +124 -0
  184. package/assets/docs/tree/global.doc.mjs +131 -0
  185. package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
  186. package/assets/docs/tree/install-once.doc.mjs +105 -0
  187. package/assets/docs/tree/integrations.doc.mjs +13 -1
  188. package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
  189. package/assets/docs/tree/layout.doc.mjs +6 -6
  190. package/assets/docs/tree/links.doc.mjs +7 -6
  191. package/assets/docs/tree/migration-setup.doc.mjs +3 -2
  192. package/assets/docs/tree/migration-verification.doc.mjs +0 -1
  193. package/assets/docs/tree/migration.doc.mjs +0 -1
  194. package/assets/docs/tree/monorepos.doc.mjs +84 -0
  195. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  196. package/assets/docs/tree/page-template.doc.mjs +4 -8
  197. package/assets/docs/tree/problems.doc.mjs +205 -0
  198. package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
  199. package/assets/docs/tree/publishing.doc.mjs +6 -6
  200. package/assets/docs/tree/quick-start.doc.mjs +53 -27
  201. package/assets/docs/tree/reference.doc.mjs +192 -0
  202. package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
  203. package/assets/docs/tree/replace-a-core-template.doc.mjs +10 -12
  204. package/assets/docs/tree/scaffold.doc.mjs +1 -1
  205. package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
  206. package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
  207. package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
  208. package/assets/docs/tree/single-component.doc.mjs +15 -6
  209. package/assets/docs/tree/start-a-template.doc.mjs +18 -8
  210. package/assets/docs/tree/subcomponent.doc.mjs +6 -6
  211. package/assets/docs/tree/template-assets.doc.mjs +2 -2
  212. package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
  213. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  214. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  215. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  216. package/assets/docs/tree/template-styles.doc.mjs +2 -2
  217. package/assets/docs/tree/templates.doc.mjs +7 -1
  218. package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
  219. package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
  220. package/assets/docs/tree/themes.doc.mjs +4 -0
  221. package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
  222. package/assets/docs/tree/troubleshooting.doc.mjs +29 -13
  223. package/assets/docs/tree/type-scale.doc.mjs +3 -3
  224. package/assets/docs/tree/uninstall.doc.mjs +109 -0
  225. package/assets/docs/tree/updates.doc.mjs +92 -0
  226. package/assets/docs/tree/upgrading.doc.mjs +6 -6
  227. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +14 -2
  228. package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
  229. package/assets/docs/tree/versioning.doc.mjs +10 -9
  230. package/assets/docs/tree/who-answers.doc.mjs +119 -0
  231. package/assets/docs/tree/write-the-template-file.doc.mjs +7 -6
  232. package/assets/docs/use-a-theme.doc.mjs +2 -2
  233. package/assets/docs/working-with-ai.doc.mjs +66 -13
  234. package/assets/theme.template.ts +1 -1
  235. package/authoring/codemod/codemod.doc.mjs +7 -3
  236. package/authoring/config/config.doc.mjs +9 -6
  237. package/authoring/config/type.ts +4 -2
  238. package/authoring/debug/parse.d.mts +5 -5
  239. package/authoring/discover/discover.doc.mjs +7 -1
  240. package/authoring/doctypes/_schema.d.mts +8 -3
  241. package/authoring/doctypes/_schema.mjs +1 -0
  242. package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
  243. package/authoring/doctypes/command/command.doc.mjs +20 -12
  244. package/authoring/doctypes/command/type.ts +14 -0
  245. package/authoring/doctypes/component/component.doc.mjs +30 -27
  246. package/authoring/doctypes/component/type.ts +21 -8
  247. package/authoring/doctypes/enum/enum.doc.mjs +7 -4
  248. package/authoring/doctypes/function/function.doc.mjs +9 -8
  249. package/authoring/doctypes/hook/hook.doc.mjs +5 -4
  250. package/authoring/doctypes/hook/type.ts +4 -0
  251. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
  252. package/authoring/doctypes/reference/reference.doc.mjs +12 -11
  253. package/authoring/doctypes/schema/schema.doc.mjs +9 -9
  254. package/authoring/doctypes/template/integration-template.doc.d.mts +11 -0
  255. package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
  256. package/authoring/doctypes/template/parse.d.mts +6 -2
  257. package/authoring/doctypes/template/parse.mjs +3 -1
  258. package/authoring/doctypes/template/template.doc.mjs +3 -3
  259. package/authoring/doctypes/template/type.ts +22 -0
  260. package/authoring/doctypes/theme/theme.doc.mjs +2 -2
  261. package/authoring/gap-report/gap-report.doc.mjs +2 -2
  262. package/authoring/identity/identity.doc.mjs +3 -3
  263. package/authoring/index.d.ts +2 -0
  264. package/authoring/integration/integration.doc.mjs +30 -6
  265. package/authoring/integration/parse.test.mjs +21 -0
  266. package/authoring/integration/schema.d.mts +16 -3
  267. package/authoring/integration/schema.mjs +34 -2
  268. package/authoring/integration/type.ts +12 -0
  269. package/clients/cli/bin/astryx.mjs +20 -3
  270. package/clients/cli/cli-command.test.mjs +166 -0
  271. package/clients/cli/commands/blog.doc.mjs +1 -0
  272. package/clients/cli/commands/build-theme.batch-report.test.mjs +17 -3
  273. package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
  274. package/clients/cli/commands/build-theme.mjs +26 -13
  275. package/clients/cli/commands/build-theme.path-safety.test.mjs +224 -6
  276. package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
  277. package/clients/cli/commands/build.doc.mjs +1 -0
  278. package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
  279. package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
  280. package/clients/cli/commands/component.doc.mjs +1 -0
  281. package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
  282. package/clients/cli/commands/discover.doc.mjs +9 -1
  283. package/clients/cli/commands/discover.mjs +144 -93
  284. package/clients/cli/commands/discover.no-source.test.mjs +448 -33
  285. package/clients/cli/commands/discover.sources.test.mjs +20 -1
  286. package/clients/cli/commands/docs.doc.mjs +1 -0
  287. package/clients/cli/commands/docs.mjs +49 -19
  288. package/clients/cli/commands/docs.test.mjs +2 -2
  289. package/clients/cli/commands/doctor-integration-components.doc.mjs +19 -4
  290. package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
  291. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
  292. package/clients/cli/commands/doctor-integration-validate.doc.mjs +22 -2
  293. package/clients/cli/commands/doctor-integration.test.mjs +888 -3
  294. package/clients/cli/commands/doctor.doc.mjs +12 -2
  295. package/clients/cli/commands/doctor.mjs +292 -7
  296. package/clients/cli/commands/doctor.test.mjs +10 -4
  297. package/clients/cli/commands/gap-report.doc.mjs +15 -2
  298. package/clients/cli/commands/gap-report.mjs +24 -2
  299. package/clients/cli/commands/gap-report.test.mjs +79 -0
  300. package/clients/cli/commands/hook.doc.mjs +1 -0
  301. package/clients/cli/commands/init.behavior.test.mjs +5 -0
  302. package/clients/cli/commands/init.doc.mjs +29 -3
  303. package/clients/cli/commands/integration-add.doc.mjs +7 -0
  304. package/clients/cli/commands/integration-authoring.test.mjs +49 -3
  305. package/clients/cli/commands/integration-check.doc.mjs +93 -0
  306. package/clients/cli/commands/integration-check.test.mjs +441 -0
  307. package/clients/cli/commands/integration-pack.doc.mjs +8 -1
  308. package/clients/cli/commands/integration-verify.doc.mjs +8 -1
  309. package/clients/cli/commands/integration.doc.mjs +6 -2
  310. package/clients/cli/commands/integration.mjs +119 -7
  311. package/clients/cli/commands/json-contract.test.mjs +11 -2
  312. package/clients/cli/commands/manifest.doc.mjs +1 -0
  313. package/clients/cli/commands/outside-project.test.mjs +774 -0
  314. package/clients/cli/commands/search.doc.mjs +1 -0
  315. package/clients/cli/commands/search.mjs +16 -11
  316. package/clients/cli/commands/search.test.mjs +429 -296
  317. package/clients/cli/commands/setup-nudge.test.mjs +102 -2
  318. package/clients/cli/commands/swizzle.doc.mjs +7 -0
  319. package/clients/cli/commands/swizzle.mjs +5 -3
  320. package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
  321. package/clients/cli/commands/template.doc.mjs +1 -0
  322. package/clients/cli/commands/text-json-parity.test.mjs +5 -0
  323. package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
  324. package/clients/cli/commands/theme-add.doc.mjs +8 -1
  325. package/clients/cli/commands/theme-build.doc.mjs +3 -2
  326. package/clients/cli/commands/theme-eject.doc.mjs +1 -0
  327. package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
  328. package/clients/cli/commands/theme-list.doc.mjs +1 -0
  329. package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
  330. package/clients/cli/commands/theme-remove.doc.mjs +7 -0
  331. package/clients/cli/commands/theme-targets.doc.mjs +1 -0
  332. package/clients/cli/commands/theme-template.doc.mjs +1 -0
  333. package/clients/cli/commands/theme-use.doc.mjs +7 -0
  334. package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
  335. package/clients/cli/commands/upgrade.doc.mjs +22 -1
  336. package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
  337. package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
  338. package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
  339. package/clients/cli/index.mjs +112 -16
  340. package/clients/cli/lib/cli-error.mjs +4 -1
  341. package/clients/cli/lib/component-format.test.mjs +1 -1
  342. package/clients/cli/lib/define-command.mjs +2 -2
  343. package/clients/cli/lib/json-shim.mjs +3 -1
  344. package/clients/cli/lib/manifest.d.ts +9 -0
  345. package/clients/cli/lib/manifest.mjs +17 -1
  346. package/clients/cli/lib/manifest.test.mjs +25 -0
  347. package/foundation/agent-docs/agent-doc-state.d.mts +35 -6
  348. package/foundation/agent-docs/agent-doc-state.mjs +66 -6
  349. package/foundation/agent-docs/agent-docs.d.mts +4 -3
  350. package/foundation/agent-docs/agent-docs.mjs +11 -9
  351. package/foundation/agent-docs/computer-agent-text.d.mts +133 -0
  352. package/foundation/agent-docs/computer-agent-text.mjs +623 -0
  353. package/foundation/agent-docs/computer-agent-text.test.mjs +602 -0
  354. package/foundation/config/project.d.mts +35 -3
  355. package/foundation/config/project.mjs +226 -7
  356. package/foundation/config/project.test.mjs +66 -0
  357. package/foundation/config/theme-state.mjs +5 -4
  358. package/foundation/discovery/authoring-self-docs.mjs +2 -1
  359. package/foundation/discovery/cli-self-docs.mjs +20 -3
  360. package/foundation/discovery/cli-self-docs.test.mjs +3 -2
  361. package/foundation/discovery/component-discovery.d.mts +190 -10
  362. package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
  363. package/foundation/discovery/component-discovery.mjs +864 -56
  364. package/foundation/discovery/component-discovery.test.mjs +96 -0
  365. package/foundation/discovery/component-replacement.mjs +20 -1
  366. package/foundation/discovery/component-replacement.test.mjs +40 -0
  367. package/foundation/discovery/copied-passages.d.mts +216 -0
  368. package/foundation/discovery/copied-passages.mjs +720 -0
  369. package/foundation/discovery/copied-passages.test.mjs +124 -0
  370. package/foundation/discovery/doc-consistency.d.mts +34 -0
  371. package/foundation/discovery/doc-consistency.mjs +513 -0
  372. package/foundation/discovery/doc-consistency.test.mjs +347 -0
  373. package/foundation/discovery/doc-fluff.d.mts +112 -0
  374. package/foundation/discovery/doc-fluff.mjs +328 -0
  375. package/foundation/discovery/doc-fluff.test.mjs +142 -0
  376. package/foundation/discovery/doc-types.d.mts +157 -0
  377. package/foundation/discovery/doc-types.mjs +1231 -0
  378. package/foundation/discovery/doc-types.test.mjs +744 -0
  379. package/foundation/discovery/docs-discovery.d.mts +88 -0
  380. package/foundation/discovery/docs-discovery.mjs +83 -2
  381. package/foundation/discovery/integration-doc-files.d.mts +22 -0
  382. package/foundation/discovery/integration-doc-files.mjs +231 -0
  383. package/foundation/discovery/integration-doc-files.test.mjs +246 -0
  384. package/foundation/discovery/module-exports.d.mts +27 -0
  385. package/foundation/discovery/module-exports.mjs +356 -31
  386. package/foundation/discovery/module-exports.test.mjs +172 -0
  387. package/foundation/discovery/package-tsconfig.d.mts +14 -0
  388. package/foundation/discovery/package-tsconfig.mjs +228 -0
  389. package/foundation/discovery/package-tsconfig.test.mjs +210 -0
  390. package/foundation/discovery/project-typescript.d.mts +32 -0
  391. package/foundation/discovery/project-typescript.mjs +89 -0
  392. package/foundation/discovery/prop-drift.d.mts +297 -0
  393. package/foundation/discovery/prop-drift.mjs +2428 -0
  394. package/foundation/discovery/prop-drift.test.mjs +2337 -0
  395. package/foundation/discovery/runner-allowlist.d.mts +40 -0
  396. package/foundation/discovery/runner-allowlist.mjs +53 -0
  397. package/foundation/discovery/stray-pointers.d.mts +52 -0
  398. package/foundation/discovery/stray-pointers.mjs +293 -0
  399. package/foundation/discovery/stray-pointers.test.mjs +86 -0
  400. package/foundation/discovery/template-adapter.mjs +74 -5
  401. package/foundation/discovery/template-needs.mjs +5 -2
  402. package/foundation/discovery/theme-imports.mjs +8 -4
  403. package/foundation/discovery/theme-imports.test.mjs +1 -1
  404. package/foundation/discovery/type-match.d.mts +53 -0
  405. package/foundation/discovery/type-match.mjs +660 -0
  406. package/foundation/discovery/type-match.test.mjs +169 -0
  407. package/foundation/discovery/type-text.d.mts +68 -0
  408. package/foundation/discovery/type-text.mjs +658 -0
  409. package/foundation/discovery/type-text.test.mjs +196 -0
  410. package/foundation/discovery/unresolved-references.d.mts +62 -0
  411. package/foundation/discovery/unresolved-references.mjs +790 -0
  412. package/foundation/discovery/unresolved-references.test.mjs +567 -0
  413. package/foundation/doc-compiler/doc-loads.test.mjs +51 -1
  414. package/foundation/doc-compiler/inputs.mjs +27 -1
  415. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  416. package/foundation/doc-compiler/links.d.mts +41 -5
  417. package/foundation/doc-compiler/links.mjs +167 -28
  418. package/foundation/doc-compiler/links.test.mjs +97 -4
  419. package/foundation/doc-compiler/read.d.mts +1 -1
  420. package/foundation/doc-compiler/tree.mjs +30 -1
  421. package/foundation/doc-compiler/tree.test.mjs +8 -1
  422. package/foundation/env/cli-command.d.mts +83 -0
  423. package/foundation/env/cli-command.mjs +152 -0
  424. package/foundation/env/cli-command.test.mjs +129 -0
  425. package/foundation/env/node-version.test.mjs +15 -3
  426. package/foundation/env/package-manager.d.mts +93 -9
  427. package/foundation/env/package-manager.global.test.mjs +66 -0
  428. package/foundation/env/package-manager.mjs +184 -13
  429. package/foundation/env/package-manager.test.mjs +341 -15
  430. package/foundation/env/project-scope.d.mts +9 -0
  431. package/foundation/env/project-scope.mjs +33 -0
  432. package/foundation/env/search-path.d.mts +42 -0
  433. package/foundation/env/search-path.mjs +205 -0
  434. package/foundation/env/search-path.test.mjs +122 -0
  435. package/foundation/env/user-dirs.d.mts +39 -0
  436. package/foundation/env/user-dirs.mjs +93 -0
  437. package/foundation/env/user-dirs.test.mjs +72 -0
  438. package/foundation/env/user-settings.d.mts +46 -0
  439. package/foundation/env/user-settings.mjs +106 -0
  440. package/foundation/env/user-settings.test.mjs +64 -0
  441. package/foundation/fs/file-protection.mjs +15 -1
  442. package/foundation/fs/module-loader.d.mts +2 -1
  443. package/foundation/fs/module-loader.mjs +60 -4
  444. package/foundation/fs/module-loader.stdout.test.mjs +3 -2
  445. package/foundation/fs/module-loader.test.mjs +194 -0
  446. package/foundation/fs/path-compare.d.mts +33 -0
  447. package/foundation/fs/path-compare.mjs +73 -0
  448. package/foundation/fs/paths.d.mts +57 -1
  449. package/foundation/fs/paths.mjs +131 -3
  450. package/foundation/fs/paths.test.mjs +10 -1
  451. package/foundation/integrations/computer-integrations.d.mts +78 -0
  452. package/foundation/integrations/computer-integrations.mjs +316 -0
  453. package/foundation/integrations/computer-integrations.test.mjs +292 -0
  454. package/foundation/integrations/contribution-inventory.d.mts +11 -0
  455. package/foundation/integrations/contribution-inventory.mjs +56 -3
  456. package/foundation/integrations/integration-warnings.mjs +3 -2
  457. package/foundation/integrations/integration-warnings.test.mjs +8 -9
  458. package/foundation/integrations/integrations.d.mts +25 -1
  459. package/foundation/integrations/integrations.mjs +46 -3
  460. package/foundation/integrations/issue.ts +6 -0
  461. package/foundation/integrations/validate-contributions.d.mts +2 -0
  462. package/foundation/integrations/validate-contributions.mjs +41 -1
  463. package/foundation/release/agent-text-worker.d.mts +4 -0
  464. package/foundation/release/agent-text-worker.mjs +52 -0
  465. package/foundation/release/cache.d.mts +310 -0
  466. package/foundation/release/cache.mjs +1216 -0
  467. package/foundation/release/cache.test.mjs +920 -0
  468. package/foundation/release/choose.d.mts +207 -0
  469. package/foundation/release/choose.mjs +677 -0
  470. package/foundation/release/choose.test.mjs +427 -0
  471. package/foundation/release/core-worker.d.mts +4 -0
  472. package/foundation/release/core-worker.mjs +38 -0
  473. package/foundation/release/global-state.d.mts +259 -0
  474. package/foundation/release/global-state.mjs +472 -0
  475. package/foundation/release/global-state.test.mjs +381 -0
  476. package/foundation/release/handoff.d.mts +60 -0
  477. package/foundation/release/handoff.e2e.test.mjs +278 -0
  478. package/foundation/release/handoff.mjs +357 -0
  479. package/foundation/release/lock-lease.d.mts +23 -0
  480. package/foundation/release/lock-lease.mjs +80 -0
  481. package/foundation/release/notices.d.mts +253 -0
  482. package/foundation/release/notices.mjs +596 -0
  483. package/foundation/release/notices.test.mjs +565 -0
  484. package/foundation/release/npm-guard.d.mts +4 -0
  485. package/foundation/release/npm-guard.mjs +126 -0
  486. package/foundation/release/project.d.mts +141 -0
  487. package/foundation/release/project.mjs +466 -0
  488. package/foundation/release/project.test.mjs +288 -0
  489. package/foundation/release/refresh-worker.d.mts +4 -0
  490. package/foundation/release/refresh-worker.mjs +27 -0
  491. package/foundation/release/run-context.d.mts +47 -0
  492. package/foundation/release/run-context.mjs +149 -0
  493. package/foundation/release/update-notice-env.d.mts +28 -0
  494. package/foundation/release/update-notice-env.mjs +39 -0
  495. package/foundation/response/base.d.ts +26 -3
  496. package/foundation/response/error-codes.d.mts +3 -1
  497. package/foundation/response/error-codes.doc.mjs +12 -0
  498. package/foundation/response/error-codes.mjs +17 -0
  499. package/foundation/response/error-codes.test.mjs +2 -0
  500. package/foundation/response/json-contract.test.mjs +7 -2
  501. package/foundation/response/json.mjs +4 -1
  502. package/foundation/response/response-types.doc.mjs +22 -11
  503. package/foundation/response/response-types.doc.test.mjs +46 -0
  504. package/foundation/response/response.doc.mjs +3 -3
  505. package/foundation/xle/browser-imports.test.mjs +74 -0
  506. package/foundation/xle/registry.mjs +4 -0
  507. package/foundation/xle/registry.test.mjs +28 -0
  508. package/package.json +11 -11
  509. package/scripts/postinstall.mjs +24 -5
@@ -17,8 +17,11 @@
17
17
  * foundation/discovery/docs-discovery, which the catalog comes from.
18
18
  */
19
19
 
20
+ import * as path from 'node:path';
20
21
  import {Project} from '../../foundation/config/project.mjs';
21
22
  import {DocsCatalog} from '../../foundation/discovery/docs-discovery.mjs';
23
+ import {checkDocTypes} from '../../foundation/discovery/doc-types.mjs';
24
+ import {integrationDocFiles} from '../../foundation/discovery/integration-doc-files.mjs';
22
25
  import {
23
26
  linkReferenceTopic,
24
27
  lowerReferenceTopic,
@@ -37,6 +40,7 @@ import {
37
40
  import {sortDiagnostics} from '../../foundation/doc-compiler/diagnostics.mjs';
38
41
  import {
39
42
  linkBlocks,
43
+ linkFields,
40
44
  parseLinkTarget,
41
45
  } from '../../foundation/doc-compiler/links.mjs';
42
46
  import {
@@ -53,8 +57,20 @@ import {
53
57
  selfDocSection,
54
58
  } from '../../foundation/discovery/authoring-self-docs.mjs';
55
59
  import {CLI_PROVIDER_ID} from '../../foundation/identity/providers.mjs';
60
+ import {
61
+ CORE_PACKAGE,
62
+ discoverOwnedComponents,
63
+ discoverValidIntegrationComponents,
64
+ } from '../../foundation/discovery/component-discovery.mjs';
65
+ import {loadComponentDoc} from '../../foundation/discovery/component-loader.mjs';
66
+ import {
67
+ discoverCoreTemplates,
68
+ discoverIntegrationTemplatesForOne,
69
+ } from '../../foundation/discovery/template-adapter.mjs';
70
+ import {findCoreDir} from '../../foundation/fs/paths.mjs';
56
71
  import {AstryxError} from '../error.mjs';
57
72
  import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
73
+ import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
58
74
 
59
75
  export {OVERLAY_LANGUAGES, overlayLanguages};
60
76
 
@@ -250,8 +266,16 @@ function linkTopic(catalog, entry, lang) {
250
266
  problems.push(...linked.problems);
251
267
  sections.push({...section, content: linked.content});
252
268
  }
269
+ // The topic's own text outside its sections, its description and
270
+ // summary, resolves against the topic's own provider.
271
+ const {resolve} = await linkerFor(providerOf(entry));
272
+ const fields = await linkFields(topicTextFields(raw.doc), resolve);
273
+ problems.push(...fields.problems);
253
274
  return {
254
- node: deepFreeze({...raw, doc: {...raw.doc, sections}}),
275
+ node: deepFreeze({
276
+ ...raw,
277
+ doc: {...raw.doc, ...fields.doc, sections},
278
+ }),
255
279
  problems,
256
280
  };
257
281
  })();
@@ -260,6 +284,82 @@ function linkTopic(catalog, entry, lang) {
260
284
  return linked;
261
285
  }
262
286
 
287
+ /**
288
+ * The text fields of a topic outside its sections: its description and
289
+ * summary, those it has.
290
+ * @param {any} doc
291
+ * @returns {{description?: string, summary?: string}}
292
+ */
293
+ function topicTextFields(doc) {
294
+ /** @type {{description?: string, summary?: string}} */
295
+ const fields = {};
296
+ if (typeof doc?.description === 'string')
297
+ fields.description = doc.description;
298
+ if (typeof doc?.summary === 'string') fields.summary = doc.summary;
299
+ return fields;
300
+ }
301
+
302
+ /**
303
+ * One line of a doc's text, such as a topic's or a tree node's summary, with
304
+ * every inline link resolved against the provider that wrote it (spec:AST-047
305
+ * FR9). A link that names no doc prints as written; doctor names it.
306
+ * @param {DocsCatalog} catalog
307
+ * @param {string} providerId the provider id of the doc the text sits in
308
+ * @param {string} text
309
+ * @returns {Promise<string>}
310
+ */
311
+ export async function linkDocText(catalog, providerId, text) {
312
+ if (typeof text !== 'string' || !text.includes('{@link')) return text;
313
+ let provider;
314
+ try {
315
+ provider = normalizeProviderId(providerId);
316
+ } catch {
317
+ return text;
318
+ }
319
+ const linked = await linkFields(
320
+ {description: text},
321
+ await linkResolver(catalog, provider),
322
+ );
323
+ return linked.doc.description ?? text;
324
+ }
325
+
326
+ /**
327
+ * A component doc with every inline link in its text fields resolved
328
+ * (spec:AST-047 FR9): its description, usage, best practices, and each prop's
329
+ * and example's description. Code fields are shown as written. A Core
330
+ * component's links resolve against the CLI's own docs provider; an
331
+ * integration's against that integration's.
332
+ * @template T
333
+ * @param {DocsCatalog} catalog
334
+ * @param {string} providerId the provider id the component's links resolve
335
+ * against
336
+ * @param {T} doc
337
+ * @returns {Promise<{doc: T, problems: LinkProblem[]}>}
338
+ */
339
+ export async function linkComponentDoc(catalog, providerId, doc) {
340
+ if (!JSON.stringify(doc ?? null).includes('{@link')) {
341
+ return {doc, problems: []};
342
+ }
343
+ return linkFields(
344
+ doc,
345
+ await linkResolver(catalog, normalizeProviderId(providerId)),
346
+ );
347
+ }
348
+
349
+ /**
350
+ * The provider id a component's doc links resolve against: the CLI's own for
351
+ * a Core component, else its owner package's (or the provider id its manifest
352
+ * declares).
353
+ * @param {string} ownerPackage
354
+ * @param {string} [providerId]
355
+ * @returns {string}
356
+ */
357
+ export function componentLinkProvider(ownerPackage, providerId) {
358
+ return ownerPackage === CORE_PACKAGE
359
+ ? CLI_PROVIDER_ID
360
+ : normalizeProviderId(providerId ?? ownerPackage);
361
+ }
362
+
263
363
  /** @type {WeakMap<DocsCatalog, Promise<DocsTree>>} */
264
364
  const treesByCatalog = new WeakMap();
265
365
 
@@ -333,12 +433,50 @@ async function buildProjectTree(catalog, fresh) {
333
433
  docs: [...cli.docs, ...added.flatMap(each => each.guides)],
334
434
  topics: await flatTopicInputs(catalog),
335
435
  });
436
+ // A summary is a doc's text too: each link in it reads as the command that
437
+ // opens its doc, wherever the tree's summaries print (spec:AST-047 FR9).
438
+ for (const node of result.nodes.values()) {
439
+ if (typeof node.summary === 'string' && node.summary.includes('{@link')) {
440
+ node.summary = await linkSummary(
441
+ catalog,
442
+ result,
443
+ node.providerId,
444
+ node.summary,
445
+ );
446
+ }
447
+ }
336
448
  return {
337
449
  ...result,
338
450
  diagnostics: sortDiagnostics([...cli.diagnostics, ...result.diagnostics]),
339
451
  };
340
452
  }
341
453
 
454
+ /**
455
+ * One summary with each inline link resolved to the command that opens its
456
+ * doc, against the provider that wrote it. A link that names no doc prints as
457
+ * written; doctor names it where it checks the doc's own fields.
458
+ * @param {DocsCatalog} catalog
459
+ * @param {DocsTree} tree
460
+ * @param {string} providerId
461
+ * @param {string} summary
462
+ * @returns {Promise<string>}
463
+ */
464
+ async function linkSummary(catalog, tree, providerId, summary) {
465
+ if (!summary.includes('{@link')) return summary;
466
+ let provider;
467
+ try {
468
+ provider = normalizeProviderId(providerId);
469
+ } catch {
470
+ return summary;
471
+ }
472
+ const find = docFinderOver(catalog, tree, provider, false);
473
+ const linked = await linkFields({summary}, async target => {
474
+ const found = await find(target);
475
+ return 'problem' in found ? found : found.link;
476
+ });
477
+ return linked.doc.summary;
478
+ }
479
+
342
480
  /** @type {WeakMap<DocsTree, Map<string, TreeNode>>} */
343
481
  const identitiesByTree = new WeakMap();
344
482
 
@@ -416,10 +554,34 @@ async function authoringDoc(catalog, kind, name) {
416
554
  * @returns {Promise<(target: string) => Promise<FoundDoc | {problem: string}>>}
417
555
  */
418
556
  async function docFinder(catalog, fromProvider) {
419
- const identities = identitiesOf(await projectTree(catalog));
557
+ return docFinderOver(catalog, await projectTree(catalog), fromProvider);
558
+ }
559
+
560
+ /**
561
+ * {@link docFinder} over a tree already built, so building the tree can
562
+ * resolve the links in its own summaries.
563
+ * @param {DocsCatalog} catalog
564
+ * @param {DocsTree} tree
565
+ * @param {string} fromProvider
566
+ * @param {boolean} [summaries] resolve the links in a found flat topic's
567
+ * summary; off while a summary is itself being resolved, so two summaries
568
+ * that link each other cannot loop
569
+ * @returns {(target: string) => Promise<FoundDoc | {problem: string}>}
570
+ */
571
+ function docFinderOver(catalog, tree, fromProvider, summaries = true) {
572
+ const identities = identitiesOf(tree);
420
573
  return async target => {
421
574
  const parsed = parseLinkTarget(target);
422
- if ('error' in parsed) return {problem: parsed.error};
575
+ if ('error' in parsed)
576
+ return {
577
+ problem: bareLinkHint(
578
+ parsed.error,
579
+ target,
580
+ catalog,
581
+ identities,
582
+ fromProvider,
583
+ ),
584
+ };
423
585
  let provider;
424
586
  try {
425
587
  provider = normalizeProviderId(parsed.provider ?? fromProvider);
@@ -428,7 +590,9 @@ async function docFinder(catalog, fromProvider) {
428
590
  problem: `"${target}" names "${parsed.provider}", which is not a provider id: an npm package name, or the \`providerId\` its manifest declares`,
429
591
  };
430
592
  }
431
- const node = identities.get(identityKey(provider, parsed.kind, parsed.name));
593
+ const node = identities.get(
594
+ identityKey(provider, parsed.kind, parsed.name),
595
+ );
432
596
  if (node) {
433
597
  return {
434
598
  link: {
@@ -477,6 +641,14 @@ async function docFinder(catalog, fromProvider) {
477
641
  const raw = await lowerRawTopic(catalog, entry);
478
642
  title = raw.doc.title ?? title;
479
643
  summary = raw.doc.description ?? summary;
644
+ if (summaries) {
645
+ summary = await linkSummary(
646
+ catalog,
647
+ tree,
648
+ providerOf(entry),
649
+ summary,
650
+ );
651
+ }
480
652
  } catch {
481
653
  // The topic budget check reports a topic that does not load; the
482
654
  // link still opens it.
@@ -495,10 +667,263 @@ async function docFinder(catalog, fromProvider) {
495
667
  };
496
668
  }
497
669
  }
670
+ if (CONTRIBUTED_KINDS.has(parsed.kind)) {
671
+ const link = await contributedDocLink(
672
+ catalog,
673
+ provider,
674
+ parsed.kind,
675
+ parsed.name,
676
+ );
677
+ if (link) {
678
+ // The summary is the target doc's own text, so its links resolve
679
+ // against the target's provider, never the linking doc's: a Core
680
+ // component's against the CLI's docs, like its other fields.
681
+ if (summaries && link.summary.includes('{@link')) {
682
+ link.summary = await linkSummary(
683
+ catalog,
684
+ tree,
685
+ provider === CORE_COMPONENT_PROVIDER ? CLI_PROVIDER_ID : provider,
686
+ link.summary,
687
+ );
688
+ }
689
+ return {link: {target, ...link}, kind: parsed.kind, typed: null};
690
+ }
691
+ }
692
+ const searchType =
693
+ parsed.kind === 'component'
694
+ ? 'component'
695
+ : parsed.kind === 'page' || parsed.kind === 'block'
696
+ ? 'template'
697
+ : 'doc';
698
+ return {
699
+ problem: `"${target}" names no doc. Find it with \`astryx search ${parsed.name} --type ${searchType}\`, then name it as \`[<provider>:]<kind>:<name>\`.`,
700
+ };
701
+ };
702
+ }
703
+
704
+ /**
705
+ * What a link written as a bare name (`{@link deploying}`) should say
706
+ * instead: the exact target to write when a topic or tree doc has that
707
+ * name, or that none does.
708
+ * @param {string} error the parse error
709
+ * @param {string} target the target as written
710
+ * @param {DocsCatalog} catalog
711
+ * @param {Map<string, any>} identities
712
+ * @param {string} fromProvider
713
+ * @returns {string}
714
+ */
715
+ function bareLinkHint(error, target, catalog, identities, fromProvider) {
716
+ const name = typeof target === 'string' ? target.trim() : '';
717
+ if (!name || name.includes(':') || /\s/.test(name)) return error;
718
+ /** @param {string} provider */
719
+ const normal = provider => {
720
+ try {
721
+ return normalizeProviderId(provider);
722
+ } catch {
723
+ return provider;
724
+ }
725
+ };
726
+ const from = normal(fromProvider);
727
+ /** @param {string} provider @param {string} kind @param {string} named */
728
+ const written = (provider, kind, named) =>
729
+ `{@link ${normal(provider) === from ? '' : `${provider}:`}${kind}:${named}}`;
730
+ const entry = catalog.resolve(name);
731
+ if (entry) {
732
+ return `${error}. "${name}" is a topic: write \`${written(entry.providerId ?? entry.package, 'generic', entry.name)}\`.`;
733
+ }
734
+ const node = [...identities.values()].find(
735
+ each => String(each.name).toLowerCase() === name.toLowerCase(),
736
+ );
737
+ if (node) {
738
+ return `${error}. "${name}" is a ${node.kind === 'generic' ? 'topic' : `${node.kind} doc`}: write \`${written(node.providerId, node.kind, node.name)}\`.`;
739
+ }
740
+ return `${error}, and no topic is named "${name}". Link a doc that exists, as \`{@link generic:<topic>}\` (\`astryx docs\` lists the topics), or remove the link.`;
741
+ }
742
+
743
+ /** The provider Core's components and templates belong to. */
744
+ const CORE_COMPONENT_PROVIDER = (() => {
745
+ try {
746
+ return normalizeProviderId(CORE_PACKAGE);
747
+ } catch {
748
+ return CORE_PACKAGE;
749
+ }
750
+ })();
751
+
752
+ /** The doc kinds no docs tree holds: components and templates. */
753
+ const CONTRIBUTED_KINDS = new Set(['component', 'page', 'block']);
754
+
755
+ /**
756
+ * The link to a component, page, or block doc (spec:AST-047 FR9). No docs tree
757
+ * holds these, so a link finds them among the component and template records
758
+ * the catalog carries, the ones `astryx component` and `astryx template` open,
759
+ * and reads as that command. A component is named by its export name, a
760
+ * template by its id; anything but Core's names its package.
761
+ * @param {DocsCatalog} catalog
762
+ * @param {string} provider normalized provider id
763
+ * @param {string} kind `component`, `page`, or `block`
764
+ * @param {string} name
765
+ * @returns {Promise<Omit<import('../../foundation/doc-compiler/links.mjs').DocLink, 'target'> | null>}
766
+ */
767
+ async function contributedDocLink(catalog, provider, kind, name) {
768
+ const contributions = await catalog.contributions();
769
+ if (!contributions) return null;
770
+ const sameProvider = (/** @type {string} */ providerId) => {
771
+ try {
772
+ return normalizeProviderId(providerId) === provider;
773
+ } catch {
774
+ return false;
775
+ }
776
+ };
777
+ if (kind === 'component') {
778
+ const record = contributions.components.find(
779
+ component =>
780
+ component.name === name && sameProvider(component.providerId),
781
+ );
782
+ if (!record) return null;
783
+ /** @type {any} */
784
+ let doc = null;
785
+ try {
786
+ doc = record.docPath ? await loadComponentDoc(record.docPath) : null;
787
+ } catch {
788
+ // The component checks report a doc that does not load; the link
789
+ // still opens the component.
790
+ }
791
+ const entry =
792
+ doc?.name === name
793
+ ? doc
794
+ : doc?.components?.find(
795
+ (/** @type {any} */ each) => each.name === name,
796
+ );
797
+ // Bare, Core's name opens Core's component unless another package ships
798
+ // the same name or replaces it (spec:AST-035 FR11); then the link selects
799
+ // Core, as it always selects any other package.
800
+ const selectPackage =
801
+ record.package !== CORE_PACKAGE ||
802
+ contributions.components.some(
803
+ other =>
804
+ other.package !== CORE_PACKAGE &&
805
+ (other.name === name || other.replaces === name),
806
+ );
498
807
  return {
499
- problem: `"${target}" names no doc. Find it with \`astryx search ${parsed.name} --type doc\`, then name it as \`[<provider>:]<kind>:<name>\`.`,
808
+ id: createDocId(provider, 'component', name),
809
+ route: null,
810
+ title: entry?.displayName ?? name,
811
+ summary: entry?.description ?? doc?.description ?? '',
812
+ command: `astryx component ${name}${selectPackage ? ` --package ${record.package}` : ''}`,
500
813
  };
814
+ }
815
+ const template = contributions.templates.find(
816
+ each =>
817
+ each.type === kind && each.id === name && sameProvider(each.providerId),
818
+ );
819
+ if (!template) return null;
820
+ // The same for a Core template: another package's template of its kind
821
+ // with its id, or one that replaces it, takes the bare id.
822
+ const selectPackage =
823
+ template.package !== CORE_PACKAGE ||
824
+ contributions.templates.some(
825
+ other =>
826
+ other.package !== CORE_PACKAGE &&
827
+ other.type === template.type &&
828
+ (other.id === name || other.replaces === name),
829
+ );
830
+ return {
831
+ id: createDocId(provider, template.type, name),
832
+ route: null,
833
+ title: template.displayName ?? template.name,
834
+ summary: template.description ?? '',
835
+ command: `astryx template ${name} --type ${template.type}${selectPackage ? ` --package ${template.package}` : ''}`,
836
+ };
837
+ }
838
+
839
+ /**
840
+ * The component and template docs one integration package's links can name:
841
+ * Core's and its own, as `doctor integration docs` checks it before any app
842
+ * configures it.
843
+ * @param {any} integration a loaded integration: its name, provider id, roots,
844
+ * and package directory
845
+ * @returns {Promise<import('../../foundation/discovery/docs-discovery.mjs').LinkableContributions>}
846
+ */
847
+ async function packageContributions(integration) {
848
+ const own = integration.providerId ?? integration.name;
849
+ /** @type {import('../../foundation/discovery/docs-discovery.mjs').LinkableComponent[]} */
850
+ const components = [];
851
+ const coreDir = findCoreDir(integration.__packageDir ?? process.cwd());
852
+ if (coreDir) {
853
+ try {
854
+ for (const record of discoverOwnedComponents(coreDir, [])) {
855
+ components.push({
856
+ providerId: CORE_PACKAGE,
857
+ package: CORE_PACKAGE,
858
+ name: record.name,
859
+ docPath: record.docPath,
860
+ });
861
+ }
862
+ } catch {
863
+ // The components check reports a Core it cannot read.
864
+ }
865
+ }
866
+ if (integration.components) {
867
+ try {
868
+ const {components: records} =
869
+ await discoverValidIntegrationComponents(integration);
870
+ for (const record of records) {
871
+ components.push({
872
+ providerId: own,
873
+ package: integration.name,
874
+ name: record.name,
875
+ docPath: record.docPath,
876
+ // Declared: this package alone cannot tell whether an app applies
877
+ // it, so a link to the Core name it names selects Core.
878
+ ...(typeof record.replaces === 'string'
879
+ ? {replaces: record.replaces}
880
+ : {}),
881
+ });
882
+ }
883
+ } catch {
884
+ // `validate` reports components that do not load.
885
+ }
886
+ }
887
+ /** @type {import('../../foundation/discovery/docs-discovery.mjs').LinkableTemplate[]} */
888
+ const templates = [];
889
+ /** @param {any} template @param {string} providerId @param {string} pkg */
890
+ const addTemplate = (template, providerId, pkg) => {
891
+ if (template.type !== 'page' && template.type !== 'block') return;
892
+ templates.push({
893
+ providerId,
894
+ package: pkg,
895
+ type: template.type,
896
+ id: template.dirName,
897
+ name: template.name,
898
+ ...(template.displayName == null
899
+ ? {}
900
+ : {displayName: template.displayName}),
901
+ ...(template.description == null
902
+ ? {}
903
+ : {description: template.description}),
904
+ ...(typeof template.replaces === 'string'
905
+ ? {replaces: template.replaces}
906
+ : {}),
907
+ });
501
908
  };
909
+ try {
910
+ for (const template of await discoverCoreTemplates()) {
911
+ addTemplate(template, CORE_PACKAGE, CORE_PACKAGE);
912
+ }
913
+ } catch {
914
+ // Core templates that do not load leave nothing to link to.
915
+ }
916
+ if (integration.templates) {
917
+ try {
918
+ const {templates: records} =
919
+ await discoverIntegrationTemplatesForOne(integration);
920
+ for (const template of records)
921
+ addTemplate(template, own, integration.name);
922
+ } catch {
923
+ // `validate` reports templates that do not load.
924
+ }
925
+ }
926
+ return {components, templates};
502
927
  }
503
928
 
504
929
  /**
@@ -654,7 +1079,7 @@ export async function docsLinkProblems(
654
1079
  for (const problem of found) {
655
1080
  if ((problem.include === true) !== references) continue;
656
1081
  problems.push(
657
- `${where}${problem.section ? ` \u00a7 ${problem.section}` : ''}: ${problem.message}`,
1082
+ `${where}${problem.section ? ` \u00a7 ${problem.section}` : ''}${problem.field ? ` (${problem.field})` : ''}: ${problem.message}`,
658
1083
  );
659
1084
  }
660
1085
  };
@@ -689,6 +1114,83 @@ export async function docsLinkProblems(
689
1114
  return problems;
690
1115
  }
691
1116
 
1117
+ /**
1118
+ * The catalog one integration package's docs and links read, as doctor checks
1119
+ * it before any app configures it: the CLI's topics, Core's and the package's
1120
+ * components and templates, and the package's own docs.
1121
+ * @param {any} integration
1122
+ * @param {{records: import('../../foundation/discovery/docs-discovery.mjs').DocsTopicRecord[], namespaces: import('../../foundation/doc-compiler/tree.mjs').TreeNamespaceInput[], guides: import('../../foundation/doc-compiler/tree.mjs').TreeDocInput[]} | null} discovered
1123
+ * @returns {DocsCatalog}
1124
+ */
1125
+ function packageCatalog(integration, discovered) {
1126
+ const catalog = DocsCatalog.fromBuiltins();
1127
+ catalog.setContributions(() => packageContributions(integration));
1128
+ if (discovered) {
1129
+ for (const record of discovered.records) catalog.add(record);
1130
+ catalog.addTreeInputs({
1131
+ namespaces: discovered.namespaces.map(input => ({...input, rank: 1})),
1132
+ guides: discovered.guides.map(input => ({...input, rank: 1})),
1133
+ });
1134
+ }
1135
+ return catalog;
1136
+ }
1137
+
1138
+ /**
1139
+ * What \`astryx doctor integration components\` checks of the links in one
1140
+ * integration's own component docs (spec:AST-047 FR9): each link in a
1141
+ * description, usage, best practice, or prop's or example's description that
1142
+ * names no doc. It prints as written, so each is a warning.
1143
+ * @param {any} integration a loaded integration
1144
+ * @param {Parameters<typeof packageCatalog>[1]} discovered the package's own
1145
+ * docs, which its components' links may name; null when it ships none
1146
+ * @returns {Promise<Array<{severity: 'warning', message: string}>>}
1147
+ */
1148
+ export async function packageComponentLinkProblems(integration, discovered) {
1149
+ const catalog = packageCatalog(integration, discovered);
1150
+ return (await componentLinkProblems(catalog, integration.name)).map(
1151
+ message => ({severity: /** @type {const} */ ('warning'), message}),
1152
+ );
1153
+ }
1154
+
1155
+ /**
1156
+ * Each link in a package's own component docs that names no doc. A family doc
1157
+ * that documents several components is read once.
1158
+ * @param {DocsCatalog} catalog
1159
+ * @param {string} owner the package whose component docs are read
1160
+ * @returns {Promise<string[]>}
1161
+ */
1162
+ async function componentLinkProblems(catalog, owner) {
1163
+ const contributions = await catalog.contributions();
1164
+ /** @type {string[]} */
1165
+ const problems = [];
1166
+ const seen = new Set();
1167
+ for (const record of contributions?.components ?? []) {
1168
+ if (record.package !== owner || !record.docPath) continue;
1169
+ if (seen.has(record.docPath)) continue;
1170
+ seen.add(record.docPath);
1171
+ /** @type {any} */
1172
+ let doc;
1173
+ try {
1174
+ doc = await loadComponentDoc(record.docPath);
1175
+ } catch {
1176
+ // The components check reports a doc that does not load.
1177
+ continue;
1178
+ }
1179
+ const linked = await linkComponentDoc(
1180
+ catalog,
1181
+ componentLinkProvider(record.package, record.providerId),
1182
+ doc,
1183
+ );
1184
+ const name = typeof doc?.name === 'string' ? doc.name : record.name;
1185
+ for (const problem of linked.problems) {
1186
+ problems.push(
1187
+ `component ${name}${problem.field ? ` (${problem.field})` : ''}: ${problem.message}`,
1188
+ );
1189
+ }
1190
+ }
1191
+ return problems;
1192
+ }
1193
+
692
1194
  /**
693
1195
  * What \`astryx doctor integration docs\` checks in one integration's docs: the
694
1196
  * docs tree they build beside the CLI's (namespaces, placements, routes) and
@@ -700,12 +1202,7 @@ export async function docsLinkProblems(
700
1202
  * @returns {Promise<Array<{severity: 'error' | 'warning', message: string}>>}
701
1203
  */
702
1204
  export async function packageDocsProblems(integration, discovered) {
703
- const catalog = DocsCatalog.fromBuiltins();
704
- for (const record of discovered.records) catalog.add(record);
705
- catalog.addTreeInputs({
706
- namespaces: discovered.namespaces.map(input => ({...input, rank: 1})),
707
- guides: discovered.guides.map(input => ({...input, rank: 1})),
708
- });
1205
+ const catalog = packageCatalog(integration, discovered);
709
1206
  const tree = await projectTree(catalog);
710
1207
  /** @type {Array<{severity: 'error' | 'warning', message: string}>} */
711
1208
  const problems = tree.diagnostics
@@ -794,6 +1291,7 @@ async function namespaceReferenceTarget(catalog, route, lang) {
794
1291
  */
795
1292
  export async function packageReferenceProblems(integration, discovered) {
796
1293
  const catalog = DocsCatalog.fromBuiltins();
1294
+ catalog.setContributions(() => packageContributions(integration));
797
1295
  for (const record of discovered.records) catalog.add(record);
798
1296
  catalog.addTreeInputs({
799
1297
  namespaces: discovered.namespaces.map(input => ({...input, rank: 1})),
@@ -927,7 +1425,8 @@ export async function topicLinks(catalog, entry) {
927
1425
  const tree = await projectTree(catalog);
928
1426
  const node = tree.get(entry.tree ? (entry.route ?? entry.name) : entry.name);
929
1427
  const placed =
930
- node && (entry.tree ? node.kind === 'generic' : node.ref?.flatTopic === entry.name);
1428
+ node &&
1429
+ (entry.tree ? node.kind === 'generic' : node.ref?.flatTopic === entry.name);
931
1430
  return placed ? placeLinks(tree, node) : {up: topicUp(entry)};
932
1431
  }
933
1432
 
@@ -950,7 +1449,8 @@ export async function resolveDocsArgument(topic, {cwd} = {}) {
950
1449
  const tree = await projectTree(catalog);
951
1450
  const owner = nameOwner(tree, catalog, topic);
952
1451
  if (owner == null) return {kind: 'unknown', catalog};
953
- if (owner.kind === 'topic') return {kind: 'topic', catalog, entry: owner.entry};
1452
+ if (owner.kind === 'topic')
1453
+ return {kind: 'topic', catalog, entry: owner.entry};
954
1454
  return treeArgument(catalog, tree, owner.node);
955
1455
  }
956
1456
 
@@ -1097,7 +1597,7 @@ export async function unknownTopicError(topic, catalog) {
1097
1597
  export function notLoaded(catalog) {
1098
1598
  const packages = [...new Set(catalog.issues.map(issue => issue.package))];
1099
1599
  if (packages.length === 0) return '';
1100
- return `. The docs of ${packages.join(', ')} did not load; run \`astryx doctor integration docs\` in that package to see why.`;
1600
+ return `. The docs of ${packages.join(', ')} did not load; run \`${formatCliCommand('doctor integration docs')}\` in that package to see why.`;
1101
1601
  }
1102
1602
 
1103
1603
  /**
@@ -1115,7 +1615,7 @@ export async function resolveTopicDocs(topic, options = {}) {
1115
1615
  if (found.kind !== 'topic') {
1116
1616
  throw found.kind === 'node'
1117
1617
  ? new AstryxError(
1118
- `"${found.node.route}" is a ${found.node.kind === 'namespace' ? 'namespace' : `${found.node.kind} doc`} in the docs tree, not a topic. Read it with \`astryx docs ${found.node.route}\`.`,
1618
+ `"${found.node.route}" is a ${found.node.kind === 'namespace' ? 'namespace' : `${found.node.kind} doc`} in the docs tree, not a topic. Read it with \`${formatCliCommand(`docs ${found.node.route}`)}\`.`,
1119
1619
  undefined,
1120
1620
  ERROR_CODES.ERR_UNKNOWN_TOPIC,
1121
1621
  )
@@ -1125,3 +1625,40 @@ export async function resolveTopicDocs(topic, options = {}) {
1125
1625
  const node = await lowerTopic(catalog, entry, effectiveLang);
1126
1626
  return {catalog, node, lang: effectiveLang, entry};
1127
1627
  }
1628
+
1629
+ /**
1630
+ * Each doc one integration package ships, checked against the published
1631
+ * authoring type for its kind with the project's own TypeScript (spec:AST-039
1632
+ * FR13). Without TypeScript the report says nothing was checked.
1633
+ * @param {any} integration a loaded integration
1634
+ * @param {string} cwd
1635
+ * @returns {Promise<import('../../foundation/discovery/doc-types.mjs').DocTypesReport & {fixtures?: number}>}
1636
+ */
1637
+ export async function integrationDocTypes(integration, cwd) {
1638
+ const packageDir = /** @type {{__packageDir?: string}} */ (integration)
1639
+ .__packageDir;
1640
+ const {files, unread, fixtures} = await integrationDocFiles(integration);
1641
+ const checked = await checkDocTypes(files, {
1642
+ packageDir: packageDir ?? cwd,
1643
+ resolveFrom: [cwd, packageDir],
1644
+ });
1645
+ // Test fixtures no reader serves don't ship as docs: only counted.
1646
+ const report =
1647
+ checked.status === 'checked' && fixtures > 0
1648
+ ? {...checked, fixtures}
1649
+ : checked;
1650
+ if (report.status !== 'checked' || unread.length === 0) return report;
1651
+ // A root its reader cannot read serves no doc; say so rather than skip it.
1652
+ const rel = (/** @type {string} */ file) =>
1653
+ path
1654
+ .relative(packageDir ?? cwd, file)
1655
+ .split(path.sep)
1656
+ .join('/') || '.';
1657
+ return {
1658
+ ...report,
1659
+ unchecked: [
1660
+ ...report.unchecked,
1661
+ ...unread.map(entry => ({doc: rel(entry.path), reason: entry.reason})),
1662
+ ].sort((a, b) => a.doc.localeCompare(b.doc)),
1663
+ };
1664
+ }