@astryxdesign/cli 0.6.3-canary.7ada42e → 0.6.3-canary.7ec7be0

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 (221) hide show
  1. package/README.md +21 -19
  2. package/api/build/_adapter.d.mts +50 -0
  3. package/api/build/_adapter.mjs +60 -0
  4. package/api/build/build.doc.mjs +13 -7
  5. package/api/build/build.test.mjs +184 -6
  6. package/api/build/build.type.d.mts +57 -2
  7. package/api/build/build.type.mjs +30 -7
  8. package/api/build/help/help.d.mts +4 -0
  9. package/api/build/help/help.mjs +24 -11
  10. package/api/build/kit/kit.d.mts +4 -1
  11. package/api/build/kit/kit.mjs +165 -49
  12. package/api/build/kit/rank.d.mts +44 -0
  13. package/api/build/kit/rank.mjs +432 -0
  14. package/api/build/kit/rank.test.mjs +196 -0
  15. package/api/component/_adapter.d.mts +6 -12
  16. package/api/component/_adapter.mjs +20 -10
  17. package/api/component/component.mjs +60 -12
  18. package/api/component/list/list.mjs +3 -2
  19. package/api/docs/_adapter.d.mts +251 -28
  20. package/api/docs/_adapter.mjs +918 -35
  21. package/api/docs/detail/detail.mjs +11 -3
  22. package/api/docs/detail/section/section.mjs +24 -13
  23. package/api/docs/detail/section/section.test.mjs +15 -6
  24. package/api/docs/docs.d.mts +5 -3
  25. package/api/docs/docs.doc.mjs +38 -17
  26. package/api/docs/docs.mjs +44 -8
  27. package/api/docs/docs.test.mjs +158 -4
  28. package/api/docs/docs.type.d.mts +181 -2
  29. package/api/docs/docs.type.mjs +117 -3
  30. package/api/docs/index/index.mjs +11 -3
  31. package/api/docs/index/index.test.mjs +1 -1
  32. package/api/docs/integration-tree.test.mjs +555 -0
  33. package/api/docs/integrationDocs.test.mjs +14 -14
  34. package/api/docs/list/list.mjs +25 -5
  35. package/api/docs/node/node.d.mts +43 -0
  36. package/api/docs/node/node.mjs +192 -0
  37. package/api/docs/reference-blocks.test.mjs +406 -0
  38. package/api/doctor/doctor.d.mts +30 -2
  39. package/api/doctor/doctor.mjs +151 -8
  40. package/api/doctor/doctor.test.mjs +95 -7
  41. package/api/index.d.mts +1 -1
  42. package/api/index.mjs +1 -0
  43. package/api/init/init.doc.mjs +1 -1
  44. package/api/integration/add-contribution.d.mts +2 -1
  45. package/api/integration/add-contribution.mjs +107 -5
  46. package/api/integration/add-contribution.test.mjs +137 -0
  47. package/api/integration/authoring-checks.mjs +138 -28
  48. package/api/integration/authoring-checks.test.mjs +171 -3
  49. package/api/integration/authoring-checks.type.mjs +6 -1
  50. package/api/integration/integration-authoring.type.d.mts +2 -0
  51. package/api/integration/integration-authoring.type.mjs +2 -0
  52. package/api/integration/integrationAdd.doc.mjs +6 -0
  53. package/api/integration/integrationAddDoc.doc.mjs +7 -1
  54. package/api/integration/integrationDocConflicts.doc.mjs +1 -1
  55. package/api/integration/integrationPackCheck.doc.mjs +1 -1
  56. package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
  57. package/api/integration/integrationTemplateConflicts.doc.mjs +3 -0
  58. package/api/integration/pack-check.mjs +34 -0
  59. package/api/integration/pack-check.test.mjs +121 -0
  60. package/api/integration/pack-check.type.d.mts +26 -2
  61. package/api/integration/pack-check.type.mjs +14 -1
  62. package/api/integration/template-conflict-compatibility.test.mjs +73 -0
  63. package/api/integration/validate-integration.test.mjs +3 -3
  64. package/api/integration/validateIntegration.doc.mjs +1 -1
  65. package/api/json/index.ts +2 -0
  66. package/api/layout/_adapter.mjs +20 -5
  67. package/api/search/search.d.mts +59 -1
  68. package/api/search/search.doc.mjs +4 -3
  69. package/api/search/search.mjs +442 -71
  70. package/api/search/search.test.mjs +91 -2
  71. package/api/search/search.type.d.mts +13 -1
  72. package/api/search/search.type.mjs +4 -1
  73. package/api/template/list/list.mjs +1 -0
  74. package/api/template/table-floating-bulk-actions.test.mjs +66 -0
  75. package/api/template/template-integration.test.mjs +1072 -3
  76. package/api/template/template.doc.mjs +27 -7
  77. package/api/template/template.mjs +45 -8
  78. package/api/template/template.type.d.mts +6 -8
  79. package/api/template/template.type.mjs +3 -2
  80. package/api/theme/template/template.test.mjs +5 -0
  81. package/api/theme/themeTemplate.doc.mjs +1 -1
  82. package/assets/docs/getting-started.doc.mjs +2 -2
  83. package/assets/docs/layout.doc.dense.mjs +2 -2
  84. package/assets/docs/layout.doc.mjs +1 -1
  85. package/assets/docs/principles.doc.mjs +6 -6
  86. package/assets/docs/styling-libraries.doc.mjs +3 -3
  87. package/assets/docs/styling.doc.mjs +4 -4
  88. package/assets/docs/theme.doc.mjs +4 -4
  89. package/assets/docs/tokens.doc.mjs +1 -1
  90. package/assets/docs/tree/api.doc.mjs +30 -0
  91. package/assets/docs/tree/cli.doc.mjs +23 -0
  92. package/assets/docs/tree/commands.doc.mjs +25 -0
  93. package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +37 -9
  94. package/assets/docs/tree/integrations.test.mjs +62 -0
  95. package/assets/docs/tree/writing-docs.doc.mjs +286 -0
  96. package/assets/docs/working-with-ai.doc.mjs +3 -3
  97. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
  98. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
  99. package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
  100. package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
  101. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
  102. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
  103. package/authoring/debug/parse.d.mts +3 -3
  104. package/authoring/doctypes/_schema.d.mts +119 -117
  105. package/authoring/doctypes/_schema.mjs +54 -3
  106. package/authoring/doctypes/base/graph-fields.doc.mjs +7 -5
  107. package/authoring/doctypes/base/type.ts +6 -5
  108. package/authoring/doctypes/command/command.doc.mjs +1 -1
  109. package/authoring/doctypes/command/type.ts +2 -2
  110. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  111. package/authoring/doctypes/enum/type.ts +1 -1
  112. package/authoring/doctypes/function/function.doc.mjs +3 -2
  113. package/authoring/doctypes/function/type.ts +3 -2
  114. package/authoring/doctypes/load-contract.test.mjs +26 -1
  115. package/authoring/doctypes/namespace/namespace.doc.mjs +6 -10
  116. package/authoring/doctypes/namespace/parse.test.mjs +23 -25
  117. package/authoring/doctypes/namespace/type.ts +5 -2
  118. package/authoring/doctypes/parse.mjs +3 -2
  119. package/authoring/doctypes/reference/reference.doc.mjs +34 -5
  120. package/authoring/doctypes/reference/type.ts +28 -11
  121. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  122. package/authoring/doctypes/schema/type.ts +1 -1
  123. package/authoring/doctypes/template/parse.d.mts +2 -0
  124. package/authoring/doctypes/template/parse.mjs +4 -0
  125. package/authoring/doctypes/template/parse.test.mjs +18 -0
  126. package/authoring/doctypes/template/template.doc.mjs +6 -0
  127. package/authoring/doctypes/template/type.ts +8 -0
  128. package/authoring/identity/identity.doc.mjs +2 -2
  129. package/authoring/index.d.ts +1 -0
  130. package/authoring/integration/type.ts +1 -1
  131. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  132. package/clients/cli/commands/build-theme.mjs +1 -1
  133. package/clients/cli/commands/build.doc.mjs +11 -6
  134. package/clients/cli/commands/build.mjs +105 -67
  135. package/clients/cli/commands/build.text-fields.test.mjs +41 -0
  136. package/clients/cli/commands/component/index.mjs +1 -1
  137. package/clients/cli/commands/component-ownership.test.mjs +3 -3
  138. package/clients/cli/commands/discover.broken-integration.test.mjs +7 -8
  139. package/clients/cli/commands/discover.mjs +1 -1
  140. package/clients/cli/commands/docs.doc.mjs +20 -8
  141. package/clients/cli/commands/docs.mjs +183 -69
  142. package/clients/cli/commands/docs.test.mjs +120 -16
  143. package/clients/cli/commands/doctor-integration-docs.doc.mjs +2 -2
  144. package/clients/cli/commands/doctor-integration-templates.doc.mjs +14 -7
  145. package/clients/cli/commands/doctor-integration.test.mjs +75 -1
  146. package/clients/cli/commands/doctor.mjs +53 -16
  147. package/clients/cli/commands/integration-add.doc.mjs +10 -0
  148. package/clients/cli/commands/integration.mjs +1 -0
  149. package/clients/cli/commands/search.mjs +11 -2
  150. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  151. package/clients/cli/commands/template.doc.mjs +23 -6
  152. package/clients/cli/commands/template.mjs +4 -91
  153. package/clients/cli/index.mjs +8 -0
  154. package/clients/cli/lib/manifest.mjs +9 -2
  155. package/foundation/agent-docs/agent-docs.d.mts +3 -2
  156. package/foundation/agent-docs/agent-docs.mjs +13 -9
  157. package/foundation/agent-docs/agent-docs.test.mjs +19 -1
  158. package/foundation/config/project.d.mts +12 -11
  159. package/foundation/config/project.mjs +73 -59
  160. package/foundation/config/project.test.mjs +141 -5
  161. package/foundation/discovery/authoring-self-docs.d.mts +12 -0
  162. package/foundation/discovery/authoring-self-docs.mjs +20 -8
  163. package/foundation/discovery/authoring-self-docs.test.mjs +25 -9
  164. package/foundation/discovery/cli-self-docs.d.mts +40 -34
  165. package/foundation/discovery/cli-self-docs.mjs +91 -115
  166. package/foundation/discovery/cli-self-docs.test.mjs +104 -166
  167. package/foundation/discovery/component-discovery.d.mts +38 -0
  168. package/foundation/discovery/component-discovery.mjs +48 -0
  169. package/foundation/discovery/docs-discovery.d.mts +109 -9
  170. package/foundation/discovery/docs-discovery.mjs +223 -24
  171. package/foundation/discovery/docs-discovery.test.mjs +103 -27
  172. package/foundation/discovery/docs-output-budget.d.mts +2 -2
  173. package/foundation/discovery/docs-output-budget.mjs +1 -1
  174. package/foundation/discovery/docs-section-key.d.mts +28 -10
  175. package/foundation/discovery/docs-section-key.mjs +134 -33
  176. package/foundation/discovery/docs-section-key.test.mjs +41 -19
  177. package/foundation/discovery/template-adapter.d.mts +92 -6
  178. package/foundation/discovery/template-adapter.mjs +453 -17
  179. package/foundation/discovery/template-adapter.test.mjs +42 -0
  180. package/foundation/discovery/template-conflict-release.d.mts +13 -0
  181. package/foundation/discovery/template-conflict-release.mjs +40 -0
  182. package/foundation/discovery/template-conflict-release.test.mjs +40 -0
  183. package/foundation/doc-compiler/bundle.mjs +61 -1
  184. package/foundation/doc-compiler/bundle.test.mjs +21 -10
  185. package/foundation/doc-compiler/compile.d.mts +113 -132
  186. package/foundation/doc-compiler/compile.mjs +57 -10
  187. package/foundation/doc-compiler/diagnostics.mjs +28 -0
  188. package/foundation/doc-compiler/doc-loads.test.mjs +2 -2
  189. package/foundation/doc-compiler/inputs.d.mts +2 -2
  190. package/foundation/doc-compiler/inputs.mjs +6 -1
  191. package/foundation/doc-compiler/ir.mjs +7 -0
  192. package/foundation/doc-compiler/lenses.d.mts +8 -5
  193. package/foundation/doc-compiler/lenses.mjs +50 -4
  194. package/foundation/doc-compiler/links.d.mts +162 -0
  195. package/foundation/doc-compiler/links.mjs +294 -0
  196. package/foundation/doc-compiler/links.test.mjs +192 -0
  197. package/foundation/doc-compiler/lower-doc.test.mjs +5 -2
  198. package/foundation/doc-compiler/read.d.mts +3 -2
  199. package/foundation/doc-compiler/read.mjs +6 -1
  200. package/foundation/doc-compiler/tree.d.mts +288 -0
  201. package/foundation/doc-compiler/tree.mjs +876 -0
  202. package/foundation/doc-compiler/tree.test.mjs +598 -0
  203. package/foundation/integrations/autolink.test.mjs +1 -1
  204. package/foundation/integrations/cli-requirement.d.mts +45 -0
  205. package/foundation/integrations/cli-requirement.mjs +154 -0
  206. package/foundation/integrations/cli-requirement.test.mjs +84 -0
  207. package/foundation/integrations/contribution-inventory.d.mts +2 -1
  208. package/foundation/integrations/contribution-inventory.mjs +10 -4
  209. package/foundation/integrations/contribution-inventory.test.mjs +19 -0
  210. package/foundation/integrations/integration-warnings.d.mts +9 -2
  211. package/foundation/integrations/integration-warnings.mjs +51 -26
  212. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  213. package/foundation/integrations/validate-contributions.mjs +25 -27
  214. package/foundation/response/response-types.doc.d.mts +5 -1
  215. package/foundation/response/response-types.doc.mjs +19 -10
  216. package/foundation/text/string-utils.d.mts +8 -0
  217. package/foundation/text/string-utils.mjs +18 -0
  218. package/foundation/xle/expand.mjs +1 -1
  219. package/foundation/xle/xle.test.mjs +13 -0
  220. package/package.json +9 -9
  221. package/assets/docs/cli.doc.mjs +0 -15
