@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
@@ -0,0 +1,277 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Compiler diagnostics — one shape for every problem the doc compiler
5
+ * finds.
6
+ *
7
+ * @input A diagnostic code, the package and file it concerns, and a message.
8
+ * @output A plain-JSON diagnostic: a stable code, the phase that found it,
9
+ * severity, provider, source, field, message, remediation, and the scope of
10
+ * what it invalidates. Lists sort into one deterministic order.
11
+ * @position Shared by every compiler phase: listing inputs, loading, parsing,
12
+ * overlaying, lowering, linking, serializing, and reading a bundle back. A
13
+ * code fixes its phase, severity, scope, and remediation, so no phase or
14
+ * reader can report the same problem two ways or downgrade it.
15
+ */
16
+
17
+ /** Compiler phases, in the order a descriptor passes through them. */
18
+ export const DIAGNOSTIC_PHASES = /** @type {const} */ ([
19
+ 'discover',
20
+ 'load',
21
+ 'parse',
22
+ 'overlay',
23
+ 'lower',
24
+ 'link',
25
+ 'serialize',
26
+ 'bundle',
27
+ ]);
28
+
29
+ /**
30
+ * What a failure invalidates: the one node it concerns, or the whole
31
+ * compilation (a bundle that cannot be read at all).
32
+ * @typedef {'node' | 'compilation'} DiagnosticScope
33
+ */
34
+
35
+ /**
36
+ * @typedef {typeof DIAGNOSTIC_PHASES[number]} DiagnosticPhase
37
+ * @typedef {'error' | 'warning'} DiagnosticSeverity
38
+ */
39
+
40
+ /**
41
+ * @typedef {object} CompilerDiagnostic
42
+ * @property {string} code stable; one of {@link DIAGNOSTIC_CODES}
43
+ * @property {DiagnosticPhase} phase
44
+ * @property {DiagnosticSeverity} severity
45
+ * @property {DiagnosticScope} scope
46
+ * @property {string | null} provider the package the problem is in
47
+ * @property {string | null} source `<package>/<path>` of the file, never a
48
+ * machine path
49
+ * @property {string | null} field the field or reference at fault, when known
50
+ * @property {string} message
51
+ * @property {string} remediation what to do about it
52
+ */
53
+
54
+ /**
55
+ * @typedef {object} DiagnosticRule
56
+ * @property {DiagnosticPhase} phase
57
+ * @property {DiagnosticSeverity} severity
58
+ * @property {DiagnosticScope} scope
59
+ * @property {string} remediation
60
+ */
61
+
62
+ /** Every code the compiler emits, with the facts it fixes. */
63
+ export const DIAGNOSTIC_CODES = Object.freeze(
64
+ /** @type {Record<string, DiagnosticRule>} */ ({
65
+ duplicate_file: {
66
+ phase: 'discover',
67
+ severity: 'error',
68
+ scope: 'node',
69
+ remediation:
70
+ 'Give each descriptor one reader: move it out of all but one of the roots that read it.',
71
+ },
72
+ duplicate_id: {
73
+ phase: 'discover',
74
+ severity: 'error',
75
+ scope: 'node',
76
+ remediation:
77
+ 'Rename one of the descriptors, so each name in a root belongs to one file.',
78
+ },
79
+ load_failed: {
80
+ phase: 'load',
81
+ severity: 'error',
82
+ scope: 'node',
83
+ remediation: 'Fix the error the file throws when it is loaded.',
84
+ },
85
+ missing_export: {
86
+ phase: 'load',
87
+ severity: 'error',
88
+ scope: 'node',
89
+ remediation: 'Export the doc as the default export of the file.',
90
+ },
91
+ invalid_doc: {
92
+ phase: 'parse',
93
+ severity: 'error',
94
+ scope: 'node',
95
+ remediation:
96
+ 'Fix the fields the message names; `astryx docs authoring` lists every field of each doc kind.',
97
+ },
98
+ wrong_kind: {
99
+ phase: 'parse',
100
+ severity: 'error',
101
+ scope: 'node',
102
+ remediation:
103
+ 'Stamp the doc with a type its root reads, or move it to the root for its type.',
104
+ },
105
+ overlay_failed: {
106
+ phase: 'overlay',
107
+ severity: 'error',
108
+ scope: 'node',
109
+ remediation:
110
+ 'Fix the translation file, or remove it to read the authored text.',
111
+ },
112
+ invalid_topic: {
113
+ phase: 'lower',
114
+ severity: 'error',
115
+ scope: 'node',
116
+ remediation:
117
+ 'Fix the topic or the extension the message names; an extension that breaks its base withdraws the whole topic.',
118
+ },
119
+ unresolved_reference: {
120
+ phase: 'link',
121
+ severity: 'warning',
122
+ scope: 'node',
123
+ remediation:
124
+ 'Point the token reference at a topic and section that exist; `astryx docs <topic> --index` lists the section keys.',
125
+ },
126
+ not_json: {
127
+ phase: 'serialize',
128
+ severity: 'error',
129
+ scope: 'node',
130
+ remediation:
131
+ 'Keep a doc to plain data: no cycles, BigInt values, or objects that cannot be written as JSON.',
132
+ },
133
+ unsupported_schema: {
134
+ phase: 'bundle',
135
+ severity: 'error',
136
+ scope: 'compilation',
137
+ remediation: 'Compile the docs again with this CLI.',
138
+ },
139
+ invalid_bundle: {
140
+ phase: 'bundle',
141
+ severity: 'error',
142
+ scope: 'compilation',
143
+ remediation:
144
+ 'Compile the docs again with this CLI; a compiled bundle is never edited by hand.',
145
+ },
146
+ }),
147
+ );
148
+
149
+ /**
150
+ * @param {string} code
151
+ * @param {object} at
152
+ * @param {string | null} [at.provider]
153
+ * @param {string | null} [at.source]
154
+ * @param {string | null} [at.field]
155
+ * @param {string} at.message
156
+ * @returns {CompilerDiagnostic}
157
+ */
158
+ export function diagnostic(
159
+ code,
160
+ {provider = null, source = null, field = null, message},
161
+ ) {
162
+ if (!Object.hasOwn(DIAGNOSTIC_CODES, code)) {
163
+ throw new Error(`Unknown compiler diagnostic code "${code}".`);
164
+ }
165
+ const rule = DIAGNOSTIC_CODES[code];
166
+ return {
167
+ code,
168
+ phase: rule.phase,
169
+ severity: rule.severity,
170
+ scope: rule.scope,
171
+ provider,
172
+ source,
173
+ field,
174
+ message,
175
+ remediation: rule.remediation,
176
+ };
177
+ }
178
+
179
+ /** @param {string | null} value */
180
+ const orderable = value => value ?? '\uffff';
181
+
182
+ /**
183
+ * Diagnostics in one order, whatever order the phases found them in: by
184
+ * source, then phase, then code, field, and message.
185
+ * @param {CompilerDiagnostic[]} list
186
+ * @returns {CompilerDiagnostic[]} a new array
187
+ */
188
+ export function sortDiagnostics(list) {
189
+ const phase = (/** @type {CompilerDiagnostic} */ d) =>
190
+ DIAGNOSTIC_PHASES.indexOf(d.phase);
191
+ return [...list].sort(
192
+ (a, b) =>
193
+ compare(orderable(a.source), orderable(b.source)) ||
194
+ phase(a) - phase(b) ||
195
+ compare(a.code, b.code) ||
196
+ compare(orderable(a.field), orderable(b.field)) ||
197
+ compare(a.message, b.message),
198
+ );
199
+ }
200
+
201
+ /**
202
+ * Code-point order: the same on every machine and locale.
203
+ * @param {string} a
204
+ * @param {string} b
205
+ */
206
+ function compare(a, b) {
207
+ return a < b ? -1 : a > b ? 1 : 0;
208
+ }
209
+
210
+ const DIAGNOSTIC_FIELDS = new Set([
211
+ 'code',
212
+ 'phase',
213
+ 'severity',
214
+ 'scope',
215
+ 'provider',
216
+ 'source',
217
+ 'field',
218
+ 'message',
219
+ 'remediation',
220
+ ]);
221
+
222
+ /**
223
+ * What is wrong with a value that claims to be a diagnostic, or null. A known
224
+ * code must carry its own phase, severity, scope, and remediation: a reader
225
+ * never reinterprets them.
226
+ * @param {unknown} value
227
+ * @returns {string | null}
228
+ */
229
+ export function diagnosticProblem(value) {
230
+ const d = /** @type {any} */ (value);
231
+ if (d == null || typeof d !== 'object' || Array.isArray(d)) {
232
+ return 'expected a diagnostic object';
233
+ }
234
+ const unknown = Object.keys(d).filter(key => !DIAGNOSTIC_FIELDS.has(key));
235
+ if (unknown.length > 0) return `unknown fields: ${unknown.join(', ')}`;
236
+ if (typeof d.code !== 'string' || !Object.hasOwn(DIAGNOSTIC_CODES, d.code)) {
237
+ return `code: ${JSON.stringify(d.code)} is not a compiler diagnostic code`;
238
+ }
239
+ const rule = DIAGNOSTIC_CODES[d.code];
240
+ for (const key of /** @type {const} */ ([
241
+ 'phase',
242
+ 'severity',
243
+ 'scope',
244
+ 'remediation',
245
+ ])) {
246
+ if (d[key] !== rule[key]) {
247
+ return `${key}: "${d.code}" always has ${key} ${JSON.stringify(rule[key])}`;
248
+ }
249
+ }
250
+ for (const key of ['provider', 'source', 'field']) {
251
+ if (d[key] !== null && (typeof d[key] !== 'string' || d[key] === '')) {
252
+ return `${key}: expected text or null`;
253
+ }
254
+ }
255
+ if (d.source !== null && !isPortableSource(d.source)) {
256
+ return 'source: expected a path inside a package, not a location on one machine';
257
+ }
258
+ if (typeof d.message !== 'string' || d.message === '') {
259
+ return 'message: expected text';
260
+ }
261
+ return null;
262
+ }
263
+
264
+ /**
265
+ * A `<package>/<path>` that names no location on one machine: not absolute,
266
+ * no drive letter or URL scheme, no backslash, no `..` segment.
267
+ * @param {string} source
268
+ * @returns {boolean}
269
+ */
270
+ export function isPortableSource(source) {
271
+ return (
272
+ !source.startsWith('/') &&
273
+ !/^[A-Za-z]:/u.test(source) &&
274
+ !source.includes('\\') &&
275
+ !/(^|\/)\.\.(\/|$)/u.test(source)
276
+ );
277
+ }
@@ -131,6 +131,27 @@ describe('lowerReferenceTopic', () => {
131
131
  });
