@astryxdesign/cli 0.6.3-canary.db4e378 → 0.6.3-canary.db52d98

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 (397) hide show
  1. package/README.md +38 -15
  2. package/api/blog/blog.doc.mjs +1 -0
  3. package/api/build/_adapter.d.mts +50 -0
  4. package/api/build/_adapter.mjs +60 -0
  5. package/api/build/build.doc.mjs +14 -7
  6. package/api/build/build.test.mjs +184 -6
  7. package/api/build/build.type.d.mts +57 -2
  8. package/api/build/build.type.mjs +30 -7
  9. package/api/build/help/help.d.mts +4 -0
  10. package/api/build/help/help.mjs +24 -11
  11. package/api/build/kit/kit.d.mts +4 -1
  12. package/api/build/kit/kit.mjs +165 -49
  13. package/api/build/kit/rank.d.mts +44 -0
  14. package/api/build/kit/rank.mjs +432 -0
  15. package/api/build/kit/rank.test.mjs +196 -0
  16. package/api/component/_adapter.d.mts +6 -12
  17. package/api/component/_adapter.mjs +20 -10
  18. package/api/component/component.doc.mjs +1 -0
  19. package/api/component/component.mjs +60 -12
  20. package/api/component/list/list.mjs +3 -2
  21. package/api/discover/discover.doc.mjs +1 -0
  22. package/api/docs/_adapter.d.mts +252 -34
  23. package/api/docs/_adapter.mjs +923 -132
  24. package/api/docs/detail/detail.mjs +11 -3
  25. package/api/docs/detail/section/section.mjs +24 -13
  26. package/api/docs/detail/section/section.test.mjs +15 -6
  27. package/api/docs/docs.d.mts +5 -3
  28. package/api/docs/docs.doc.mjs +39 -17
  29. package/api/docs/docs.mjs +44 -8
  30. package/api/docs/docs.test.mjs +158 -4
  31. package/api/docs/docs.type.d.mts +181 -2
  32. package/api/docs/docs.type.mjs +117 -3
  33. package/api/docs/index/index.mjs +11 -3
  34. package/api/docs/index/index.test.mjs +1 -1
  35. package/api/docs/integration-tree.test.mjs +555 -0
  36. package/api/docs/integrationDocs.test.mjs +14 -14
  37. package/api/docs/list/list.mjs +28 -12
  38. package/api/docs/node/node.d.mts +43 -0
  39. package/api/docs/node/node.mjs +192 -0
  40. package/api/docs/reference-blocks.test.mjs +406 -0
  41. package/api/doctor/doctor.d.mts +54 -4
  42. package/api/doctor/doctor.doc.mjs +1 -0
  43. package/api/doctor/doctor.mjs +331 -16
  44. package/api/doctor/doctor.test.mjs +420 -7
  45. package/api/gap-report/gap-report.doc.mjs +1 -0
  46. package/api/hook/_adapter.mjs +19 -5
  47. package/api/hook/hook.doc.mjs +1 -0
  48. package/api/hook/list/list.d.mts +1 -1
  49. package/api/hook/list/list.mjs +69 -17
  50. package/api/index.d.mts +1 -1
  51. package/api/index.mjs +1 -0
  52. package/api/init/init.doc.mjs +2 -1
  53. package/api/integration/add-contribution.d.mts +2 -1
  54. package/api/integration/add-contribution.mjs +114 -12
  55. package/api/integration/add-contribution.test.mjs +174 -3
  56. package/api/integration/add-theme.mjs +34 -64
  57. package/api/integration/add-theme.test.mjs +105 -21
  58. package/api/integration/authoring-checks.mjs +138 -28
  59. package/api/integration/authoring-checks.test.mjs +179 -7
  60. package/api/integration/authoring-checks.type.mjs +6 -1
  61. package/api/integration/integration-authoring.type.d.mts +2 -0
  62. package/api/integration/integration-authoring.type.mjs +2 -0
  63. package/api/integration/integration-block-exports.test.mjs +10 -6
  64. package/api/integration/integrationAdd.doc.mjs +7 -0
  65. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  66. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  67. package/api/integration/integrationAddComponent.doc.mjs +1 -0
  68. package/api/integration/integrationAddDoc.doc.mjs +8 -1
  69. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  70. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  71. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  72. package/api/integration/integrationDocConflicts.doc.mjs +2 -1
  73. package/api/integration/integrationPackCheck.doc.mjs +2 -1
  74. package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
  75. package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
  76. package/api/integration/pack-check.mjs +34 -0
  77. package/api/integration/pack-check.test.mjs +138 -47
  78. package/api/integration/pack-check.type.d.mts +26 -2
  79. package/api/integration/pack-check.type.mjs +14 -1
  80. package/api/integration/summarizeIssues.doc.mjs +1 -0
  81. package/api/integration/template-conflict-compatibility.test.mjs +73 -0
  82. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  83. package/api/integration/validate-integration.mjs +50 -102
  84. package/api/integration/validate-integration.test.mjs +88 -26
  85. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  86. package/api/integration/validateIntegration.doc.mjs +2 -1
  87. package/api/json/assertResponse.doc.mjs +1 -0
  88. package/api/json/index.ts +2 -0
  89. package/api/json/isError.doc.mjs +1 -0
  90. package/api/json/parseResponse.doc.mjs +1 -0
  91. package/api/layout/_adapter.mjs +20 -5
  92. package/api/layout/layoutCheck.doc.mjs +1 -0
  93. package/api/layout/layoutExpand.doc.mjs +1 -0
  94. package/api/layout/layoutGrammar.doc.mjs +1 -0
  95. package/api/search/search.d.mts +59 -1
  96. package/api/search/search.doc.mjs +5 -3
  97. package/api/search/search.mjs +458 -77
  98. package/api/search/search.test.mjs +91 -2
  99. package/api/search/search.type.d.mts +13 -1
  100. package/api/search/search.type.mjs +4 -1
  101. package/api/swizzle/swizzle.doc.mjs +1 -0
  102. package/api/template/list/list.mjs +1 -0
  103. package/api/template/table-floating-bulk-actions.test.mjs +66 -0
  104. package/api/template/template-integration.test.mjs +1072 -3
  105. package/api/template/template-suffix.test.mjs +41 -21
  106. package/api/template/template.doc.mjs +28 -7
  107. package/api/template/template.mjs +45 -8
  108. package/api/template/template.type.d.mts +6 -8
  109. package/api/template/template.type.mjs +3 -2
  110. package/api/theme/_adapter.d.mts +2 -3
  111. package/api/theme/_adapter.mjs +4 -5
  112. package/api/theme/add/add.binary.test.mjs +10 -17
  113. package/api/theme/add/add.test.mjs +14 -1
  114. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  115. package/api/theme/integration-themes.test.mjs +39 -28
  116. package/api/theme/list/list.test.mjs +19 -20
  117. package/api/theme/listThemes.doc.mjs +6 -5
  118. package/api/theme/template/template.test.mjs +5 -0
  119. package/api/theme/themeAdd.doc.mjs +4 -3
  120. package/api/theme/themeBuild.doc.mjs +1 -0
  121. package/api/theme/themeList.doc.mjs +6 -3
  122. package/api/theme/themeListAvailable.doc.mjs +5 -3
  123. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  124. package/api/theme/themeTargets.doc.mjs +1 -0
  125. package/api/theme/themeTemplate.doc.mjs +2 -1
  126. package/api/upgrade/_adapter.d.mts +32 -5
  127. package/api/upgrade/_adapter.mjs +97 -69
  128. package/api/upgrade/provider-agreement.test.mjs +152 -0
  129. package/api/upgrade/run/run.mjs +356 -59
  130. package/api/upgrade/upgrade.doc.mjs +6 -1
  131. package/api/upgrade/upgrade.type.d.mts +34 -0
  132. package/api/upgrade/upgrade.type.mjs +15 -0
  133. package/assets/codemods/__tests__/runner.test.mjs +330 -8
  134. package/assets/codemods/integration-discovery.mjs +8 -2
  135. package/assets/codemods/integration-discovery.test.mjs +15 -0
  136. package/assets/codemods/integration-runner.mjs +56 -4
  137. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  138. package/assets/codemods/run-codemod.mjs +177 -34
  139. package/assets/codemods/runner.mjs +350 -102
  140. package/assets/codemods/transforms/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  141. package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  142. package/assets/codemods/transforms/next/index.mjs +19 -1
  143. package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
  144. package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
  145. package/assets/docs/getting-started.doc.mjs +2 -2
  146. package/assets/docs/layout.doc.dense.mjs +2 -2
  147. package/assets/docs/layout.doc.mjs +1 -1
  148. package/assets/docs/principles.doc.mjs +6 -6
  149. package/assets/docs/styling-libraries.doc.mjs +3 -3
  150. package/assets/docs/styling.doc.mjs +4 -4
  151. package/assets/docs/theme.doc.mjs +5 -5
  152. package/assets/docs/tokens.doc.mjs +1 -1
  153. package/assets/docs/tree/api.doc.mjs +30 -0
  154. package/assets/docs/tree/cli.doc.mjs +23 -0
  155. package/assets/docs/tree/commands.doc.mjs +25 -0
  156. package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +66 -38
  157. package/assets/docs/tree/integrations.test.mjs +62 -0
  158. package/assets/docs/tree/writing-docs.doc.mjs +286 -0
  159. package/assets/docs/working-with-ai.doc.mjs +3 -3
  160. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
  161. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
  162. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  163. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  164. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  165. package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
  166. package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
  167. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
  168. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
  169. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  170. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  171. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  172. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  173. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  174. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  175. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  176. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  177. package/authoring/codemod/codemod.doc.mjs +1 -1
  178. package/authoring/codemod/type.ts +12 -0
  179. package/authoring/config/config.doc.mjs +1 -1
  180. package/authoring/debug/debug.doc.d.mts +11 -0
  181. package/authoring/debug/debug.doc.mjs +182 -0
  182. package/authoring/debug/parse.d.mts +3 -3
  183. package/authoring/doctypes/_schema.d.mts +119 -117
  184. package/authoring/doctypes/_schema.mjs +54 -3
  185. package/authoring/doctypes/base/graph-fields.doc.mjs +8 -6
  186. package/authoring/doctypes/base/type.ts +6 -5
  187. package/authoring/doctypes/command/command.doc.mjs +1 -1
  188. package/authoring/doctypes/command/type.ts +2 -2
  189. package/authoring/doctypes/component/type.ts +2 -2
  190. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  191. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  192. package/authoring/doctypes/enum/type.ts +1 -1
  193. package/authoring/doctypes/function/function.doc.mjs +3 -2
  194. package/authoring/doctypes/function/type.ts +3 -2
  195. package/authoring/doctypes/hook/type.ts +2 -2
  196. package/authoring/doctypes/load-contract.test.mjs +28 -2
  197. package/authoring/doctypes/namespace/namespace.doc.mjs +6 -10
  198. package/authoring/doctypes/namespace/parse.test.mjs +23 -25
  199. package/authoring/doctypes/namespace/type.ts +5 -2
  200. package/authoring/doctypes/parse.d.mts +4 -2
  201. package/authoring/doctypes/parse.mjs +10 -5
  202. package/authoring/doctypes/reference/reference.doc.mjs +35 -6
  203. package/authoring/doctypes/reference/type.ts +30 -13
  204. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  205. package/authoring/doctypes/schema/type.ts +1 -2
  206. package/authoring/doctypes/template/parse.d.mts +2 -0
  207. package/authoring/doctypes/template/parse.mjs +4 -0
  208. package/authoring/doctypes/template/parse.test.mjs +18 -0
  209. package/authoring/doctypes/template/template.doc.mjs +9 -3
  210. package/authoring/doctypes/template/type.ts +8 -0
  211. package/authoring/doctypes/theme/parse.d.mts +35 -0
  212. package/authoring/doctypes/theme/parse.mjs +76 -0
  213. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  214. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  215. package/authoring/doctypes/theme/type.ts +42 -0
  216. package/authoring/doctypes/types.ts +2 -1
  217. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  218. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  219. package/authoring/identity/identity.doc.mjs +2 -2
  220. package/authoring/index.d.mts +1 -0
  221. package/authoring/index.d.ts +7 -4
  222. package/authoring/index.mjs +2 -1
  223. package/authoring/integration/integration.doc.mjs +2 -2
  224. package/authoring/integration/type.ts +4 -10
  225. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  226. package/clients/cli/commands/blog.doc.mjs +1 -1
  227. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  228. package/clients/cli/commands/build-theme.mjs +11 -45
  229. package/clients/cli/commands/build.doc.mjs +12 -7
  230. package/clients/cli/commands/build.mjs +105 -67
  231. package/clients/cli/commands/build.text-fields.test.mjs +41 -0
  232. package/clients/cli/commands/component/index.mjs +1 -1
  233. package/clients/cli/commands/component-ownership.test.mjs +3 -3
  234. package/clients/cli/commands/component.doc.mjs +1 -1
  235. package/clients/cli/commands/discover.broken-integration.test.mjs +7 -8
  236. package/clients/cli/commands/discover.doc.mjs +1 -1
  237. package/clients/cli/commands/discover.mjs +1 -1
  238. package/clients/cli/commands/docs.doc.mjs +21 -9
  239. package/clients/cli/commands/docs.mjs +184 -70
  240. package/clients/cli/commands/docs.test.mjs +120 -16
  241. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  242. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
  243. package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
  244. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  245. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  246. package/clients/cli/commands/doctor-integration.test.mjs +90 -8
  247. package/clients/cli/commands/doctor.doc.mjs +1 -1
  248. package/clients/cli/commands/doctor.mjs +53 -16
  249. package/clients/cli/commands/gap-report.doc.mjs +1 -1
  250. package/clients/cli/commands/hook.doc.mjs +1 -1
  251. package/clients/cli/commands/init.doc.mjs +1 -1
  252. package/clients/cli/commands/integration-add.controls.test.mjs +1 -1
  253. package/clients/cli/commands/integration-add.doc.mjs +11 -1
  254. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  255. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  256. package/clients/cli/commands/integration.doc.mjs +1 -1
  257. package/clients/cli/commands/integration.mjs +1 -0
  258. package/clients/cli/commands/layout-check.doc.mjs +1 -1
  259. package/clients/cli/commands/layout-expand.doc.mjs +1 -1
  260. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  261. package/clients/cli/commands/layout.doc.mjs +1 -1
  262. package/clients/cli/commands/manifest.doc.mjs +1 -1
  263. package/clients/cli/commands/search.doc.mjs +1 -1
  264. package/clients/cli/commands/search.mjs +11 -2
  265. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  266. package/clients/cli/commands/swizzle.doc.mjs +1 -1
  267. package/clients/cli/commands/template.doc.mjs +24 -7
  268. package/clients/cli/commands/template.mjs +4 -91
  269. package/clients/cli/commands/text-json-parity.test.mjs +719 -0
  270. package/clients/cli/commands/theme-add.doc.mjs +2 -2
  271. package/clients/cli/commands/theme-build.doc.mjs +1 -1
  272. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  273. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -3
  274. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  275. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  276. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  277. package/clients/cli/commands/theme-template.doc.mjs +1 -1
  278. package/clients/cli/commands/theme.doc.mjs +1 -1
  279. package/clients/cli/commands/upgrade.doc.mjs +3 -2
  280. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  281. package/clients/cli/commands/upgrade.mjs +29 -7
  282. package/clients/cli/formatters/index.mjs +2 -0
  283. package/clients/cli/formatters/index.test.mjs +6 -0
  284. package/clients/cli/index.mjs +8 -0
  285. package/clients/cli/lib/hook-format.mjs +14 -5
  286. package/clients/cli/lib/manifest.mjs +9 -2
  287. package/foundation/agent-docs/agent-docs.d.mts +3 -2
  288. package/foundation/agent-docs/agent-docs.mjs +13 -9
  289. package/foundation/agent-docs/agent-docs.test.mjs +19 -1
  290. package/foundation/config/project-themes.test.mjs +11 -19
  291. package/foundation/config/project.d.mts +20 -11
  292. package/foundation/config/project.mjs +123 -80
  293. package/foundation/config/project.test.mjs +144 -21
  294. package/foundation/discovery/authoring-self-docs.d.mts +18 -0
  295. package/foundation/discovery/authoring-self-docs.mjs +37 -15
  296. package/foundation/discovery/authoring-self-docs.test.mjs +25 -9
  297. package/foundation/discovery/authoring-surface.d.mts +74 -0
  298. package/foundation/discovery/authoring-surface.mjs +525 -0
  299. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  300. package/foundation/discovery/cli-self-docs.d.mts +119 -0
  301. package/foundation/discovery/cli-self-docs.mjs +490 -0
  302. package/foundation/discovery/cli-self-docs.test.mjs +375 -0
  303. package/foundation/discovery/component-discovery.d.mts +38 -0
  304. package/foundation/discovery/component-discovery.mjs +48 -0
  305. package/foundation/discovery/component-loader.d.mts +35 -38
  306. package/foundation/discovery/component-loader.mjs +53 -222
  307. package/foundation/discovery/docs-discovery.d.mts +112 -11
  308. package/foundation/discovery/docs-discovery.mjs +231 -36
  309. package/foundation/discovery/docs-discovery.test.mjs +111 -32
  310. package/foundation/discovery/docs-output-budget.d.mts +2 -2
  311. package/foundation/discovery/docs-output-budget.mjs +1 -1
  312. package/foundation/discovery/docs-section-key.d.mts +28 -10
  313. package/foundation/discovery/docs-section-key.mjs +134 -33
  314. package/foundation/discovery/docs-section-key.test.mjs +41 -19
  315. package/foundation/discovery/template-adapter.d.mts +99 -6
  316. package/foundation/discovery/template-adapter.mjs +480 -57
  317. package/foundation/discovery/template-adapter.test.mjs +57 -0
  318. package/foundation/discovery/template-conflict-release.d.mts +13 -0
  319. package/foundation/discovery/template-conflict-release.mjs +40 -0
  320. package/foundation/discovery/template-conflict-release.test.mjs +40 -0
  321. package/foundation/discovery/theme-discovery.d.mts +67 -7
  322. package/foundation/discovery/theme-discovery.mjs +916 -186
  323. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  324. package/foundation/doc-compiler/bundle.d.mts +47 -0
  325. package/foundation/doc-compiler/bundle.mjs +278 -0
  326. package/foundation/doc-compiler/bundle.test.mjs +266 -0
  327. package/foundation/doc-compiler/compile.d.mts +220 -39
  328. package/foundation/doc-compiler/compile.mjs +311 -15
  329. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  330. package/foundation/doc-compiler/diagnostics.mjs +305 -0
  331. package/foundation/doc-compiler/doc-compiler.test.mjs +28 -1
  332. package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
  333. package/foundation/doc-compiler/import.d.mts +24 -0
  334. package/foundation/doc-compiler/import.mjs +59 -0
  335. package/foundation/doc-compiler/inputs.d.mts +102 -0
  336. package/foundation/doc-compiler/inputs.mjs +291 -0
  337. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  338. package/foundation/doc-compiler/ir.d.mts +13 -0
  339. package/foundation/doc-compiler/ir.mjs +196 -12
  340. package/foundation/doc-compiler/lenses.d.mts +8 -5
  341. package/foundation/doc-compiler/lenses.mjs +50 -4
  342. package/foundation/doc-compiler/links.d.mts +162 -0
  343. package/foundation/doc-compiler/links.mjs +294 -0
  344. package/foundation/doc-compiler/links.test.mjs +192 -0
  345. package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
  346. package/foundation/doc-compiler/overlays.d.mts +37 -0
  347. package/foundation/doc-compiler/overlays.mjs +206 -0
  348. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  349. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  350. package/foundation/doc-compiler/read.d.mts +127 -0
  351. package/foundation/doc-compiler/read.mjs +325 -0
  352. package/foundation/doc-compiler/read.test.mjs +313 -0
  353. package/foundation/doc-compiler/source.d.mts +33 -0
  354. package/foundation/doc-compiler/source.mjs +128 -0
  355. package/foundation/doc-compiler/tree.d.mts +288 -0
  356. package/foundation/doc-compiler/tree.mjs +876 -0
  357. package/foundation/doc-compiler/tree.test.mjs +598 -0
  358. package/foundation/fs/file-protection.d.mts +33 -0
  359. package/foundation/fs/file-protection.mjs +825 -0
  360. package/foundation/fs/file-protection.test.mjs +250 -0
  361. package/foundation/integrations/autolink.d.mts +58 -1
  362. package/foundation/integrations/autolink.mjs +143 -57
  363. package/foundation/integrations/autolink.test.mjs +1 -1
  364. package/foundation/integrations/cli-requirement.d.mts +45 -0
  365. package/foundation/integrations/cli-requirement.mjs +154 -0
  366. package/foundation/integrations/cli-requirement.test.mjs +84 -0
  367. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  368. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  369. package/foundation/integrations/contribution-inventory.d.mts +3 -2
  370. package/foundation/integrations/contribution-inventory.mjs +27 -24
  371. package/foundation/integrations/contribution-inventory.test.mjs +86 -27
  372. package/foundation/integrations/integration-warnings.d.mts +9 -2
  373. package/foundation/integrations/integration-warnings.mjs +51 -26
  374. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  375. package/foundation/integrations/integrations.d.mts +3 -0
  376. package/foundation/integrations/integrations.mjs +11 -97
  377. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  378. package/foundation/integrations/provider-resolution.d.mts +152 -0
  379. package/foundation/integrations/provider-resolution.mjs +576 -0
  380. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  381. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  382. package/foundation/integrations/theme-descriptor.mjs +44 -0
  383. package/foundation/integrations/validate-contributions.mjs +121 -29
  384. package/foundation/response/error-codes.d.mts +3 -1
  385. package/foundation/response/error-codes.d.ts +2 -0
  386. package/foundation/response/error-codes.doc.mjs +12 -2
  387. package/foundation/response/error-codes.mjs +7 -1
  388. package/foundation/response/error-codes.test.mjs +55 -11
  389. package/foundation/response/response-types.doc.d.mts +5 -1
  390. package/foundation/response/response-types.doc.mjs +20 -11
  391. package/foundation/response/response.doc.mjs +1 -1
  392. package/foundation/text/string-utils.d.mts +8 -0
  393. package/foundation/text/string-utils.mjs +40 -10
  394. package/foundation/xle/expand.mjs +1 -1
  395. package/foundation/xle/xle.test.mjs +13 -0
  396. package/package.json +10 -9
  397. package/assets/templates/themes/manifest.json +0 -95
