@astryxdesign/cli 0.6.3-canary.35a722f → 0.6.3-canary.395846b

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.
@@ -4,9 +4,9 @@
4
4
  * @file docs.detail.section leaf — load a single section of a topic.
5
5
  *
6
6
  * @input A topic name, a section query, and optional {lang, zh, dense}. Resolves
7
- * the topic via the shared adapter, keeps the 0.6.x first title-substring
8
- * match, then falls back to a stable key or normalized title key, and links
9
- * only that section.
7
+ * the topic via the shared adapter, finds the section in its lowered compiled
8
+ * node by its stable key, then by exact title, then by a title that contains
9
+ * the query, and links only that section.
10
10
  * @output { type: 'docs.detail.section', data: ReferenceSection } with any
11
11
  * token-ref blocks inlined — matching `astryx --json docs <topic> <section>`.
12
12
  * Throws ERR_UNKNOWN_SECTION when nothing matches, or when the query matches
@@ -17,7 +17,10 @@
17
17
 
18
18
  import {AstryxError} from '../../../error.mjs';
19
19
  import {ERROR_CODES} from '../../../../foundation/response/error-codes.mjs';
20
- import {findDocSection} from '../../../../foundation/discovery/docs-section-key.mjs';
20
+ import {
21
+ findDocSection,
22
+ sectionKey,
23
+ } from '../../../../foundation/discovery/docs-section-key.mjs';
21
24
  import {linkReferenceSection} from '../../../../foundation/doc-compiler/compile.mjs';
