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

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 (276) hide show
  1. package/README.md +22 -1
  2. package/api/blog/blog.doc.mjs +1 -0
  3. package/api/build/build.doc.mjs +1 -0
  4. package/api/component/component.doc.mjs +1 -0
  5. package/api/discover/discover.doc.mjs +1 -0
  6. package/api/docs/_adapter.d.mts +3 -8
  7. package/api/docs/_adapter.mjs +13 -105
  8. package/api/docs/detail/section/section.mjs +9 -15
  9. package/api/docs/detail/section/section.test.mjs +15 -6
  10. package/api/docs/docs.doc.mjs +1 -0
  11. package/api/docs/list/list.mjs +3 -7
  12. package/api/doctor/doctor.d.mts +25 -3
  13. package/api/doctor/doctor.doc.mjs +1 -0
  14. package/api/doctor/doctor.mjs +186 -14
  15. package/api/doctor/doctor.test.mjs +332 -7
  16. package/api/gap-report/gap-report.doc.mjs +1 -0
  17. package/api/hook/_adapter.mjs +19 -5
  18. package/api/hook/hook.doc.mjs +1 -0
  19. package/api/hook/list/list.d.mts +1 -1
  20. package/api/hook/list/list.mjs +69 -17
  21. package/api/init/init.doc.mjs +1 -0
  22. package/api/integration/add-contribution.mjs +7 -7
  23. package/api/integration/add-contribution.test.mjs +37 -3
  24. package/api/integration/add-theme.mjs +34 -64
  25. package/api/integration/add-theme.test.mjs +105 -21
  26. package/api/integration/authoring-checks.test.mjs +8 -4
  27. package/api/integration/integration-block-exports.test.mjs +10 -6
  28. package/api/integration/integrationAdd.doc.mjs +1 -0
  29. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  30. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  31. package/api/integration/integrationAddComponent.doc.mjs +1 -0
  32. package/api/integration/integrationAddDoc.doc.mjs +1 -0
  33. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  34. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  35. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  36. package/api/integration/integrationDocConflicts.doc.mjs +1 -0
  37. package/api/integration/integrationPackCheck.doc.mjs +1 -0
  38. package/api/integration/integrationTemplateConflicts.doc.mjs +1 -0
  39. package/api/integration/pack-check.test.mjs +17 -47
  40. package/api/integration/summarizeIssues.doc.mjs +1 -0
  41. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  42. package/api/integration/validate-integration.mjs +50 -102
  43. package/api/integration/validate-integration.test.mjs +85 -23
  44. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  45. package/api/integration/validateIntegration.doc.mjs +1 -0
  46. package/api/json/assertResponse.doc.mjs +1 -0
  47. package/api/json/isError.doc.mjs +1 -0
  48. package/api/json/parseResponse.doc.mjs +1 -0
  49. package/api/layout/layoutCheck.doc.mjs +1 -0
  50. package/api/layout/layoutExpand.doc.mjs +1 -0
  51. package/api/layout/layoutGrammar.doc.mjs +1 -0
  52. package/api/search/search.doc.mjs +1 -0
  53. package/api/search/search.mjs +16 -6
  54. package/api/swizzle/swizzle.doc.mjs +1 -0
  55. package/api/template/template-suffix.test.mjs +41 -21
  56. package/api/template/template.doc.mjs +1 -0
  57. package/api/theme/_adapter.d.mts +2 -3
  58. package/api/theme/_adapter.mjs +4 -5
  59. package/api/theme/add/add.binary.test.mjs +10 -17
  60. package/api/theme/add/add.test.mjs +14 -1
  61. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  62. package/api/theme/integration-themes.test.mjs +39 -28
  63. package/api/theme/list/list.test.mjs +19 -20
  64. package/api/theme/listThemes.doc.mjs +6 -5
  65. package/api/theme/themeAdd.doc.mjs +4 -3
  66. package/api/theme/themeBuild.doc.mjs +1 -0
  67. package/api/theme/themeList.doc.mjs +6 -3
  68. package/api/theme/themeListAvailable.doc.mjs +5 -3
  69. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  70. package/api/theme/themeTargets.doc.mjs +1 -0
  71. package/api/theme/themeTemplate.doc.mjs +1 -0
  72. package/api/upgrade/_adapter.d.mts +32 -5
  73. package/api/upgrade/_adapter.mjs +97 -69
  74. package/api/upgrade/provider-agreement.test.mjs +152 -0
  75. package/api/upgrade/run/run.mjs +356 -59
  76. package/api/upgrade/upgrade.doc.mjs +6 -1
  77. package/api/upgrade/upgrade.type.d.mts +34 -0
  78. package/api/upgrade/upgrade.type.mjs +15 -0
  79. package/assets/codemods/__tests__/runner.test.mjs +330 -8
  80. package/assets/codemods/integration-discovery.mjs +8 -2
  81. package/assets/codemods/integration-discovery.test.mjs +15 -0
  82. package/assets/codemods/integration-runner.mjs +56 -4
  83. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  84. package/assets/codemods/run-codemod.mjs +177 -34
  85. package/assets/codemods/runner.mjs +350 -102
  86. package/assets/codemods/transforms/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  87. package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  88. package/assets/codemods/transforms/next/index.mjs +19 -1
  89. package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
  90. package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
  91. package/assets/docs/cli-integrations.doc.mjs +30 -30
  92. package/assets/docs/cli.doc.mjs +15 -0
  93. package/assets/docs/theme.doc.mjs +1 -1
  94. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  95. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  96. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  97. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  98. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  99. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  100. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  101. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  102. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  103. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  104. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  105. package/authoring/codemod/codemod.doc.mjs +1 -1
  106. package/authoring/codemod/type.ts +12 -0
  107. package/authoring/config/config.doc.mjs +1 -1
  108. package/authoring/debug/debug.doc.d.mts +11 -0
  109. package/authoring/debug/debug.doc.mjs +182 -0
  110. package/authoring/doctypes/_schema.d.mts +71 -141
  111. package/authoring/doctypes/_schema.mjs +29 -2
  112. package/authoring/doctypes/base/graph-fields.doc.mjs +1 -1
  113. package/authoring/doctypes/command/command.doc.mjs +1 -1
  114. package/authoring/doctypes/command/type.ts +1 -1
  115. package/authoring/doctypes/component/type.ts +2 -2
  116. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  117. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  118. package/authoring/doctypes/enum/type.ts +1 -1
  119. package/authoring/doctypes/function/function.doc.mjs +1 -1
  120. package/authoring/doctypes/function/type.ts +1 -1
  121. package/authoring/doctypes/hook/type.ts +2 -2
  122. package/authoring/doctypes/load-contract.test.mjs +3 -2
  123. package/authoring/doctypes/namespace/namespace.doc.mjs +2 -2
  124. package/authoring/doctypes/namespace/parse.test.mjs +23 -25
  125. package/authoring/doctypes/namespace/type.ts +5 -2
  126. package/authoring/doctypes/parse.d.mts +4 -2
  127. package/authoring/doctypes/parse.mjs +10 -5
  128. package/authoring/doctypes/reference/reference.doc.mjs +6 -4
  129. package/authoring/doctypes/reference/type.ts +9 -10
  130. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  131. package/authoring/doctypes/schema/type.ts +1 -2
  132. package/authoring/doctypes/template/template.doc.mjs +3 -3
  133. package/authoring/doctypes/theme/parse.d.mts +35 -0
  134. package/authoring/doctypes/theme/parse.mjs +76 -0
  135. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  136. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  137. package/authoring/doctypes/theme/type.ts +42 -0
  138. package/authoring/doctypes/types.ts +2 -1
  139. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  140. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  141. package/authoring/index.d.mts +1 -0
  142. package/authoring/index.d.ts +7 -4
  143. package/authoring/index.mjs +2 -1
  144. package/authoring/integration/integration.doc.mjs +2 -2
  145. package/authoring/integration/type.ts +3 -9
  146. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  147. package/clients/cli/commands/blog.doc.mjs +1 -1
  148. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  149. package/clients/cli/commands/build-theme.mjs +10 -44
  150. package/clients/cli/commands/build.doc.mjs +1 -1
  151. package/clients/cli/commands/component.doc.mjs +1 -1
  152. package/clients/cli/commands/discover.doc.mjs +1 -1
  153. package/clients/cli/commands/docs.doc.mjs +1 -1
  154. package/clients/cli/commands/docs.mjs +15 -58
  155. package/clients/cli/commands/docs.test.mjs +11 -14
  156. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  157. package/clients/cli/commands/doctor-integration-docs.doc.mjs +1 -1
  158. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -1
  159. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  160. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  161. package/clients/cli/commands/doctor-integration.test.mjs +15 -7
  162. package/clients/cli/commands/doctor.doc.mjs +1 -1
  163. package/clients/cli/commands/gap-report.doc.mjs +1 -1
  164. package/clients/cli/commands/hook.doc.mjs +1 -1
  165. package/clients/cli/commands/init.doc.mjs +1 -1
  166. package/clients/cli/commands/integration-add.controls.test.mjs +1 -1
  167. package/clients/cli/commands/integration-add.doc.mjs +1 -1
  168. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  169. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  170. package/clients/cli/commands/integration.doc.mjs +1 -1
  171. package/clients/cli/commands/layout-check.doc.mjs +1 -1
  172. package/clients/cli/commands/layout-expand.doc.mjs +1 -1
  173. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  174. package/clients/cli/commands/layout.doc.mjs +1 -1
  175. package/clients/cli/commands/manifest.doc.mjs +1 -1
  176. package/clients/cli/commands/search.doc.mjs +1 -1
  177. package/clients/cli/commands/swizzle.doc.mjs +1 -1
  178. package/clients/cli/commands/template.doc.mjs +1 -1
  179. package/clients/cli/commands/text-json-parity.test.mjs +718 -0
  180. package/clients/cli/commands/theme-add.doc.mjs +2 -2
  181. package/clients/cli/commands/theme-build.doc.mjs +1 -1
  182. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  183. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -3
  184. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  185. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  186. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  187. package/clients/cli/commands/theme-template.doc.mjs +1 -1
  188. package/clients/cli/commands/theme.doc.mjs +1 -1
  189. package/clients/cli/commands/upgrade.doc.mjs +3 -2
  190. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  191. package/clients/cli/commands/upgrade.mjs +29 -7
  192. package/clients/cli/formatters/index.mjs +2 -0
  193. package/clients/cli/formatters/index.test.mjs +6 -0
  194. package/clients/cli/lib/hook-format.mjs +14 -5
  195. package/foundation/config/project-themes.test.mjs +11 -19
  196. package/foundation/config/project.d.mts +8 -0
  197. package/foundation/config/project.mjs +50 -21
  198. package/foundation/config/project.test.mjs +3 -16
  199. package/foundation/discovery/authoring-self-docs.d.mts +6 -0
  200. package/foundation/discovery/authoring-self-docs.mjs +17 -7
  201. package/foundation/discovery/authoring-self-docs.test.mjs +3 -2
  202. package/foundation/discovery/authoring-surface.d.mts +74 -0
  203. package/foundation/discovery/authoring-surface.mjs +525 -0
  204. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  205. package/foundation/discovery/cli-self-docs.d.mts +113 -0
  206. package/foundation/discovery/cli-self-docs.mjs +514 -0
  207. package/foundation/discovery/cli-self-docs.test.mjs +437 -0
  208. package/foundation/discovery/component-loader.d.mts +35 -38
  209. package/foundation/discovery/component-loader.mjs +53 -222
  210. package/foundation/discovery/docs-discovery.d.mts +3 -2
  211. package/foundation/discovery/docs-discovery.mjs +14 -17
  212. package/foundation/discovery/docs-discovery.test.mjs +15 -15
  213. package/foundation/discovery/docs-section-key.d.mts +19 -8
  214. package/foundation/discovery/docs-section-key.mjs +119 -32
  215. package/foundation/discovery/docs-section-key.test.mjs +41 -19
  216. package/foundation/discovery/template-adapter.d.mts +7 -0
  217. package/foundation/discovery/template-adapter.mjs +27 -40
  218. package/foundation/discovery/template-adapter.test.mjs +15 -0
  219. package/foundation/discovery/theme-discovery.d.mts +67 -7
  220. package/foundation/discovery/theme-discovery.mjs +916 -186
  221. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  222. package/foundation/doc-compiler/bundle.d.mts +47 -0
  223. package/foundation/doc-compiler/bundle.mjs +218 -0
  224. package/foundation/doc-compiler/bundle.test.mjs +255 -0
  225. package/foundation/doc-compiler/compile.d.mts +200 -0
  226. package/foundation/doc-compiler/compile.mjs +259 -9
  227. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  228. package/foundation/doc-compiler/diagnostics.mjs +277 -0
  229. package/foundation/doc-compiler/doc-compiler.test.mjs +28 -1
  230. package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
  231. package/foundation/doc-compiler/import.d.mts +24 -0
  232. package/foundation/doc-compiler/import.mjs +59 -0
  233. package/foundation/doc-compiler/inputs.d.mts +102 -0
  234. package/foundation/doc-compiler/inputs.mjs +286 -0
  235. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  236. package/foundation/doc-compiler/ir.d.mts +13 -0
  237. package/foundation/doc-compiler/ir.mjs +189 -12
  238. package/foundation/doc-compiler/lower-doc.test.mjs +492 -0
  239. package/foundation/doc-compiler/overlays.d.mts +37 -0
  240. package/foundation/doc-compiler/overlays.mjs +206 -0
  241. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  242. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  243. package/foundation/doc-compiler/read.d.mts +126 -0
  244. package/foundation/doc-compiler/read.mjs +320 -0
  245. package/foundation/doc-compiler/read.test.mjs +313 -0
  246. package/foundation/doc-compiler/source.d.mts +33 -0
  247. package/foundation/doc-compiler/source.mjs +128 -0
  248. package/foundation/fs/file-protection.d.mts +33 -0
  249. package/foundation/fs/file-protection.mjs +825 -0
  250. package/foundation/fs/file-protection.test.mjs +250 -0
  251. package/foundation/integrations/autolink.d.mts +58 -1
  252. package/foundation/integrations/autolink.mjs +143 -57
  253. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  254. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  255. package/foundation/integrations/contribution-inventory.d.mts +1 -1
  256. package/foundation/integrations/contribution-inventory.mjs +17 -20
  257. package/foundation/integrations/contribution-inventory.test.mjs +67 -27
  258. package/foundation/integrations/integrations.d.mts +3 -0
  259. package/foundation/integrations/integrations.mjs +11 -97
  260. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  261. package/foundation/integrations/provider-resolution.d.mts +152 -0
  262. package/foundation/integrations/provider-resolution.mjs +576 -0
  263. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  264. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  265. package/foundation/integrations/theme-descriptor.mjs +44 -0
  266. package/foundation/integrations/validate-contributions.mjs +104 -10
  267. package/foundation/response/error-codes.d.mts +3 -1
  268. package/foundation/response/error-codes.d.ts +2 -0
  269. package/foundation/response/error-codes.doc.mjs +12 -2
  270. package/foundation/response/error-codes.mjs +7 -1
  271. package/foundation/response/error-codes.test.mjs +55 -11
  272. package/foundation/response/response-types.doc.mjs +1 -1
  273. package/foundation/response/response.doc.mjs +1 -1
  274. package/foundation/text/string-utils.mjs +22 -10
  275. package/package.json +10 -9
  276. package/assets/templates/themes/manifest.json +0 -95