@@ -0,0 +1,299 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Every authored descriptor becomes exactly one compiler input.
5
+ *
6
+ * The repo check is the completeness oracle for what Core and the CLI ship:
7
+ * every `.doc.mjs` under a descriptor root is read once, and nothing else is.
8
+ */
9
+
10
+ import {afterEach, beforeEach, describe, expect, it} from 'vitest';
11
+ import * as fs from 'node:fs';
12
+ import * as os from 'node:os';
13
+ import * as path from 'node:path';
14
+ import {Project} from '../config/project.mjs';
15
+ import {CLI_ROOT} from '../fs/paths.mjs';
16
+ import {collectDocInputs, packageSource} from './inputs.mjs';
17
+
18
+ const REPO_ROOT = path.resolve(CLI_ROOT, '..', '..');
19
+ const SKIP = new Set(['__tests__', '__fixtures__', 'fixtures', 'node_modules']);
20
+
21
+ /**
22
+ * Every `.doc.mjs` under a directory, by real path.
23
+ * @param {string} dir
24
+ * @param {Set<string>} into
25
+ */
26
+ function docFiles(dir, into) {
27
+ for (const entry of fs.readdirSync(dir, {withFileTypes: true})) {
28
+ const full = path.join(dir, entry.name);
29
+ if (entry.isDirectory()) {
30
+ if (!SKIP.has(entry.name)) docFiles(full, into);
31
+ } else if (entry.name.endsWith('.doc.mjs')) {
32
+ into.add(fs.realpathSync(full));
33
+ }
34
+ }
35
+ return into;
36
+ }
37
+
38
+ let tmpDir;
39
+
40
+ beforeEach(() => {
41
+ // Inside the repo, so the project finds this checkout's Core.
42
+ tmpDir = fs.mkdtempSync(path.join(REPO_ROOT, '.astryx-doc-inputs-'));
43
+ fs.writeFileSync(
44
+ path.join(tmpDir, 'package.json'),
45
+ JSON.stringify({name: 'consumer', version: '1.0.0'}),
46
+ );
47
+ });
48
+
49
+ afterEach(() => {
50
+ fs.rmSync(tmpDir, {recursive: true, force: true});
51
+ });
52
+
53
+ describe('collectDocInputs over what this repo ships', () => {
54
+ it('reads every descriptor Core and the CLI ship exactly once', async () => {
55
+ const {inputs, problems} = await collectDocInputs(
56
+ await Project.load(tmpDir),
57
+ );
58
+ expect(problems).toEqual([]);
59
+
60
+ // What ships comes from the packages themselves, not from the module under
61
+ // test: Core's source, and every directory the CLI's package.json ships.
62
+ const shipped = new Set();
63
+ docFiles(path.join(REPO_ROOT, 'packages', 'core', 'src'), shipped);
64
+ const {files} = JSON.parse(
65
+ fs.readFileSync(path.join(CLI_ROOT, 'package.json'), 'utf-8'),
66
+ );
67
+ for (const entry of files) {
68
+ const full = path.join(CLI_ROOT, entry);
69
+ if (fs.statSync(full).isDirectory()) docFiles(full, shipped);
70
+ }
71
+ const read = inputs.map(input => input.file);
72
+ const rel = (/** @type {string} */ file) => path.relative(REPO_ROOT, file);
73
+ expect(read.filter(file => !shipped.has(file)).map(rel)).toEqual([]);
74
+ expect([...shipped].filter(file => !read.includes(file)).map(rel)).toEqual(
75
+ [],
76
+ );
77
+ expect(new Set(read).size).toBe(read.length);
78
+ expect(new Set(inputs.map(input => input.id)).size).toBe(inputs.length);
79
+ }, 120_000);
80
+
81
+ it('pins the core docs that `component <Name>` reads but the list leaves out', async () => {
82
+ const {inputs} = await collectDocInputs(await Project.load(tmpDir));
83
+ // Each is readable by name; listing them would change `component --list`,
84
+ // so a new entry here is a decision, not a silent drift.
85
+ expect(
86
+ inputs
87
+ .filter(input => input.listed === false)
88
+ .map(input => input.name)
89
+ .sort(),
90
+ ).toEqual([
91
+ 'Chat',
92
+ 'ChatComposerTokenElement',
93
+ 'Code',
94
+ 'ContextMenuItem',
95
+ 'Heading',
96
+ 'Indicator',
97
+ 'Layer',
98
+ 'NavMenu',
99
+ 'Resizable',
100
+ 'SyntaxTheme',
101
+ ]);
102
+ });
103
+
104
+ it('keys templates by type and directory, not by their display title', async () => {
105
+ const {inputs} = await collectDocInputs(await Project.load(tmpDir));
106
+ const byName = new Map(
107
+ inputs
108
+ .filter(input => input.root === 'templates')
109
+ .map(input => [input.name, input]),
110
+ );
111
+ // A showcase shares its title with the block it shows; both stay inputs.
112
+ expect(byName.get('block/BannerStatuses')?.source).toBe(
113
+ '@astryxdesign/cli/assets/templates/blocks/components/Banner/BannerStatuses.doc.mjs',
114
+ );
115
+ expect(byName.get('block/BannerShowcase')?.source).toBe(
116
+ '@astryxdesign/cli/assets/templates/blocks/components/Banner/BannerShowcase.doc.mjs',
117
+ );
118
+ });
119
+ });
120
+
121
+ describe('collectDocInputs over an integration', () => {
122
+ /**
123
+ * @param {string} rel
124
+ * @param {string} text
125
+ */
126
+ function write(rel, text) {
127
+ const file = path.join(tmpDir, 'node_modules', '@acme', 'kit', rel);
128
+ fs.mkdirSync(path.dirname(file), {recursive: true});
129
+ fs.writeFileSync(file, text);
130
+ }
131
+
132
+ it('lists each descriptor once, owned by the package, with where it ships', async () => {
133
+ fs.writeFileSync(
134
+ path.join(tmpDir, 'package.json'),
135
+ JSON.stringify({
136
+ name: 'consumer',
137
+ version: '1.0.0',
138
+ dependencies: {'@acme/kit': '^1.0.0'},
139
+ }),
140
+ );
141
+ write(
142
+ 'package.json',
143
+ JSON.stringify({name: '@acme/kit', version: '1.0.0'}),
144
+ );
145
+ write(
146
+ 'astryx.integration.mjs',
147
+ "export default {components: './components', templates: './templates', docs: './docs', themes: './themes'};\n",
148
+ );
149
+ write(
150
+ 'components/AcmeCard.tsx',
151
+ 'export function AcmeCard() { return null; }\n',
152
+ );
153
+ write(
154
+ 'components/AcmeCard.doc.mjs',
155
+ "export default {type: 'component', name: 'AcmeCard', displayName: 'Acme Card', usage: {description: 'A card.'}, props: []};\n",
156
+ );
157
+ write(
158
+ 'templates/hero.tsx',
159
+ 'export default function Hero() { return null; }\n',
160
+ );
161
+ write(
162
+ 'templates/hero.doc.mjs',
163
+ "export default {type: 'block', name: 'Hero block', description: 'A hero.'};\n",
164
+ );
165
+ const topic = (/** @type {object} */ fields) =>
166
+ `export default ${JSON.stringify({
167
+ type: 'generic',
168
+ title: 'Acme',
169
+ description: 'Acme notes.',
170
+ sections: [{title: 'Acme', content: [{type: 'prose', text: 'Hi.'}]}],
171
+ ...fields,
172
+ })};\n`;
173
+ write('docs/acme-guide.doc.mjs', topic({name: 'acme-guide'}));
174
+ write(
175
+ 'docs/theme-notes.doc.mjs',
176
+ topic({name: 'theme-notes', extends: 'theme'}),
177
+ );
178
+ write('themes/ocean/oceanTheme.ts', 'export const oceanTheme = {};\n');
179
+ write(
180
+ 'themes/ocean/oceanTheme.doc.mjs',
181
+ "/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */\nexport default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Blue.', maintained: true};\n",
182
+ );
183
+
184
+ const project = await Project.load(tmpDir);
185
+ expect(await project.issues()).toEqual([]);
186
+ const {inputs, problems} = await collectDocInputs(project);
187
+ expect(problems).toEqual([]);
188
+ expect(
189
+ inputs
190
+ .filter(input => input.owner === '@acme/kit')
191
+ .map(({id, source, role}) => ({id, source, role})),
192
+ ).toEqual([
193
+ {
194
+ id: '@acme/kit:components:AcmeCard',
195
+ source: '@acme/kit/components/AcmeCard.doc.mjs',
196
+ role: undefined,
197
+ },
198
+ {
199
+ id: '@acme/kit:templates:block/hero',
200
+ source: '@acme/kit/templates/hero.doc.mjs',
201
+ role: undefined,
202
+ },
203
+ {
204
+ id: '@acme/kit:themes:ocean',
205
+ source: '@acme/kit/themes/ocean/oceanTheme.doc.mjs',
206
+ role: undefined,
207
+ },
208
+ {
209
+ id: '@acme/kit:docs:theme+theme-notes',
210
+ source: '@acme/kit/docs/theme-notes.doc.mjs',
211
+ role: 'extension',
212
+ },
213
+ {
214
+ id: '@acme/kit:docs:acme-guide',
215
+ source: '@acme/kit/docs/acme-guide.doc.mjs',
216
+ role: 'base',
217
+ },
218
+ ]);
219
+ });
220
+ });
221
+
222
+ describe('collectDocInputs problems', () => {
223
+ /** @param {object} overrides */
224
+ const project = overrides =>
225
+ /** @type {any} */ ({
226
+ cwd: os.tmpdir(),
227
+ components: async () => [],
228
+ templates: async () => [],
229
+ themes: async () => [],
230
+ docs: async () => ({entries: () => []}),
231
+ ...overrides,
232
+ });
233
+
234
+ it('reports a file two roots both claim, and reads it once', async () => {
235
+ const file = path.join(tmpDir, 'Shared.doc.mjs');
236
+ fs.writeFileSync(file, 'export default {};\n');
237
+ const {inputs, problems} = await collectDocInputs(
238
+ project({
239
+ components: async () => [
240
+ {name: 'Shared', package: '@acme/kit', docPath: file},
241
+ ],
242
+ templates: async () => [
243
+ {
244
+ type: 'block',
245
+ dirName: 'shared',
246
+ package: '@acme/kit',
247
+ docPath: file,
248
+ },
249
+ ],
250
+ }),
251
+ );
252
+ expect(
253
+ inputs.filter(input => input.file === fs.realpathSync(file)),
254
+ ).toHaveLength(1);
255
+ expect(problems).toEqual([
256
+ {
257
+ code: 'duplicate_file',
258
+ provider: '@acme/kit',
259
+ source: expect.stringMatching(/\/Shared\.doc\.mjs$/),
260
+ message: expect.stringContaining(
261
+ 'is read as templates "block/shared" and as components "Shared"',
262
+ ),
263
+ },
264
+ ]);
265
+ });
266
+
267
+ it('reports two files under one input id', async () => {
268
+ const one = path.join(tmpDir, 'a', 'Card.doc.mjs');
269
+ const two = path.join(tmpDir, 'b', 'Card.doc.mjs');
270
+ for (const file of [one, two]) {
271
+ fs.mkdirSync(path.dirname(file), {recursive: true});
272
+ fs.writeFileSync(file, 'export default {};\n');
273
+ }
274
+ const {problems} = await collectDocInputs(
275
+ project({
276
+ components: async () => [
277
+ {name: 'Card', package: '@acme/kit', docPath: one},
278
+ {name: 'Card', package: '@acme/kit', docPath: two},
279
+ ],
280
+ }),
281
+ );
282
+ expect(problems).toEqual([
283
+ {
284
+ code: 'duplicate_id',
285
+ provider: '@acme/kit',
286
+ source: expect.stringMatching(/\/Card\.doc\.mjs$/),
287
+ message: expect.stringContaining('both read as components "Card"'),
288
+ },
289
+ ]);
290
+ });
291
+ });
292
+
293
+ describe('packageSource', () => {
294
+ it('names the package a file ships in and its path inside it', () => {
295
+ expect(
296
+ packageSource(path.join(CLI_ROOT, 'api', 'docs', 'docs.doc.mjs')),
297
+ ).toBe('@astryxdesign/cli/api/docs/docs.doc.mjs');
298
+ });
299
+ });
@@ -7,3 +7,16 @@
7
7
  * @returns {import('./compile.mjs').CompiledReferenceNode}
