@astryxdesign/cli 0.6.3-canary.ea2f048 → 0.6.3-canary.ebaebc4

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 (188) hide show
  1. package/README.md +2 -1
  2. package/api/build/build.type.d.mts +2 -2
  3. package/api/build/build.type.mjs +2 -2
  4. package/api/component/component.type.d.mts +6 -6
  5. package/api/component/component.type.mjs +19 -19
  6. package/api/discover/discover.type.d.mts +4 -4
  7. package/api/discover/discover.type.mjs +10 -10
  8. package/api/docs/_adapter.d.mts +37 -24
  9. package/api/docs/_adapter.mjs +169 -83
  10. package/api/docs/compiled-topics.test.mjs +78 -0
  11. package/api/docs/detail/detail.mjs +14 -63
  12. package/api/docs/detail/section/section.d.mts +1 -1
  13. package/api/docs/detail/section/section.mjs +44 -20
  14. package/api/docs/detail/section/section.test.mjs +41 -0
  15. package/api/docs/docs.d.mts +7 -2
  16. package/api/docs/docs.doc.mjs +27 -10
  17. package/api/docs/docs.mjs +16 -9
  18. package/api/docs/docs.test.mjs +6 -0
  19. package/api/docs/docs.type.d.mts +40 -3
  20. package/api/docs/docs.type.mjs +36 -8
  21. package/api/docs/index/index.d.mts +18 -0
  22. package/api/docs/index/index.mjs +32 -0
  23. package/api/docs/index/index.test.mjs +62 -0
  24. package/api/docs/integrationDocs.test.mjs +106 -0
  25. package/api/doctor/doctor.d.mts +48 -0
  26. package/api/doctor/doctor.mjs +232 -0
  27. package/api/doctor/doctor.test.mjs +196 -0
  28. package/api/hook/hook.type.d.mts +3 -3
  29. package/api/hook/hook.type.mjs +11 -11
  30. package/api/hook/list/list.d.mts +1 -1
  31. package/api/integration/add-contribution.mjs +5 -3
  32. package/api/integration/add-contribution.test.mjs +4 -4
  33. package/api/integration/integration-authoring.type.d.mts +1 -1
  34. package/api/integration/pack-check.mjs +49 -7
  35. package/api/integration/pack-check.test.mjs +249 -0
  36. package/api/search/search.d.mts +1 -1
  37. package/api/search/search.mjs +5 -5
  38. package/api/search/search.type.d.mts +2 -2
  39. package/api/search/search.type.mjs +1 -1
  40. package/api/swizzle/swizzle.type.d.mts +2 -2
  41. package/api/swizzle/swizzle.type.mjs +2 -2
  42. package/api/template/template.d.mts +1 -1
  43. package/api/template/template.type.d.mts +6 -6
  44. package/api/template/template.type.mjs +12 -12
  45. package/api/theme/build/build.mjs +20 -6
  46. package/api/theme/build/build.test.mjs +127 -0
  47. package/api/theme/palette/generate/generate.mjs +1 -1
  48. package/api/theme/palette/generate/generator.d.mts +10 -13
  49. package/api/theme/palette/generate/generator.mjs +7 -3
  50. package/api/theme/theme.type.d.mts +170 -11
  51. package/api/theme/theme.type.mjs +94 -27
  52. package/api/upgrade/_adapter.mjs +71 -5
  53. package/api/upgrade/project-context.test.mjs +272 -0
  54. package/api/upgrade/upgrade.doc.mjs +4 -3
  55. package/api/upgrade/upgrade.type.d.mts +5 -5
  56. package/api/upgrade/upgrade.type.mjs +11 -11
  57. package/assets/codemods/integration-discovery.mjs +40 -2
  58. package/assets/codemods/integration-discovery.test.mjs +58 -0
  59. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  60. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  61. package/assets/docs/README.md +9 -0
  62. package/assets/docs/authoring.doc.mjs +14 -0
  63. package/assets/docs/cli-integrations.doc.mjs +86 -15
  64. package/assets/docs/styling-libraries.doc.mjs +1 -1
  65. package/assets/docs/working-with-ai.doc.mjs +1 -1
  66. package/authoring/_shared/contract.ts +22 -0
  67. package/authoring/codemod/codemod.doc.mjs +6 -1
  68. package/authoring/codemod/parse.d.mts +8 -8
  69. package/authoring/codemod/parse.mjs +8 -6
  70. package/authoring/config/parse.d.mts +13 -13
  71. package/authoring/config/parse.mjs +8 -8
  72. package/authoring/config/type.ts +3 -3
  73. package/authoring/debug/parse.d.mts +5 -5
  74. package/authoring/debug/parse.mjs +3 -3
  75. package/authoring/doctypes/_schema.d.mts +788 -23
  76. package/authoring/doctypes/_schema.mjs +492 -39
  77. package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
  78. package/authoring/doctypes/base/graph-fields.doc.mjs +62 -0
  79. package/authoring/doctypes/base/type.ts +40 -0
  80. package/authoring/doctypes/command/command.doc.mjs +3 -2
  81. package/authoring/doctypes/command/parse.d.mts +2 -2
  82. package/authoring/doctypes/command/parse.mjs +1 -1
  83. package/authoring/doctypes/command/type.ts +3 -2
  84. package/authoring/doctypes/component/component.doc.mjs +6 -3
  85. package/authoring/doctypes/component/parse.d.mts +2 -2
  86. package/authoring/doctypes/component/parse.mjs +1 -1
  87. package/authoring/doctypes/component/type.ts +4 -3
  88. package/authoring/doctypes/enum/parse.d.mts +2 -2
  89. package/authoring/doctypes/enum/parse.mjs +1 -1
  90. package/authoring/doctypes/enum/type.ts +3 -1
  91. package/authoring/doctypes/function/function.doc.mjs +4 -0
  92. package/authoring/doctypes/function/parse.d.mts +2 -2
  93. package/authoring/doctypes/function/parse.mjs +1 -1
  94. package/authoring/doctypes/function/type.ts +6 -2
  95. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  96. package/authoring/doctypes/hook/parse.d.mts +2 -2
  97. package/authoring/doctypes/hook/parse.mjs +1 -1
  98. package/authoring/doctypes/hook/type.ts +3 -2
  99. package/authoring/doctypes/legacy.d.mts +8 -6
  100. package/authoring/doctypes/legacy.mjs +5 -4
  101. package/authoring/doctypes/load-contract.test.mjs +207 -0
  102. package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
  103. package/authoring/doctypes/namespace/namespace.doc.mjs +132 -0
  104. package/authoring/doctypes/namespace/parse.d.mts +12 -0
  105. package/authoring/doctypes/namespace/parse.mjs +25 -0
  106. package/authoring/doctypes/namespace/parse.test.mjs +165 -0
  107. package/authoring/doctypes/namespace/type.ts +71 -0
  108. package/authoring/doctypes/parse.d.mts +20 -18
  109. package/authoring/doctypes/parse.mjs +16 -10
  110. package/authoring/doctypes/parse.test.mjs +77 -3
  111. package/authoring/doctypes/reference/parse.d.mts +2 -2
  112. package/authoring/doctypes/reference/parse.mjs +8 -5
  113. package/authoring/doctypes/reference/reference.doc.mjs +17 -4
  114. package/authoring/doctypes/reference/type.ts +51 -5
  115. package/authoring/doctypes/schema/parse.d.mts +2 -2
  116. package/authoring/doctypes/schema/parse.mjs +1 -1
  117. package/authoring/doctypes/schema/type.ts +3 -2
  118. package/authoring/doctypes/template/parse.d.mts +92 -1
  119. package/authoring/doctypes/template/parse.mjs +36 -2
  120. package/authoring/doctypes/template/parse.test.mjs +8 -2
  121. package/authoring/doctypes/template/template.doc.mjs +4 -0
  122. package/authoring/doctypes/template/type.ts +5 -2
  123. package/authoring/doctypes/types.ts +10 -9
  124. package/authoring/gap-report/parse.d.mts +10 -10
  125. package/authoring/gap-report/parse.mjs +6 -6
  126. package/authoring/gap-report/type.ts +1 -1
  127. package/authoring/identity/identity.doc.d.mts +9 -0
  128. package/authoring/identity/identity.doc.mjs +61 -0
  129. package/authoring/identity/type.ts +132 -0
  130. package/authoring/index.d.mts +1 -0
  131. package/authoring/index.d.ts +49 -17
  132. package/authoring/index.mjs +1 -0
  133. package/authoring/integration/integration.doc.mjs +13 -6
  134. package/authoring/integration/parse.d.mts +2 -2
  135. package/authoring/integration/parse.mjs +1 -1
  136. package/authoring/integration/parse.test.mjs +10 -1
  137. package/authoring/integration/schema.d.mts +6 -4
  138. package/authoring/integration/schema.mjs +9 -3
  139. package/authoring/integration/type.ts +23 -6
  140. package/authoring/shadcn/receipt.d.mts +6 -6
  141. package/clients/cli/commands/docs.doc.mjs +13 -3
  142. package/clients/cli/commands/docs.mjs +121 -21
  143. package/clients/cli/commands/docs.test.mjs +88 -0
  144. package/clients/cli/commands/integration-authoring.test.mjs +13 -9
  145. package/clients/cli/commands/theme-palette-generate.doc.mjs +8 -4
  146. package/clients/cli/commands/upgrade.doc.mjs +2 -2
  147. package/clients/cli/formatters/index.mjs +162 -1
  148. package/clients/cli/formatters/index.test.mjs +91 -0
  149. package/clients/cli/lib/manifest.mjs +7 -2
  150. package/foundation/config/project.mjs +21 -6
  151. package/foundation/discovery/authoring-self-docs.d.mts +69 -0
  152. package/foundation/discovery/authoring-self-docs.mjs +214 -0
  153. package/foundation/discovery/authoring-self-docs.test.mjs +154 -0
  154. package/foundation/discovery/component-discovery.d.mts +1 -1
  155. package/foundation/discovery/component-discovery.mjs +2 -1
  156. package/foundation/discovery/docs-discovery.d.mts +11 -4
  157. package/foundation/discovery/docs-discovery.mjs +208 -88
  158. package/foundation/discovery/docs-discovery.test.mjs +279 -13
  159. package/foundation/discovery/docs-output-budget.d.mts +28 -0
  160. package/foundation/discovery/docs-output-budget.mjs +50 -0
  161. package/foundation/discovery/docs-section-key.d.mts +98 -0
  162. package/foundation/discovery/docs-section-key.mjs +221 -0
  163. package/foundation/discovery/docs-section-key.test.mjs +224 -0
  164. package/foundation/discovery/template-adapter.mjs +2 -1
  165. package/foundation/discovery/theming-targets.test.mjs +4 -0
  166. package/foundation/doc-compiler/compile.d.mts +162 -0
  167. package/foundation/doc-compiler/compile.mjs +262 -0
  168. package/foundation/doc-compiler/doc-compiler.test.mjs +687 -0
  169. package/foundation/doc-compiler/ir.d.mts +9 -0
  170. package/foundation/doc-compiler/ir.mjs +287 -0
  171. package/foundation/doc-compiler/lenses.d.mts +33 -0
  172. package/foundation/doc-compiler/lenses.mjs +127 -0
  173. package/foundation/identity/provider-identity.d.mts +90 -0
  174. package/foundation/identity/provider-identity.mjs +320 -0
  175. package/foundation/identity/provider-identity.test.mjs +254 -0
  176. package/foundation/identity/providers.d.mts +7 -0
  177. package/foundation/identity/providers.mjs +16 -0
  178. package/foundation/integrations/autolink.mjs +12 -5
  179. package/foundation/integrations/integration-warnings.mjs +6 -0
  180. package/foundation/integrations/integrations.d.mts +46 -2
  181. package/foundation/integrations/integrations.mjs +167 -8
  182. package/foundation/integrations/integrations.test.mjs +384 -1
  183. package/foundation/integrations/provider-conflicts.test.mjs +125 -0
  184. package/foundation/integrations/validate-contributions.d.mts +2 -0
  185. package/foundation/integrations/validate-contributions.mjs +10 -0
  186. package/foundation/response/json-contract.test.mjs +46 -17
  187. package/foundation/response/response-types.doc.mjs +6 -1
  188. package/package.json +9 -11