132
132
  });
133
133
 
134
+ it('keeps the topic named as it is when extended, and renames it only when replaced', () => {
135
+ const extended = lowerReferenceTopic(
136
+ input(file(demo()), [extension('acme', 'Acme start.')]),
137
+ );
138
+ expect(extended.doc.title).toBe('demo title');
139
+ expect(extended.doc.description).toBe('About demo.');
140
+ const replacement = authored(
141
+ 'acme-demo',
142
+ [{title: 'Quick Start', content: [prose('Acme start.')]}],
143
+ {replaces: 'demo'},
144
+ );
145
+ const replaced = lowerReferenceTopic({
146
+ ...input(file(replacement)),
147
+ id: 'demo',
148
+ provider: '@acme/replacement',
149
+ replaces: 'demo',
150
+ });
151
+ expect(replaced.doc.title).toBe('acme-demo title');
152
+ expect(replaced.doc.description).toBe('About acme-demo.');
153
+ });
154
+
134
155
  it('applies extensions in configuration order, so the last one wins', () => {
135
156
  const node = lowerReferenceTopic(
136
157
  input(file(demo()), [
@@ -544,6 +565,7 @@ describe('readers go through the compiler', () => {
544
565
  'lowerReferenceTopic',
545
566
  'linkReferenceTopic',
546
567
  'linkReferenceSection',
568
+ 'lowerDoc',
547
569
  ],
548
570
  };
549
571
  /** The docs adapter and leaves drive the compiler; nothing else does. */
@@ -618,12 +640,17 @@ describe('readers go through the compiler', () => {
618
640
  return found;
619
641
  }
620
642
 
643
+ /** Temporary folders other tests create with mkdtemp and delete mid-run. */
644
+ const TRANSIENT_DIR = /^__[a-z][a-z_]*_[A-Za-z0-9]{6}$/;
645
+
621
646
  /** @param {string} dir @returns {string[]} */
622
647
  const sources = dir =>
623
648
  fs.readdirSync(dir, {withFileTypes: true}).flatMap(entry => {
624
649
  const full = path.join(dir, entry.name);
625
650
  if (entry.isDirectory()) {
626
- return entry.name === 'node_modules' ? [] : sources(full);
651
+ const skip =
652
+ entry.name === 'node_modules' || TRANSIENT_DIR.test(entry.name);
653
+ return skip ? [] : sources(full);
627
654
  }
628
655
  return entry.name.endsWith('.mjs') && !entry.name.endsWith('.test.mjs')
629
656
  ? [full]