@@ -0,0 +1,192 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Links between docs (spec:AST-047 FR9): the target grammar, and how a
5
+ * list of blocks comes back with every link resolved or named as a problem.
6
+ */
7
+
8
+ import {describe, expect, it} from 'vitest';
9
+ import {
10
+ linkBlocks,
11
+ linkSections,
12
+ parseLinkTarget,
13
+ unlinkText,
14
+ } from './links.mjs';
15
+
16
+ /** A resolver over two docs, the second from another provider. */
17
+ const resolve = async (/** @type {string} */ target) => {
18
+ const docs = {
19
+ 'command:doctor': {route: 'cli/commands/doctor', title: 'astryx doctor'},
20
+ '@acme/kit:generic:setup': {route: 'acme/setup', title: 'Set up Acme'},
21
+ };
22
+ const doc = /** @type {any} */ (docs)[target];
23
+ return doc
24
+ ? {
25
+ target,
26
+ id: `id:${target}`,
27
+ route: doc.route,
28
+ title: doc.title,
29
+ summary: `About ${doc.title}.`,
30
+ command: `astryx docs ${doc.route}`,
31
+ }
32
+ : {problem: `"${target}" names no doc`};
33
+ };
34
+
35
+ describe('parseLinkTarget', () => {
36
+ it('reads a doc of the same provider, or of a named one', () => {
37
+ expect(parseLinkTarget('command:theme build')).toEqual({
38
+ provider: null,
39
+ kind: 'command',
40
+ name: 'theme build',
41
+ });
42
+ expect(parseLinkTarget('@astryxdesign/cli:function:search')).toEqual({
43
+ provider: '@astryxdesign/cli',
44
+ kind: 'function',
45
+ name: 'search',
46
+ });
47
+ });
48
+
49
+ it('refuses a target that is not `[<provider>:]<kind>:<name>`', () => {
50
+ for (const bad of ['', 'search', 'a:b:c:d', 'command:', 'widget:x']) {
51
+ expect(parseLinkTarget(bad)).toHaveProperty('error');
52
+ }
53
+ });
54
+ });
55
+
56
+ describe('linkBlocks', () => {
57
+ it('reads an inline link as the command that opens its doc', async () => {
58
+ const {content, problems} = await linkBlocks(
59
+ [
60
+ {type: 'prose', text: 'Check it with {@link command:doctor}.'},
61
+ {type: 'list', style: 'unordered', items: ['See {@link @acme/kit:generic:setup}']},
62
+ {type: 'table', headers: ['Doc'], rows: [['{@link command:doctor}']]},
63
+ {type: 'code', lang: 'js', code: '{@link command:doctor}'},
64
+ ],
65
+ resolve,
66
+ );
67
+ expect(problems).toEqual([]);
68
+ expect(content[0].text).toBe('Check it with `astryx docs cli/commands/doctor`.');
69
+ expect(content[1].items).toEqual(['See `astryx docs acme/setup`']);
70
+ expect(content[2].rows).toEqual([['`astryx docs cli/commands/doctor`']]);
71
+ // Code is an example: it is shown as written.
72
+ expect(content[3].code).toBe('{@link command:doctor}');
73
+ });
74
+
75
+ it('shows a link written in code ticks as written', async () => {
76
+ const {content, problems} = await linkBlocks(
77
+ [{type: 'prose', text: 'Write `{@link <target>}` to link; {@link command:doctor} checks it.'}],
78
+ resolve,
79
+ );
80
+ expect(problems).toEqual([]);
81
+ expect(content[0].text).toBe(
82
+ 'Write `{@link <target>}` to link; `astryx docs cli/commands/doctor` checks it.',
83
+ );
84
+ });
85
+
86
+ it('gives a reference block and each workflow step the doc they name', async () => {
87
+ const {content, problems} = await linkBlocks(
88
+ [
89
+ {type: 'reference', target: 'command:doctor'},
90
+ {
91
+ type: 'workflow',
92
+ steps: [{title: 'Check', references: ['command:doctor']}],
93
+ },
94
+ ],
95
+ resolve,
96
+ );
97
+ expect(problems).toEqual([]);
98
+ expect(content[0].link).toMatchObject({
99
+ route: 'cli/commands/doctor',
100
+ command: 'astryx docs cli/commands/doctor',
101
+ title: 'astryx doctor',
102
+ });
103
+ expect(content[1].steps[0].links[0].command).toBe(
104
+ 'astryx docs cli/commands/doctor',
105
+ );
106
+ });
107
+
108
+ it('includes what a reference block names, and marks what it cannot include', async () => {
109
+ /** @type {any[]} */
110
+ const asked = [];
111
+ const include = async (/** @type {any} */ block) => {
112
+ asked.push(block.target);
113
+ return {
114
+ content: [{type: 'prose', text: 'The doctor command.'}],
115
+ problems: block.projection ? ['projection.fields: no such field'] : [],
116
+ };
117
+ };
118
+ const {content, problems} = await linkBlocks(
119
+ [
120
+ {type: 'reference', target: 'command:doctor'},
121
+ {
122
+ type: 'reference',
123
+ target: 'command:doctor',
124
+ projection: {fields: ['--nope']},
125
+ },
126
+ {type: 'reference', target: 'command:gone'},
127
+ ],
128
+ resolve,
129
+ {section: 'check'},
130
+ include,
131
+ );
132
+ // A target that names no doc is never handed to the includer.
133
+ expect(asked).toEqual(['command:doctor', 'command:doctor']);
134
+ expect(content[0]).toMatchObject({
135
+ link: {command: 'astryx docs cli/commands/doctor'},
136
+ content: [{type: 'prose', text: 'The doctor command.'}],
137
+ });
138
+ expect(content[2]).toEqual({
139
+ type: 'reference',
140
+ target: 'command:gone',
141
+ link: null,
142
+ });
143
+ // Both are the authoring check's: the block includes content, where a
144
+ // link only points at it.
145
+ expect(problems).toEqual([
146
+ {
147
+ target: 'command:doctor',
148
+ message: 'projection.fields: no such field',
149
+ include: true,
150
+ section: 'check',
151
+ },
152
+ {
153
+ target: 'command:gone',
154
+ message: '"command:gone" names no doc',
155
+ include: true,
156
+ section: 'check',
157
+ },
158
+ ]);
159
+ });
160
+
161
+ it('names every link that finds no doc, and never guesses', async () => {
162
+ const {content, problems} = await linkSections(
163
+ [
164
+ {
165
+ id: 'one',
166
+ title: 'One',
167
+ content: [
168
+ {type: 'prose', text: 'See {@link command:nope}.'},
169
+ {type: 'reference', target: 'generic:gone'},
170
+ {type: 'collection', source: {slot: 'guides'}},
171
+ ],
172
+ },
173
+ ],
174
+ resolve,
175
+ ).then(({sections, problems}) => ({content: sections[0].content, problems}));
176
+ expect(content[0].text).toBe('See {@link command:nope}.');
177
+ expect(content[1].link).toBeNull();
178
+ expect(problems.map(p => [p.section, p.target])).toEqual([
179
+ ['one', 'command:nope'],
180
+ ['one', 'generic:gone'],
181
+ ['one', 'collection:guides'],
182
+ ]);
183
+ });
184
+ });
185
+
186
+ describe('unlinkText', () => {
187
+ it('keeps the name of each link, for an index', () => {
188
+ expect(unlinkText('Run {@link command:theme build} or {@link x}.')).toBe(
189
+ 'Run theme build or x.',
190
+ );
191
+ });
192
+ });
@@ -386,7 +386,10 @@ describe('parseCompiledDocNode and parseCompiledDocsBundle', () => {
386
386
  it('accepts a node of every kind and a bundle, as given', () => {
387
387
  const value = bundle();
388
388
  expect(parseCompiledDocsBundle(value)).toBe(value);
389
- expect(COMPILED_DOC_KINDS).toHaveLength(9);
389
+ expect(COMPILED_DOC_KINDS).toHaveLength(10);
390
+ // A namespace doc, which the docs tree reads, lowers to a node too.
391
+ const namespace = {...node(), kind: 'namespace'};
392
+ expect(parseCompiledDocNode(namespace)).toBe(namespace);
390
393
  });
391
394
 
392
395
  it('names schema skew with its own diagnostic, before anything else', () => {
@@ -413,7 +416,7 @@ describe('parseCompiledDocNode and parseCompiledDocsBundle', () => {
413
416
  ],
414
417
  [
415
418
  'an unknown kind',
416
- (/** @type {any} */ n) => (n.kind = 'namespace'),
419
+ (/** @type {any} */ n) => (n.kind = 'workflow'),
417
420
  /not a compiled doc kind/,
418
421
  ],
419
422
  [
@@ -73,11 +73,12 @@ export const DOC_EXPORTS: Readonly<{
73
73
  hooks: string[];
74
74
  templates: string[];
75
75
  'self-docs': string[];
76
+ tree: string[];
76
77
  }>;
77
78
  /** The localized overlays a docs read can apply. */
78
79
  export const OVERLAY_LANGUAGES: string[];
79
80
  export type ReadOptions = {
80
- root: "components" | "hooks" | "templates" | "themes" | "self-docs";
81
+ root: "components" | "hooks" | "templates" | "themes" | "self-docs" | "tree";
81
82
  /**
82
83
  * overlay language; null reads the authored
83
84
  * text
@@ -101,7 +102,7 @@ export type ReadOptions = {
101
102
  * how to import the module (default
102
103
  * `user`)
103
104
  */
104
- loader?: "template" | "user" | "native" | undefined;
105
+ loader?: "template" | "native" | "user" | undefined;
105
106
  /**
106
107
  * which exports name the doc, in
107
108
  * precedence order, for a reader that has always read a narrower set than its
@@ -45,6 +45,8 @@ export const DOC_EXPORTS = Object.freeze({
45
45
  hooks: ['default', 'docs'],
46
46
  templates: ['default', 'doc'],
47
47
  'self-docs': ['doc', 'docs', 'default'],
48
+ // The docs tree's own files: namespace docs and the guides it places.
49
+ tree: ['docs', 'default'],
48
50
  });
49
51
 
50
52
  /** How a reader imports a doc module. */
@@ -59,7 +61,7 @@ const LOADERS = Object.freeze({
59
61
 
60
62
  /**
61
63
  * @typedef {object} ReadOptions
62
- * @property {'components' | 'hooks' | 'templates' | 'themes' | 'self-docs'} root
64
+ * @property {'components' | 'hooks' | 'templates' | 'themes' | 'self-docs' | 'tree'} root
63
65
  * @property {string | null} [lang] overlay language; null reads the authored
64
66
  * text
65
67
  * @property {string} [label] how a parse error names the file (default: its
@@ -307,14 +309,17 @@ export async function loadTopicInput(entry, lang) {
307
309
  extensions.push({
308
310
  ...(await loadTopicFile(extension.path, lang)),
309
311
  provider: extension.package,
312
+ providerId: extension.providerId ?? extension.package,
310
313
  });
311
314
  }
312
315
  return {
313
316
  id: entry.name,
314
317
  provider: entry.package,
318
+ providerId: entry.providerId ?? entry.package,
315
319
  replaces: entry.replaces ?? null,
316
320
  lang,
317
321
  base: await loadTopicFile(entry.path, lang),
318
322
  extensions,
323
+ ...(entry.tree === true ? {tree: true} : {}),
319
324
  };
320
325
  }
@@ -0,0 +1,288 @@
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
+ * Build the tree. Pure: the same inputs give the same tree, whatever order
6
+ * they arrive in.
7
+ *
8
+ * A doc's home is decided once, in this order: its explicit `placement`, then
9
+ * the one adoption rule in its package that matches its group and kind. A
10
+ * placement that fails withdraws the doc; it never falls back to adoption. A
11
+ * doc with neither is a flat topic: it keeps its flat name as its route, and its
12
+ * home is the generated Unorganized level. The CLI keeps its own routes: an
13
+ * integration's node that would take one is withdrawn with a diagnostic.
14
+ *
15
+ * @param {{namespaces: TreeNamespaceInput[], docs: TreeDocInput[], topics?: TreeTopicInput[]}} inputs
16
+ * @returns {DocsTree}
17
+ */
18
+ export function buildDocsTree({ namespaces, docs, topics }: {
19
+ namespaces: TreeNamespaceInput[];
20
+ docs: TreeDocInput[];
21
+ topics?: TreeTopicInput[];
22
+ }): DocsTree;
23
+ /**
24
+ * The files under {@link TREE_DOCS_DIR}, sorted.
25
+ * @param {string} [dir]
26
+ * @returns {string[]}
27
+ */
28
+ export function treeDocFiles(dir?: string): string[];
29
+ /**
30
+ * The CLI's own tree inputs: the namespace docs and guides under
31
+ * assets/docs/tree, and, unless left out, every typed self-doc with its
32
+ * `namespace` group. A file that fails to load or parse is a diagnostic, never
33
+ * a thrown error.
34
+ * @param {{selfDocs?: boolean, dir?: string}} [options]
35
+ * @returns {Promise<{namespaces: TreeNamespaceInput[], docs: TreeDocInput[], diagnostics: CompilerDiagnostic[]}>}
36
+ */
37
+ export function loadTreeInputs({ selfDocs, dir, }?: {
38
+ selfDocs?: boolean;
39
+ dir?: string;
40
+ }): Promise<{
41
+ namespaces: TreeNamespaceInput[];
42
+ docs: TreeDocInput[];
43
+ diagnostics: CompilerDiagnostic[];
44
+ }>;
45
+ /**
46
+ * The CLI's own docs tree, built once per process. With `selfDocs: false` it
47
+ * holds only the namespaces and guides, which is all a topic list needs.
48
+ * @param {{selfDocs?: boolean, fresh?: boolean}} [options]
49
+ * @returns {Promise<DocsTree>}
50
+ */
51
+ export function loadDocsTree({ selfDocs, fresh }?: {
52
+ selfDocs?: boolean;
53
+ fresh?: boolean;
54
+ }): Promise<DocsTree>;
55
+ export { routeSegment };
56
+ /** Where the CLI keeps the docs that only the tree reads. */
57
+ export const TREE_DOCS_DIR: string;
58
+ /** One route segment: lowercase letters and digits joined by single hyphens. */
59
+ export const ROUTE_SEGMENT_RE: RegExp;
60
+ /**
61
+ * The generated level that `groupBy: 'kind'` makes for each kind: its route
62
+ * segment, title, and summary.
63
+ * @type {Readonly<Record<string, {segment: string, title: string, summary: string}>>}
64
+ */
65
+ export const KIND_GROUPS: Readonly<Record<string, {
66
+ segment: string;
67
+ title: string;
68
+ summary: string;
69
+ }>>;
70
+ /**
71
+ * @typedef {import('../../authoring/doctypes/namespace/type').NamespaceDoc} NamespaceDoc
72
+ * @typedef {import('../../authoring/doctypes/base/type').DocPlacement} DocPlacement
73
+ * @typedef {import('./diagnostics.mjs').CompilerDiagnostic} CompilerDiagnostic
74
+ */
75
+ /**
76
+ * @typedef {object} TreeNamespaceInput
77
+ * @property {string} provider the package that owns the namespace
78
+ * @property {string} providerId the provider's ProviderId (its manifest
79
+ * `providerId`, else its package name); node ids are built from it
80
+ * @property {number} [rank] which provider wins a contested route: the CLI's
81
+ * own docs are 0, then each integration in configured order
82
+ * @property {string} source `<package>/<path>` of its file
83
+ * @property {NamespaceDoc} doc
84
+ */
85
+ /**
86
+ * @typedef {object} TreeDocInput
87
+ * @property {string} provider the package that authored the doc
88
+ * @property {string} providerId the provider's ProviderId (its manifest
89
+ * `providerId`, else its package name); node ids are built from it
90
+ * @property {number} [rank] which provider wins a contested route: the CLI's
91
+ * own docs are 0, then each integration in configured order
92
+ * @property {string} source
93
+ * @property {import('../../authoring/doctypes/base/type').AuthoredDocKind} kind
94
+ * the authored kind: `generic`, `command`, `function`, `schema`, or `enum`
95
+ * @property {string} name the doc's stable name
96
+ * @property {string} title
97
+ * @property {string} summary
98
+ * @property {string | null} group the discovery group adoption reads, or null
99
+ * @property {DocPlacement | undefined} placement
100
+ * @property {any} [ref] what a reader needs to open the doc, carried as given
101
+ */
102
+ /**
103
+ * @typedef {object} TreeSlot
104
+ * @property {string} name
105
+ * @property {string} title
106
+ * @property {string[]} children child routes, in reading order
107
+ */
108
+ /**
109
+ * A flat topic: a reference topic that no namespace places. The tree gives it
110
+ * a home in the generated Unorganized level, under its own name.
111
+ * @typedef {object} TreeTopicInput
112
+ * @property {string} provider the package that owns the topic
113
+ * @property {string} providerId the provider's ProviderId
114
+ * @property {string} name the topic's name, which stays its route
115
+ * @property {string} title
116
+ * @property {string} summary
117
+ * @property {string} source where the topic comes from, for diagnostics
118
+ * @property {string[]} [aliases] every other name the topic answers to: the
119
+ * topics it replaced, directly or through a chain
120
+ */
121
+ /** The route of the generated level that holds every flat topic. */
122
+ export const UNORGANIZED: "unorganized";
123
+ export type NamespaceDoc = import("../../authoring/doctypes/namespace/type").NamespaceDoc;
124
+ export type DocPlacement = import("../../authoring/doctypes/base/type").DocPlacement;
125
+ export type CompilerDiagnostic = import("./diagnostics.mjs").CompilerDiagnostic;
126
+ export type TreeNamespaceInput = {
127
+ /**
128
+ * the package that owns the namespace
129
+ */
130
+ provider: string;
131
+ /**
132
+ * the provider's ProviderId (its manifest
133
+ * `providerId`, else its package name); node ids are built from it
134
+ */
135
+ providerId: string;
136
+ /**
137
+ * which provider wins a contested route: the CLI's
138
+ * own docs are 0, then each integration in configured order
139
+ */
140
+ rank?: number | undefined;
141
+ /**
142
+ * `<package>/<path>` of its file
143
+ */
144
+ source: string;
145
+ doc: NamespaceDoc;
146
+ };
147
+ export type TreeDocInput = {
148
+ /**
149
+ * the package that authored the doc
150
+ */
151
+ provider: string;
152
+ /**
153
+ * the provider's ProviderId (its manifest
154
+ * `providerId`, else its package name); node ids are built from it
155
+ */
156
+ providerId: string;
157
+ /**
158
+ * which provider wins a contested route: the CLI's
159
+ * own docs are 0, then each integration in configured order
160
+ */
161
+ rank?: number | undefined;
162
+ source: string;
163
+ /**
164
+ * the authored kind: `generic`, `command`, `function`, `schema`, or `enum`
165
+ */
166
+ kind: import("../../authoring/doctypes/base/type").AuthoredDocKind;
167
+ /**
168
+ * the doc's stable name
169
+ */
170
+ name: string;
171
+ title: string;
172
+ summary: string;
173
+ /**
174
+ * the discovery group adoption reads, or null
175
+ */
176
+ group: string | null;
177
+ placement: DocPlacement | undefined;
178
+ /**
179
+ * what a reader needs to open the doc, carried as given
180
+ */
181
+ ref?: any;
182
+ };
183
+ export type TreeSlot = {
184
+ name: string;
185
+ title: string;
186
+ /**
187
+ * child routes, in reading order
188
+ */
189
+ children: string[];
190
+ };
191
+ /**
192
+ * A flat topic: a reference topic that no namespace places. The tree gives it
193
+ * a home in the generated Unorganized level, under its own name.
194
+ */
195
+ export type TreeTopicInput = {
196
+ /**
197
+ * the package that owns the topic
198
+ */
199
+ provider: string;
200
+ /**
201
+ * the provider's ProviderId
202
+ */
203
+ providerId: string;
204
+ /**
205
+ * the topic's name, which stays its route
206
+ */
207
+ name: string;
208
+ title: string;
209
+ summary: string;
210
+ /**
211
+ * where the topic comes from, for diagnostics
212
+ */
213
+ source: string;
214
+ /**
215
+ * every other name the topic answers to: the
216
+ * topics it replaced, directly or through a chain
217
+ */
218
+ aliases?: string[] | undefined;
219
+ };
220
+ export type TreeNode = {
221
+ /**
222
+ * the doc's DocId, built from its provider's
223
+ * ProviderId, kind, and name: stable when the route moves; null on a
224
+ * generated level, which has no authored doc
225
+ */
226
+ id: string | null;
227
+ route: string;
228
+ /**
229
+ * `namespace` or the doc's authored kind
230
+ */
231
+ kind: string;
232
+ /**
233
+ * the package that owns it
234
+ */
235
+ provider: string;
236
+ /**
237
+ * its provider's ProviderId
238
+ */
239
+ providerId: string;
240
+ name: string;
241
+ title: string;
242
+ summary: string;
243
+ /**
244
+ * the parent's route; null at the top
245
+ */
246
+ parent: string | null;
247
+ /**
248
+ * the parent slot this node sits in
249
+ */
250
+ slot: string | null;
251
+ order: number | null;
252
+ /**
253
+ * made by the compiler (a `groupBy: 'kind'`
254
+ * level, or the Unorganized level), not authored
255
+ */
256
+ generated: boolean;
257
+ /**
258
+ * a namespace's slots; empty for a leaf
259
+ */
260
+ slots: TreeSlot[];
261
+ source: string;
262
+ ref?: any;
263
+ };
264
+ export type DocsTree = {
265
+ /**
266
+ * by route, in route order
267
+ */
268
+ nodes: Map<string, TreeNode>;
269
+ /**
270
+ * sorted
271
+ */
272
+ diagnostics: CompilerDiagnostic[];
273
+ get: (route: string) => TreeNode | undefined;
274
+ /**
275
+ * the node at a
276
+ * route compared without case, as topic names are
277
+ */
278
+ getFolded: (route: string) => TreeNode | undefined;
279
+ /**
280
+ * the namespaces with no parent
281
+ */
282
+ roots: () => TreeNode[];
283
+ /**
284
+ * top first, not the node
285
+ */
286
+ ancestors: (node: TreeNode) => TreeNode[];
287
+ };
288
+ import { routeSegment } from '../discovery/docs-section-key.mjs';