@@ -3,16 +3,208 @@
3
3
  /**
4
4
  * @file Sealed doc load-boundary schemas (doctypes-internal).
5
5
  *
6
- * These zod schemas are the implementation detail behind the doctypes parsers.
7
- * They are NOT part of the public authoring surface: nothing outside
8
- * `authoring/doctypes/**` imports them, and they never appear in a public type.
9
- * They accept BOTH the stamped formats (`type: 'component' | 'function' |
10
- * 'generic'`) and the legacy loose `export const docs = {...}` shape, so the
11
- * ~600+ existing docs keep validating unchanged.
6
+ * Existing doctypes keep their historical top-level passthrough policy so
7
+ * already-published docs continue to load. NamespaceDoc and every semantic
8
+ * content block are strict: a misspelled field cannot reach a renderer as
9
+ * missing data.
12
10
  */
13
11
 
14
12
  import {z} from 'zod';
15
13
 
14
+ /** @typedef {import('./base/type.js').AuthoredDocGraphFields} AuthoredDocGraphFieldsType */
15
+ /** @typedef {import('./base/type.js').AuthoredDocKind} AuthoredDocKind */
16
+ /** @typedef {import('./namespace/type.js').NamespaceDoc} NamespaceDoc */
17
+ /** @typedef {import('./reference/type.js').ReferenceContentBlock} ReferenceContentBlock */
18
+ /** @typedef {import('./reference/type.js').ReferenceDoc} ReferenceDoc */
19
+ /** @typedef {import('./component/type.js').SingleComponentDoc} SingleComponentDoc */
20
+ /** @typedef {import('./base/type.js').ComponentPropDoc} ComponentPropDoc */
21
+ /** @typedef {import('./hook/type.js').HookDoc} HookDoc */
22
+ /** @typedef {import('./function/type.js').FunctionDoc} FunctionDoc */
23
+ /** @typedef {import('./schema/type.js').SchemaDoc} SchemaDoc */
24
+ /** @typedef {import('./command/type.js').CommandDoc} CommandDoc */
25
+ /** @typedef {import('./enum/type.js').EnumDoc} EnumDoc */
26
+
27
+ const nonEmptyString = z.string().min(1);
28
+
29
+ /** Every authored doc-kind discriminant accepted by parseDoc. */
30
+ export const AuthoredDocKindSchema = z.enum([
31
+ 'component',
32
+ 'function',
33
+ 'generic',
34
+ 'page',
35
+ 'block',
36
+ 'schema',
37
+ 'command',
38
+ 'enum',
39
+ 'namespace',
40
+ ]);
41
+
42
+ /**
43
+ * @typedef {import('../_shared/contract.js').Expect<
44
+ * import('../_shared/contract.js').Equal<z.infer<typeof AuthoredDocKindSchema>, AuthoredDocKind>
45
+ * >} _AuthoredDocKindDriftLock
46
+ */
47
+
48
+ /** Shared optional graph fields for every authored doc kind. */
49
+ export const AuthoredDocGraphFields = {
50
+ placement: z
51
+ .object({
52
+ parent: nonEmptyString,
53
+ slot: nonEmptyString.optional(),
54
+ order: z.number().int().safe().optional(),
55
+ })
56
+ .strict()
57
+ .optional(),
58
+ aliases: z.array(nonEmptyString).optional(),
59
+ audience: z.enum(['public', 'internal']).optional(),
60
+ };
61
+
62
+ const _AuthoredDocGraphSchema = z.object(AuthoredDocGraphFields).strict();
63
+
64
+ /**
65
+ * @typedef {import('../_shared/contract.js').Expect<
66
+ * import('../_shared/contract.js').MutuallyAssignable<
67
+ * z.infer<typeof _AuthoredDocGraphSchema>,
68
+ * AuthoredDocGraphFieldsType
69
+ * >
70
+ * >} _AuthoredDocGraphDriftLock
71
+ */
72
+
73
+ const ProseBlockSchema = z
74
+ .object({type: z.literal('prose'), text: nonEmptyString})
75
+ .strict();
76
+ const HeadingBlockSchema = z
77
+ .object({
78
+ type: z.literal('heading'),
79
+ level: z.union([z.literal(3), z.literal(4), z.literal(5), z.literal(6)]),
80
+ text: nonEmptyString,
81
+ })
82
+ .strict();
83
+ const CodeBlockSchema = z
84
+ .object({
85
+ type: z.literal('code'),
86
+ lang: nonEmptyString,
87
+ code: z.string(),
88
+ label: nonEmptyString.optional(),
89
+ })
90
+ .strict();
91
+ const TableBlockSchema = z
92
+ .object({
93
+ type: z.literal('table'),
94
+ headers: z.array(z.string()).min(1),
95
+ rows: z.array(z.array(z.string())),
96
+ })
97
+ .strict()
98
+ .superRefine((table, context) => {
99
+ table.rows.forEach((row, index) => {
100
+ if (row.length !== table.headers.length) {
101
+ context.addIssue({
102
+ code: 'custom',
103
+ path: ['rows', index],
104
+ message: `expected ${table.headers.length} cells`,
105
+ });
106
+ }
107
+ });
108
+ });
109
+ const ListBlockSchema = z
110
+ .object({
111
+ type: z.literal('list'),
112
+ style: z.enum(['ordered', 'unordered', 'do', 'dont']),
113
+ items: z.array(nonEmptyString).min(1),
114
+ })
115
+ .strict();
116
+ const TokenReferenceBlockSchema = z
117
+ .object({
118
+ type: z.literal('token-ref'),
119
+ topic: nonEmptyString,
120
+ section: nonEmptyString,
121
+ })
122
+ .strict();
123
+ const WorkflowBlockSchema = z
124
+ .object({
125
+ type: z.literal('workflow'),
126
+ title: nonEmptyString.optional(),
127
+ steps: z
128
+ .array(
129
+ z
130
+ .object({
131
+ title: nonEmptyString,
132
+ description: nonEmptyString.optional(),
133
+ references: z.array(nonEmptyString).min(1).optional(),
134
+ })
135
+ .strict(),
136
+ )
137
+ .min(1),
138
+ })
139
+ .strict();
140
+ const CollectionBlockSchema = z
141
+ .object({
142
+ type: z.literal('collection'),
143
+ title: nonEmptyString.optional(),
144
+ source: z.object({slot: nonEmptyString}).strict(),
145
+ presentation: z.enum(['list', 'cards', 'compact']).optional(),
146
+ whenEmpty: z.enum(['show', 'omit']).optional(),
147
+ })
148
+ .strict();
149
+ const ReferenceBlockSchema = z
150
+ .object({
151
+ type: z.literal('reference'),
152
+ target: nonEmptyString,
153
+ projection: z
154
+ .object({
155
+ fields: z.array(nonEmptyString).min(1).optional(),
156
+ sections: z.array(nonEmptyString).min(1).optional(),
157
+ })
158
+ .strict()
159
+ .optional(),
160
+ presentation: z.enum(['summary', 'compact', 'full']).optional(),
161
+ })
162
+ .strict();
163
+
164
+ /** Runtime schema for every existing and V1 semantic content block. */
165
+ export const ReferenceContentBlockSchema = z.discriminatedUnion('type', [
166
+ ProseBlockSchema,
167
+ HeadingBlockSchema,
168
+ CodeBlockSchema,
169
+ TableBlockSchema,
170
+ ListBlockSchema,
171
+ TokenReferenceBlockSchema,
172
+ WorkflowBlockSchema,
173
+ CollectionBlockSchema,
174
+ ReferenceBlockSchema,
175
+ ]);
176
+
177
+ /**
178
+ * @typedef {import('../_shared/contract.js').Expect<
179
+ * import('../_shared/contract.js').Equal<
180
+ * z.infer<typeof ReferenceContentBlockSchema>,
181
+ * ReferenceContentBlock
182
+ * >
183
+ * >} _ReferenceContentBlockDriftLock
184
+ */
185
+
186
+ const ReferenceSectionSchema = z
187
+ .object({
188
+ id: nonEmptyString.optional(),
189
+ title: nonEmptyString,
190
+ category: z.string().optional(),
191
+ content: z.array(ReferenceContentBlockSchema),
192
+ previewType: z
193
+ .enum([
194
+ 'swatch',
195
+ 'shadow-box',
196
+ 'radius-box',
197
+ 'spacing-bar',
198
+ 'size-bar',
199
+ 'border-line',
200
+ 'duration-bar',
201
+ 'easing-curve',
202
+ 'font-sample',
203
+ ])
204
+ .optional(),
205
+ })
206
+ .strict();
207
+
16
208
  const PropSchema = z