8
8
  */
9
9
  export function parseCompiledReferenceNode(value: unknown): import("./compile.mjs").CompiledReferenceNode;
10
+ /**
11
+ * Validate a compiled node of any kind.
12
+ * @param {unknown} value
13
+ * @returns {import('./compile.mjs').CompiledDocNode | import('./compile.mjs').CompiledReferenceNode}
14
+ */
15
+ export function parseCompiledDocNode(value: unknown): import("./compile.mjs").CompiledDocNode | import("./compile.mjs").CompiledReferenceNode;
16
+ /**
17
+ * Validate a compiled docs bundle: every node, every diagnostic, and one node
18
+ * per id.
19
+ * @param {unknown} value
20
+ * @returns {import('./bundle.mjs').CompiledDocsBundle}
21
+ */
22
+ export function parseCompiledDocsBundle(value: unknown): import("./bundle.mjs").CompiledDocsBundle;
@@ -1,13 +1,14 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file The compiled-node contract and its sealed parser.
4
+ * @file The compiled-doc contract and its sealed parsers.
5
5
  *
6
- * @input Any value that claims to be a compiled reference node — typically one
7
- * read back from JSON.
6
+ * @input Any value that claims to be a compiled node or a compiled docs bundle
7
+ * — typically one read back from JSON.
8
8
  * @output The same value once it validates; a thrown Error naming the problems
