@astryxdesign/cli 0.6.3-canary.db4e378 → 0.6.3-canary.ddb63c3
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 +20 -1
- package/api/blog/blog.doc.mjs +1 -0
- package/api/build/build.doc.mjs +1 -0
- package/api/component/component.doc.mjs +1 -0
- package/api/discover/discover.doc.mjs +1 -0
- package/api/docs/_adapter.d.mts +3 -8
- package/api/docs/_adapter.mjs +13 -105
- package/api/docs/docs.doc.mjs +1 -0
- package/api/docs/list/list.mjs +3 -7
- package/api/doctor/doctor.d.mts +25 -3
- package/api/doctor/doctor.doc.mjs +1 -0
- package/api/doctor/doctor.mjs +185 -13
- package/api/doctor/doctor.test.mjs +326 -1
- package/api/gap-report/gap-report.doc.mjs +1 -0
- package/api/hook/_adapter.mjs +19 -5
- package/api/hook/hook.doc.mjs +1 -0
- package/api/hook/list/list.d.mts +1 -1
- package/api/hook/list/list.mjs +69 -17
- package/api/init/init.doc.mjs +1 -0
- package/api/integration/add-contribution.mjs +7 -7
- package/api/integration/add-contribution.test.mjs +37 -3
- package/api/integration/add-theme.mjs +34 -64
- package/api/integration/add-theme.test.mjs +105 -21
- package/api/integration/authoring-checks.test.mjs +8 -4
- package/api/integration/integration-block-exports.test.mjs +10 -6
- package/api/integration/integrationAdd.doc.mjs +1 -0
- package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
- package/api/integration/integrationAddCodemod.doc.mjs +1 -0
- package/api/integration/integrationAddComponent.doc.mjs +1 -0
- package/api/integration/integrationAddDoc.doc.mjs +1 -0
- package/api/integration/integrationAddTemplate.doc.mjs +1 -0
- package/api/integration/integrationAddTheme.doc.mjs +6 -5
- package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
- package/api/integration/integrationDocConflicts.doc.mjs +1 -0
- package/api/integration/integrationPackCheck.doc.mjs +1 -0
- package/api/integration/integrationTemplateConflicts.doc.mjs +1 -0
- package/api/integration/pack-check.test.mjs +17 -47
- package/api/integration/summarizeIssues.doc.mjs +1 -0
- package/api/integration/validate-integration-fixes.test.mjs +1389 -0
- package/api/integration/validate-integration.mjs +50 -102
- package/api/integration/validate-integration.test.mjs +85 -23
- package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
- package/api/integration/validateIntegration.doc.mjs +1 -0
- package/api/json/assertResponse.doc.mjs +1 -0
- package/api/json/isError.doc.mjs +1 -0
- package/api/json/parseResponse.doc.mjs +1 -0
- package/api/layout/layoutCheck.doc.mjs +1 -0
- package/api/layout/layoutExpand.doc.mjs +1 -0
- package/api/layout/layoutGrammar.doc.mjs +1 -0
- package/api/search/search.doc.mjs +1 -0
- package/api/search/search.mjs +16 -6
- package/api/swizzle/swizzle.doc.mjs +1 -0
- package/api/template/template-suffix.test.mjs +41 -21
- package/api/template/template.doc.mjs +1 -0
- package/api/theme/_adapter.d.mts +2 -3
- package/api/theme/_adapter.mjs +4 -5
- package/api/theme/add/add.binary.test.mjs +10 -17
- package/api/theme/add/add.test.mjs +14 -1
- package/api/theme/generateTonalPalette.doc.mjs +1 -0
- package/api/theme/integration-themes.test.mjs +39 -28
- package/api/theme/list/list.test.mjs +19 -20
- package/api/theme/listThemes.doc.mjs +6 -5
- package/api/theme/themeAdd.doc.mjs +4 -3
- package/api/theme/themeBuild.doc.mjs +1 -0
- package/api/theme/themeList.doc.mjs +6 -3
- package/api/theme/themeListAvailable.doc.mjs +5 -3
- package/api/theme/themePaletteGenerate.doc.mjs +1 -0
- package/api/theme/themeTargets.doc.mjs +1 -0
- package/api/theme/themeTemplate.doc.mjs +1 -0
- package/api/upgrade/_adapter.d.mts +12 -3
- package/api/upgrade/_adapter.mjs +81 -66
- package/api/upgrade/provider-agreement.test.mjs +152 -0
- package/api/upgrade/run/run.mjs +1 -0
- package/api/upgrade/upgrade.doc.mjs +1 -0
- package/assets/codemods/integration-discovery.mjs +8 -2
- package/assets/codemods/integration-discovery.test.mjs +15 -0
- package/assets/codemods/runner.mjs +115 -5
- package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +216 -0
- package/assets/codemods/transforms/next/index.mjs +11 -1
- package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
- package/assets/docs/cli-integrations.doc.mjs +17 -30
- package/assets/docs/cli.doc.mjs +15 -0
- package/assets/docs/theme.doc.mjs +1 -1
- package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
- package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
- package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
- package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
- package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
- package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
- package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
- package/authoring/codemod/codemod.doc.mjs +1 -1
- package/authoring/config/config.doc.mjs +1 -1
- package/authoring/debug/debug.doc.d.mts +11 -0
- package/authoring/debug/debug.doc.mjs +182 -0
- package/authoring/doctypes/base/graph-fields.doc.mjs +1 -1
- package/authoring/doctypes/command/command.doc.mjs +1 -1
- package/authoring/doctypes/command/type.ts +1 -1
- package/authoring/doctypes/component/type.ts +2 -2
- package/authoring/doctypes/doctypes-new.test.mjs +48 -6
- package/authoring/doctypes/enum/enum.doc.mjs +1 -1
- package/authoring/doctypes/enum/type.ts +1 -1
- package/authoring/doctypes/function/function.doc.mjs +1 -1
- package/authoring/doctypes/function/type.ts +1 -1
- package/authoring/doctypes/hook/type.ts +2 -2
- package/authoring/doctypes/load-contract.test.mjs +2 -1
- package/authoring/doctypes/parse.d.mts +4 -2
- package/authoring/doctypes/parse.mjs +7 -3
- package/authoring/doctypes/reference/reference.doc.mjs +1 -1
- package/authoring/doctypes/reference/type.ts +2 -2
- package/authoring/doctypes/schema/schema.doc.mjs +1 -1
- package/authoring/doctypes/schema/type.ts +1 -2
- package/authoring/doctypes/template/template.doc.mjs +3 -3
- package/authoring/doctypes/theme/parse.d.mts +35 -0
- package/authoring/doctypes/theme/parse.mjs +76 -0
- package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
- package/authoring/doctypes/theme/theme.doc.mjs +79 -0
- package/authoring/doctypes/theme/type.ts +42 -0
- package/authoring/doctypes/types.ts +2 -1
- package/authoring/gap-report/gap-report.doc.d.mts +12 -0
- package/authoring/gap-report/gap-report.doc.mjs +183 -0
- package/authoring/index.d.mts +1 -0
- package/authoring/index.d.ts +6 -4
- package/authoring/index.mjs +2 -1
- package/authoring/integration/integration.doc.mjs +2 -2
- package/authoring/integration/type.ts +3 -9
- package/clients/cli/__tests__/cliManifest.test.ts +27 -29
- package/clients/cli/commands/blog.doc.mjs +1 -1
- package/clients/cli/commands/build.doc.mjs +1 -1
- package/clients/cli/commands/component.doc.mjs +1 -1
- package/clients/cli/commands/discover.doc.mjs +1 -1
- package/clients/cli/commands/docs.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration-docs.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
- package/clients/cli/commands/doctor-integration.test.mjs +15 -7
- package/clients/cli/commands/doctor.doc.mjs +1 -1
- package/clients/cli/commands/gap-report.doc.mjs +1 -1
- package/clients/cli/commands/hook.doc.mjs +1 -1
- package/clients/cli/commands/init.doc.mjs +1 -1
- package/clients/cli/commands/integration-add.controls.test.mjs +1 -1
- package/clients/cli/commands/integration-add.doc.mjs +1 -1
- package/clients/cli/commands/integration-pack.doc.mjs +1 -1
- package/clients/cli/commands/integration-real-world.test.mjs +3 -9
- package/clients/cli/commands/integration.doc.mjs +1 -1
- package/clients/cli/commands/layout-check.doc.mjs +1 -1
- package/clients/cli/commands/layout-expand.doc.mjs +1 -1
- package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
- package/clients/cli/commands/layout.doc.mjs +1 -1
- package/clients/cli/commands/manifest.doc.mjs +1 -1
- package/clients/cli/commands/search.doc.mjs +1 -1
- package/clients/cli/commands/swizzle.doc.mjs +1 -1
- package/clients/cli/commands/template.doc.mjs +1 -1
- package/clients/cli/commands/theme-add.doc.mjs +2 -2
- package/clients/cli/commands/theme-build.doc.mjs +1 -1
- package/clients/cli/commands/theme-list.doc.mjs +2 -2
- package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -3
- package/clients/cli/commands/theme-palette.doc.mjs +1 -1
- package/clients/cli/commands/theme-targets.doc.mjs +1 -1
- package/clients/cli/commands/theme-template.doc.mjs +1 -1
- package/clients/cli/commands/theme.doc.mjs +1 -1
- package/clients/cli/commands/upgrade.doc.mjs +1 -1
- package/clients/cli/lib/hook-format.mjs +14 -5
- package/foundation/config/project-themes.test.mjs +11 -19
- package/foundation/config/project.d.mts +8 -0
- package/foundation/config/project.mjs +50 -21
- package/foundation/config/project.test.mjs +3 -16
- package/foundation/discovery/authoring-self-docs.d.mts +6 -0
- package/foundation/discovery/authoring-self-docs.mjs +17 -7
- package/foundation/discovery/authoring-surface.d.mts +74 -0
- package/foundation/discovery/authoring-surface.mjs +525 -0
- package/foundation/discovery/authoring-surface.test.mjs +392 -0
- package/foundation/discovery/cli-self-docs.d.mts +113 -0
- package/foundation/discovery/cli-self-docs.mjs +514 -0
- package/foundation/discovery/cli-self-docs.test.mjs +437 -0
- package/foundation/discovery/component-loader.d.mts +35 -38
- package/foundation/discovery/component-loader.mjs +53 -222
- package/foundation/discovery/docs-discovery.d.mts +3 -2
- package/foundation/discovery/docs-discovery.mjs +8 -12
- package/foundation/discovery/docs-discovery.test.mjs +8 -5
- package/foundation/discovery/template-adapter.d.mts +7 -0
- package/foundation/discovery/template-adapter.mjs +27 -40
- package/foundation/discovery/template-adapter.test.mjs +15 -0
- package/foundation/discovery/theme-discovery.d.mts +67 -7
- package/foundation/discovery/theme-discovery.mjs +916 -186
- package/foundation/discovery/theme-discovery.test.mjs +613 -219
- package/foundation/doc-compiler/bundle.d.mts +47 -0
- package/foundation/doc-compiler/bundle.mjs +218 -0
- package/foundation/doc-compiler/bundle.test.mjs +255 -0
- package/foundation/doc-compiler/compile.d.mts +200 -0
- package/foundation/doc-compiler/compile.mjs +254 -5
- package/foundation/doc-compiler/diagnostics.d.mts +126 -0
- package/foundation/doc-compiler/diagnostics.mjs +277 -0
- package/foundation/doc-compiler/doc-compiler.test.mjs +28 -1
- package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
- package/foundation/doc-compiler/import.d.mts +24 -0
- package/foundation/doc-compiler/import.mjs +59 -0
- package/foundation/doc-compiler/inputs.d.mts +102 -0
- package/foundation/doc-compiler/inputs.mjs +286 -0
- package/foundation/doc-compiler/inputs.test.mjs +299 -0
- package/foundation/doc-compiler/ir.d.mts +13 -0
- package/foundation/doc-compiler/ir.mjs +189 -12
- package/foundation/doc-compiler/lower-doc.test.mjs +492 -0
- package/foundation/doc-compiler/overlays.d.mts +37 -0
- package/foundation/doc-compiler/overlays.mjs +206 -0
- package/foundation/doc-compiler/parse-readable.d.mts +9 -0
- package/foundation/doc-compiler/parse-readable.mjs +29 -0
- package/foundation/doc-compiler/read.d.mts +126 -0
- package/foundation/doc-compiler/read.mjs +320 -0
- package/foundation/doc-compiler/read.test.mjs +313 -0
- package/foundation/doc-compiler/source.d.mts +33 -0
- package/foundation/doc-compiler/source.mjs +128 -0
- package/foundation/integrations/autolink.d.mts +58 -1
- package/foundation/integrations/autolink.mjs +143 -57
- package/foundation/integrations/contribution-fixes.d.mts +145 -0
- package/foundation/integrations/contribution-fixes.mjs +1284 -0
- package/foundation/integrations/contribution-inventory.d.mts +1 -1
- package/foundation/integrations/contribution-inventory.mjs +17 -20
- package/foundation/integrations/contribution-inventory.test.mjs +67 -27
- package/foundation/integrations/integrations.d.mts +3 -0
- package/foundation/integrations/integrations.mjs +11 -97
- package/foundation/integrations/provider-ledger.test.mjs +275 -0
- package/foundation/integrations/provider-resolution.d.mts +152 -0
- package/foundation/integrations/provider-resolution.mjs +576 -0
- package/foundation/integrations/provider-resolution.test.mjs +369 -0
- package/foundation/integrations/theme-descriptor.d.mts +8 -0
- package/foundation/integrations/theme-descriptor.mjs +44 -0
- package/foundation/integrations/validate-contributions.mjs +104 -10
- package/foundation/response/error-codes.doc.mjs +2 -2
- package/foundation/response/error-codes.mjs +1 -1
- package/foundation/response/response-types.doc.mjs +1 -1
- package/foundation/response/response.doc.mjs +1 -1
- package/foundation/text/string-utils.mjs +22 -10
- package/package.json +9 -9
- package/assets/templates/themes/manifest.json +0 -95
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Colocated tests for the provider resolver: one outcome per real package
|
|
5
|
+
* directory, precedence, and the wrappers that keep their old results.
|
|
6
|
+
*
|
|
7
|
+
* Fixtures live under a repo-local temp dir, not /tmp, because Vite refuses to
|
|
8
|
+
* dynamically import a module from outside the project root.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {afterEach, beforeEach, describe, expect, it} from 'vitest';
|
|
12
|
+
import * as fs from 'node:fs';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import {packageKey, resolveProviders} from './provider-resolution.mjs';
|
|
15
|
+
import {markProviderConflicts} from './integrations.mjs';
|
|
16
|
+
import {autolinkIntegrations} from './autolink.mjs';
|
|
17
|
+
import {Project, providerLedgerOf} from '../config/project.mjs';
|
|
18
|
+
|
|
19
|
+
let tmpDir;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
tmpDir = fs.mkdtempSync(
|
|
23
|
+
path.join(process.cwd(), '.astryx-provider-resolution-'),
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A loaded-integration record in a real directory.
|
|
33
|
+
* @param {string} dir directory under the temp root
|
|
34
|
+
* @param {Record<string, unknown>} fields
|
|
35
|
+
* @returns {any}
|
|
36
|
+
*/
|
|
37
|
+
function record(dir, fields) {
|
|
38
|
+
const packageDir = path.join(tmpDir, dir);
|
|
39
|
+
fs.mkdirSync(packageDir, {recursive: true});
|
|
40
|
+
return {
|
|
41
|
+
providerId: fields.name,
|
|
42
|
+
__spec: fields.name,
|
|
43
|
+
__packageDir: packageDir,
|
|
44
|
+
__manifestFile: path.join(packageDir, 'astryx.integration.mjs'),
|
|
45
|
+
...fields,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} source
|
|
51
|
+
* @param {any} integration
|
|
52
|
+
*/
|
|
53
|
+
const candidate = (source, integration) => ({
|
|
54
|
+
source,
|
|
55
|
+
integration,
|
|
56
|
+
spec: integration.__spec,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/** @param {Map<string, any>} ledger */
|
|
60
|
+
function outcomes(ledger) {
|
|
61
|
+
return [...ledger.values()].map(entry => [entry.label, entry.outcome]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
describe('resolveProviders ledger', () => {
|
|
65
|
+
it('records one outcome for every candidate, keyed by real directory', () => {
|
|
66
|
+
const widgets = record('widgets', {
|
|
67
|
+
name: '@acme/widgets',
|
|
68
|
+
version: '1.0.0',
|
|
69
|
+
});
|
|
70
|
+
const renamed = record('renamed', {
|
|
71
|
+
name: '@acme/renamed',
|
|
72
|
+
version: '2.0.0',
|
|
73
|
+
providerId: '@acme/widgets',
|
|
74
|
+
});
|
|
75
|
+
const broken = record('broken', {
|
|
76
|
+
name: '@acme/broken',
|
|
77
|
+
version: '1.0.0',
|
|
78
|
+
__loadError: 'boom',
|
|
79
|
+
});
|
|
80
|
+
const {integrations, ledger} = resolveProviders([
|
|
81
|
+
candidate('configured', widgets),
|
|
82
|
+
candidate('configured', renamed),
|
|
83
|
+
candidate('configured', broken),
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
expect([...ledger.keys()]).toEqual(
|
|
87
|
+
[widgets, renamed, broken].map(entry => packageKey(entry.__packageDir)),
|
|
88
|
+
);
|
|
89
|
+
expect(outcomes(ledger)).toEqual([
|
|
90
|
+
['@acme/widgets@1.0.0', 'contributes'],
|
|
91
|
+
['@acme/renamed@2.0.0', 'set-aside'],
|
|
92
|
+
['@acme/broken@1.0.0', 'load-failed'],
|
|
93
|
+
]);
|
|
94
|
+
const setAside = ledger.get(packageKey(renamed.__packageDir));
|
|
95
|
+
expect(setAside).toMatchObject({
|
|
96
|
+
winner: packageKey(widgets.__packageDir),
|
|
97
|
+
reason: 'claimed-earlier',
|
|
98
|
+
integration: integrations[1],
|
|
99
|
+
});
|
|
100
|
+
expect(integrations[1].__providerConflict.claimedBy).toBe('@acme/widgets');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('keeps two packages that share a name apart', () => {
|
|
104
|
+
const old = record('widgets-old', {
|
|
105
|
+
name: '@acme/widgets',
|
|
106
|
+
version: '1.0.0',
|
|
107
|
+
__spec: 'widgets-old',
|
|
108
|
+
});
|
|
109
|
+
const next = record('widgets-next', {
|
|
110
|
+
name: '@acme/widgets',
|
|
111
|
+
version: '2.0.0',
|
|
112
|
+
__spec: 'widgets-next',
|
|
113
|
+
});
|
|
114
|
+
const {ledger} = resolveProviders([
|
|
115
|
+
candidate('configured', old),
|
|
116
|
+
candidate('configured', next),
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
expect(outcomes(ledger)).toEqual([
|
|
120
|
+
['@acme/widgets@1.0.0', 'contributes'],
|
|
121
|
+
['@acme/widgets@2.0.0', 'set-aside'],
|
|
122
|
+
]);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('folds every spelling of one real directory into one entry', () => {
|
|
126
|
+
const ui = record('ui', {name: '@acme/ui', version: '0.1.22'});
|
|
127
|
+
const link = path.join(tmpDir, 'legacy-ui');
|
|
128
|
+
fs.symlinkSync(ui.__packageDir, link, 'dir');
|
|
129
|
+
const legacy = {...ui, __spec: '@acme/legacy-ui', __packageDir: link};
|
|
130
|
+
const {integrations, ledger} = resolveProviders([
|
|
131
|
+
candidate('configured', ui),
|
|
132
|
+
candidate('configured', legacy),
|
|
133
|
+
]);
|
|
134
|
+
|
|
135
|
+
expect(integrations).toEqual([ui]);
|
|
136
|
+
expect([...ledger.keys()]).toEqual([packageKey(ui.__packageDir)]);
|
|
137
|
+
const [entry] = ledger.values();
|
|
138
|
+
expect(entry.outcome).toBe('contributes');
|
|
139
|
+
expect(entry.refs.map(ref => ref.spec)).toEqual([
|
|
140
|
+
'@acme/ui',
|
|
141
|
+
'@acme/legacy-ui',
|
|
142
|
+
]);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('records an autolinked copy of a loaded package as alias-of it', () => {
|
|
146
|
+
const ui = record('ui', {name: '@acme/ui', version: '0.1.22'});
|
|
147
|
+
const copy = record('legacy-ui', {
|
|
148
|
+
name: '@acme/ui',
|
|
149
|
+
version: '0.1.22',
|
|
150
|
+
__spec: '@acme/legacy-ui',
|
|
151
|
+
__autolinked: true,
|
|
152
|
+
});
|
|
153
|
+
const {integrations, ledger} = resolveProviders([
|
|
154
|
+
candidate('configured', ui),
|
|
155
|
+
candidate('autolinked', copy),
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
expect(integrations).toEqual([ui]);
|
|
159
|
+
expect(ledger.get(packageKey(copy.__packageDir))).toMatchObject({
|
|
160
|
+
outcome: 'alias-of',
|
|
161
|
+
aliasOf: packageKey(ui.__packageDir),
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('records an autolinked package that failed to load, and lists it nowhere', () => {
|
|
166
|
+
const packageDir = path.join(tmpDir, 'unreadable');
|
|
167
|
+
const {integrations, ledger} = resolveProviders([
|
|
168
|
+
{
|
|
169
|
+
source: 'autolinked',
|
|
170
|
+
spec: '@acme/unreadable',
|
|
171
|
+
packageDir,
|
|
172
|
+
error: 'bad json',
|
|
173
|
+
},
|
|
174
|
+
]);
|
|
175
|
+
|
|
176
|
+
expect(integrations).toEqual([]);
|
|
177
|
+
expect(ledger.get(packageKey(packageDir))).toMatchObject({
|
|
178
|
+
outcome: 'load-failed',
|
|
179
|
+
error: 'bad json',
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('lets the package being authored replace its installed copy and claim first', () => {
|
|
184
|
+
const installed = record('installed', {
|
|
185
|
+
name: '@acme/widgets',
|
|
186
|
+
version: '1.0.0',
|
|
187
|
+
});
|
|
188
|
+
const rival = record('rival', {
|
|
189
|
+
name: '@acme/rival',
|
|
190
|
+
version: '1.0.0',
|
|
191
|
+
providerId: '@acme/widgets',
|
|
192
|
+
});
|
|
193
|
+
const local = record('local', {
|
|
194
|
+
name: '@acme/widgets',
|
|
195
|
+
version: '2.0.0-dev',
|
|
196
|
+
__local: true,
|
|
197
|
+
});
|
|
198
|
+
const {integrations, ledger} = resolveProviders([
|
|
199
|
+
candidate('configured', rival),
|
|
200
|
+
candidate('configured', installed),
|
|
201
|
+
candidate('local', local),
|
|
202
|
+
]);
|
|
203
|
+
|
|
204
|
+
expect(integrations.map(entry => entry.name)).toEqual([
|
|
205
|
+
'@acme/rival',
|
|
206
|
+
'@acme/widgets',
|
|
207
|
+
]);
|
|
208
|
+
expect(integrations[1]).toBe(local);
|
|
209
|
+
expect(ledger.get(packageKey(installed.__packageDir))).toMatchObject({
|
|
210
|
+
outcome: 'set-aside',
|
|
211
|
+
reason: 'replaced-by-authored',
|
|
212
|
+
winner: packageKey(local.__packageDir),
|
|
213
|
+
});
|
|
214
|
+
expect(ledger.get(packageKey(rival.__packageDir))).toMatchObject({
|
|
215
|
+
outcome: 'set-aside',
|
|
216
|
+
reason: 'authored-claims',
|
|
217
|
+
winner: packageKey(local.__packageDir),
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('keeps configured precedence ahead of autolinked', () => {
|
|
222
|
+
const configured = record('configured', {
|
|
223
|
+
name: '@acme/one',
|
|
224
|
+
version: '1.0.0',
|
|
225
|
+
});
|
|
226
|
+
const autolinked = record('autolinked', {
|
|
227
|
+
name: '@acme/two',
|
|
228
|
+
version: '1.0.0',
|
|
229
|
+
providerId: '@acme/one',
|
|
230
|
+
__autolinked: true,
|
|
231
|
+
});
|
|
232
|
+
const {ledger} = resolveProviders([
|
|
233
|
+
candidate('configured', configured),
|
|
234
|
+
candidate('autolinked', autolinked),
|
|
235
|
+
]);
|
|
236
|
+
|
|
237
|
+
expect(outcomes(ledger)).toEqual([
|
|
238
|
+
['@acme/one@1.0.0', 'contributes'],
|
|
239
|
+
['@acme/two@1.0.0', 'set-aside'],
|
|
240
|
+
]);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('under the codemod policy, records the installed copy standing in', () => {
|
|
244
|
+
const local = record('local', {
|
|
245
|
+
name: '@acme/widgets',
|
|
246
|
+
version: '2.0.0-dev',
|
|
247
|
+
__local: true,
|
|
248
|
+
});
|
|
249
|
+
const installed = record('installed', {
|
|
250
|
+
name: '@acme/widgets',
|
|
251
|
+
version: '1.0.0',
|
|
252
|
+
});
|
|
253
|
+
const {integrations, ledger} = resolveProviders(
|
|
254
|
+
[candidate('configured', local), candidate('installed', installed)],
|
|
255
|
+
{codemods: true},
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
expect(integrations).toEqual([installed]);
|
|
259
|
+
expect(ledger.get(packageKey(local.__packageDir))).toMatchObject({
|
|
260
|
+
outcome: 'set-aside',
|
|
261
|
+
reason: 'installed-stands-in',
|
|
262
|
+
winner: packageKey(installed.__packageDir),
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
describe('markProviderConflicts', () => {
|
|
268
|
+
const a = {name: 'a', version: '1', providerId: 'x', __spec: 'a'};
|
|
269
|
+
const b = {name: 'b', version: '1', providerId: 'x', __spec: 'b'};
|
|
270
|
+
const alias = {name: 'a', version: '1', providerId: 'x', __spec: 'a-alias'};
|
|
271
|
+
const local = {
|
|
272
|
+
name: 'l',
|
|
273
|
+
version: '1',
|
|
274
|
+
providerId: 'x',
|
|
275
|
+
__spec: 'l',
|
|
276
|
+
__local: true,
|
|
277
|
+
};
|
|
278
|
+
/** @param {any[]} list */
|
|
279
|
+
const claimsOf = list =>
|
|
280
|
+
markProviderConflicts(list).map(entry => [
|
|
281
|
+
entry?.name ?? null,
|
|
282
|
+
entry?.__providerConflict?.claimedBy ?? null,
|
|
283
|
+
]);
|
|
284
|
+
|
|
285
|
+
it('drops an alias of the winner and keeps a record listed twice', () => {
|
|
286
|
+
expect(claimsOf([a, b, alias, a, undefined])).toEqual([
|
|
287
|
+
['a', null],
|
|
288
|
+
['b', 'a'],
|
|
289
|
+
['a', null],
|
|
290
|
+
[null, null],
|
|
291
|
+
]);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('lets the package being authored claim first', () => {
|
|
295
|
+
expect(claimsOf([a, undefined, b, alias, a, local])).toEqual([
|
|
296
|
+
['a', 'l'],
|
|
297
|
+
[null, null],
|
|
298
|
+
['b', 'l'],
|
|
299
|
+
['a', 'l'],
|
|
300
|
+
['a', 'l'],
|
|
301
|
+
['l', null],
|
|
302
|
+
]);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
describe('Project.load keeps a ledger', () => {
|
|
307
|
+
/**
|
|
308
|
+
* @param {string} dir node_modules key
|
|
309
|
+
* @param {{name: string, version: string}} pkg
|
|
310
|
+
*/
|
|
311
|
+
function install(dir, pkg) {
|
|
312
|
+
const pkgDir = path.join(tmpDir, 'node_modules', ...dir.split('/'));
|
|
313
|
+
fs.mkdirSync(pkgDir, {recursive: true});
|
|
314
|
+
fs.writeFileSync(path.join(pkgDir, 'package.json'), JSON.stringify(pkg));
|
|
315
|
+
fs.writeFileSync(
|
|
316
|
+
path.join(pkgDir, 'astryx.integration.mjs'),
|
|
317
|
+
'export default {};\n',
|
|
318
|
+
);
|
|
319
|
+
return pkgDir;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
it('records the autolink alias it drops as alias-of the loaded copy', async () => {
|
|
323
|
+
fs.writeFileSync(
|
|
324
|
+
path.join(tmpDir, 'package.json'),
|
|
325
|
+
JSON.stringify({
|
|
326
|
+
name: 'consumer',
|
|
327
|
+
dependencies: {
|
|
328
|
+
'@acme/legacy-ui': 'npm:@acme/ui@0.1.22',
|
|
329
|
+
'@acme/ui': '0.1.22',
|
|
330
|
+
},
|
|
331
|
+
}),
|
|
332
|
+
);
|
|
333
|
+
const legacy = install('@acme/legacy-ui', {
|
|
334
|
+
name: '@acme/ui',
|
|
335
|
+
version: '0.1.22',
|
|
336
|
+
});
|
|
337
|
+
const ui = install('@acme/ui', {name: '@acme/ui', version: '0.1.22'});
|
|
338
|
+
|
|
339
|
+
const project = await Project.load(tmpDir, {fresh: true});
|
|
340
|
+
expect(project.loadedIntegrations.map(entry => entry.__spec)).toEqual([
|
|
341
|
+
'@acme/legacy-ui',
|
|
342
|
+
]);
|
|
343
|
+
const ledger = providerLedgerOf(project);
|
|
344
|
+
expect(ledger.get(packageKey(ui))).toMatchObject({
|
|
345
|
+
outcome: 'alias-of',
|
|
346
|
+
aliasOf: packageKey(legacy),
|
|
347
|
+
});
|
|
348
|
+
expect(await autolinkIntegrations({projectDir: tmpDir})).toHaveLength(1);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('records a dependency key that repeats a configured package', async () => {
|
|
352
|
+
fs.writeFileSync(
|
|
353
|
+
path.join(tmpDir, 'package.json'),
|
|
354
|
+
JSON.stringify({name: 'consumer', dependencies: {'@acme/ui': '0.1.22'}}),
|
|
355
|
+
);
|
|
356
|
+
fs.writeFileSync(
|
|
357
|
+
path.join(tmpDir, 'astryx.config.mjs'),
|
|
358
|
+
"export default {integrations: ['@acme/ui']};\n",
|
|
359
|
+
);
|
|
360
|
+
const ui = install('@acme/ui', {name: '@acme/ui', version: '0.1.22'});
|
|
361
|
+
|
|
362
|
+
const ledger = providerLedgerOf(await Project.load(tmpDir, {fresh: true}));
|
|
363
|
+
expect([...ledger.keys()]).toEqual([packageKey(ui)]);
|
|
364
|
+
expect(ledger.get(packageKey(ui))?.refs.map(ref => ref.source)).toEqual([
|
|
365
|
+
'configured',
|
|
366
|
+
'autolinked',
|
|
367
|
+
]);
|
|
368
|
+
});
|
|
369
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
|
|
2
|
+
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {import('../../authoring/doctypes/theme/type.js').ThemeDoc} doc
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
8
|
+
export function themeDescriptorSource(doc: import("../../authoring/doctypes/theme/type.js").ThemeDoc): string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file The source text of a typed integration theme descriptor.
|
|
5
|
+
*
|
|
6
|
+
* @input A theme's descriptor fields.
|
|
7
|
+
* @output The `.doc.mjs` source that declares them under their ThemeDoc type.
|
|
8
|
+
* @position Shared by `integration add theme`, which scaffolds a descriptor,
|
|
9
|
+
* and the codemod that turns a 0.6 theme catalog into descriptors, so both
|
|
10
|
+
* write the same bytes.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A single-quoted JavaScript string literal for any text.
|
|
15
|
+
* @param {string} value
|
|
16
|
+
*/
|
|
17
|
+
function quote(value) {
|
|
18
|
+
const escaped = value
|
|
19
|
+
.replace(/\\/gu, '\\\\')
|
|
20
|
+
.replace(/'/gu, "\\'")
|
|
21
|
+
.replace(/\n/gu, '\\n')
|
|
22
|
+
.replace(/\r/gu, '\\r')
|
|
23
|
+
.replace(/\u2028/gu, '\\u2028')
|
|
24
|
+
.replace(/\u2029/gu, '\\u2029');
|
|
25
|
+
return `'${escaped}'`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {import('../../authoring/doctypes/theme/type.js').ThemeDoc} doc
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
export function themeDescriptorSource(doc) {
|
|
33
|
+
return [
|
|
34
|
+
"/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */",
|
|
35
|
+
'export default {',
|
|
36
|
+
" type: 'theme',",
|
|
37
|
+
` name: ${quote(doc.name)},`,
|
|
38
|
+
` displayName: ${quote(doc.displayName)},`,
|
|
39
|
+
` description: ${quote(doc.description)},`,
|
|
40
|
+
` maintained: ${doc.maintained},`,
|
|
41
|
+
'};',
|
|
42
|
+
'',
|
|
43
|
+
].join('\n');
|
|
44
|
+
}
|
|
@@ -25,6 +25,23 @@ import * as fs from 'node:fs';
|
|
|
25
25
|
import * as path from 'node:path';
|
|
26
26
|
import {isValidSemver} from '../env/semver.mjs';
|
|
27
27
|
import {findSourceOnlyCandidates} from './contribution-inventory.mjs';
|
|
28
|
+
import {
|
|
29
|
+
CODEMOD_FILE_RE,
|
|
30
|
+
CODEMOD_SKIP_DIRS,
|
|
31
|
+
CODEMOD_TEST_RE,
|
|
32
|
+
createFixContext,
|
|
33
|
+
DOC_CANDIDATE_RE,
|
|
34
|
+
heldRootFix,
|
|
35
|
+
newComponentDocNote,
|
|
36
|
+
notACodemodFix,
|
|
37
|
+
notAComponentFix,
|
|
38
|
+
readContributionStamp,
|
|
39
|
+
sharedCodemodsRootFix,
|
|
40
|
+
stampOf,
|
|
41
|
+
themeImporting,
|
|
42
|
+
TEMPLATE_CANDIDATE_RE,
|
|
43
|
+
} from './contribution-fixes.mjs';
|
|
44
|
+
import {MANIFEST_BASENAMES} from './integrations.mjs';
|
|
28
45
|
import {discoverIntegrationCodemods} from '../../assets/codemods/integration-discovery.mjs';
|
|
29
46
|
import {discoverIntegrationTemplatesForOne} from '../discovery/template-adapter.mjs';
|
|
30
47
|
import * as componentDiscovery from '../discovery/component-discovery.mjs';
|
|
@@ -119,32 +136,82 @@ function checkRoots(resolved, issues) {
|
|
|
119
136
|
*/
|
|
120
137
|
async function checkCodemods(integration, issues) {
|
|
121
138
|
if (!integration.codemods || !fs.existsSync(integration.codemods)) return;
|
|
139
|
+
const context = integration.__packageDir
|
|
140
|
+
? createFixContext(integration.__packageDir, integration)
|
|
141
|
+
: null;
|
|
142
|
+
const shared = context && sharedCodemodsRootFix(context);
|
|
122
143
|
for (const entry of fs.readdirSync(integration.codemods, {
|
|
123
144
|
withFileTypes: true,
|
|
124
145
|
})) {
|
|
125
146
|
if (
|
|
126
147
|
entry.isFile() &&
|
|
127
|
-
|
|
128
|
-
|
|
148
|
+
CODEMOD_FILE_RE.test(entry.name) &&
|
|
149
|
+
!CODEMOD_TEST_RE.test(entry.name) &&
|
|
150
|
+
// The manifest sits beside package.json and is never a codemod.
|
|
151
|
+
!(
|
|
152
|
+
integration.codemods === integration.__packageDir &&
|
|
153
|
+
MANIFEST_BASENAMES.includes(entry.name)
|
|
154
|
+
)
|
|
129
155
|
) {
|
|
156
|
+
const shown = path
|
|
157
|
+
.relative(
|
|
158
|
+
integration.__packageDir ?? path.dirname(integration.codemods),
|
|
159
|
+
path.join(integration.codemods, entry.name),
|
|
160
|
+
)
|
|
161
|
+
.split(path.sep)
|
|
162
|
+
.join('/');
|
|
163
|
+
const root = path.dirname(shown);
|
|
164
|
+
const full = path.join(integration.codemods, entry.name);
|
|
165
|
+
const stamp =
|
|
166
|
+
context &&
|
|
167
|
+
(DOC_CANDIDATE_RE.test(entry.name) ||
|
|
168
|
+
TEMPLATE_CANDIDATE_RE.test(entry.name))
|
|
169
|
+
? stampOf(context, full)
|
|
170
|
+
: null;
|
|
171
|
+
// A theme's entry module may sit beside its descriptor.
|
|
172
|
+
const themeDoc = ['.doc.mjs', '.doc.ts', '.doc.js']
|
|
173
|
+
.map(suffix => full.replace(/\.(?:ts|mjs|js)$/u, suffix))
|
|
174
|
+
.find(candidate => candidate !== full && fs.existsSync(candidate));
|
|
175
|
+
const themeStamp =
|
|
176
|
+
context && !stamp && themeDoc ? stampOf(context, themeDoc) : null;
|
|
177
|
+
let fix = `Fix: move it into the folder named for the version it migrates to, for example ${root}/1.2.0/${entry.name}.`;
|
|
178
|
+
if (shared) fix = sharedCodemodsRootFix(context, entry.name) ?? fix;
|
|
179
|
+
else if (context && stamp) fix = notACodemodFix(context, full, stamp);
|
|
180
|
+
else if (context && themeDoc && themeStamp?.type === 'theme') {
|
|
181
|
+
fix = notACodemodFix(context, themeDoc, themeStamp, entry.name);
|
|
182
|
+
} else if (context) {
|
|
183
|
+
const owner = themeImporting(context, full);
|
|
184
|
+
if (owner) {
|
|
185
|
+
fix = notACodemodFix(
|
|
186
|
+
context,
|
|
187
|
+
owner.doc,
|
|
188
|
+
owner.stamp,
|
|
189
|
+
owner.source,
|
|
190
|
+
entry.name,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
130
194
|
issues.push(
|
|
131
195
|
issueWarning(
|
|
132
196
|
'codemod_outside_version',
|
|
133
|
-
`Codemod file "${
|
|
197
|
+
`Codemod file "${shown}" is outside a version folder, so upgrade will never load it. ${fix}`,
|
|
134
198
|
),
|
|
135
199
|
);
|
|
136
200
|
}
|
|
137
201
|
if (
|
|
138
202
|
entry.isDirectory() &&
|
|
139
|
-
!
|
|
140
|
-
entry.name,
|
|
141
|
-
) &&
|
|
203
|
+
!CODEMOD_SKIP_DIRS.has(entry.name) &&
|
|
142
204
|
!isValidSemver(entry.name)
|
|
143
205
|
) {
|
|
206
|
+
const fix =
|
|
207
|
+
shared ??
|
|
208
|
+
(context &&
|
|
209
|
+
heldRootFix(context, path.join(integration.codemods, entry.name))) ??
|
|
210
|
+
'Fix: rename it to the exact version its codemods migrate to.';
|
|
144
211
|
issues.push(
|
|
145
212
|
issueError(
|
|
146
213
|
'invalid_codemod_version',
|
|
147
|
-
`Codemod folder "${entry.name}" is not an exact semver version such as 1.2.0
|
|
214
|
+
`Codemod folder "${entry.name}" is not an exact semver version such as 1.2.0. ${fix}`,
|
|
148
215
|
),
|
|
149
216
|
);
|
|
150
217
|
}
|
|
@@ -196,24 +263,51 @@ async function checkComponents(integration, issues) {
|
|
|
196
263
|
if (typeof discover !== 'function') return; // feature not present yet
|
|
197
264
|
try {
|
|
198
265
|
const records = (await discover(integration)) ?? [];
|
|
266
|
+
/** @type {import('./contribution-fixes.mjs').FixContext | undefined} */
|
|
267
|
+
let context;
|
|
199
268
|
for (const record of records) {
|
|
200
269
|
if (record?.sourcePath == null) {
|
|
270
|
+
const docPath = record?.docPath;
|
|
271
|
+
let fix = `Fix: add ${record?.name}.tsx beside ${docPath ? path.basename(docPath) : `${record?.name}.doc.mjs`}.`;
|
|
272
|
+
const stamp = docPath ? readContributionStamp(docPath, false) : null;
|
|
273
|
+
if (stamp && stamp.type !== 'component' && integration.__packageDir) {
|
|
274
|
+
context ??= createFixContext(integration.__packageDir, integration);
|
|
275
|
+
fix = notAComponentFix(context, docPath, stamp);
|
|
276
|
+
}
|
|
201
277
|
issues.push(
|
|
202
278
|
issueError(
|
|
203
279
|
'invalid_component',
|
|
204
|
-
`Component "${record?.name}" is missing its same-stem source file ${record?.name}.tsx
|
|
280
|
+
`Component "${record?.name}" is missing its same-stem source file ${record?.name}.tsx. ${fix}`,
|
|
205
281
|
),
|
|
206
282
|
);
|
|
207
283
|
}
|
|
208
284
|
}
|
|
285
|
+
const overlap = integration.__packageDir
|
|
286
|
+
? newComponentDocNote(
|
|
287
|
+
(context ??= createFixContext(integration.__packageDir, integration)),
|
|
288
|
+
)
|
|
289
|
+
: '';
|
|
209
290
|
for (const name of findSourceOnlyCandidates(
|
|
210
291
|
integration.components,
|
|
211
292
|
records.map(record => record.name),
|
|
212
293
|
)) {
|
|
294
|
+
// A hidden doc still pairs with its source; discovery just skips it.
|
|
295
|
+
if (
|
|
296
|
+
['.doc.ts', '.doc.mjs', '.doc.js'].some(suffix =>
|
|
297
|
+
fs.existsSync(
|
|
298
|
+
path.join(
|
|
299
|
+
/** @type {string} */ (integration.components),
|
|
300
|
+
`${name}${suffix}`,
|
|
301
|
+
),
|
|
302
|
+
),
|
|
303
|
+
)
|
|
304
|
+
) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
213
307
|
issues.push(
|
|
214
308
|
issueWarning(
|
|
215
309
|
'source_without_component_doc',
|
|
216
|
-
`Component source "${name}.tsx" has no same-stem metadata file ${name}.doc.mjs, so Astryx ignores it
|
|
310
|
+
`Component source "${name}.tsx" has no same-stem metadata file ${name}.doc.mjs, so Astryx ignores it. Fix: add ${name}.doc.mjs beside it with type: 'component'; \`astryx docs authoring component-doc\` lists its fields.${overlap}`,
|
|
217
311
|
),
|
|
218
312
|
);
|
|
219
313
|
}
|
|
@@ -250,7 +344,7 @@ async function checkDocs(integration, issues) {
|
|
|
250
344
|
}
|
|
251
345
|
|
|
252
346
|
/**
|
|
253
|
-
* Validate the integration's source-theme
|
|
347
|
+
* Validate the integration's source-theme descriptors. The same discovery function
|
|
254
348
|
* powers Project and theme list/add, so validation cannot accept a shape that
|
|
255
349
|
* consumers later fail to use.
|
|
256
350
|
* @param {LoadedIntegration} integration
|
|
@@ -12,7 +12,7 @@ export const doc = {
|
|
|
12
12
|
type: 'enum',
|
|
13
13
|
name: 'error-codes',
|
|
14
14
|
displayName: 'Error Codes',
|
|
15
|
-
namespace: 'cli',
|
|
15
|
+
namespace: 'cli/api',
|
|
16
16
|
description:
|
|
17
17
|
'Stable, append-only machine-readable error codes on the --json error envelope (envelope.code). Codes never change or get removed; branch on these, not on prose.',
|
|
18
18
|
members: [
|
|
@@ -203,7 +203,7 @@ export const doc = {
|
|
|
203
203
|
{
|
|
204
204
|
value: 'ERR_THEME_INVALID',
|
|
205
205
|
description:
|
|
206
|
-
'A theme definition or contributed theme
|
|
206
|
+
'A theme definition or contributed theme descriptor is invalid.',
|
|
207
207
|
},
|
|
208
208
|
{
|
|
209
209
|
value: 'ERR_THEME_LOAD',
|
|
@@ -185,7 +185,7 @@ export const ERROR_CODES = Object.freeze({
|
|
|
185
185
|
ERR_WRITE_FAILED: 'ERR_WRITE_FAILED',
|
|
186
186
|
|
|
187
187
|
// ── Theme build ──────────────────────────────────────────────────
|
|
188
|
-
/** A theme definition or contributed theme
|
|
188
|
+
/** A theme definition or contributed theme descriptor is invalid. */
|
|
189
189
|
ERR_THEME_INVALID: 'ERR_THEME_INVALID',
|
|
190
190
|
/** A theme file could not be loaded / parsed into a defineTheme result. */
|
|
191
191
|
ERR_THEME_LOAD: 'ERR_THEME_LOAD',
|
|
@@ -13,7 +13,7 @@ export const doc = {
|
|
|
13
13
|
type: 'enum',
|
|
14
14
|
name: 'response-types',
|
|
15
15
|
displayName: 'Response Types',
|
|
16
|
-
namespace: 'cli',
|
|
16
|
+
namespace: 'cli/api',
|
|
17
17
|
description:
|
|
18
18
|
'The `type` discriminant present on every --json success envelope. Consumers switch on it to narrow `data`.',
|
|
19
19
|
members: [
|
|
@@ -12,7 +12,7 @@ export const doc = {
|
|
|
12
12
|
type: 'schema',
|
|
13
13
|
name: 'output',
|
|
14
14
|
displayName: 'Output Envelope',
|
|
15
|
-
namespace: 'cli',
|
|
15
|
+
namespace: 'cli/api',
|
|
16
16
|
description:
|
|
17
17
|
'The single JSON envelope every command emits under --json. Success is ' +
|
|
18
18
|
'{ apiVersion, type, data, meta? }; failure is { apiVersion, error, code, ' +
|