17
209
  .object({
18
210
  name: z.string().min(1, 'prop name is required'),
@@ -42,6 +234,7 @@ const ReturnSchema = z
42
234
  .passthrough();
43
235
 
44
236
  const BaseDocFields = {
237
+ ...AuthoredDocGraphFields,
45
238
  name: z.string().min(1, 'name is required'),
46
239
  displayName: z.string().optional(),
47
240
  description: z.string().optional(),
@@ -56,21 +249,69 @@ const BaseDocFields = {
56
249
  isHiddenFromOverview: z.boolean().optional(),
57
250
  };
58
251
 
59
- /** New-format stamped component doc (`type: 'component'`). */
60
- export const ComponentDocKindSchema = z
252
+ const ComponentBaseSchema = z
61
253
  .object({
62
254
  ...BaseDocFields,
63
255
  type: z.literal('component'),
64
- props: z.array(PropSchema),
65
256
  theming: z.unknown().optional(),
66
257
  playground: z.unknown().optional(),
67
258
  examples: z.array(z.unknown()).optional(),
68
259
  })
69
260
  .passthrough();
70
261
 
71
- /** Return entry for the generalized function doc: `name` is optional so CLI/API
72
- * functions can document their `{type, data}` envelope entries (which have no
73
- * field name), while hooks keep listing named return fields. */
262
+ /**
263
+ * One entry in a group doc's `components`: a full ComponentEntry or a
264
+ * name-only ComponentRef. Readers look every entry up by `name`, so that much
265
+ * is checked here; the rest passes through, as on an unstamped doc.
266
+ */
267
+ const ComponentGroupEntrySchema = z
268
+ .object({name: z.string().min(1, 'component name is required')})
269
+ .passthrough();
270
+
271
+ /**
272
+ * New-format stamped component doc (`type: 'component'`): one component's
273
+ * `props`, or the `components` a group doc documents together. These are the
274
+ * shapes the published ComponentDoc type allows, and the ones an unstamped doc
275
+ * may already take.
276
+ */
277
+ export const ComponentDocKindSchema = ComponentBaseSchema.extend({
278
+ props: z.array(PropSchema).optional(),
279
+ components: z.array(ComponentGroupEntrySchema).optional(),
280
+ }).superRefine((doc, context) => {
281
+ if (doc.props == null && doc.components == null) {
282
+ context.addIssue({
283
+ code: 'custom',
284
+ path: ['props'],
285
+ message:
286
+ 'expected the props array, or `components` for a doc that groups several components',
287
+ });
288
+ }
289
+ });
290
+
291
+ /**
292
+ * A stamped component doc as it loads. The loader accepts what the unstamped
293
+ * format always accepted, so stamping an existing doc never breaks it:
294
+ * `displayName` may be missing, `category` is any string, `usage`, `theming`,
295
+ * `playground` and `examples` pass through unchecked, and a doc has `props`,
296
+ * `components`, or both; each `components` entry needs only a `name`. Every
297
+ * other field matches the published type.
298
+ *
299
+ * @typedef {Omit<SingleComponentDoc,
300
+ * 'type' | 'displayName' | 'category' | 'usage' | 'theming' | 'examples' | 'playground' | 'props'>
301
+ * & {type: 'component', displayName?: string, category?: string, usage?: unknown,
302
+ * theming?: unknown, examples?: unknown[], playground?: unknown,
303
+ * props?: ComponentPropDoc[], components?: Array<{name: string}>}} LoadedComponentDoc
304
+ */
305
+ /**
306
+ * @typedef {import('../_shared/contract.js').Expect<
307
+ * import('../_shared/contract.js').MutuallyAssignable<
308
+ * import('../_shared/contract.js').NamedFields<z.infer<typeof ComponentDocKindSchema>>,
309
+ * import('../_shared/contract.js').NamedFields<LoadedComponentDoc>
310
+ * >
311
+ * >} _ComponentDocDriftLock
312
+ */
313
+
314
+ /** Return entry for generalized function docs. */
74
315
  const FunctionReturnSchema = z
75
316
  .object({
76
317
  name: z.string().min(1).optional(),
@@ -79,8 +320,7 @@ const FunctionReturnSchema = z
79
320
  })
80
321
  .passthrough();
81
322
 
82
- /** New-format stamped function doc (`type: 'function'`) — hooks and CLI/API
83
- * functions alike (the discriminant and schema are shared). */
323
+ /** New-format stamped function doc (`type: 'function'`). */
84
324
  export const FunctionDocKindSchema = z
85
325
  .object({
86
326
  ...BaseDocFields,
@@ -90,30 +330,95 @@ export const FunctionDocKindSchema = z
90
330
  })
91
331
  .passthrough();
92
332
 
93
- /** New-format stamped generic reference/topic doc (`type: 'generic'`). */
333
+ /**
334
+ * A stamped function doc as it loads: as with components, `displayName` may be
335
+ * missing and `usage` passes through unchecked.
336
+ *
337
+ * @typedef {Omit<FunctionDoc, 'type' | 'displayName' | 'usage'>
338
+ * & {type: 'function', displayName?: string, usage?: unknown}} LoadedFunctionDoc
339
+ */
340
+ /**
341
+ * @typedef {import('../_shared/contract.js').Expect<
342
+ * import('../_shared/contract.js').MutuallyAssignable<
343
+ * import('../_shared/contract.js').NamedFields<z.infer<typeof FunctionDocKindSchema>>,
344
+ * import('../_shared/contract.js').NamedFields<LoadedFunctionDoc>
345
+ * >
346
+ * >} _FunctionDocDriftLock
347
+ */
348
+
349
+ /**
350
+ * Every HookDoc is a FunctionDoc, so the one function schema covers both.
351
+ *
352
+ * @typedef {import('../_shared/contract.js').Expect<[HookDoc] extends [FunctionDoc] ? true : false>} _HookDocIsFunctionDocLock
353
+ */
354
+
355
+ /**
356
+ * Stamped generic reference/topic doc (`type: 'generic'`). `title` and
357
+ * `sections` stay optional at this parser boundary for docs produced by the
358
+ * shipped v0.3.0 factory-removal codemod. When present, all rich fields and
359
+ * semantic blocks are validated.
360
+ */
94
361
  export const GenericDocKindSchema = z
95
362
  .object({
96
363
  ...BaseDocFields,
97
364
  type: z.literal('generic'),
98
- // Declared rather than left to the passthrough: these two are read by
99
- // docs discovery to resolve one topic against another, so a non-string
100
- // should fail at the load boundary, not halfway through resolution.
101
- replaces: z.string().optional(),
102
- extends: z.string().optional(),
365
+ title: nonEmptyString.optional(),
366
+ sections: z.array(ReferenceSectionSchema).min(1).optional(),
367
+ replaces: nonEmptyString.optional(),
368
+ extends: nonEmptyString.optional(),
369
+ tokenCategory: z.string().optional(),
103
370
  })
104
- .passthrough();
371
+ .passthrough()
372
+ .superRefine((doc, context) => {
373
+ if (doc.replaces != null && doc.extends != null) {
374
+ context.addIssue({
375
+ code: 'custom',
376
+ path: ['extends'],
377
+ message: 'declares both `replaces` and `extends`; choose one',
378
+ });
379
+ }
380
+ const sectionIds = new Set();
381
+ doc.sections?.forEach((section, index) => {
382
+ if (section.id == null) return;
383
+ if (sectionIds.has(section.id)) {
384
+ context.addIssue({
385
+ code: 'custom',
386
+ path: ['sections', index, 'id'],
387
+ message: `duplicate section id "${section.id}"`,
388
+ });
389
+ }
390
+ sectionIds.add(section.id);
391
+ });
392
+ });
393
+
394
+ /**
395
+ * A stamped generic doc as the load check accepts it. `title`, `description`
396
+ * and `sections` may be missing, as in docs the v0.3.0 factory-removal codemod
397
+ * produced; `parseReference` then fills them (title from `displayName` or
398
+ * `name`, an empty description, no sections), so its result is a full
399
+ * ReferenceDoc. Only a doc with a description and sections is a usable topic
400
+ * (see `problemsInTopic`).
401
+ *
402
+ * @typedef {Omit<ReferenceDoc, 'type' | 'title' | 'description' | 'sections'>
403
+ * & {type: 'generic'}
404
+ * & Partial<Pick<ReferenceDoc, 'title' | 'description' | 'sections'>>} LoadedReferenceDoc
405
+ */
406
+ /**
407
+ * @typedef {import('../_shared/contract.js').Expect<
408
+ * import('../_shared/contract.js').MutuallyAssignable<
409
+ * import('../_shared/contract.js').NamedFields<z.infer<typeof GenericDocKindSchema>>,
410
+ * import('../_shared/contract.js').NamedFields<LoadedReferenceDoc>
411
+ * >
412
+ * >} _ReferenceDocDriftLock
413
+ */
105
414
 
106
- /** Recursive field descriptor for a SchemaDoc (objects nest via `fields`). The
107
- * explicit cast breaks the self-referential type inference (TS7022) that the
108
- * authoring-contract `checkJs` pass would otherwise flag. */
415
+ /** Recursive field descriptor for a SchemaDoc. */
109
416
  const SchemaFieldSchema =
110
- /** @type {import('zod').ZodType<import('./schema/type').SchemaFieldDoc>} */ (
417
+ /** @type {import('zod').ZodType<import('./schema/type.js').SchemaFieldDoc>} */ (
111
418
  z.lazy(() =>
112
419
  z
113
420
  .object({
114
421
  name: z.string().min(1, 'field name is required'),
115
- // `{error}` covers a missing (undefined) type; `.min(1)` covers an
116
- // empty string — both give the same author-friendly message.
117
422
  type: z
118
423
  .string({error: 'field type is required'})
119
424
  .min(1, 'field type is required'),
@@ -128,15 +433,15 @@ const SchemaFieldSchema =
128
433
  )
129
434
  );
130
435
 
131
- /** New stamped schema doc (`type: 'schema'`) — documents an authored object. */
436
+ /** New stamped schema doc (`type: 'schema'`). */
132
437
  export const SchemaDocKindSchema = z
133
438
  .object({
439
+ ...AuthoredDocGraphFields,
134
440
  type: z.literal('schema'),
135
441
  name: z.string().min(1, 'name is required'),
136
442
  displayName: z.string().min(1, 'displayName is required'),
137
443
  description: z.string(),
138
444
  namespace: z.string().optional(),
139
- aliases: z.array(z.string()).optional(),
140
445
  appliesTo: z.string().optional(),
141
446
  fields: z.array(SchemaFieldSchema),
142
447
  examples: z
@@ -146,21 +451,29 @@ export const SchemaDocKindSchema = z
146
451
  .passthrough(),
147
452
  )
148
453
  .optional(),
149
- notes: z.array(z.unknown()).optional(),
454
+ notes: z.array(ReferenceContentBlockSchema).optional(),
150
455
  })
151
456
  .passthrough();
152
457
 
153
- /** New stamped command doc (`type: 'command'`) — a function's terminal binding;
154
- * references a FunctionDoc via `fn`. */
458
+ /**
459
+ * @typedef {import('../_shared/contract.js').Expect<
460
+ * import('../_shared/contract.js').MutuallyAssignable<
461
+ * import('../_shared/contract.js').NamedFields<z.infer<typeof SchemaDocKindSchema>>,
462
+ * import('../_shared/contract.js').NamedFields<SchemaDoc & {type: 'schema'}>
463
+ * >
464
+ * >} _SchemaDocDriftLock
465
+ */
466
+
467
+ /** New stamped command doc (`type: 'command'`). */
155
468
  export const CommandDocKindSchema = z
156
469
  .object({
470
+ ...AuthoredDocGraphFields,
157
471
  type: z.literal('command'),
158
472
  name: z.string().min(1, 'name is required'),
159
473
  displayName: z.string().min(1, 'displayName is required'),
160
474
  summary: z.string(),
161
475
  description: z.string().optional(),
162
476
  namespace: z.string().optional(),
163
- aliases: z.array(z.string()).optional(),
164
477
  fn: z.string().optional(),
165
478
  args: z
166
479
  .array(
@@ -207,20 +520,28 @@ export const CommandDocKindSchema = z
207
520
  .array(z.object({code: z.number(), when: z.string()}).passthrough())
208
521
  .optional(),
209
522
  related: z.array(z.string()).optional(),
210
- notes: z.array(z.unknown()).optional(),
523
+ notes: z.array(ReferenceContentBlockSchema).optional(),
211
524
  })
212
525
  .passthrough();
213
526
 
214
- /** New stamped enum doc (`type: 'enum'`) — a closed vocabulary (error codes,
215
- * response-type discriminants). */
527
+ /**
528
+ * @typedef {import('../_shared/contract.js').Expect<
529
+ * import('../_shared/contract.js').MutuallyAssignable<
530
+ * import('../_shared/contract.js').NamedFields<z.infer<typeof CommandDocKindSchema>>,
531
+ * import('../_shared/contract.js').NamedFields<CommandDoc & {type: 'command'}>
532
+ * >
533
+ * >} _CommandDocDriftLock
534
+ */
535
+
536
+ /** New stamped enum doc (`type: 'enum'`). */
216
537
  export const EnumDocKindSchema = z
217
538
  .object({
539
+ ...AuthoredDocGraphFields,
218
540
  type: z.literal('enum'),
219
541
  name: z.string().min(1, 'name is required'),
220
542
  displayName: z.string().min(1, 'displayName is required'),
221
543
  description: z.string(),
222
544
  namespace: z.string().optional(),
223
- aliases: z.array(z.string()).optional(),
224
545
  members: z.array(
225
546
  z
226
547
  .object({
@@ -233,8 +554,108 @@ export const EnumDocKindSchema = z
233
554
  })
234
555
  .passthrough();
235
556
 
236
- // ── Legacy loose format (unchanged, kept for back-compat) ─────────────
557
+ /**
558
+ * @typedef {import('../_shared/contract.js').Expect<
559
+ * import('../_shared/contract.js').MutuallyAssignable<
560
+ * import('../_shared/contract.js').NamedFields<z.infer<typeof EnumDocKindSchema>>,
561
+ * import('../_shared/contract.js').NamedFields<EnumDoc & {type: 'enum'}>
562
+ * >
563
+ * >} _EnumDocDriftLock
564
+ */
565
+
566
+ const NamespaceSlotSchema = z
567
+ .object({
568
+ title: nonEmptyString,
569
+ accepts: z
570
+ .object({
571
+ kinds: z.array(AuthoredDocKindSchema).min(1),
572
+ providers: z.enum(['same', 'configured']).optional(),
573
+ })
574
+ .strict(),
575
+ })
576
+ .strict();
577
+
578
+ /** The one new authored doctype: a hierarchy and layout owner. */
579
+ export const NamespaceDocKindSchema = z
580
+ .object({
581
+ ...AuthoredDocGraphFields,
582
+ type: z.literal('namespace'),
583
+ name: nonEmptyString,
584
+ title: nonEmptyString,
585
+ summary: nonEmptyString,
586
+ keywords: z.array(nonEmptyString).optional(),
587
+ slots: z
588
+ .record(nonEmptyString, NamespaceSlotSchema)
589
+ .refine(slots => Object.keys(slots).length > 0, {
590
+ message: 'at least one slot is required',
591
+ }),
592
+ adopts: z
593
+ .array(
594
+ z
595
+ .object({
596
+ source: z
597
+ .object({
598
+ group: nonEmptyString,
599
+ kinds: z.array(AuthoredDocKindSchema).min(1).optional(),
600
+ })
601
+ .strict(),
602
+ into: nonEmptyString,
603
+ groupBy: z.literal('kind').optional(),
604
+ })
605
+ .strict(),
606
+ )
607
+ .optional(),
608
+ blocks: z.array(ReferenceContentBlockSchema).optional(),
609
+ })
610
+ .strict()
611
+ .superRefine((doc, context) => {
612
+ const slots = new Set(Object.keys(doc.slots));
613
+ doc.adopts?.forEach((rule, index) => {
614
+ const slot = doc.slots[rule.into];
615
+ if (slot == null) {
616
+ context.addIssue({
617
+ code: 'custom',
618
+ path: ['adopts', index, 'into'],
619
+ message: `must name a declared slot; received "${rule.into}"`,
620
+ });
621
+ return;
622
+ }
623
+ /** @type {AuthoredDocKind[]} */
624
+ const adoptedKinds =
625
+ rule.groupBy === 'kind' ? ['namespace'] : (rule.source.kinds ?? []);
626
+ adoptedKinds.forEach(kind => {
627
+ if (!slot.accepts.kinds.includes(kind)) {
628
+ context.addIssue({
629
+ code: 'custom',
630
+ path: ['adopts', index, 'into'],
631
+ message: `slot "${rule.into}" does not accept adopted kind "${kind}"`,
632
+ });
633
+ }
634
+ });
635
+ });
636
+ doc.blocks?.forEach((block, index) => {
637
+ if (block.type === 'collection' && !slots.has(block.source.slot)) {
638
+ context.addIssue({
639
+ code: 'custom',
640
+ path: ['blocks', index, 'source', 'slot'],
641
+ message: `must name a declared slot; received "${block.source.slot}"`,
642
+ });
643
+ }
644
+ });
645
+ });
646
+
647
+ /**
648
+ * @typedef {import('../_shared/contract.js').Expect<
649
+ * import('../_shared/contract.js').Equal<
650
+ * z.infer<typeof NamespaceDocKindSchema>,
651
+ * NamespaceDoc
652
+ * >
653
+ * >} _NamespaceDocDriftLock
654
+ */
655
+
656
+ // Legacy loose format stays permissive for backward compatibility.
237
657
  const LegacyBaseDocSchema = z.object({
658
+ ...AuthoredDocGraphFields,
238
659
  name: z.string().min(1, 'name is required'),
239
660
  displayName: z.string().optional(),
240
661
  description: z.string().optional(),
@@ -255,6 +676,37 @@ const LegacyBaseDocSchema = z.object({
255
676
  relatedHooks: z.array(z.string()).optional(),
256
677
  });
257
678
 
679
+ const LegacyReferenceDocSchema = LegacyBaseDocSchema.extend({
680
+ title: nonEmptyString,
681
+ description: z.string(),
682
+ sections: z.array(ReferenceSectionSchema).min(1),
683
+ replaces: nonEmptyString.optional(),
684
+ extends: nonEmptyString.optional(),
685
+ tokenCategory: z.string().optional(),
686
+ })
687
+ .passthrough()
688
+ .superRefine((doc, context) => {
689
+ if (doc.replaces != null && doc.extends != null) {
690
+ context.addIssue({
691
+ code: 'custom',
692
+ path: ['extends'],
693
+ message: 'declares both `replaces` and `extends`; choose one',
694
+ });
695
+ }
696
+ const sectionIds = new Set();
697
+ doc.sections.forEach((section, index) => {
698
+ if (section.id == null) return;
699
+ if (sectionIds.has(section.id)) {
700
+ context.addIssue({
701
+ code: 'custom',
702
+ path: ['sections', index, 'id'],
703
+ message: `duplicate section id "${section.id}"`,
704
+ });
705
+ }
706
+ sectionIds.add(section.id);
707
+ });
708
+ });
709
+
258
710
  const LegacySingleComponentDocSchema = LegacyBaseDocSchema.extend({
259
711
  props: z.array(PropSchema),
260
712
  }).passthrough();
@@ -274,10 +726,11 @@ const LegacySubComponentDocSchema = LegacyBaseDocSchema.extend({
274
726
  props: z.array(PropSchema),
275
727
  }).passthrough();
276
728
 
277
- /** The permissive legacy union (sub-component first, then hook, multi, single). */
729
+ /** The permissive legacy union (sub-component, hook, multi, single, then reference). */
278
730
  export const LegacyDocSchema = z.union([
279
731
  LegacySubComponentDocSchema,
280
732
  LegacyHookDocSchema,
281
733
  LegacyMultiComponentDocSchema,
282
734
  LegacySingleComponentDocSchema,
735
+ LegacyReferenceDocSchema,
283
736
  ]);
@@ -0,0 +1,9 @@
1
+ // @generated by scripts/sync-api-types.mjs from the JSDoc in authoring/**/*.mjs.
2
+ // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
+
4
+ /**
5
+ * @file SchemaDoc for graph metadata shared by every authored doc kind.
6
+ * @position packages/cli/authoring/doctypes/base — doc-type documentation
7
+ */
8
+ /** @type {import('@astryxdesign/cli/authoring').SchemaDoc} */
9
+ export const doc: import("@astryxdesign/cli/authoring").SchemaDoc;