9
- * otherwise. An unsupported schema version fails with its own message before
10
- * anything else is checked.
9
+ * otherwise, carrying a compiler diagnostic (`unsupported_schema` or
10
+ * `invalid_bundle`). An unsupported schema version fails with its own message
11
+ * before anything else is checked.
11
12
  * @position The load boundary for compiled nodes that did not come straight
12
13
  * from ./compile.mjs in this process. The value is returned as given, not
13
14
  * rebuilt, so key order (which response JSON follows) survives. A node is
@@ -15,7 +16,8 @@
15
16
  */
16
17
 
17
18
  import {SECTION_KEY_RE} from '../discovery/docs-section-key.mjs';
18
- import {COMPILED_DOC_SCHEMA_VERSION} from './compile.mjs';
19
+ import {COMPILED_DOC_KINDS, COMPILED_DOC_SCHEMA_VERSION} from './compile.mjs';
20
+ import {diagnostic, diagnosticProblem} from './diagnostics.mjs';
19
21
 
20
22
  const NODE_FIELDS = new Set([
21
23
  'schemaVersion',
@@ -25,6 +27,7 @@ const NODE_FIELDS = new Set([
25
27
  'lang',
26
28
  'provenance',
27
29
  'sourceTitles',
30
+ 'sectionProviders',
28
31
  'doc',
29
32
  ]);
30
33
  const RESOLVED_FIELDS = new Set([
@@ -65,15 +68,13 @@ const isPackageName = value =>
65
68
  */
66
69
  export function parseCompiledReferenceNode(value) {
67
70
  const node = /** @type {any} */ (value);
68
- if (node?.schemaVersion !== COMPILED_DOC_SCHEMA_VERSION) {
69
- throw new Error(
70
- `Compiled doc schema version ${JSON.stringify(node?.schemaVersion)} is not supported; this CLI reads version ${COMPILED_DOC_SCHEMA_VERSION}. Compile the docs again with this CLI.`,
71
- );
72
- }
71
+ const skew = schemaVersionProblem(node);
72
+ if (skew) throw compiledDocError('unsupported_schema', skew);
73
73
  const problems = jsonProblems(node, 'node');
74
74
  if (problems.length === 0) problems.push(...structureProblems(node));
75
75
  if (problems.length > 0) {
76
- throw new Error(
76
+ throw compiledDocError(
77
+ 'invalid_bundle',
77
78
  `Invalid compiled doc node: ${problems.slice(0, MAX_PROBLEMS).join('; ')}`,
78
79
  );
79
80
  }
@@ -170,6 +171,12 @@ function structureProblems(node) {
170
171
  'provenance: expected {provider, replaces, extensions} naming packages, not paths',
171
172
  );
172
173
  }
174
+ const providers = isRecord(node.sectionProviders)
175
+ ? node.sectionProviders
176
+ : null;
177
+ if (!providers || !Object.values(providers).every(isText)) {
178
+ problems.push('sectionProviders: expected section key -> provider id');
179
+ }
173
180
  const titles = isRecord(node.sourceTitles) ? node.sourceTitles : null;
174
181
  if (!titles || !Object.values(titles).every(isText)) {
175
182
  problems.push('sourceTitles: expected section key -> authored title');
@@ -285,3 +292,180 @@ function resolutionProblem(resolved) {
285
292
  return `status: expected resolved, unknown-topic or unknown-section, got ${JSON.stringify(resolved.status)}`;
286
293
  }
287
294
  }
295
+
296
+ const DOC_NODE_FIELDS = new Set([
297
+ 'schemaVersion',
298
+ 'kind',
299
+ 'stage',
300
+ 'id',
301
+ 'lang',
302
+ 'provenance',
303
+ 'doc',
304
+ ]);
305
+ const BUNDLE_FIELDS = new Set([
306
+ 'schemaVersion',
307
+ 'lang',
308
+ 'nodes',
309
+ 'diagnostics',
310
+ ]);
311
+
312
+ /**
313
+ * A package-relative source, never a location on one machine.
314
+ * @param {unknown} value
315
+ * @returns {boolean}
316
+ */
317
+ const isPackageSource = value =>
318
+ isPackageName(value) &&
319
+ !/(^|\/)\.\.(\/|$)/.test(/** @type {string} */ (value));
320
+
321
+ /**
322
+ * An Error for a value that is not a compiled doc, carrying the diagnostic a
323
+ * reader reports.
324
+ * @param {'unsupported_schema' | 'invalid_bundle'} code
325
+ * @param {string} message
326
+ * @returns {Error & {diagnostic: import('./diagnostics.mjs').CompilerDiagnostic}}
327
+ */
328
+ function compiledDocError(code, message) {
329
+ const error = /** @type {Error & {diagnostic: any}} */ (new Error(message));
330
+ error.diagnostic = diagnostic(code, {message});
331
+ return error;
332
+ }
333
+
334
+ /**
335
+ * @param {unknown} value
336
+ */
337
+ function schemaVersionProblem(value) {
338
+ const version = /** @type {any} */ (value)?.schemaVersion;
339
+ return version === COMPILED_DOC_SCHEMA_VERSION
340
+ ? null
341
+ : `Compiled doc schema version ${JSON.stringify(version)} is not supported; this CLI reads version ${COMPILED_DOC_SCHEMA_VERSION}. Compile the docs again with this CLI.`;
342
+ }
343
+
344
+ /**
345
+ * Validate a compiled node of any kind.
346
+ * @param {unknown} value
347
+ * @returns {import('./compile.mjs').CompiledDocNode | import('./compile.mjs').CompiledReferenceNode}
348
+ */
349
+ export function parseCompiledDocNode(value) {
350
+ const skew = schemaVersionProblem(value);
351
+ if (skew) throw compiledDocError('unsupported_schema', skew);
352
+ const problems = nodeProblems(value, 'node');
353
+ if (problems.length > 0) {
354
+ throw compiledDocError(
355
+ 'invalid_bundle',
356
+ `Invalid compiled doc node: ${problems.slice(0, MAX_PROBLEMS).join('; ')}`,
357
+ );
358
+ }
359
+ return /** @type {any} */ (value);
360
+ }
361
+
362
+ /**
363
+ * Validate a compiled docs bundle: every node, every diagnostic, and one node
364
+ * per id.
365
+ * @param {unknown} value
366
+ * @returns {import('./bundle.mjs').CompiledDocsBundle}
367
+ */
368
+ export function parseCompiledDocsBundle(value) {
369
+ const skew = schemaVersionProblem(value);
370
+ if (skew) throw compiledDocError('unsupported_schema', skew);
371
+ const bundle = /** @type {any} */ (value);
372
+ /** @type {string[]} */
373
+ const problems = jsonProblems(bundle, 'bundle');
374
+ if (problems.length === 0) {
375
+ const unknown = Object.keys(bundle).filter(key => !BUNDLE_FIELDS.has(key));
376
+ if (unknown.length > 0)
377
+ problems.push(`unknown fields: ${unknown.join(', ')}`);
378
+ if (bundle.lang !== null && !isText(bundle.lang)) {
379
+ problems.push('lang: expected a language or null');
380
+ }
381
+ if (!Array.isArray(bundle.nodes)) {
382
+ problems.push('nodes: expected an array');
383
+ } else {
384
+ const ids = new Set();
385
+ bundle.nodes.forEach(
386
+ (/** @type {unknown} */ node, /** @type {number} */ index) => {
387
+ for (const problem of nodeProblems(node, `nodes[${index}]`)) {
388
+ problems.push(problem);
389
+ }
390
+ const id = /** @type {any} */ (node)?.id;
391
+ if (ids.has(id))
392
+ problems.push(`nodes[${index}].id: "${id}" appears twice`);
393
+ ids.add(id);
394
+ },
395
+ );
396
+ }
397
+ if (!Array.isArray(bundle.diagnostics)) {
398
+ problems.push('diagnostics: expected an array');
399
+ } else {
400
+ bundle.diagnostics.forEach(
401
+ (/** @type {unknown} */ d, /** @type {number} */ index) => {
402
+ const problem = diagnosticProblem(d);
403
+ if (problem) problems.push(`diagnostics[${index}]: ${problem}`);
404
+ },
405
+ );
406
+ }
407
+ }
408
+ if (problems.length > 0) {
409
+ throw compiledDocError(
410
+ 'invalid_bundle',
411
+ `Invalid compiled docs bundle: ${problems.slice(0, MAX_PROBLEMS).join('; ')}`,
412
+ );
413
+ }
414
+ return bundle;
415
+ }
416
+
417
+ /**
418
+ * Problems with one node of any kind, each prefixed with where it is.
419
+ * @param {unknown} value
420
+ * @param {string} at
421
+ * @returns {string[]}
422
+ */
423
+ function nodeProblems(value, at) {
424
+ const node = /** @type {any} */ (value);
425
+ if (node?.schemaVersion !== COMPILED_DOC_SCHEMA_VERSION) {
426
+ return [`${at}.schemaVersion: expected ${COMPILED_DOC_SCHEMA_VERSION}`];
427
+ }
428
+ const json = jsonProblems(node, at);
429
+ if (json.length > 0) return json;
430
+ if (node.kind === 'reference') {
431
+ return structureProblems(node).map(problem => `${at}: ${problem}`);
432
+ }
433
+ /** @type {string[]} */
434
+ const problems = [];
435
+ const unknown = Object.keys(node).filter(key => !DOC_NODE_FIELDS.has(key));
436
+ if (unknown.length > 0)
437
+ problems.push(`${at}: unknown fields: ${unknown.join(', ')}`);
438
+ if (!COMPILED_DOC_KINDS.includes(node.kind)) {
439
+ problems.push(
440
+ `${at}.kind: ${JSON.stringify(node.kind)} is not a compiled doc kind`,
441
+ );
442
+ }
443
+ if (node.stage !== 'lowered')
444
+ problems.push(`${at}.stage: expected "lowered"`);
445
+ if (!isText(node.id)) problems.push(`${at}.id: expected an id`);
446
+ if (node.lang !== null && !isText(node.lang)) {
447
+ problems.push(`${at}.lang: expected a language or null`);
448
+ }
449
+ const provenance = node.provenance;
450
+ if (
451
+ !isRecord(provenance) ||
452
+ Object.keys(provenance).length !== 2 ||
453
+ !isPackageName(provenance.provider) ||
454
+ !isPackageSource(provenance.source)
455
+ ) {
456
+ problems.push(
457
+ `${at}.provenance: expected {provider, source} naming a package and a path inside it, not a machine path`,
458
+ );
459
+ }
460
+ if (!isRecord(node.doc) || !isText(node.doc.name)) {
461
+ problems.push(`${at}.doc: expected a doc with a name`);
462
+ } else if (
463
+ (node.kind === 'page' || node.kind === 'block' || node.kind === 'theme') &&
464
+ node.doc.type !== node.kind
465
+ ) {
466
+ problems.push(
467
+ `${at}.doc.type: a ${node.kind} node holds a ${node.kind} doc`,
468
+ );
469
+ }
470
+ return problems;
471
+ }
@@ -18,14 +18,17 @@ export function readerSections(node: import("./compile.mjs").CompiledReferenceNo
18
18
  export function detailView(node: import("./compile.mjs").CompiledReferenceNode): any;
19
19
  /**
20
20
  * `docs.index`: what the topic is, and each section's key, title and summary.
21
+ * The index leaf adds the moves.
21
22
  * @param {import('./compile.mjs').CompiledReferenceNode} node
22
- * @returns {import('../../api/docs/docs.type.mjs').DocsIndex}
23
+ * @returns {Omit<import('../../api/docs/docs.type.mjs').DocsIndex, 'links'>}
23
24
  */
24
- export function indexView(node: import("./compile.mjs").CompiledReferenceNode): import("../../api/docs/docs.type.mjs").DocsIndex;
25
+ export function indexView(node: import("./compile.mjs").CompiledReferenceNode): Omit<import("../../api/docs/docs.type.mjs").DocsIndex, "links">;
25
26
  /**
26
- * `docs.detail.section`: one section with its token references inlined. A
27
- * referenced section's content takes the reference's place; the section takes
28
- * the preview type of the last reference that has one, unless it has its own.
27
+ * `docs.detail.section`: one section with its token references and reference
28
+ * blocks inlined, so a read returns only the stable block kinds. A referenced
29
+ * section's content takes the token reference's place; the section takes the
30
+ * preview type of the last reference that has one, unless it has its own. A
31
+ * reference block becomes the content it includes (see referenceView).
29
32
  * @param {import('./compile.mjs').CompiledReferenceNode} node
30
33
  * @param {any} section a linked section of `node`
31
34
  * @returns {any}
@@ -62,17 +62,20 @@ export function detailView(node) {
62
62
 
63
63
  /**
64
64
  * `docs.index`: what the topic is, and each section's key, title and summary.
65
+ * The index leaf adds the moves.
65
66
  * @param {import('./compile.mjs').CompiledReferenceNode} node
66
- * @returns {import('../../api/docs/docs.type.mjs').DocsIndex}
67
+ * @returns {Omit<import('../../api/docs/docs.type.mjs').DocsIndex, 'links'>}
67
68
  */
68
69
  export function indexView(node) {
69
70
  return buildDocsIndexData(node.doc);
70
71
  }
71
72
 
72
73
  /**
73
- * `docs.detail.section`: one section with its token references inlined. A
74
- * referenced section's content takes the reference's place; the section takes
75
- * the preview type of the last reference that has one, unless it has its own.
74
+ * `docs.detail.section`: one section with its token references and reference
75
+ * blocks inlined, so a read returns only the stable block kinds. A referenced
76
+ * section's content takes the token reference's place; the section takes the
77
+ * preview type of the last reference that has one, unless it has its own. A
78
+ * reference block becomes the content it includes (see referenceView).
76
79
  * @param {import('./compile.mjs').CompiledReferenceNode} node
77
80
  * @param {any} section a linked section of `node`
78
81
  * @returns {any}
@@ -83,6 +86,10 @@ export function sectionView(node, section) {
83
86
  /** @type {string | null} */
84
87
  let previewType = null;
85
88
  for (const block of section.content) {
89
+ if (block?.type === 'reference') {
90
+ content.push(...referenceView(node, block));
91
+ continue;
92
+ }
86
93
  if (block?.type !== 'token-ref') {
87
94
  content.push(structuredClone(block));
88
95
  continue;
@@ -125,3 +132,42 @@ export function sectionView(node, section) {
125
132
  view.content = content;
126
133
  return withSourceTitle(view, authoredTitle(node, section));
127
134
  }
135
+
136
+ /**
137
+ * A reference block as a read shows it (spec:AST-047 FR9): the content it
138
+ * includes, then where that content comes from and the command that opens it.
139
+ * A reference that includes nothing (a summary, or a doc that is not included
140
+ * whole) shows the doc's title and summary; one whose doc is missing says so
141
+ * where its content would be, as a token reference does.
142
+ * @param {import('./compile.mjs').CompiledReferenceNode} node
143
+ * @param {any} block a linked reference block
144
+ * @returns {any[]}
145
+ */
146
+ function referenceView(node, block) {
147
+ if (!('link' in block)) {
148
+ throw new Error(
149
+ `The reference to "${block.target}" in "${node.id}" was read before it was linked.`,
150
+ );
151
+ }
152
+ const link = block.link;
153
+ if (link == null) {
154
+ return [
155
+ {type: 'prose', text: `[reference: "${block.target}" names no doc]`},
156
+ ];
157
+ }
158
+ const included = (block.content ?? []).map((/** @type {any} */ each) =>
159
+ structuredClone(each),
160
+ );
161
+ if (included.length === 0) {
162
+ const summary = String(link.summary ?? '').trim();
163
+ const lead =
164
+ summary === ''
165
+ ? link.title
166
+ : `${link.title}: ${summary}${/[.!?]$/.test(summary) ? '' : '.'}`;
167
+ return [{type: 'prose', text: `${lead} Read it with \`${link.command}\`.`}];
168
+ }
169
+ return [
170
+ ...included,
171
+ {type: 'prose', text: `From ${link.title}: \`${link.command}\``},
172
+ ];
173
+ }