@astryxdesign/cli 0.6.3-canary.f22695a → 0.6.3

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 (197) hide show
  1. package/README.md +1 -2
  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 +24 -37
  9. package/api/docs/_adapter.mjs +83 -169
  10. package/api/docs/detail/detail.mjs +63 -14
  11. package/api/docs/detail/section/section.d.mts +1 -1
  12. package/api/docs/detail/section/section.mjs +20 -44
  13. package/api/docs/detail/section/section.test.mjs +0 -41
  14. package/api/docs/docs.d.mts +2 -7
  15. package/api/docs/docs.doc.mjs +10 -27
  16. package/api/docs/docs.mjs +9 -16
  17. package/api/docs/docs.test.mjs +0 -6
  18. package/api/docs/docs.type.d.mts +3 -40
  19. package/api/docs/docs.type.mjs +8 -36
  20. package/api/docs/integrationDocs.test.mjs +0 -106
  21. package/api/doctor/doctor.d.mts +0 -48
  22. package/api/doctor/doctor.mjs +0 -232
  23. package/api/doctor/doctor.test.mjs +0 -196
  24. package/api/hook/hook.type.d.mts +3 -3
  25. package/api/hook/hook.type.mjs +11 -11
  26. package/api/hook/list/list.d.mts +1 -1
  27. package/api/integration/add-contribution.mjs +3 -5
  28. package/api/integration/add-contribution.test.mjs +4 -4
  29. package/api/integration/integration-authoring.type.d.mts +1 -1
  30. package/api/integration/pack-check.mjs +7 -49
  31. package/api/integration/pack-check.test.mjs +0 -249
  32. package/api/search/search.d.mts +1 -1
  33. package/api/search/search.mjs +5 -5
  34. package/api/search/search.type.d.mts +2 -2
  35. package/api/search/search.type.mjs +1 -1
  36. package/api/swizzle/swizzle.type.d.mts +2 -2
  37. package/api/swizzle/swizzle.type.mjs +2 -2
  38. package/api/template/template.d.mts +1 -1
  39. package/api/template/template.type.d.mts +6 -6
  40. package/api/template/template.type.mjs +12 -12
  41. package/api/theme/build/build.mjs +6 -20
  42. package/api/theme/build/build.test.mjs +0 -127
  43. package/api/theme/palette/generate/generate.mjs +1 -1
  44. package/api/theme/palette/generate/generator.d.mts +13 -10
  45. package/api/theme/palette/generate/generator.mjs +3 -7
  46. package/api/theme/theme.type.d.mts +11 -170
  47. package/api/theme/theme.type.mjs +27 -94
  48. package/api/upgrade/_adapter.mjs +5 -71
  49. package/api/upgrade/upgrade.doc.mjs +3 -4
  50. package/api/upgrade/upgrade.type.d.mts +5 -5
  51. package/api/upgrade/upgrade.type.mjs +11 -11
  52. package/assets/codemods/integration-discovery.mjs +2 -40
  53. package/assets/codemods/integration-discovery.test.mjs +0 -58
  54. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +5 -27
  55. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +5 -20
  56. package/assets/docs/README.md +0 -9
  57. package/assets/docs/cli-integrations.doc.mjs +15 -86
  58. package/assets/docs/styling-libraries.doc.mjs +1 -1
  59. package/assets/docs/working-with-ai.doc.mjs +1 -1
  60. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +3 -19
  61. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +65 -383
  62. package/authoring/_shared/contract.ts +0 -22
  63. package/authoring/codemod/codemod.doc.mjs +1 -6
  64. package/authoring/codemod/parse.d.mts +8 -8
  65. package/authoring/codemod/parse.mjs +6 -8
  66. package/authoring/config/parse.d.mts +13 -13
  67. package/authoring/config/parse.mjs +8 -8
  68. package/authoring/config/type.ts +3 -3
  69. package/authoring/debug/parse.d.mts +5 -5
  70. package/authoring/debug/parse.mjs +3 -3
  71. package/authoring/doctypes/_schema.d.mts +23 -788
  72. package/authoring/doctypes/_schema.mjs +39 -492
  73. package/authoring/doctypes/base/type.ts +0 -40
  74. package/authoring/doctypes/command/command.doc.mjs +2 -3
  75. package/authoring/doctypes/command/parse.d.mts +2 -2
  76. package/authoring/doctypes/command/parse.mjs +1 -1
  77. package/authoring/doctypes/command/type.ts +2 -3
  78. package/authoring/doctypes/component/component.doc.mjs +3 -6
  79. package/authoring/doctypes/component/parse.d.mts +2 -2
  80. package/authoring/doctypes/component/parse.mjs +1 -1
  81. package/authoring/doctypes/component/type.ts +3 -4
  82. package/authoring/doctypes/enum/parse.d.mts +2 -2
  83. package/authoring/doctypes/enum/parse.mjs +1 -1
  84. package/authoring/doctypes/enum/type.ts +1 -3
  85. package/authoring/doctypes/function/function.doc.mjs +0 -4
  86. package/authoring/doctypes/function/parse.d.mts +2 -2
  87. package/authoring/doctypes/function/parse.mjs +1 -1
  88. package/authoring/doctypes/function/type.ts +2 -6
  89. package/authoring/doctypes/hook/hook.doc.mjs +0 -4
  90. package/authoring/doctypes/hook/parse.d.mts +2 -2
  91. package/authoring/doctypes/hook/parse.mjs +1 -1
  92. package/authoring/doctypes/hook/type.ts +2 -3
  93. package/authoring/doctypes/legacy.d.mts +6 -8
  94. package/authoring/doctypes/legacy.mjs +4 -5
  95. package/authoring/doctypes/parse.d.mts +18 -20
  96. package/authoring/doctypes/parse.mjs +10 -16
  97. package/authoring/doctypes/parse.test.mjs +3 -77
  98. package/authoring/doctypes/reference/parse.d.mts +2 -2
  99. package/authoring/doctypes/reference/parse.mjs +5 -8
  100. package/authoring/doctypes/reference/reference.doc.mjs +4 -17
  101. package/authoring/doctypes/reference/type.ts +5 -51
  102. package/authoring/doctypes/schema/parse.d.mts +2 -2
  103. package/authoring/doctypes/schema/parse.mjs +1 -1
  104. package/authoring/doctypes/schema/type.ts +2 -3
  105. package/authoring/doctypes/template/parse.d.mts +1 -92
  106. package/authoring/doctypes/template/parse.mjs +2 -36
  107. package/authoring/doctypes/template/parse.test.mjs +2 -8
  108. package/authoring/doctypes/template/template.doc.mjs +0 -4
  109. package/authoring/doctypes/template/type.ts +2 -5
  110. package/authoring/doctypes/types.ts +9 -10
  111. package/authoring/gap-report/parse.d.mts +10 -10
  112. package/authoring/gap-report/parse.mjs +6 -6
  113. package/authoring/gap-report/type.ts +1 -1
  114. package/authoring/index.d.mts +0 -1
  115. package/authoring/index.d.ts +17 -49
  116. package/authoring/index.mjs +0 -1
  117. package/authoring/integration/integration.doc.mjs +6 -13
  118. package/authoring/integration/parse.d.mts +2 -2
  119. package/authoring/integration/parse.mjs +1 -1
  120. package/authoring/integration/parse.test.mjs +1 -10
  121. package/authoring/integration/schema.d.mts +4 -6
  122. package/authoring/integration/schema.mjs +3 -9
  123. package/authoring/integration/type.ts +6 -23
  124. package/authoring/shadcn/receipt.d.mts +6 -6
  125. package/clients/cli/commands/docs.doc.mjs +3 -13
  126. package/clients/cli/commands/docs.mjs +21 -121
  127. package/clients/cli/commands/docs.test.mjs +0 -88
  128. package/clients/cli/commands/integration-authoring.test.mjs +9 -13
  129. package/clients/cli/commands/theme-palette-generate.doc.mjs +4 -8
  130. package/clients/cli/commands/upgrade.doc.mjs +2 -2
  131. package/clients/cli/formatters/index.mjs +1 -162
  132. package/clients/cli/formatters/index.test.mjs +0 -91
  133. package/clients/cli/lib/manifest.mjs +2 -7
  134. package/foundation/config/project.mjs +6 -21
  135. package/foundation/discovery/component-discovery.d.mts +1 -1
  136. package/foundation/discovery/component-discovery.mjs +1 -2
  137. package/foundation/discovery/docs-discovery.d.mts +4 -11
  138. package/foundation/discovery/docs-discovery.mjs +88 -208
  139. package/foundation/discovery/docs-discovery.test.mjs +13 -279
  140. package/foundation/discovery/template-adapter.mjs +1 -2
  141. package/foundation/integrations/autolink.mjs +5 -12
  142. package/foundation/integrations/integration-warnings.mjs +0 -6
  143. package/foundation/integrations/integrations.d.mts +2 -46
  144. package/foundation/integrations/integrations.mjs +8 -167
  145. package/foundation/integrations/integrations.test.mjs +1 -384
  146. package/foundation/integrations/validate-contributions.d.mts +0 -2
  147. package/foundation/integrations/validate-contributions.mjs +0 -10
  148. package/foundation/response/json-contract.test.mjs +17 -46
  149. package/foundation/response/response-types.doc.mjs +1 -6
  150. package/package.json +11 -9
  151. package/api/docs/compiled-topics.test.mjs +0 -78
  152. package/api/docs/index/index.d.mts +0 -18
  153. package/api/docs/index/index.mjs +0 -32
  154. package/api/docs/index/index.test.mjs +0 -62
  155. package/api/upgrade/project-context.test.mjs +0 -272
  156. package/assets/docs/authoring.doc.mjs +0 -14
  157. package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +0 -14
  158. package/assets/templates/blocks/components/Timer/TimerFormats.tsx +0 -34
  159. package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +0 -14
  160. package/assets/templates/blocks/components/Timer/TimerInline.tsx +0 -14
  161. package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +0 -13
  162. package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +0 -47
  163. package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +0 -14
  164. package/assets/templates/blocks/components/Timer/TimerTypography.tsx +0 -31
  165. package/authoring/doctypes/base/graph-fields.doc.d.mts +0 -9
  166. package/authoring/doctypes/base/graph-fields.doc.mjs +0 -62
  167. package/authoring/doctypes/load-contract.test.mjs +0 -207
  168. package/authoring/doctypes/namespace/namespace.doc.d.mts +0 -9
  169. package/authoring/doctypes/namespace/namespace.doc.mjs +0 -132
  170. package/authoring/doctypes/namespace/parse.d.mts +0 -12
  171. package/authoring/doctypes/namespace/parse.mjs +0 -25
  172. package/authoring/doctypes/namespace/parse.test.mjs +0 -165
  173. package/authoring/doctypes/namespace/type.ts +0 -71
  174. package/authoring/identity/identity.doc.d.mts +0 -9
  175. package/authoring/identity/identity.doc.mjs +0 -61
  176. package/authoring/identity/type.ts +0 -132
  177. package/foundation/discovery/authoring-self-docs.d.mts +0 -69
  178. package/foundation/discovery/authoring-self-docs.mjs +0 -214
  179. package/foundation/discovery/authoring-self-docs.test.mjs +0 -154
  180. package/foundation/discovery/docs-output-budget.d.mts +0 -28
  181. package/foundation/discovery/docs-output-budget.mjs +0 -50
  182. package/foundation/discovery/docs-section-key.d.mts +0 -98
  183. package/foundation/discovery/docs-section-key.mjs +0 -221
  184. package/foundation/discovery/docs-section-key.test.mjs +0 -224
  185. package/foundation/doc-compiler/compile.d.mts +0 -162
  186. package/foundation/doc-compiler/compile.mjs +0 -262
  187. package/foundation/doc-compiler/doc-compiler.test.mjs +0 -687
  188. package/foundation/doc-compiler/ir.d.mts +0 -9
  189. package/foundation/doc-compiler/ir.mjs +0 -287
  190. package/foundation/doc-compiler/lenses.d.mts +0 -33
  191. package/foundation/doc-compiler/lenses.mjs +0 -127
  192. package/foundation/identity/provider-identity.d.mts +0 -90
  193. package/foundation/identity/provider-identity.mjs +0 -320
  194. package/foundation/identity/provider-identity.test.mjs +0 -254
  195. package/foundation/identity/providers.d.mts +0 -7
  196. package/foundation/identity/providers.mjs +0 -16
  197. package/foundation/integrations/provider-conflicts.test.mjs +0 -125