@@ -65,8 +65,96 @@ export function linkReferenceTopic(node: CompiledReferenceNode, lowerTarget: (to
65
65
  export function linkReferenceSection<S extends {
66
66
  content: any[];
67
67
  }>(section: S, lowerTarget: (topic: string) => Promise<CompiledReferenceNode | null>): Promise<S>;
68
+ /**
69
+ * @typedef {import('./diagnostics.mjs').CompilerDiagnostic} CompilerDiagnostic
70
+ */
71
+ /**
72
+ * One authored doc of any kind but a reference topic, as its root loaded it.
73
+ * @typedef {object} DocFileInput
74
+ * @property {string} id the input's id: provider, root, and name
75
+ * @property {keyof typeof ROOT_KINDS} root
76
+ * @property {string} provider the package that contributes it
77
+ * @property {string} source `<package>/<path>` of the file
78
+ * @property {string | null} lang the overlay language, or null
79
+ * @property {AuthoredFile} file `doc` is the authored export, not a parse
80
+ * result; `overlay` is the translation the module exports for `lang`
81
+ * @property {string} [label] how a parse error names the file (default: its
82
+ * file name)
83
+ * @property {boolean} [useParsed] carry the parser's result instead of the
84
+ * authored export, for a reader that has always read the checked value
85
+ */
86
+ /**
87
+ * The parser that checks a root's docs. Templates and themes have their own;
88
+ * every other root dispatches on the stamped type.
89
+ * @param {string} root
90
+ * @returns {(input: unknown, label?: string) => any}
91
+ */
92
+ export function parserFor(root: string): (input: unknown, label?: string) => any;
93
+ /**
94
+ * A compiled node for any kind but a reference topic.
95
+ * @typedef {object} CompiledDocNode
96
+ * @property {number} schemaVersion
97
+ * @property {Exclude<typeof COMPILED_DOC_KINDS[number], 'reference'>} kind
98
+ * @property {'lowered'} stage
99
+ * @property {string} id
100
+ * @property {string | null} lang
101
+ * @property {{provider: string, source: string}} provenance
102
+ * @property {any} doc the authored doc, overlaid for `lang`, as JSON carries
103
+ * it: key order kept, `undefined` and functions dropped
104
+ */
105
+ /**
106
+ * The result of lowering one doc.
107
+ *
108
+ * `view` is the doc as readers have always read it: the authored export (or,
109
+ * where a reader has always read it, the parser's result), with its
110
+ * translation laid over it, not copied and not converted. Readers print from
111
+ * the view, so nothing they print depends on JSON. `node` is the sealed,
112
+ * JSON-only form a whole-project compile collects.
113
+ *
114
+ * @typedef {object} LoweredDoc
115
+ * @property {any} [view] absent when the file could not be read
116
+ * @property {CompiledDocNode | null} node null when not asked for, or when a
117
+ * problem is fatal to the node
118
+ * @property {CompilerDiagnostic[]} diagnostics
119
+ * @property {boolean} [loadFailed] importing the file threw
120
+ * @property {unknown} [loadFailure] what importing the file threw (any value,
121
+ * `undefined` included)
122
+ * @property {boolean} [missing] the file exports no doc
123
+ * @property {null | undefined} [missingValue] the empty export, as the reader
124
+ * picked it
125
+ * @property {boolean} [failed] the kind's parser threw
126
+ * @property {unknown} [failure] what the kind's parser threw
127
+ * @property {boolean} [overlayFailed] laying the translation over threw
128
+ * @property {unknown} [overlayFailure] what laying the translation over threw
129
+ */
130
+ /**
131
+ * Lower one doc of any kind but a reference topic.
132
+ *
133
+ * With `check`, the doc is held to its kind's parser, and a failure is
134
+ * recorded, not fatal: readers that never checked docs keep reading it, and a
135
+ * checked reader turns it into the error it has always thrown. A doc stamped
136
+ * with a kind its root does not read keeps its root's kind and carries a
137
+ * `wrong_kind` diagnostic. With `node`, the view is also carried as JSON; a
138
+ * value JSON cannot hold withdraws the node, never the view.
139
+ *
140
+ * @param {DocFileInput} input
141
+ * @param {{check?: boolean, node?: boolean}} [options]
142
+ * @returns {LoweredDoc}
143
+ */
144
+ export function lowerDoc(input: DocFileInput, { check, node: wantNode }?: {
145
+ check?: boolean;
146
+ node?: boolean;
147
+ }): LoweredDoc;
68
148
  /** Bumped whenever the shape of a compiled node changes. */
69
149
  export const COMPILED_DOC_SCHEMA_VERSION: 1;
150
+ /** Every kind a compiled node has: one per authored doc kind a root reads. */
151
+ export const COMPILED_DOC_KINDS: readonly ["component", "function", "reference", "page", "block", "schema", "command", "enum", "theme"];
152
+ /**
153
+ * The roots that read docs, and the kinds each may hold. A doc without a
154
+ * stamped `type` (the legacy form) takes its root's first kind.
155
+ * @type {Readonly<Record<string, readonly string[]>>}
156
+ */
157
+ export const ROOT_KINDS: Readonly<Record<string, readonly string[]>>;
70
158
  /**
71
159
  * One authored file, as discovery loaded it.
72
160
  */
@@ -160,3 +248,115 @@ export type CompiledReferenceNode = {
160
248
  */
161
249
  doc: any;
162
250
  };
251
+ export type CompilerDiagnostic = import("./diagnostics.mjs").CompilerDiagnostic;
252
+ /**
253
+ * One authored doc of any kind but a reference topic, as its root loaded it.
254
+ */
255
+ export type DocFileInput = {
256
+ /**
257
+ * the input's id: provider, root, and name
258
+ */
259
+ id: string;
260
+ root: keyof typeof ROOT_KINDS;
261
+ /**
262
+ * the package that contributes it
263
+ */
264
+ provider: string;
265
+ /**
266
+ * `<package>/<path>` of the file
267
+ */
268
+ source: string;
269
+ /**
270
+ * the overlay language, or null
271
+ */
272
+ lang: string | null;
273
+ /**
274
+ * `doc` is the authored export, not a parse
275
+ * result; `overlay` is the translation the module exports for `lang`
276
+ */
277
+ file: AuthoredFile;
278
+ /**
279
+ * how a parse error names the file (default: its
280
+ * file name)
281
+ */
282
+ label?: string | undefined;
283
+ /**
284
+ * carry the parser's result instead of the
285
+ * authored export, for a reader that has always read the checked value
286
+ */
287
+ useParsed?: boolean | undefined;
288
+ };
289
+ /**
290
+ * A compiled node for any kind but a reference topic.
291
+ */
292
+ export type CompiledDocNode = {
293
+ schemaVersion: number;
294
+ kind: Exclude<(typeof COMPILED_DOC_KINDS)[number], "reference">;
295
+ stage: "lowered";
296
+ id: string;
297
+ lang: string | null;
298
+ provenance: {
299
+ provider: string;
300
+ source: string;
301
+ };
302
+ /**
303
+ * the authored doc, overlaid for `lang`, as JSON carries
304
+ * it: key order kept, `undefined` and functions dropped
305
+ */
306
+ doc: any;
307
+ };
308
+ /**
309
+ * The result of lowering one doc.
310
+ *
311
+ * `view` is the doc as readers have always read it: the authored export (or,
312
+ * where a reader has always read it, the parser's result), with its
313
+ * translation laid over it, not copied and not converted. Readers print from
314
+ * the view, so nothing they print depends on JSON. `node` is the sealed,
315
+ * JSON-only form a whole-project compile collects.
316
+ */
317
+ export type LoweredDoc = {
318
+ /**
319
+ * absent when the file could not be read
320
+ */
321
+ view?: any;
322
+ /**
323
+ * null when not asked for, or when a
324
+ * problem is fatal to the node
325
+ */
326
+ node: CompiledDocNode | null;
327
+ diagnostics: CompilerDiagnostic[];
328
+ /**
329
+ * importing the file threw
330
+ */
331
+ loadFailed?: boolean | undefined;
332
+ /**
333
+ * what importing the file threw (any value,
334
+ * `undefined` included)
335
+ */
336
+ loadFailure?: unknown;
337
+ /**
338
+ * the file exports no doc
339
+ */
340
+ missing?: boolean | undefined;
341
+ /**
342
+ * the empty export, as the reader
343
+ * picked it
344
+ */
345
+ missingValue?: null | undefined;
346
+ /**
347
+ * the kind's parser threw
348
+ */
349
+ failed?: boolean | undefined;
350
+ /**
351
+ * what the kind's parser threw
352
+ */
353
+ failure?: unknown;
354
+ /**
355
+ * laying the translation over threw
356
+ */
357
+ overlayFailed?: boolean | undefined;
358
+ /**
359
+ * what laying the translation over threw
360
+ */
361
+ overlayFailure?: unknown;
362
+ };
@@ -1,7 +1,7 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file Doc compiler — authored reference topics in, compiled nodes out.
4
+ * @file Doc compiler — authored docs in, compiled nodes out.
5
5
  *
6
6
  * @input A {@link ReferenceTopicInput}: one topic's own file and the files of
7
7
  * the extensions merged onto it, each already through the authored-doc parser
@@ -16,21 +16,68 @@
16
16
  * JSON form, the one `--json` output has always shown.
17
17
  * @position The one step between authored docs and every docs reader. The docs
18
18
  * API, doctor and search read compiled nodes, and ./lenses.mjs turns them into
19
- * response shapes. Internal to the CLI: the public way in is `docs()`.
19
+ * response shapes. Every other doc kind (components, hooks, templates, themes,
20
+ * and the CLI's self-docs) lowers through {@link lowerDoc}, which ./read.mjs
21
+ * feeds. Internal to the CLI: the public way in is the docs API.
20
22
  */
21
23
 
24
+ import {parseTemplate} from '../../authoring/doctypes/template/parse.mjs';
25
+ import {parseTheme} from '../../authoring/doctypes/theme/parse.mjs';
22
26
  import {mergeTopic, problemsInTopic} from '../discovery/docs-discovery.mjs';
23
27
  import {
24
28
  sectionKey,
25
- sectionKeyProblems,
29
+ sectionKeyErrors,
26
30
  sourceTitle,
27
31
  withSectionKeys,
28
32
  withSourceTitle,
29
33
  } from '../discovery/docs-section-key.mjs';
34
+ import {diagnostic as rawDiagnostic} from './diagnostics.mjs';
35
+ import {scrubPaths} from './source.mjs';
36
+ import {overlayAuthoredDoc} from './overlays.mjs';
37
+ import {parseReadableDoc} from './parse-readable.mjs';
38
+
39
+ /**
40
+ * A compiler diagnostic whose message names files by package, never by their
41
+ * location on this machine.
42
+ * @param {string} code
43
+ * @param {Parameters<typeof rawDiagnostic>[1]} at
44
+ */
45
+ function diagnostic(code, at) {
46
+ return rawDiagnostic(code, {
47
+ ...at,
48
+ message: scrubPaths(at.message) || '(the error had no message)',
49
+ });
50
+ }
30
51
 
31
52
  /** Bumped whenever the shape of a compiled node changes. */
32
53
  export const COMPILED_DOC_SCHEMA_VERSION = 1;
33
54
 
55
+ /** Every kind a compiled node has: one per authored doc kind a root reads. */
56
+ export const COMPILED_DOC_KINDS = /** @type {const} */ ([
57
+ 'component',
58
+ 'function',
59
+ 'reference',
60
+ 'page',
61
+ 'block',
62
+ 'schema',
63
+ 'command',
64
+ 'enum',
65
+ 'theme',
66
+ ]);
67
+
68
+ /**
69
+ * The roots that read docs, and the kinds each may hold. A doc without a
70
+ * stamped `type` (the legacy form) takes its root's first kind.
71
+ * @type {Readonly<Record<string, readonly string[]>>}
72
+ */
73
+ export const ROOT_KINDS = Object.freeze({
74
+ components: ['component'],
75
+ hooks: ['function'],
76
+ templates: ['page', 'block'],
77
+ themes: ['theme'],
78
+ 'self-docs': ['command', 'function', 'schema', 'enum'],
79
+ });
80
+
34
81
  /**
35
82
  * One authored file, as discovery loaded it.
36
83
  * @typedef {object} AuthoredFile
@@ -83,11 +130,12 @@ export function lowerReferenceTopic(input) {
83
130
  let doc = readAuthoredFile(input.base);
84
131
  for (const extension of input.extensions) {
85
132
  doc = mergeTopic(doc, readAuthoredFile(extension));
86
- // Merging matches on keys, so this holds unless merge itself regresses.
87
- const problems = sectionKeyProblems(doc.sections);
133
+ // Explicit authored IDs remain strict. Legacy title-derived collisions are
134
+ // assigned deterministic compatibility keys after every extension merges.
135
+ const problems = sectionKeyErrors(doc.sections);
88
136
  if (problems.length > 0) {
89
137
  throw new Error(
90
- `${extension.file}, extending ${input.id}, leaves two sections with one key: ${problems.join('; ')}`,
138
+ `${extension.file}, extending ${input.id}, leaves duplicate authored section IDs: ${problems.join('; ')}`,
91
139
  );
92
140
  }
93
141
  }
@@ -191,9 +239,12 @@ function asJson(value, topic) {
191
239
  try {
192
240
  return JSON.parse(JSON.stringify(value));
193
241
  } catch (err) {
194
- throw new Error(
195
- `${topic} cannot be compiled: ${err instanceof Error ? err.message : String(err)}`,
196
- {cause: err},
242
+ throw Object.assign(
243
+ new Error(
244
+ `${topic} cannot be compiled: ${err instanceof Error ? err.message : String(err)}`,
245
+ {cause: err},
246
+ ),
247
+ {compilerCode: 'not_json'},
197
248
  );
198
249
  }
199
250
  }
@@ -260,3 +311,202 @@ function applyOverlay(docs, translation) {
260
311
  }),
261
312
  };
262
313
  }
314
+
315
+ /**
316
+ * @typedef {import('./diagnostics.mjs').CompilerDiagnostic} CompilerDiagnostic
317
+ */
318
+
319
+ /**
320
+ * One authored doc of any kind but a reference topic, as its root loaded it.
321
+ * @typedef {object} DocFileInput
322
+ * @property {string} id the input's id: provider, root, and name
323
+ * @property {keyof typeof ROOT_KINDS} root
324
+ * @property {string} provider the package that contributes it
325
+ * @property {string} source `<package>/<path>` of the file
326
+ * @property {string | null} lang the overlay language, or null
327
+ * @property {AuthoredFile} file `doc` is the authored export, not a parse
328
+ * result; `overlay` is the translation the module exports for `lang`
329
+ * @property {string} [label] how a parse error names the file (default: its
330
+ * file name)
331
+ * @property {boolean} [useParsed] carry the parser's result instead of the
332
+ * authored export, for a reader that has always read the checked value
333
+ */
334
+
335
+ /**
336
+ * The parser that checks a root's docs. Templates and themes have their own;
337
+ * every other root dispatches on the stamped type.
338
+ * @param {string} root
339
+ * @returns {(input: unknown, label?: string) => any}
340
+ */
341
+ export function parserFor(root) {
342
+ if (root === 'themes') return parseTheme;
343
+ if (root === 'templates') return parseTemplate;
344
+ return parseReadableDoc;
345
+ }
346
+
347
+ /**
348
+ * A compiled node for any kind but a reference topic.
349
+ * @typedef {object} CompiledDocNode
350
+ * @property {number} schemaVersion
351
+ * @property {Exclude<typeof COMPILED_DOC_KINDS[number], 'reference'>} kind
352
+ * @property {'lowered'} stage
353
+ * @property {string} id
354
+ * @property {string | null} lang
355
+ * @property {{provider: string, source: string}} provenance
356
+ * @property {any} doc the authored doc, overlaid for `lang`, as JSON carries
357
+ * it: key order kept, `undefined` and functions dropped
358
+ */
359
+
360
+ /**
361
+ * The result of lowering one doc.
362
+ *
363
+ * `view` is the doc as readers have always read it: the authored export (or,
364
+ * where a reader has always read it, the parser's result), with its
365
+ * translation laid over it, not copied and not converted. Readers print from
366
+ * the view, so nothing they print depends on JSON. `node` is the sealed,
367
+ * JSON-only form a whole-project compile collects.
368
+ *
369
+ * @typedef {object} LoweredDoc
370
+ * @property {any} [view] absent when the file could not be read
371
+ * @property {CompiledDocNode | null} node null when not asked for, or when a
372
+ * problem is fatal to the node
373
+ * @property {CompilerDiagnostic[]} diagnostics
374
+ * @property {boolean} [loadFailed] importing the file threw
375
+ * @property {unknown} [loadFailure] what importing the file threw (any value,
376
+ * `undefined` included)
377
+ * @property {boolean} [missing] the file exports no doc
378
+ * @property {null | undefined} [missingValue] the empty export, as the reader
379
+ * picked it
380
+ * @property {boolean} [failed] the kind's parser threw
381
+ * @property {unknown} [failure] what the kind's parser threw
382
+ * @property {boolean} [overlayFailed] laying the translation over threw
383
+ * @property {unknown} [overlayFailure] what laying the translation over threw
384
+ */
385
+
386
+ /**
387
+ * Lower one doc of any kind but a reference topic.
388
+ *
389
+ * With `check`, the doc is held to its kind's parser, and a failure is
390
+ * recorded, not fatal: readers that never checked docs keep reading it, and a
391
+ * checked reader turns it into the error it has always thrown. A doc stamped
392
+ * with a kind its root does not read keeps its root's kind and carries a
393
+ * `wrong_kind` diagnostic. With `node`, the view is also carried as JSON; a
394
+ * value JSON cannot hold withdraws the node, never the view.
395
+ *
396
+ * @param {DocFileInput} input
397
+ * @param {{check?: boolean, node?: boolean}} [options]
398
+ * @returns {LoweredDoc}
399
+ */
400
+ export function lowerDoc(input, {check = true, node: wantNode = true} = {}) {
401
+ const {file} = input;
402
+ const at = {provider: input.provider, source: input.source};
403
+ /** @type {CompilerDiagnostic[]} */
404
+ const diagnostics = [];
405
+ if ('error' in file) {
406
+ diagnostics.push(
407
+ diagnostic('load_failed', {
408
+ ...at,
409
+ message: `${file.file} could not be loaded: ${messageOf(file.error)}`,
410
+ }),
411
+ );
412
+ return {node: null, diagnostics, loadFailed: true, loadFailure: file.error};
413
+ }
414
+ if (file.doc == null) {
415
+ diagnostics.push(
416
+ diagnostic('missing_export', {
417
+ ...at,
418
+ message: `${file.file} exports no doc.`,
419
+ }),
420
+ );
421
+ return {node: null, diagnostics, missing: true, missingValue: file.doc};
422
+ }
423
+ const allowed = ROOT_KINDS[input.root];
424
+ if (!allowed) throw new Error(`No doc root is named "${input.root}".`);
425
+ const stamped =
426
+ typeof file.doc === 'object' && 'type' in file.doc
427
+ ? file.doc.type
428
+ : undefined;
429
+ const kindFits = stamped === undefined || allowed.includes(stamped);
430
+ if (!kindFits) {
431
+ diagnostics.push(
432
+ diagnostic('wrong_kind', {
433
+ ...at,
434
+ message: `${file.file} is stamped type ${JSON.stringify(stamped)}, which the ${input.root} root does not read (it reads ${allowed.join(', ')}).`,
435
+ }),
436
+ );
437
+ }
438
+ /** @type {LoweredDoc} */
439
+ const result = {node: null, diagnostics};
440
+ let view = file.doc;
441
+ // A theme descriptor is read statically; its parse result is the doc.
442
+ if (check || input.root === 'themes') {
443
+ try {
444
+ const parsed = parserFor(input.root)(file.doc, input.label ?? file.file);
445
+ if (input.useParsed || input.root === 'themes') view = parsed;
446
+ } catch (error) {
447
+ result.failed = true;
448
+ result.failure = error;
449
+ diagnostics.push(
450
+ diagnostic('invalid_doc', {...at, message: messageOf(error)}),
451
+ );
452
+ }
453
+ }
454
+ if ('overlayError' in file) {
455
+ result.overlayFailed = true;
456
+ result.overlayFailure = file.overlayError;
457
+ } else if (file.overlay) {
458
+ try {
459
+ view = overlayAuthoredDoc(view, file.overlay);
460
+ } catch (error) {
461
+ result.overlayFailed = true;
462
+ result.overlayFailure = error;
463
+ }
464
+ }
465
+ if (result.overlayFailed) {
466
+ diagnostics.push(
467
+ diagnostic('overlay_failed', {
468
+ ...at,
469
+ message: `${file.file}'s translation could not be applied: ${messageOf(result.overlayFailure)}`,
470
+ }),
471
+ );
472
+ return result;
473
+ }
474
+ result.view = view;
475
+ if (!wantNode) return result;
476
+ let json;
477
+ try {
478
+ const text = JSON.stringify(view);
479
+ if (text === undefined) throw new TypeError('the doc is not a JSON value');
480
+ json = JSON.parse(text);
481
+ } catch (error) {
482
+ diagnostics.push(
483
+ diagnostic('not_json', {
484
+ ...at,
485
+ message: `${file.file} cannot be compiled: ${messageOf(error)}`,
486
+ }),
487
+ );
488
+ return result;
489
+ }
490
+ result.node = {
491
+ schemaVersion: COMPILED_DOC_SCHEMA_VERSION,
492
+ kind: /** @type {CompiledDocNode['kind']} */ (
493
+ kindFits && stamped !== undefined ? stamped : allowed[0]
494
+ ),
495
+ stage: 'lowered',
496
+ id: input.id,
497
+ lang: input.lang,
498
+ provenance: {provider: input.provider, source: input.source},
499
+ doc: json,
500
+ };
501
+ return result;
502
+ }
503
+
504
+ /** @param {unknown} error */
505
+ function messageOf(error) {
506
+ // Any value can be thrown; describing one must never throw in its place.
507
+ try {
508
+ return error instanceof Error ? String(error.message) : String(error);
509
+ } catch {
510
+ return Object.prototype.toString.call(error);
511
+ }
512
+ }
@@ -0,0 +1,126 @@
1
+ // @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
2
+ // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
+
4
+ /**
5
+ * @param {string} code
6
+ * @param {object} at
7
+ * @param {string | null} [at.provider]
8
+ * @param {string | null} [at.source]
9
+ * @param {string | null} [at.field]
10
+ * @param {string} at.message
11
+ * @returns {CompilerDiagnostic}
12
+ */
13
+ export function diagnostic(code: string, { provider, source, field, message }: {
14
+ provider?: string | null | undefined;
15
+ source?: string | null | undefined;
16
+ field?: string | null | undefined;
17
+ message: string;
18
+ }): CompilerDiagnostic;
19
+ /**
20
+ * Diagnostics in one order, whatever order the phases found them in: by
21
+ * source, then phase, then code, field, and message.
22
+ * @param {CompilerDiagnostic[]} list
23
+ * @returns {CompilerDiagnostic[]} a new array
24
+ */
25
+ export function sortDiagnostics(list: CompilerDiagnostic[]): CompilerDiagnostic[];
26
+ /**
27
+ * What is wrong with a value that claims to be a diagnostic, or null. A known
28
+ * code must carry its own phase, severity, scope, and remediation: a reader
29
+ * never reinterprets them.
30
+ * @param {unknown} value
31
+ * @returns {string | null}
32
+ */
33
+ export function diagnosticProblem(value: unknown): string | null;
34
+ /**
35
+ * A `<package>/<path>` that names no location on one machine: not absolute,
36
+ * no drive letter or URL scheme, no backslash, no `..` segment.
37
+ * @param {string} source
38
+ * @returns {boolean}
39
+ */
40
+ export function isPortableSource(source: string): boolean;
41
+ /**
42
+ * @file Compiler diagnostics — one shape for every problem the doc compiler
43
+ * finds.
44
+ *
45
+ * @input A diagnostic code, the package and file it concerns, and a message.
46
+ * @output A plain-JSON diagnostic: a stable code, the phase that found it,
47
+ * severity, provider, source, field, message, remediation, and the scope of
48
+ * what it invalidates. Lists sort into one deterministic order.
49
+ * @position Shared by every compiler phase: listing inputs, loading, parsing,
50
+ * overlaying, lowering, linking, serializing, and reading a bundle back. A
51
+ * code fixes its phase, severity, scope, and remediation, so no phase or
52
+ * reader can report the same problem two ways or downgrade it.
53
+ */
54
+ /** Compiler phases, in the order a descriptor passes through them. */
55
+ export const DIAGNOSTIC_PHASES: readonly ["discover", "load", "parse", "overlay", "lower", "link", "serialize", "bundle"];
56
+ /**
57
+ * What a failure invalidates: the one node it concerns, or the whole
58
+ * compilation (a bundle that cannot be read at all).
59
+ * @typedef {'node' | 'compilation'} DiagnosticScope
60
+ */
61
+ /**
62
+ * @typedef {typeof DIAGNOSTIC_PHASES[number]} DiagnosticPhase
63
+ * @typedef {'error' | 'warning'} DiagnosticSeverity
64
+ */
65
+ /**
66
+ * @typedef {object} CompilerDiagnostic
67
+ * @property {string} code stable; one of {@link DIAGNOSTIC_CODES}
68
+ * @property {DiagnosticPhase} phase
69
+ * @property {DiagnosticSeverity} severity
70
+ * @property {DiagnosticScope} scope
71
+ * @property {string | null} provider the package the problem is in
72
+ * @property {string | null} source `<package>/<path>` of the file, never a
73
+ * machine path
74
+ * @property {string | null} field the field or reference at fault, when known
75
+ * @property {string} message
76
+ * @property {string} remediation what to do about it
77
+ */
78
+ /**
79
+ * @typedef {object} DiagnosticRule
80
+ * @property {DiagnosticPhase} phase
81
+ * @property {DiagnosticSeverity} severity
82
+ * @property {DiagnosticScope} scope
83
+ * @property {string} remediation
84
+ */
85
+ /** Every code the compiler emits, with the facts it fixes. */
86
+ export const DIAGNOSTIC_CODES: Readonly<Record<string, DiagnosticRule>>;
87
+ /**
88
+ * What a failure invalidates: the one node it concerns, or the whole
89
+ * compilation (a bundle that cannot be read at all).
90
+ */
91
+ export type DiagnosticScope = "node" | "compilation";
92
+ export type DiagnosticPhase = (typeof DIAGNOSTIC_PHASES)[number];
93
+ export type DiagnosticSeverity = "error" | "warning";
94
+ export type CompilerDiagnostic = {
95
+ /**
96
+ * stable; one of {@link DIAGNOSTIC_CODES}
97
+ */
98
+ code: string;
99
+ phase: DiagnosticPhase;
100
+ severity: DiagnosticSeverity;
101
+ scope: DiagnosticScope;
102
+ /**
103
+ * the package the problem is in
104
+ */
105
+ provider: string | null;
106
+ /**
107
+ * `<package>/<path>` of the file, never a
108
+ * machine path
109
+ */
110
+ source: string | null;
111
+ /**
112
+ * the field or reference at fault, when known
113
+ */
114
+ field: string | null;
115
+ message: string;
116
+ /**
117
+ * what to do about it
118
+ */
119
+ remediation: string;
120
+ };
121
+ export type DiagnosticRule = {
122
+ phase: DiagnosticPhase;
123
+ severity: DiagnosticSeverity;
124
+ scope: DiagnosticScope;
125
+ remediation: string;
126
+ };