22
25
  import {
23
26
  readerSections,
@@ -49,13 +52,16 @@ export async function section(topic, sectionName, options = {}) {
49
52
 
50
53
  const {catalog, node, lang} = await resolveTopicDocs(topic, options);
51
54
  const sections = readerSections(node);
52
- const {section: match} = findDocSection(sections, sectionName);
55
+ const {section: match, candidates} = findDocSection(sections, sectionName);
53
56
  if (!match) {
57
+ const ambiguous = candidates.length > 1;
54
58
  throw new AstryxError(
55
- `Section "${sectionName}" not found in "${topic}"`,
56
- sections.map(s => ({
57
- name: s.title,
58
- reason: 'available section',
59
+ ambiguous
60
+ ? `Section "${sectionName}" matches ${candidates.length} sections in "${topic}". Read one by its key.`
61
+ : `Section "${sectionName}" not found in "${topic}"`,
62
+ (ambiguous ? candidates : sections).map(s => ({
63
+ name: sectionKey(s),
64
+ reason: s.title,
59
65
  })),
60
66
  ERROR_CODES.ERR_UNKNOWN_SECTION,
61
67
  );
@@ -30,17 +30,6 @@ describe('docs.detail.section leaf', () => {
30
30
  }
31
31
  expect(err).toBeInstanceOf(AstryxError);
32
32
  expect(err.code).toBe('ERR_UNKNOWN_SECTION');
33
- expect(err.suggestions).toEqual(
34
- expect.arrayContaining([
35
- expect.objectContaining({
36
- name: expect.any(String),
37
- reason: 'available section',
38
- }),
39
- ]),
40
- );
41
- expect(err.suggestions.some(suggestion => /\s/u.test(suggestion.name))).toBe(
42
- true,
43
- );
44
33
  }, SLOW);
45
34
 
46
35
  it('does not return the first section for an empty section name', async () => {
@@ -61,10 +50,12 @@ describe('docs.detail.section leaf', () => {
61
50
  expect(res.data.id).toBe(target.id);
62
51
  }, SLOW);
63
52
 
64
- it('keeps a previously accepted ambiguous query on its first match', async () => {
65
- const res = await section('theme', 'e');
66
- expect(res.type).toBe('docs.detail.section');
67
- expect(res.data).toBeDefined();
53
+ it('refuses a query that matches more than one section', async () => {
54
+ const err = await section('theme', 'e').catch(e => e);
55
+ expect(err).toBeInstanceOf(AstryxError);
56
+ expect(err.code).toBe('ERR_UNKNOWN_SECTION');
57
+ expect(err.message).toMatch(/matches \d+ sections/);
58
+ expect(err.suggestions.length).toBeGreaterThan(1);
68
59
  }, SLOW);
69
60
 
70
61
  it.each([null, 'zh', 'dense'])(
@@ -994,7 +994,7 @@ export async function checkDocsProgressiveDisclosure(ctx) {
994
994
  return {
995
995
  id,
996
996
  label,
997
- status: 'warn',
997
+ status: 'fail',
998
998
  message: joinProblems(problems),
999
999
  fix: 'Fix the doc each problem names; split a section that is too large into smaller ones, each with its own key.',
1000
1000
  };
@@ -391,7 +391,7 @@ describe('checkDocsProgressiveDisclosure', () => {
391
391
  expect(c.message).toMatch(/^\d+ topics: /);
392
392
  }, SLOW);
393
393
 
394
- it('warns on an invalid doc an integration contributed', async () => {
394
+ it('fails on an invalid doc an integration contributed', async () => {
395
395
  const c = await checkDocsProgressiveDisclosure({
396
396
  docsCatalogIssues: [
397
397
  {
@@ -402,13 +402,13 @@ describe('checkDocsProgressiveDisclosure', () => {
402
402
  },
403
403
  ],
404
404
  });
405
- expect(c.status).toBe('warn');
405
+ expect(c.status).toBe('fail');
406
406
  expect(c.message).toBe('@acme/widgets: bad.doc.mjs exports no doc');
407
407
  });
408
408
 
409
- it('warns when the docs catalog cannot be built', async () => {
409
+ it('fails when the docs catalog cannot be built', async () => {
410
410
  const c = await checkDocsProgressiveDisclosure({docsCatalogError: 'boom'});
411
- expect(c.status).toBe('warn');
411
+ expect(c.status).toBe('fail');
412
412
  expect(c.message).toContain('boom');
413
413
  });
414
414
 
@@ -436,7 +436,7 @@ describe('checkDocsProgressiveDisclosure', () => {
436
436
  }),
437
437
  docsCatalogIssues: [],
438
438
  });
439
- expect(c.status).toBe('warn');
439
+ expect(c.status).toBe('fail');
440
440
  expect(c.message).toMatch(/^2 problems: /);
441
441
  expect(c.message).toContain('huge everything: 41 KB, over the 32 KB one read may return');
442
442
  expect(c.message).toContain('broken: ');
@@ -812,7 +812,7 @@ describe('checkDocsProgressiveDisclosure languages', () => {
812
812
  docsCatalog: DocsCatalog.fromBuiltins({deploying: path.join(dir, 'deploying.doc.mjs')}),
813
813
  docsCatalogIssues: [],
814
814
  });
815
- expect(c.status).toBe('warn');
815
+ expect(c.status).toBe('fail');
816
816
  expect(c.message).toContain('deploying [zh]: zh overlay broken');
817
817
  expect(c.message).toContain('deploying [dense] overview: 41 KB');
818
818
  expect(c.message).not.toMatch(/deploying overview:/);
@@ -25,7 +25,7 @@ export namespace AuthoredDocGraphFields {
25
25
  internal: "internal";
26
26
  }>>;
27
27
  }
28
- /** Runtime schema for the stable content-block union published in 0.6.x. */
28
+ /** Runtime schema for every existing and V1 semantic content block. */
29
29
  export const ReferenceContentBlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
30
30
  type: z.ZodLiteral<"prose">;
31
31
  text: z.ZodString;
@@ -55,74 +55,6 @@ export const ReferenceContentBlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
55
55
  type: z.ZodLiteral<"token-ref">;
56
56
  topic: z.ZodString;
57
57
  section: z.ZodString;
58
- }, z.core.$strict>], "type">;
59
- /** Runtime schema for graph-only blocks used by NamespaceDoc. */
60
- export const GraphContentBlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
61
- type: z.ZodLiteral<"workflow">;
62
- title: z.ZodOptional<z.ZodString>;
63
- steps: z.ZodArray<z.ZodObject<{
64
- title: z.ZodString;
65
- description: z.ZodOptional<z.ZodString>;
66
- references: z.ZodOptional<z.ZodArray<z.ZodString>>;
67
- }, z.core.$strict>>;
68
- }, z.core.$strict>, z.ZodObject<{
69
- type: z.ZodLiteral<"collection">;
70
- title: z.ZodOptional<z.ZodString>;
71
- source: z.ZodObject<{
72
- slot: z.ZodString;
73
- }, z.core.$strict>;
74
- presentation: z.ZodOptional<z.ZodEnum<{
75
- list: "list";
76
- cards: "cards";
77
- compact: "compact";
78
- }>>;
79
- whenEmpty: z.ZodOptional<z.ZodEnum<{
80
- show: "show";
81
- omit: "omit";
82
- }>>;
83
- }, z.core.$strict>, z.ZodObject<{
84
- type: z.ZodLiteral<"reference">;
85
- target: z.ZodString;
86
- projection: z.ZodOptional<z.ZodObject<{
87
- fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
88
- sections: z.ZodOptional<z.ZodArray<z.ZodString>>;
89
- }, z.core.$strict>>;
90
- presentation: z.ZodOptional<z.ZodEnum<{
91
- compact: "compact";
92
- summary: "summary";
93
- full: "full";
94
- }>>;
95
- }, z.core.$strict>], "type">;
96
- /** Namespace content accepts both stable reference blocks and graph-only blocks. */
97
- export const NamespaceContentBlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
98
- type: z.ZodLiteral<"prose">;
99
- text: z.ZodString;
100
- }, z.core.$strict>, z.ZodObject<{
101
- type: z.ZodLiteral<"heading">;
102
- level: z.ZodUnion<readonly [z.ZodLiteral<3>, z.ZodLiteral<4>, z.ZodLiteral<5>, z.ZodLiteral<6>]>;
103
- text: z.ZodString;
104
- }, z.core.$strict>, z.ZodObject<{
105
- type: z.ZodLiteral<"code">;
106
- lang: z.ZodString;
107
- code: z.ZodString;
108
- label: z.ZodOptional<z.ZodString>;
109
- }, z.core.$strict>, z.ZodObject<{
110
- type: z.ZodLiteral<"table">;
111
- headers: z.ZodArray<z.ZodString>;
112
- rows: z.ZodArray<z.ZodArray<z.ZodString>>;
113
- }, z.core.$strict>, z.ZodObject<{
114
- type: z.ZodLiteral<"list">;
115
- style: z.ZodEnum<{
116
- ordered: "ordered";
117
- unordered: "unordered";
118
- do: "do";
119
- dont: "dont";
120
- }>;
121
- items: z.ZodArray<z.ZodString>;
122
- }, z.core.$strict>, z.ZodObject<{
123
- type: z.ZodLiteral<"token-ref">;
124
- topic: z.ZodString;
125
- section: z.ZodString;
126
58
  }, z.core.$strict>, z.ZodObject<{
127
59
  type: z.ZodLiteral<"workflow">;
128
60
  title: z.ZodOptional<z.ZodString>;
@@ -303,6 +235,41 @@ export const GenericDocKindSchema: z.ZodObject<{
303
235
  type: z.ZodLiteral<"token-ref">;
304
236
  topic: z.ZodString;
305
237
  section: z.ZodString;
238
+ }, z.core.$strict>, z.ZodObject<{
239
+ type: z.ZodLiteral<"workflow">;
240
+ title: z.ZodOptional<z.ZodString>;
241
+ steps: z.ZodArray<z.ZodObject<{
242
+ title: z.ZodString;
243
+ description: z.ZodOptional<z.ZodString>;
244
+ references: z.ZodOptional<z.ZodArray<z.ZodString>>;
245
+ }, z.core.$strict>>;
246
+ }, z.core.$strict>, z.ZodObject<{
247
+ type: z.ZodLiteral<"collection">;
248
+ title: z.ZodOptional<z.ZodString>;
249
+ source: z.ZodObject<{
250
+ slot: z.ZodString;
251
+ }, z.core.$strict>;
252
+ presentation: z.ZodOptional<z.ZodEnum<{
253
+ list: "list";
254
+ cards: "cards";
255
+ compact: "compact";
256
+ }>>;
257
+ whenEmpty: z.ZodOptional<z.ZodEnum<{
258
+ show: "show";
259
+ omit: "omit";
260
+ }>>;
261
+ }, z.core.$strict>, z.ZodObject<{
262
+ type: z.ZodLiteral<"reference">;
263
+ target: z.ZodString;
264
+ projection: z.ZodOptional<z.ZodObject<{
265
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
266
+ sections: z.ZodOptional<z.ZodArray<z.ZodString>>;
267
+ }, z.core.$strict>>;
268
+ presentation: z.ZodOptional<z.ZodEnum<{
269
+ compact: "compact";
270
+ summary: "summary";
271
+ full: "full";
272
+ }>>;
306
273
  }, z.core.$strict>], "type">>;
307
274
  previewType: z.ZodOptional<z.ZodEnum<{
308
275
  swatch: "swatch";
@@ -384,6 +351,41 @@ export const SchemaDocKindSchema: z.ZodObject<{
384
351
  type: z.ZodLiteral<"token-ref">;
385
352
  topic: z.ZodString;
386
353
  section: z.ZodString;
354
+ }, z.core.$strict>, z.ZodObject<{
355
+ type: z.ZodLiteral<"workflow">;
356
+ title: z.ZodOptional<z.ZodString>;
357
+ steps: z.ZodArray<z.ZodObject<{
358
+ title: z.ZodString;
359
+ description: z.ZodOptional<z.ZodString>;
360
+ references: z.ZodOptional<z.ZodArray<z.ZodString>>;
361
+ }, z.core.$strict>>;
362
+ }, z.core.$strict>, z.ZodObject<{
363
+ type: z.ZodLiteral<"collection">;
364
+ title: z.ZodOptional<z.ZodString>;
365
+ source: z.ZodObject<{
366
+ slot: z.ZodString;
367
+ }, z.core.$strict>;
368
+ presentation: z.ZodOptional<z.ZodEnum<{
369
+ list: "list";
370
+ cards: "cards";
371
+ compact: "compact";
372
+ }>>;
373
+ whenEmpty: z.ZodOptional<z.ZodEnum<{
374
+ show: "show";
375
+ omit: "omit";
376
+ }>>;
377
+ }, z.core.$strict>, z.ZodObject<{
378
+ type: z.ZodLiteral<"reference">;
379
+ target: z.ZodString;
380
+ projection: z.ZodOptional<z.ZodObject<{
381
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
382
+ sections: z.ZodOptional<z.ZodArray<z.ZodString>>;
383
+ }, z.core.$strict>>;
384
+ presentation: z.ZodOptional<z.ZodEnum<{
385
+ compact: "compact";
386
+ summary: "summary";
387
+ full: "full";
388
+ }>>;
387
389
  }, z.core.$strict>], "type">>>;
388
390
  placement: z.ZodOptional<z.ZodObject<{
389
391
  parent: z.ZodString;
@@ -468,6 +470,41 @@ export const CommandDocKindSchema: z.ZodObject<{
468
470
  type: z.ZodLiteral<"token-ref">;
469
471
  topic: z.ZodString;
470
472
  section: z.ZodString;
473
+ }, z.core.$strict>, z.ZodObject<{
474
+ type: z.ZodLiteral<"workflow">;
475
+ title: z.ZodOptional<z.ZodString>;
476
+ steps: z.ZodArray<z.ZodObject<{
477
+ title: z.ZodString;
478
+ description: z.ZodOptional<z.ZodString>;
479
+ references: z.ZodOptional<z.ZodArray<z.ZodString>>;
480
+ }, z.core.$strict>>;
481
+ }, z.core.$strict>, z.ZodObject<{
482
+ type: z.ZodLiteral<"collection">;
483
+ title: z.ZodOptional<z.ZodString>;
484
+ source: z.ZodObject<{
485
+ slot: z.ZodString;
486
+ }, z.core.$strict>;
487
+ presentation: z.ZodOptional<z.ZodEnum<{
488
+ list: "list";
489
+ cards: "cards";
490
+ compact: "compact";
491
+ }>>;
492
+ whenEmpty: z.ZodOptional<z.ZodEnum<{
493
+ show: "show";
494
+ omit: "omit";
495
+ }>>;
496
+ }, z.core.$strict>, z.ZodObject<{
497
+ type: z.ZodLiteral<"reference">;
498
+ target: z.ZodString;
499
+ projection: z.ZodOptional<z.ZodObject<{
500
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
501
+ sections: z.ZodOptional<z.ZodArray<z.ZodString>>;
502
+ }, z.core.$strict>>;
503
+ presentation: z.ZodOptional<z.ZodEnum<{
504
+ compact: "compact";
505
+ summary: "summary";
506
+ full: "full";
507
+ }>>;
471
508
  }, z.core.$strict>], "type">>>;
472
509
  placement: z.ZodOptional<z.ZodObject<{
473
510
  parent: z.ZodString;
@@ -840,6 +877,41 @@ export const LegacyDocSchema: z.ZodUnion<readonly [z.ZodObject<{
840
877
  type: z.ZodLiteral<"token-ref">;
841
878
  topic: z.ZodString;
842
879
  section: z.ZodString;
880
+ }, z.core.$strict>, z.ZodObject<{
881
+ type: z.ZodLiteral<"workflow">;
882
+ title: z.ZodOptional<z.ZodString>;
883
+ steps: z.ZodArray<z.ZodObject<{
884
+ title: z.ZodString;
885
+ description: z.ZodOptional<z.ZodString>;
886
+ references: z.ZodOptional<z.ZodArray<z.ZodString>>;
887
+ }, z.core.$strict>>;
888
+ }, z.core.$strict>, z.ZodObject<{
889
+ type: z.ZodLiteral<"collection">;
890
+ title: z.ZodOptional<z.ZodString>;
891
+ source: z.ZodObject<{
892
+ slot: z.ZodString;
893
+ }, z.core.$strict>;
894
+ presentation: z.ZodOptional<z.ZodEnum<{
895
+ list: "list";
896
+ cards: "cards";
897
+ compact: "compact";
898
+ }>>;
899
+ whenEmpty: z.ZodOptional<z.ZodEnum<{
900
+ show: "show";
901
+ omit: "omit";
902
+ }>>;
903
+ }, z.core.$strict>, z.ZodObject<{
904
+ type: z.ZodLiteral<"reference">;
905
+ target: z.ZodString;
906
+ projection: z.ZodOptional<z.ZodObject<{
907
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
908
+ sections: z.ZodOptional<z.ZodArray<z.ZodString>>;
909
+ }, z.core.$strict>>;
910
+ presentation: z.ZodOptional<z.ZodEnum<{
911
+ compact: "compact";
912
+ summary: "summary";
913
+ full: "full";
914
+ }>>;
843
915
  }, z.core.$strict>], "type">>;
844
916
  previewType: z.ZodOptional<z.ZodEnum<{
845
917
  swatch: "swatch";
@@ -861,7 +933,6 @@ export type AuthoredDocGraphFieldsType = import("./base/type.js").AuthoredDocGra
861
933
  export type AuthoredDocKind = import("./base/type.js").AuthoredDocKind;
862
934
  export type NamespaceDoc = import("./namespace/type.js").NamespaceDoc;
863
935
  export type ReferenceContentBlock = import("./reference/type.js").ReferenceContentBlock;
864
- export type GraphContentBlock = import("./reference/type.js").GraphContentBlock;
865
936
  export type ReferenceDoc = import("./reference/type.js").ReferenceDoc;
866
937
  export type SingleComponentDoc = import("./component/type.js").SingleComponentDoc;
867
938
  export type ComponentPropDoc = import("./base/type.js").ComponentPropDoc;
@@ -873,7 +944,6 @@ export type EnumDoc = import("./enum/type.js").EnumDoc;
873
944
  export type _AuthoredDocKindDriftLock = import("../_shared/contract.js").Expect<import("../_shared/contract.js").Equal<z.infer<typeof AuthoredDocKindSchema>, AuthoredDocKind>>;
874
945
  export type _AuthoredDocGraphDriftLock = import("../_shared/contract.js").Expect<import("../_shared/contract.js").MutuallyAssignable<z.infer<typeof _AuthoredDocGraphSchema>, AuthoredDocGraphFieldsType>>;
875
946
  export type _ReferenceContentBlockDriftLock = import("../_shared/contract.js").Expect<import("../_shared/contract.js").Equal<z.infer<typeof ReferenceContentBlockSchema>, ReferenceContentBlock>>;
876
- export type _GraphContentBlockDriftLock = import("../_shared/contract.js").Expect<import("../_shared/contract.js").Equal<z.infer<typeof GraphContentBlockSchema>, GraphContentBlock>>;
877
947
  /**
878
948
  * A stamped component doc as it loads. The loader accepts what the unstamped
879
949
  * format always accepted, so stamping an existing doc never breaks it:
@@ -15,7 +15,6 @@ import {z} from 'zod';
15
15
  /** @typedef {import('./base/type.js').AuthoredDocKind} AuthoredDocKind */
16
16
  /** @typedef {import('./namespace/type.js').NamespaceDoc} NamespaceDoc */
17
17
  /** @typedef {import('./reference/type.js').ReferenceContentBlock} ReferenceContentBlock */
18
- /** @typedef {import('./reference/type.js').GraphContentBlock} GraphContentBlock */
19
18
  /** @typedef {import('./reference/type.js').ReferenceDoc} ReferenceDoc */
20
19
  /** @typedef {import('./component/type.js').SingleComponentDoc} SingleComponentDoc */
21
20
  /** @typedef {import('./base/type.js').ComponentPropDoc} ComponentPropDoc */
@@ -162,7 +161,7 @@ const ReferenceBlockSchema = z
162
161
  })
163
162
  .strict();
164
163
 
165
- /** Runtime schema for the stable content-block union published in 0.6.x. */
164
+ /** Runtime schema for every existing and V1 semantic content block. */
166
165
  export const ReferenceContentBlockSchema = z.discriminatedUnion('type', [
167
166
  ProseBlockSchema,
168
167
  HeadingBlockSchema,
@@ -170,23 +169,6 @@ export const ReferenceContentBlockSchema = z.discriminatedUnion('type', [
170
169
  TableBlockSchema,
171
170
  ListBlockSchema,
172
171
  TokenReferenceBlockSchema,
173
- ]);
174
-
175
- /** Runtime schema for graph-only blocks used by NamespaceDoc. */
176
- export const GraphContentBlockSchema = z.discriminatedUnion('type', [
177
- WorkflowBlockSchema,
178
- CollectionBlockSchema,
179
- ReferenceBlockSchema,
180
- ]);
181
-
182
- /** Namespace content accepts both stable reference blocks and graph-only blocks. */
183
- export const NamespaceContentBlockSchema = z.discriminatedUnion('type', [
184
- ProseBlockSchema,
185
- HeadingBlockSchema,
186
- CodeBlockSchema,
187
- TableBlockSchema,
188
- ListBlockSchema,
189
- TokenReferenceBlockSchema,
190
172
  WorkflowBlockSchema,
191
173
  CollectionBlockSchema,
192
174
  ReferenceBlockSchema,
@@ -201,15 +183,6 @@ export const NamespaceContentBlockSchema = z.discriminatedUnion('type', [
201
183
  * >} _ReferenceContentBlockDriftLock
202
184
  */
203
185
 
204
- /**
205
- * @typedef {import('../_shared/contract.js').Expect<
206
- * import('../_shared/contract.js').Equal<
207
- * z.infer<typeof GraphContentBlockSchema>,
208
- * GraphContentBlock
209
- * >
210
- * >} _GraphContentBlockDriftLock
211
- */
212
-
213
186
  const ReferenceSectionSchema = z
214
187
  .object({
215
188
  id: nonEmptyString.optional(),
@@ -632,7 +605,7 @@ export const NamespaceDocKindSchema = z
632
605
  .strict(),
633
606
  )
634
607
  .optional(),
635
- blocks: z.array(NamespaceContentBlockSchema).optional(),
608
+ blocks: z.array(ReferenceContentBlockSchema).optional(),
636
609
  })
637
610
  .strict()
638
611
  .superRefine((doc, context) => {
@@ -71,7 +71,7 @@ describe('load check vs published type', () => {
71
71
  expect(() => parseDoc(EXAMPLES[kind], `${kind}.doc.mjs`)).not.toThrow();
72
72
  }
73
73
  expect(() => parseDoc({type: 'widget', name: 'x'}, 'x.doc.mjs')).toThrow(
74
- /x\.doc\.mjs is invalid/u,
74
+ /unsupported type "widget"/,
75
75
  );
76
76
  });
77
77
  });
@@ -78,9 +78,9 @@ export const doc = {
78
78
  },
79
79
  {
80
80
  name: 'blocks',
81
- type: '(ReferenceContentBlock | GraphContentBlock)[]',
81
+ type: 'ReferenceContentBlock[]',
82
82
  description:
83
- 'Ordered layout content. Graph-only workflow, collection, and reference blocks are available here without widening the stable ReferenceContentBlock union used by existing topic renderers.',
83
+ 'Ordered layout content. V1 adds only workflow, collection, and reference to the existing prose, heading, code, table, list, and token-ref blocks.',
84
84
  },
85
85
  ],
86
86
  examples: [
@@ -134,30 +134,32 @@ describe('NamespaceDoc', () => {
134
134
  });
135
135
  });
136
136
 
137
- describe('semantic graph blocks', () => {
138
- it('keeps graph-only blocks out of the stable ReferenceDoc section union', () => {
139
- expect(() =>
140
- parseReference({
141
- type: 'generic',
142
- name: 'publishing',
143
- title: 'Publishing',
144
- description: 'Publish an integration.',
145
- sections: [
146
- {
147
- id: 'start',
148
- title: 'Start',
149
- content: namespaceDoc.blocks,
150
- },
151
- ],
152
- }),
153
- ).toThrow(/Invalid discriminator value/u);
137
+ describe('semantic blocks in existing docs', () => {
138
+ it('accepts workflow, collection, and reference in a ReferenceDoc section', () => {
139
+ const parsed = parseReference({
140
+ type: 'generic',
141
+ name: 'publishing',
142
+ title: 'Publishing',
143
+ description: 'Publish an integration.',
144
+ sections: [
145
+ {
146
+ id: 'start',
147
+ title: 'Start',
148
+ content: namespaceDoc.blocks,
149
+ },
150
+ ],
151
+ });
152
+ expect(parsed.sections[0].id).toBe('start');
153
+ expect(parsed.sections[0].content.map(block => block.type)).toEqual([
154
+ 'workflow',
155
+ 'collection',
156
+ 'reference',
157
+ ]);
154
158
  });
155
159
 
156
- it('keeps shape-sniffing an unknown stamp for 0.6.x compatibility', () => {
157
- expect(parseDoc({type: 'choice', name: 'x', props: []})).toMatchObject({
158
- type: 'choice',
159
- name: 'x',
160
- props: [],
161
- });
160
+ it('rejects an unknown stamped doc kind instead of treating it as legacy', () => {
161
+ expect(() => parseDoc({type: 'choice', name: 'x', props: []})).toThrow(
162
+ /unsupported type "choice"/u,
163
+ );
162
164
  });
163
165
  });
@@ -7,10 +7,7 @@
7
7
  */
8
8
 
9
9
  import type {AuthoredDocGraphFields, AuthoredDocKind} from '../base/type.js';
10
- import type {
11
- GraphContentBlock,
12
- ReferenceContentBlock,
13
- } from '../reference/type.js';
10
+ import type {ReferenceContentBlock} from '../reference/type.js';
14
11
 
15
12
  /** Which providers may contribute appearances to a namespace slot. */
16
13
  export type NamespaceProviderScope = 'same' | 'configured';
@@ -70,5 +67,5 @@ export interface NamespaceDoc extends AuthoredDocGraphFields {
70
67
  /** Optional source-adoption rules for otherwise-unplaced docs. */
71
68
  adopts?: NamespaceAdoptionRule[];
72
69
  /** Ordered renderer-neutral content and collection blocks. */
73
- blocks?: (ReferenceContentBlock | GraphContentBlock)[];
70
+ blocks?: ReferenceContentBlock[];
74
71
  }
@@ -67,9 +67,8 @@ export function parseDoc(input, label = 'doc') {
67
67
  case 'theme':
68
68
  return parseTheme(input, label);
69
69
  case undefined:
70
- default:
71
- // 0.6.x shape-sniffed unknown stamps. Keep accepting them through the
72
- // patch compatibility window; canonical writers emit a known stamp.
73
70
  return parseLegacyDoc(input, label);
71
+ default:
72
+ throw new Error(`${label} has unsupported type ${JSON.stringify(type)}.`);
74
73
  }
75
74
  }
@@ -95,7 +95,7 @@ export const doc = {
95
95
  name: 'sections[].content',
96
96
  type: 'ReferenceContentBlock[]',
97
97
  description:
98
- 'Ordered content blocks: prose, heading, code, table, list, and token-ref. Graph-only workflow, collection, and reference blocks are available through GraphContentBlock on NamespaceDoc, without widening this stable union.',
98
+ 'Ordered content blocks: prose, heading, code, table, list, and token-ref. workflow, collection, and reference are declared for the docs graph and parse, but a topic that uses one fails to load until the docs graph ships.',
99
99
  required: true,
100
100
  },
101
101
  {
@@ -144,7 +144,7 @@ export const docs = {
144
144
  },
145
145
  {
146
146
  type: 'prose',
147
- text: 'Each `sections[].content` is an ordered array of ReferenceContentBlock, the stable discriminated union of prose, heading, code, table, list, and token-ref. Docs-graph-only workflow, collection, and reference blocks are exported separately as GraphContentBlock and accepted by NamespaceDoc. choice, callout, and checklist remain invalid. ReferenceContentBlock is also reused by the `notes` field on SchemaDoc and CommandDoc.',
147
+ text: 'Each `sections[].content` is an ordered array of ReferenceContentBlock, a discriminated union. workflow, collection, and reference are declared for the docs graph: they parse, but topic loading rejects them until the docs graph ships. choice, callout, and checklist remain invalid. The same union is reused by the `notes` field on SchemaDoc and CommandDoc.',
148
148
  },
149
149
  {
150
150
  type: 'code',
@@ -156,9 +156,7 @@ export const docs = {
156
156
  | { type: 'code'; lang: string; code: string; label?: string }
157
157
  | { type: 'table'; headers: string[]; rows: string[][] }
158
158
  | { type: 'list'; style: 'ordered' | 'unordered' | 'do' | 'dont'; items: string[] }
159
- | { type: 'token-ref'; topic: string; section: string };
160
-
161
- type GraphContentBlock =
159
+ | { type: 'token-ref'; topic: string; section: string }
162
160
  | { type: 'workflow'; title?: string; steps: WorkflowStep[] }
163
161
  | { type: 'collection'; source: {slot: string}; presentation?: 'list' | 'cards' | 'compact'; whenEmpty?: 'show' | 'omit' }
164
162
  | { type: 'reference'; target: string; projection?: {fields?: string[]; sections?: string[]} };`,
@@ -41,13 +41,8 @@ export interface ReferenceDocBlock {
41
41
  presentation?: 'summary' | 'compact' | 'full';
42
42
  }
43
43
 
44
- /** Graph-only content blocks. These are additive and do not widen the stable
45
- * {@link ReferenceContentBlock} union consumed by existing exhaustive renderers. */
46
- export type GraphContentBlock =
47
- WorkflowDocBlock | CollectionDocBlock | ReferenceDocBlock;
48
-
49
44
  /**
50
- * A content block within a reference doc section.
45
+ * A content block within a reference doc section or namespace.
51
46
  * Ordered arrays of these blocks form renderer-neutral documentation content.
52
47
  * A new semantic kind must ship with every renderer or fail visibly at a legacy
53
48
  * reader boundary until that renderer is available.
@@ -60,6 +55,9 @@ export type GraphContentBlock =
60
55
  * { type: 'table', headers: ['Token', 'Value'], rows: [['--spacing-4', '16px']] }
61
56
  * { type: 'list', style: 'do', items: ['Use semantic tokens'] }
62
57
  * { type: 'token-ref', topic: 'tokens', section: 'Color Tokens' }
58
+ * { type: 'workflow', steps: [{title: 'Validate', references: ['command:doctor']}] }
59
+ * { type: 'collection', source: {slot: 'guides'}, presentation: 'cards' }
60
+ * { type: 'reference', target: 'schema:integration', projection: {fields: ['docs']} }
63
61
  * ```
64
62
  */
65
63
  export type ReferenceContentBlock =
@@ -82,7 +80,10 @@ export type ReferenceContentBlock =
82
80
  topic: string;
83
81
  /** Section title to pull from that topic. e.g. `'Color Tokens'` */
84
82
  section: string;
85
- };
83
+ }
84
+ | WorkflowDocBlock
85
+ | CollectionDocBlock
86
+ | ReferenceDocBlock;
86
87
 
87
88
  /**
88
89
  * A reference documentation file (.doc.mjs).
@@ -131,7 +131,6 @@ export type {
131
131
  // reference
132
132
  ReferenceSection,
133
133
  ReferenceContentBlock,
134
- GraphContentBlock,
135
134
  ReferenceTokenPreviewType,
136
135
  ReferenceTranslationDoc,
137
136
  WorkflowStep,