@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.
- package/README.md +1 -2
- package/api/build/build.type.d.mts +2 -2
- package/api/build/build.type.mjs +2 -2
- package/api/component/component.type.d.mts +6 -6
- package/api/component/component.type.mjs +19 -19
- package/api/discover/discover.type.d.mts +4 -4
- package/api/discover/discover.type.mjs +10 -10
- package/api/docs/_adapter.d.mts +24 -37
- package/api/docs/_adapter.mjs +83 -169
- package/api/docs/detail/detail.mjs +63 -14
- package/api/docs/detail/section/section.d.mts +1 -1
- package/api/docs/detail/section/section.mjs +20 -44
- package/api/docs/detail/section/section.test.mjs +0 -41
- package/api/docs/docs.d.mts +2 -7
- package/api/docs/docs.doc.mjs +10 -27
- package/api/docs/docs.mjs +9 -16
- package/api/docs/docs.test.mjs +0 -6
- package/api/docs/docs.type.d.mts +3 -40
- package/api/docs/docs.type.mjs +8 -36
- package/api/docs/integrationDocs.test.mjs +0 -106
- package/api/doctor/doctor.d.mts +0 -48
- package/api/doctor/doctor.mjs +0 -232
- package/api/doctor/doctor.test.mjs +0 -196
- package/api/hook/hook.type.d.mts +3 -3
- package/api/hook/hook.type.mjs +11 -11
- package/api/hook/list/list.d.mts +1 -1
- package/api/integration/add-contribution.mjs +3 -5
- package/api/integration/add-contribution.test.mjs +4 -4
- package/api/integration/integration-authoring.type.d.mts +1 -1
- package/api/integration/pack-check.mjs +7 -49
- package/api/integration/pack-check.test.mjs +0 -249
- package/api/search/search.d.mts +1 -1
- package/api/search/search.mjs +5 -5
- package/api/search/search.type.d.mts +2 -2
- package/api/search/search.type.mjs +1 -1
- package/api/swizzle/swizzle.type.d.mts +2 -2
- package/api/swizzle/swizzle.type.mjs +2 -2
- package/api/template/template.d.mts +1 -1
- package/api/template/template.type.d.mts +6 -6
- package/api/template/template.type.mjs +12 -12
- package/api/theme/build/build.mjs +6 -20
- package/api/theme/build/build.test.mjs +0 -127
- package/api/theme/palette/generate/generate.mjs +1 -1
- package/api/theme/palette/generate/generator.d.mts +13 -10
- package/api/theme/palette/generate/generator.mjs +3 -7
- package/api/theme/theme.type.d.mts +11 -170
- package/api/theme/theme.type.mjs +27 -94
- package/api/upgrade/_adapter.mjs +5 -71
- package/api/upgrade/upgrade.doc.mjs +3 -4
- package/api/upgrade/upgrade.type.d.mts +5 -5
- package/api/upgrade/upgrade.type.mjs +11 -11
- package/assets/codemods/integration-discovery.mjs +2 -40
- package/assets/codemods/integration-discovery.test.mjs +0 -58
- package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +5 -27
- package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +5 -20
- package/assets/docs/README.md +0 -9
- package/assets/docs/cli-integrations.doc.mjs +15 -86
- package/assets/docs/styling-libraries.doc.mjs +1 -1
- package/assets/docs/working-with-ai.doc.mjs +1 -1
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +3 -19
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +65 -383
- package/authoring/_shared/contract.ts +0 -22
- package/authoring/codemod/codemod.doc.mjs +1 -6
- package/authoring/codemod/parse.d.mts +8 -8
- package/authoring/codemod/parse.mjs +6 -8
- package/authoring/config/parse.d.mts +13 -13
- package/authoring/config/parse.mjs +8 -8
- package/authoring/config/type.ts +3 -3
- package/authoring/debug/parse.d.mts +5 -5
- package/authoring/debug/parse.mjs +3 -3
- package/authoring/doctypes/_schema.d.mts +23 -788
- package/authoring/doctypes/_schema.mjs +39 -492
- package/authoring/doctypes/base/type.ts +0 -40
- package/authoring/doctypes/command/command.doc.mjs +2 -3
- package/authoring/doctypes/command/parse.d.mts +2 -2
- package/authoring/doctypes/command/parse.mjs +1 -1
- package/authoring/doctypes/command/type.ts +2 -3
- package/authoring/doctypes/component/component.doc.mjs +3 -6
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +3 -4
- package/authoring/doctypes/enum/parse.d.mts +2 -2
- package/authoring/doctypes/enum/parse.mjs +1 -1
- package/authoring/doctypes/enum/type.ts +1 -3
- package/authoring/doctypes/function/function.doc.mjs +0 -4
- package/authoring/doctypes/function/parse.d.mts +2 -2
- package/authoring/doctypes/function/parse.mjs +1 -1
- package/authoring/doctypes/function/type.ts +2 -6
- package/authoring/doctypes/hook/hook.doc.mjs +0 -4
- package/authoring/doctypes/hook/parse.d.mts +2 -2
- package/authoring/doctypes/hook/parse.mjs +1 -1
- package/authoring/doctypes/hook/type.ts +2 -3
- package/authoring/doctypes/legacy.d.mts +6 -8
- package/authoring/doctypes/legacy.mjs +4 -5
- package/authoring/doctypes/parse.d.mts +18 -20
- package/authoring/doctypes/parse.mjs +10 -16
- package/authoring/doctypes/parse.test.mjs +3 -77
- package/authoring/doctypes/reference/parse.d.mts +2 -2
- package/authoring/doctypes/reference/parse.mjs +5 -8
- package/authoring/doctypes/reference/reference.doc.mjs +4 -17
- package/authoring/doctypes/reference/type.ts +5 -51
- package/authoring/doctypes/schema/parse.d.mts +2 -2
- package/authoring/doctypes/schema/parse.mjs +1 -1
- package/authoring/doctypes/schema/type.ts +2 -3
- package/authoring/doctypes/template/parse.d.mts +1 -92
- package/authoring/doctypes/template/parse.mjs +2 -36
- package/authoring/doctypes/template/parse.test.mjs +2 -8
- package/authoring/doctypes/template/template.doc.mjs +0 -4
- package/authoring/doctypes/template/type.ts +2 -5
- package/authoring/doctypes/types.ts +9 -10
- package/authoring/gap-report/parse.d.mts +10 -10
- package/authoring/gap-report/parse.mjs +6 -6
- package/authoring/gap-report/type.ts +1 -1
- package/authoring/index.d.mts +0 -1
- package/authoring/index.d.ts +17 -49
- package/authoring/index.mjs +0 -1
- package/authoring/integration/integration.doc.mjs +6 -13
- package/authoring/integration/parse.d.mts +2 -2
- package/authoring/integration/parse.mjs +1 -1
- package/authoring/integration/parse.test.mjs +1 -10
- package/authoring/integration/schema.d.mts +4 -6
- package/authoring/integration/schema.mjs +3 -9
- package/authoring/integration/type.ts +6 -23
- package/authoring/shadcn/receipt.d.mts +6 -6
- package/clients/cli/commands/docs.doc.mjs +3 -13
- package/clients/cli/commands/docs.mjs +21 -121
- package/clients/cli/commands/docs.test.mjs +0 -88
- package/clients/cli/commands/integration-authoring.test.mjs +9 -13
- package/clients/cli/commands/theme-palette-generate.doc.mjs +4 -8
- package/clients/cli/commands/upgrade.doc.mjs +2 -2
- package/clients/cli/formatters/index.mjs +1 -162
- package/clients/cli/formatters/index.test.mjs +0 -91
- package/clients/cli/lib/manifest.mjs +2 -7
- package/foundation/config/project.mjs +6 -21
- package/foundation/discovery/component-discovery.d.mts +1 -1
- package/foundation/discovery/component-discovery.mjs +1 -2
- package/foundation/discovery/docs-discovery.d.mts +4 -11
- package/foundation/discovery/docs-discovery.mjs +88 -208
- package/foundation/discovery/docs-discovery.test.mjs +13 -279
- package/foundation/discovery/template-adapter.mjs +1 -2
- package/foundation/integrations/autolink.mjs +5 -12
- package/foundation/integrations/integration-warnings.mjs +0 -6
- package/foundation/integrations/integrations.d.mts +2 -46
- package/foundation/integrations/integrations.mjs +8 -167
- package/foundation/integrations/integrations.test.mjs +1 -384
- package/foundation/integrations/validate-contributions.d.mts +0 -2
- package/foundation/integrations/validate-contributions.mjs +0 -10
- package/foundation/response/json-contract.test.mjs +17 -46
- package/foundation/response/response-types.doc.mjs +1 -6
- package/package.json +11 -9
- package/api/docs/compiled-topics.test.mjs +0 -78
- package/api/docs/index/index.d.mts +0 -18
- package/api/docs/index/index.mjs +0 -32
- package/api/docs/index/index.test.mjs +0 -62
- package/api/upgrade/project-context.test.mjs +0 -272
- package/assets/docs/authoring.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerFormats.tsx +0 -34
- package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerInline.tsx +0 -14
- package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +0 -13
- package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +0 -47
- package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerTypography.tsx +0 -31
- package/authoring/doctypes/base/graph-fields.doc.d.mts +0 -9
- package/authoring/doctypes/base/graph-fields.doc.mjs +0 -62
- package/authoring/doctypes/load-contract.test.mjs +0 -207
- package/authoring/doctypes/namespace/namespace.doc.d.mts +0 -9
- package/authoring/doctypes/namespace/namespace.doc.mjs +0 -132
- package/authoring/doctypes/namespace/parse.d.mts +0 -12
- package/authoring/doctypes/namespace/parse.mjs +0 -25
- package/authoring/doctypes/namespace/parse.test.mjs +0 -165
- package/authoring/doctypes/namespace/type.ts +0 -71
- package/authoring/identity/identity.doc.d.mts +0 -9
- package/authoring/identity/identity.doc.mjs +0 -61
- package/authoring/identity/type.ts +0 -132
- package/foundation/discovery/authoring-self-docs.d.mts +0 -69
- package/foundation/discovery/authoring-self-docs.mjs +0 -214
- package/foundation/discovery/authoring-self-docs.test.mjs +0 -154
- package/foundation/discovery/docs-output-budget.d.mts +0 -28
- package/foundation/discovery/docs-output-budget.mjs +0 -50
- package/foundation/discovery/docs-section-key.d.mts +0 -98
- package/foundation/discovery/docs-section-key.mjs +0 -221
- package/foundation/discovery/docs-section-key.test.mjs +0 -224
- package/foundation/doc-compiler/compile.d.mts +0 -162
- package/foundation/doc-compiler/compile.mjs +0 -262
- package/foundation/doc-compiler/doc-compiler.test.mjs +0 -687
- package/foundation/doc-compiler/ir.d.mts +0 -9
- package/foundation/doc-compiler/ir.mjs +0 -287
- package/foundation/doc-compiler/lenses.d.mts +0 -33
- package/foundation/doc-compiler/lenses.mjs +0 -127
- package/foundation/identity/provider-identity.d.mts +0 -90
- package/foundation/identity/provider-identity.mjs +0 -320
- package/foundation/identity/provider-identity.test.mjs +0 -254
- package/foundation/identity/providers.d.mts +0 -7
- package/foundation/identity/providers.mjs +0 -16
- 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(
|
|
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 =
|
|
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
|
-
|
|
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
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
|
|
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
|
|
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
|
|
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
|