@@ -31,9 +31,7 @@ function topic(fields) {
31
31
  name: 'deploying',
32
32
  title: 'Deploying',
33
33
  description: 'How to ship it.',
34
- sections: [
35
- {title: 'Overview', content: [{type: 'prose', text: 'Ship it.'}]},
36
- ],
34
+ sections: [{title: 'Overview', content: [{type: 'prose', text: 'Ship it.'}]}],
37
35
  ...fields,
38
36
  };
39
37
  }
@@ -99,9 +97,7 @@ describe('discoverIntegrationDocs', () => {
99
97
  }),
100
98
  );
101
99
  expect(errors).toEqual([]);
102
- expect(
103
- records.map(r => [r.name, r.package, r.replaces, r.extendsTopic]),
104
- ).toEqual([
100
+ expect(records.map(r => [r.name, r.package, r.replaces, r.extendsTopic])).toEqual([
105
101
  ['deploying', '@acme/widgets', undefined, undefined],
106
102
  ['getting-started', '@acme/widgets', 'getting-started', undefined],
107
103
  ['theme-extra', '@acme/widgets', undefined, 'theme'],
@@ -130,9 +126,7 @@ describe('discoverIntegrationDocs', () => {
130
126
 
131
127
  it('reports a doc that exports nothing, rather than skipping it silently', async () => {
132
128
  const {records, errors} = await discoverIntegrationDocs(
133
- integration('@acme/empty', {
134
- 'deploying.doc.mjs': 'export const nope = 1;\n',
135
- }),
129
+ integration('@acme/empty', {'deploying.doc.mjs': 'export const nope = 1;\n'}),
136
130
  );
137
131
  expect(records).toEqual([]);
138
132
  expect(errors).toHaveLength(1);
@@ -159,49 +153,6 @@ describe('discoverIntegrationDocs', () => {
159
153
  expect(records).toEqual([]);
160
154
  expect(errors[0].message).toContain('declares both');
161
155
  });
162
-
163
- it('rejects graph blocks at the legacy topic-reader boundary', async () => {
164
- const {records, errors} = await discoverIntegrationDocs(
165
- integration('@acme/graph-block', {
166
- 'deploying.doc.mjs': topic({
167
- sections: [
168
- {
169
- id: 'steps',
170
- title: 'Steps',
171
- content: [
172
- {
173
- type: 'workflow',
174
- steps: [{title: 'Install', description: 'Run install.'}],
175
- },
176
- ],
177
- },
178
- ],
179
- }),
180
- }),
181
- );
182
- expect(records).toEqual([]);
183
- expect(errors[0].message).toContain('requires the compiled graph renderer');
184
- });
185
-
186
- it('names a namespace doc instead of listing topic fields it lacks', async () => {
187
- const {records, errors} = await discoverIntegrationDocs(
188
- integration('@acme/namespace', {
189
- 'guides.doc.mjs': {
190
- type: 'namespace',
191
- name: 'guides',
192
- title: 'Guides',
193
- summary: 'Every guide.',
194
- slots: {guides: {title: 'Guides', accepts: {kinds: ['generic']}}},
195
- },
196
- }),
197
- );
198
- expect(records).toEqual([]);
199
- expect(errors).toHaveLength(1);
200
- expect(errors[0].message).toContain(
201
- '"guides" is a namespace doc. Only the docs graph reads namespace docs',
202
- );
203
- expect(errors[0].message).not.toContain('sections:');
204
- });
205
156
  });
206
157
 
207
158
  describe('problemsInTopic', () => {
@@ -219,11 +170,7 @@ describe('problemsInTopic', () => {
219
170
  // A misspelled required field: the block renders nothing at all.
220
171
  expect(
221
172
  problemsInTopic(
222
- topic({
223
- sections: [
224
- {title: 'Overview', content: [{type: 'prose', txt: 'oops'}]},
225
- ],
226
- }),
173
+ topic({sections: [{title: 'Overview', content: [{type: 'prose', txt: 'oops'}]}]}),
227
174
  ),
228
175
  ).toEqual([
229
176
  'sections[0].content[0].text: required for a prose block',
@@ -233,12 +180,7 @@ describe('problemsInTopic', () => {
233
180
  expect(
234
181
  problemsInTopic(
235
182
  topic({
236
- sections: [
237
- {
238
- title: 'Overview',
239
- content: [{type: 'heading', level: 2, text: 'x'}],
240
- },
241
- ],
183
+ sections: [{title: 'Overview', content: [{type: 'heading', level: 2, text: 'x'}]}],
242
184
  }),
243
185
  ),
244
186
  ).toContain('sections[0].content[0].level: 2 is not one of 3, 4, 5, 6');
@@ -254,27 +196,11 @@ describe('problemsInTopic', () => {
254
196
  ],
255
197
  }),
256
198
  ),
257
- ).toContain(
258
- 'sections[0].content[0].rows[0]: has 1 cells but the table has 2 headers',
259
- );
260
- });
261
-
262
- it('rejects graph metadata at the legacy topic-reader boundary', () => {
263
- for (const fields of [
264
- {placement: {parent: 'namespace:cli'}},
265
- {aliases: ['setup']},
266
- {audience: 'internal'},
267
- ]) {
268
- expect(problemsInTopic(topic(fields)).join('\n')).toContain(
269
- 'requires the compiled graph reader',
270
- );
271
- }
199
+ ).toContain('sections[0].content[0].rows[0]: has 1 cells but the table has 2 headers');
272
200
  });
273
201
 
274
202
  it('rejects a name that is not URL-safe', () => {
275
- expect(problemsInTopic(topic({name: 'not a topic'})).join('\n')).toContain(
276
- 'URL-safe',
277
- );
203
+ expect(problemsInTopic(topic({name: 'not a topic'})).join('\n')).toContain('URL-safe');
278
204
  });
279
205
  });
280
206
 
@@ -302,23 +228,11 @@ describe('DocsCatalog', () => {
302
228
  expect(catalog.resolve('deploying').package).toBe('@acme/widgets');
303
229
  });
304
230
 
305
- it('treats topic identities case-insensitively without losing display case', () => {
306
- const catalog = DocsCatalog.fromBuiltins();
307
- expect(catalog.add(record({name: 'Deploying'}))).toBeNull();
308
- expect(catalog.resolve('deploying').name).toBe('Deploying');
309
- expect(catalog.resolve('DEPLOYING').name).toBe('Deploying');
310
-
311
- const issue = catalog.add(
312
- record({name: 'deploying', package: '@acme/duplicate'}),
313
- );
314
- expect(issue).toMatchObject({code: 'invalid_doc', severity: 'error'});
315
- });
316
-
317
231
  it('refuses to shadow an existing topic by name alone', () => {
318
232
  const catalog = DocsCatalog.fromBuiltins({tokens: '/cli/tokens.doc.mjs'});
319
233
  const issue = catalog.add(record({name: 'tokens'}));
320
234
  expect(issue).toMatchObject({code: 'invalid_doc', severity: 'error'});
321
- expect(issue.message).toContain('already provided by @astryxdesign/cli');
235
+ expect(issue.message).toContain("already provided by @astryxdesign/cli");
322
236
  expect(issue.message).toContain("replaces: 'tokens'");
323
237
  // The built-in topic is untouched.
324
238
  expect(catalog.resolve('tokens').package).toBe(BUILTIN_DOCS_PACKAGE);
@@ -330,9 +244,7 @@ describe('DocsCatalog', () => {
330
244
  tokens: '/cli/tokens.doc.mjs',
331
245
  });
332
246
  expect(
333
- catalog.add(
334
- record({name: 'getting-started', replaces: 'getting-started'}),
335
- ),
247
+ catalog.add(record({name: 'getting-started', replaces: 'getting-started'})),
336
248
  ).toBeNull();
337
249
  expect(catalog.names()).toEqual(['getting-started', 'tokens']);
338
250
  const entry = catalog.resolve('getting-started');
@@ -364,16 +276,12 @@ describe('DocsCatalog', () => {
364
276
 
365
277
  it('warns, and lets the later package win, when two replace one topic', () => {
366
278
  const catalog = DocsCatalog.fromBuiltins({tokens: '/cli/tokens.doc.mjs'});
367
- expect(
368
- catalog.add(record({name: 'tokens', replaces: 'tokens'})),
369
- ).toBeNull();
279
+ expect(catalog.add(record({name: 'tokens', replaces: 'tokens'}))).toBeNull();
370
280
  const issue = catalog.add(
371
281
  record({name: 'tokens', package: '@acme/later', replaces: 'tokens'}),
372
282
  );
373
283
  expect(issue).toMatchObject({code: 'duplicate_doc', severity: 'warning'});
374
- expect(issue.message).toContain(
375
- '@acme/later is configured later, so it wins',
376
- );
284
+ expect(issue.message).toContain('@acme/later is configured later, so it wins');
377
285
  expect(catalog.resolve('tokens').package).toBe('@acme/later');
378
286
  });
379
287
 
@@ -419,189 +327,15 @@ describe('mergeTopic', () => {
419
327
  {title: 'Internal', content: [{type: 'prose', text: 'the meta way'}]},
420
328
  ],
421
329
  });
422
- expect(merged.sections.map(s => s.title)).toEqual([
423
- 'Install',
424
- 'Tokens',
425
- 'Internal',
426
- ]);
330
+ expect(merged.sections.map(s => s.title)).toEqual(['Install', 'Tokens', 'Internal']);
427
331
  expect(merged.sections[0].content[0].text).toBe('yarn add');
428
332
  expect(merged.sections[1].content[0].text).toBe('use tokens');
429
333
  // The base is untouched.
430
334
  expect(base.sections[0].content[0].text).toBe('npm i');
431
335
  });
432
336
 
433
- it('replaces a section by stable ID even when its title changes', () => {
434
- const merged = mergeTopic(
435
- {
436
- ...base,
437
- sections: [
438
- {id: 'install', title: 'Install', content: []},
439
- {id: 'tokens', title: 'Tokens', content: []},
440
- ],
441
- },
442
- {
443
- sections: [{id: 'install', title: 'Setup', content: []}],
444
- },
445
- );
446
- expect(merged.sections.map(section => [section.id, section.title])).toEqual(
447
- [
448
- ['install', 'Setup'],
449
- ['tokens', 'Tokens'],
450
- ],
451
- );
452
- });
453
-
454
- it('migrates a legacy section to a stable ID without duplicating it', () => {
455
- const merged = mergeTopic(base, {
456
- sections: [
457
- {
458
- id: 'install',
459
- title: 'Install',
460
- content: [{type: 'prose', text: 'yarn add'}],
461
- },
462
- ],
463
- });
464
- expect(
465
- merged.sections.map(section => [section.id ?? null, section.title]),
466
- ).toEqual([
467
- ['install', 'Install'],
468
- [null, 'Tokens'],
469
- ]);
470
- expect(merged.sections[0].content[0].text).toBe('yarn add');
471
- });
472
-
473
- it('lets a legacy extension replace a section that has since gained an ID', () => {
474
- const merged = mergeTopic(
475
- {
476
- ...base,
477
- sections: [
478
- {id: 'setup-steps', title: 'Install', content: []},
479
- {title: 'Tokens', content: []},
480
- ],
481
- },
482
- {
483
- sections: [
484
- {title: 'Install', content: [{type: 'prose', text: 'yarn add'}]},
485
- ],
486
- },
487
- );
488
- expect(
489
- merged.sections.map(section => [section.id ?? null, section.title]),
490
- ).toEqual([
491
- ['setup-steps', 'Install'],
492
- [null, 'Tokens'],
493
- ]);
494
- expect(merged.sections[0].content[0].text).toBe('yarn add');
495
- });
496
-
497
- it('keeps two different authored IDs distinct under one title', () => {
498
- const merged = mergeTopic(
499
- {...base, sections: [{id: 'install', title: 'Install', content: []}]},
500
- {sections: [{id: 'install-yarn', title: 'Install', content: []}]},
501
- );
502
- expect(merged.sections.map(section => section.id)).toEqual([
503
- 'install',
504
- 'install-yarn',
505
- ]);
506
- });
507
-
508
337
  it('takes the title and description only when the overlay states them', () => {
509
338
  expect(mergeTopic(base, {sections: []}).title).toBe('Theme');
510
- expect(mergeTopic(base, {title: 'Theming', sections: []}).title).toBe(
511
- 'Theming',
512
- );
513
- });
514
- });
515
-
516
- describe('problemsInTopic section keys', () => {
517
- /** @param {object[]} sections */
518
- const doc = sections => ({
519
- type: 'generic',
520
- name: 'keys',
521
- title: 'Keys',
522
- description: 'Section keys.',
523
- sections: sections.map(s => ({
524
- content: [{type: 'prose', text: 'x'}],
525
- ...s,
526
- })),
527
- });
528
-
529
- it('rejects two sections that derive the same key', () => {
530
- expect(
531
- problemsInTopic(doc([{title: 'Quick Start'}, {title: 'Quick-start'}])),
532
- ).toEqual([
533
- expect.stringContaining('"quick-start" is already used by sections[0]'),
534
- ]);
535
- });
536
-
537
- it('rejects an unsafe id', () => {
538
- expect(
539
- problemsInTopic(doc([{id: 'Quick Start', title: 'Quick Start'}])),
540
- ).toEqual([expect.stringContaining('is not a stable key')]);
541
- });
542
-
543
- it('rejects a title no key derives from, unless it has an id', () => {
544
- expect(problemsInTopic(doc([{title: '亮/暗模式'}]))).toEqual([
545
- expect.stringContaining('Give the section an id'),
546
- ]);
547
- expect(
548
- problemsInTopic(doc([{id: 'light-dark', title: '亮/暗模式'}])),
549
- ).toEqual([]);
550
- });
551
- });
552
-
553
- describe('mergeTopic by section key', () => {
554
- const base = {
555
- title: 'Theme',
556
- sections: [
557
- {title: 'Quick Start', content: [{type: 'prose', text: 'base'}]},
558
- {title: 'Light/Dark Mode', content: [{type: 'prose', text: 'base'}]},
559
- ],
560
- };
561
- const titles = doc =>
562
- doc.sections.map(s => [s.id ?? null, s.title, s.content[0].text]);
563
-
564
- it('replaces the section whose derived key an extension id names', () => {
565
- const merged = mergeTopic(base, {
566
- sections: [
567
- {
568
- id: 'quick-start',
569
- title: 'Quick Start with Acme',
570
- content: [{type: 'prose', text: 'acme'}],
571
- },
572
- ],
573
- });
574
- expect(titles(merged)).toEqual([
575
- ['quick-start', 'Quick Start with Acme', 'acme'],
576
- [null, 'Light/Dark Mode', 'base'],
577
- ]);
578
- });
579
-
580
- it('replaces the section a title variant derives the same key as', () => {
581
- const merged = mergeTopic(base, {
582
- sections: [
583
- {title: 'Light-Dark Mode', content: [{type: 'prose', text: 'acme'}]},
584
- ],
585
- });
586
- expect(titles(merged)).toEqual([
587
- [null, 'Quick Start', 'base'],
588
- [null, 'Light-Dark Mode', 'acme'],
589
- ]);
590
- });
591
-
592
- it('prefers the key over a legacy title for an extension with an id', () => {
593
- const merged = mergeTopic(base, {
594
- sections: [
595
- {
596
- id: 'light-dark-mode',
597
- title: 'Quick Start',
598
- content: [{type: 'prose', text: 'acme'}],
599
- },
600
- ],
601
- });
602
- expect(titles(merged)).toEqual([
603
- [null, 'Quick Start', 'base'],
604
- ['light-dark-mode', 'Quick Start', 'acme'],
605
- ]);
339
+ expect(mergeTopic(base, {title: 'Theming', sections: []}).title).toBe('Theming');
606
340
  });
607
341
  });
@@ -27,11 +27,10 @@ import {createJiti} from 'jiti';
27
27
  import {loadModuleWithParser} from '../fs/module-loader.mjs';
28
28
  import {parseTemplate} from '../../authoring/doctypes/template/parse.mjs';
29
29
  import {CLI_ROOT, discoverExternalPackages} from '../fs/paths.mjs';
30
- import {CORE_PROVIDER_ID} from '../identity/providers.mjs';
31
30
  import {Project} from '../config/project.mjs';
32
31
 
33
32
  /** Identity used for core (built-in) templates in package-scoped listings. */
34
- const CORE_PACKAGE = CORE_PROVIDER_ID;
33
+ const CORE_PACKAGE = '@astryxdesign/core';
35
34
 
36
35
  /**
37
36
  * Identity for a template in package-scoped views. Core (built-in) templates
@@ -234,13 +234,7 @@ export async function autolinkIntegrations({
234
234
 
235
235
  /** @type {import('./integrations.mjs').LoadedIntegration[]} */
236
236
  const autolinked = [];
237
- // One package reached twice (an alias beside the package it aliases, at the
238
- // same version) loads once. The same name at another version is kept, so the
239
- // provider-identity pass in Project.load reports it instead of dropping it.
240
- /** @param {{name: string, version?: string}} integration */
241
- const identity = integration =>
242
- `${integration.name}\u0000${integration.version ?? ''}`;
243
- const seen = new Set(loaded.map(identity));
237
+ const names = new Set(loaded.map(integration => integration.name));
244
238
 
245
239
  for (const candidate of candidates) {
246
240
  /** @type {import('./integrations.mjs').LoadedIntegration|undefined} */
@@ -256,11 +250,10 @@ export async function autolinkIntegrations({
256
250
  continue;
257
251
  }
258
252
  if (!integration || integration.__loadError) continue;
259
- // Identity is the resolved package's own name and version, so an alias and
260
- // the package it aliases collapse here even when they are two directories
261
- // on disk.
262
- if (seen.has(identity(integration))) continue;
263
- seen.add(identity(integration));
253
+ // Identity is the resolved package's own name, so an alias and the package
254
+ // it aliases collapse here even when they are two directories on disk.
255
+ if (names.has(integration.name)) continue;
256
+ names.add(integration.name);
264
257
  autolinked.push({
265
258
  ...integration,
266
259
  __autolinked: true,
@@ -41,12 +41,6 @@ export async function warnOnIntegrationIssues(loadedIntegrations, {json = false}
41
41
  }
42
42
  for (const integration of loadedIntegrations) {
43
43
  if (!integration || typeof integration !== 'object') continue;
44
- // A package set aside for a provider-ID conflict is fine in isolation,
45
- // so `doctor integration validate` would not explain it. Say it here.
46
- if (integration.__providerConflict) {
47
- console.error(`Warning: ${integration.__providerConflict.message}`);
48
- continue;
49
- }
50
44
  let issues;
51
45
  try {
52
46
  issues = await validateLoadedIntegration(integration);
@@ -1,23 +1,6 @@
1
1
  // @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
2
2
  // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
3
 
4
- /**
5
- * Resolve provider identity across loaded integrations, in precedence order.
6
- *
7
- * Artifact and document IDs are provider-scoped, so two packages cannot both
8
- * contribute under one provider ID. The same package reached twice (an npm
9
- * alias beside the package it aliases, with the same name and version) loads
10
- * once. Any other later claimant, including the same package at another
11
- * version, stays as an inert entry that carries the conflict. The package being
12
- * authored claims its ID before precedence order is considered, because the
13
- * source being edited is authoritative. The winner still contributes; Project
14
- * issues, Doctor, and the per-command warning name the one set aside instead of
15
- * dropping it without a word.
16
- *
17
- * @param {LoadedIntegration[]} integrations in precedence order
18
- * @returns {LoadedIntegration[]}
19
- */
20
- export function markProviderConflicts(integrations: LoadedIntegration[]): LoadedIntegration[];
21
4
  /**
22
5
  * Return the conventional root manifest paths present in `dir`, in
23
6
  * load-precedence order. Unlike {@link resolveManifestPath} this never throws —
@@ -92,15 +75,12 @@ export function loadLocalIntegration(packageDir: string, { fresh }?: {
92
75
  * Load configured integrations.
93
76
  *
94
77
  * @param {string[]} [specs] package names
95
- * @param {{cwd?: string, fresh?: boolean, resolveProviders?: boolean}} [options]
96
- * `resolveProviders: false` leaves provider identity to a caller that
97
- * resolves it once over a larger set (Project.load)
78
+ * @param {{cwd?: string, fresh?: boolean}} [options]
98
79
  * @returns {Promise<LoadedIntegration[]>}
99
80
  */
100
- export function loadIntegrations(specs?: string[], { cwd, fresh, resolveProviders }?: {
81
+ export function loadIntegrations(specs?: string[], { cwd, fresh }?: {
101
82
  cwd?: string;
102
83
  fresh?: boolean;
103
- resolveProviders?: boolean;
104
84
  }): Promise<LoadedIntegration[]>;
105
85
  /**
106
86
  * A fully-resolved, loaded integration. Identity (`name`, `version`) comes from
@@ -109,10 +89,6 @@ export function loadIntegrations(specs?: string[], { cwd, fresh, resolveProvider
109
89
  * are internal bookkeeping used by Doctor integration validation and Project.
110
90
  * @typedef {object} LoadedIntegration
111
91
  * @property {string} name
112
- * @property {import('../../authoring/identity/type').ProviderId} [providerId]
113
- * normalized stable provider identity; absent only for a legacy unnamed local
114
- * package. Unique among contributing integrations: a later claimant is kept
115
- * inert with `__providerConflict` (see {@link markProviderConflicts})
116
92
  * @property {string} [version]
117
93
  * @property {string} [components]
118
94
  * @property {string} [templates]
@@ -131,10 +107,6 @@ export function loadIntegrations(specs?: string[], { cwd, fresh, resolveProvider
131
107
  * @property {string} __manifestFile
132
108
  * @property {string} [__loadError] set when the manifest failed to load/validate;
133
109
  * such an integration contributes nothing and is surfaced via Project.issues()
134
- * @property {{providerId: import('../../authoring/identity/type').ProviderId, claimedBy: string, message: string}} [__providerConflict]
135
- * set on a package whose provider ID an earlier-loaded package already
136
- * claims; it contributes nothing and is reported as a `duplicate_provider`
137
- * warning
138
110
  * @property {string[]} [__unknownKeys] manifest keys this CLI does not know —
139
111
  * surfaced as a warning; the rest of the manifest still contributes
140
112
  * @property {boolean} [__autolinked] loaded because the project declares the
@@ -162,12 +134,6 @@ export const MANIFEST_BASENAMES: string[];
162
134
  */
163
135
  export type LoadedIntegration = {
164
136
  name: string;
165
- /**
166
- * normalized stable provider identity; absent only for a legacy unnamed local
167
- * package. Unique among contributing integrations: a later claimant is kept
168
- * inert with `__providerConflict` (see {@link markProviderConflicts})
169
- */
170
- providerId?: import("../../authoring/identity/type").ProviderId | undefined;
171
137
  version?: string | undefined;
172
138
  components?: string | undefined;
173
139
  templates?: string | undefined;
@@ -197,16 +163,6 @@ export type LoadedIntegration = {
197
163
  * such an integration contributes nothing and is surfaced via Project.issues()
198
164
  */
199
165
  __loadError?: string | undefined;
200
- /**
201
- * set on a package whose provider ID an earlier-loaded package already
202
- * claims; it contributes nothing and is reported as a `duplicate_provider`
203
- * warning
204
- */
205
- __providerConflict?: {
206
- providerId: import("../../authoring/identity/type").ProviderId;
207
- claimedBy: string;
208
- message: string;
209
- } | undefined;
210
166
  /**
211
167
  * manifest keys this CLI does not know —
212
168
  * surfaced as a warning; the rest of the manifest still contributes