@astryxdesign/cli 0.6.3-canary.db4e378 → 0.6.3-canary.db7b338
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 +22 -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/detail/section/section.mjs +9 -15
- package/api/docs/detail/section/section.test.mjs +15 -6
- 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 +186 -14
- package/api/doctor/doctor.test.mjs +332 -7
- 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 +32 -5
- package/api/upgrade/_adapter.mjs +97 -69
- package/api/upgrade/provider-agreement.test.mjs +152 -0
- package/api/upgrade/run/run.mjs +356 -59
- package/api/upgrade/upgrade.doc.mjs +6 -1
- package/api/upgrade/upgrade.type.d.mts +34 -0
- package/api/upgrade/upgrade.type.mjs +15 -0
- package/assets/codemods/__tests__/runner.test.mjs +330 -8
- package/assets/codemods/integration-discovery.mjs +8 -2
- package/assets/codemods/integration-discovery.test.mjs +15 -0
- package/assets/codemods/integration-runner.mjs +56 -4
- package/assets/codemods/integration-runner.protection.test.mjs +153 -0
- package/assets/codemods/run-codemod.mjs +177 -34
- package/assets/codemods/runner.mjs +350 -102
- package/assets/codemods/transforms/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
- package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
- package/assets/codemods/transforms/next/index.mjs +19 -1
- package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
- package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
- package/assets/docs/cli-integrations.doc.mjs +30 -30
- package/assets/docs/cli.doc.mjs +15 -0
- package/assets/docs/theme.doc.mjs +1 -1
- package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
- package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
- package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
- package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
- 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/codemod/type.ts +12 -0
- 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/_schema.d.mts +71 -141
- package/authoring/doctypes/_schema.mjs +29 -2
- 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 +3 -2
- package/authoring/doctypes/namespace/namespace.doc.mjs +2 -2
- package/authoring/doctypes/namespace/parse.test.mjs +23 -25
- package/authoring/doctypes/namespace/type.ts +5 -2
- package/authoring/doctypes/parse.d.mts +4 -2
- package/authoring/doctypes/parse.mjs +10 -5
- package/authoring/doctypes/reference/reference.doc.mjs +6 -4
- package/authoring/doctypes/reference/type.ts +9 -10
- 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 +7 -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-theme.adaptations.test.mjs +100 -1
- package/clients/cli/commands/build-theme.mjs +10 -44
- 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/docs.mjs +15 -58
- package/clients/cli/commands/docs.test.mjs +11 -14
- 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/text-json-parity.test.mjs +718 -0
- 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.behavior.test.mjs +4 -3
- 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 +3 -2
- package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
- package/clients/cli/commands/upgrade.mjs +29 -7
- package/clients/cli/formatters/index.mjs +2 -0
- package/clients/cli/formatters/index.test.mjs +6 -0
- 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-self-docs.test.mjs +3 -2
- 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 +14 -17
- package/foundation/discovery/docs-discovery.test.mjs +15 -15
- package/foundation/discovery/docs-section-key.d.mts +19 -8
- package/foundation/discovery/docs-section-key.mjs +119 -32
- package/foundation/discovery/docs-section-key.test.mjs +41 -19
- 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 +259 -9
- 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/fs/file-protection.d.mts +33 -0
- package/foundation/fs/file-protection.mjs +825 -0
- package/foundation/fs/file-protection.test.mjs +250 -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.d.mts +3 -1
- package/foundation/response/error-codes.d.ts +2 -0
- package/foundation/response/error-codes.doc.mjs +12 -2
- package/foundation/response/error-codes.mjs +7 -1
- package/foundation/response/error-codes.test.mjs +55 -11
- 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 +10 -9
- package/assets/templates/themes/manifest.json +0 -95
|
@@ -32,7 +32,7 @@ afterEach(() => {
|
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
describe('integrationAddTheme', () => {
|
|
35
|
-
it('writes a
|
|
35
|
+
it('writes a typed same-stem descriptor and source with no central catalog', async () => {
|
|
36
36
|
setup();
|
|
37
37
|
const result = await integrationAddTheme('ocean', {cwd: tmpDir});
|
|
38
38
|
|
|
@@ -45,7 +45,7 @@ describe('integrationAddTheme', () => {
|
|
|
45
45
|
manifest: 'astryx.integration.mjs',
|
|
46
46
|
files: [
|
|
47
47
|
'themes/ocean/oceanTheme.ts',
|
|
48
|
-
'themes/
|
|
48
|
+
'themes/ocean/oceanTheme.doc.mjs',
|
|
49
49
|
'package.json',
|
|
50
50
|
'astryx.integration.mjs',
|
|
51
51
|
],
|
|
@@ -56,21 +56,17 @@ describe('integrationAddTheme', () => {
|
|
|
56
56
|
expect(
|
|
57
57
|
fs.readFileSync(path.join(tmpDir, 'themes/ocean/oceanTheme.ts'), 'utf-8'),
|
|
58
58
|
).toContain('export const oceanTheme = defineTheme');
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
files: ['oceanTheme.ts'],
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
});
|
|
59
|
+
|
|
60
|
+
const descriptor = fs.readFileSync(
|
|
61
|
+
path.join(tmpDir, 'themes/ocean/oceanTheme.doc.mjs'),
|
|
62
|
+
'utf-8',
|
|
63
|
+
);
|
|
64
|
+
expect(descriptor).toContain("@astryxdesign/cli/authoring').ThemeDoc");
|
|
65
|
+
expect(descriptor).toContain("type: 'theme'");
|
|
66
|
+
expect(descriptor).toContain("name: 'ocean'");
|
|
67
|
+
expect(fs.existsSync(path.join(tmpDir, 'themes/manifest.json'))).toBe(
|
|
68
|
+
false,
|
|
69
|
+
);
|
|
74
70
|
expect(
|
|
75
71
|
fs.readFileSync(path.join(tmpDir, 'astryx.integration.mjs'), 'utf-8'),
|
|
76
72
|
).toContain("themes: './themes'");
|
|
@@ -96,6 +92,7 @@ describe('integrationAddTheme', () => {
|
|
|
96
92
|
expect(result.data.dryRun).toBe(true);
|
|
97
93
|
expect(result.data.root).toEqual({path: './themes', created: true});
|
|
98
94
|
expect(result.data.files).toContain('themes/ocean/oceanTheme.ts');
|
|
95
|
+
expect(result.data.files).toContain('themes/ocean/oceanTheme.doc.mjs');
|
|
99
96
|
expect(fs.existsSync(path.join(tmpDir, 'themes'))).toBe(false);
|
|
100
97
|
expect(
|
|
101
98
|
fs.readFileSync(path.join(tmpDir, 'astryx.integration.mjs'), 'utf-8'),
|
|
@@ -125,22 +122,69 @@ describe('integrationAddTheme', () => {
|
|
|
125
122
|
expect(
|
|
126
123
|
fs.existsSync(path.join(tmpDir, 'src/themes/ocean/oceanTheme.ts')),
|
|
127
124
|
).toBe(true);
|
|
125
|
+
expect(
|
|
126
|
+
fs.existsSync(path.join(tmpDir, 'src/themes/ocean/oceanTheme.doc.mjs')),
|
|
127
|
+
).toBe(true);
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
-
it('
|
|
130
|
+
it('keeps each theme to its own folder: a second theme touches no shared file', async () => {
|
|
131
|
+
setup({manifest: "export default {themes: './themes'};\n"});
|
|
132
|
+
await integrationAddTheme('ocean', {cwd: tmpDir});
|
|
133
|
+
const shared = ['package.json', 'astryx.integration.mjs'].map(file =>
|
|
134
|
+
fs.readFileSync(path.join(tmpDir, file), 'utf-8'),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const result = await integrationAddTheme('reef', {cwd: tmpDir});
|
|
138
|
+
|
|
139
|
+
expect(result.data.files).toEqual([
|
|
140
|
+
'themes/reef/reefTheme.ts',
|
|
141
|
+
'themes/reef/reefTheme.doc.mjs',
|
|
142
|
+
]);
|
|
143
|
+
expect(fs.readdirSync(path.join(tmpDir, 'themes')).sort()).toEqual([
|
|
144
|
+
'ocean',
|
|
145
|
+
'reef',
|
|
146
|
+
]);
|
|
147
|
+
expect(
|
|
148
|
+
['package.json', 'astryx.integration.mjs'].map(file =>
|
|
149
|
+
fs.readFileSync(path.join(tmpDir, file), 'utf-8'),
|
|
150
|
+
),
|
|
151
|
+
).toEqual(shared);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('refuses an obsolete central catalog without changing its bytes', async () => {
|
|
131
155
|
setup();
|
|
132
156
|
fs.mkdirSync(path.join(tmpDir, 'themes'));
|
|
133
157
|
const catalog = path.join(tmpDir, 'themes', 'manifest.json');
|
|
134
|
-
fs.writeFileSync(catalog, '{
|
|
158
|
+
fs.writeFileSync(catalog, '{"version":1}\n');
|
|
135
159
|
|
|
136
160
|
await expect(
|
|
137
161
|
integrationAddTheme('ocean', {cwd: tmpDir}),
|
|
138
162
|
).rejects.toMatchObject({code: 'ERR_THEME_INVALID'});
|
|
139
|
-
expect(fs.readFileSync(catalog, 'utf-8')).toBe('{
|
|
163
|
+
expect(fs.readFileSync(catalog, 'utf-8')).toBe('{"version":1}\n');
|
|
140
164
|
expect(fs.existsSync(path.join(tmpDir, 'themes', 'ocean'))).toBe(false);
|
|
141
165
|
});
|
|
142
166
|
|
|
143
|
-
it('refuses
|
|
167
|
+
it('refuses an invalid existing descriptor without changing it', async () => {
|
|
168
|
+
setup();
|
|
169
|
+
const existing = path.join(tmpDir, 'themes', 'forest');
|
|
170
|
+
fs.mkdirSync(existing, {recursive: true});
|
|
171
|
+
const descriptor = path.join(existing, 'forestTheme.doc.mjs');
|
|
172
|
+
fs.writeFileSync(descriptor, 'export default {type: "theme"};\n');
|
|
173
|
+
fs.writeFileSync(
|
|
174
|
+
path.join(existing, 'forestTheme.ts'),
|
|
175
|
+
'export const forestTheme = {};\n',
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
await expect(
|
|
179
|
+
integrationAddTheme('ocean', {cwd: tmpDir}),
|
|
180
|
+
).rejects.toMatchObject({code: 'ERR_THEME_INVALID'});
|
|
181
|
+
expect(fs.readFileSync(descriptor, 'utf-8')).toBe(
|
|
182
|
+
'export default {type: "theme"};\n',
|
|
183
|
+
);
|
|
184
|
+
expect(fs.existsSync(path.join(tmpDir, 'themes', 'ocean'))).toBe(false);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('refuses a duplicate valid theme directory', async () => {
|
|
144
188
|
setup();
|
|
145
189
|
await integrationAddTheme('ocean', {cwd: tmpDir});
|
|
146
190
|
await expect(
|
|
@@ -148,6 +192,46 @@ describe('integrationAddTheme', () => {
|
|
|
148
192
|
).rejects.toMatchObject({code: 'ERR_FILE_EXISTS'});
|
|
149
193
|
});
|
|
150
194
|
|
|
195
|
+
it('refuses an existing invalid theme directory', async () => {
|
|
196
|
+
setup();
|
|
197
|
+
fs.mkdirSync(path.join(tmpDir, 'themes', 'ocean'), {recursive: true});
|
|
198
|
+
fs.writeFileSync(
|
|
199
|
+
path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.ts'),
|
|
200
|
+
'export const oceanTheme = {};\n',
|
|
201
|
+
);
|
|
202
|
+
await expect(
|
|
203
|
+
integrationAddTheme('ocean', {cwd: tmpDir}),
|
|
204
|
+
).rejects.toMatchObject({code: 'ERR_THEME_INVALID'});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it.each([
|
|
208
|
+
['an empty folder', []],
|
|
209
|
+
['a folder holding .gitkeep', ['.gitkeep']],
|
|
210
|
+
['a folder holding NOTES.md', ['NOTES.md']],
|
|
211
|
+
])('fills %s', async (_, files) => {
|
|
212
|
+
setup();
|
|
213
|
+
const dir = path.join(tmpDir, 'themes', 'ocean');
|
|
214
|
+
fs.mkdirSync(dir, {recursive: true});
|
|
215
|
+
for (const file of files) fs.writeFileSync(path.join(dir, file), 'x\n');
|
|
216
|
+
const result = await integrationAddTheme('ocean', {cwd: tmpDir});
|
|
217
|
+
expect(result.data.written).toBe(true);
|
|
218
|
+
expect(fs.readdirSync(dir).sort()).toEqual(
|
|
219
|
+
[...files, 'oceanTheme.doc.mjs', 'oceanTheme.ts'].sort(),
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('refuses to overwrite a file it would write', async () => {
|
|
224
|
+
setup();
|
|
225
|
+
await integrationAddTheme('ocean', {cwd: tmpDir});
|
|
226
|
+
await expect(
|
|
227
|
+
integrationAddTheme('ocean', {cwd: tmpDir}),
|
|
228
|
+
).rejects.toMatchObject({
|
|
229
|
+
code: 'ERR_FILE_EXISTS',
|
|
230
|
+
message:
|
|
231
|
+
'Refusing to overwrite existing file themes/ocean/oceanTheme.ts.',
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
151
235
|
it.each(['../ocean', 'Ocean', 'ocean theme', '.ocean'])(
|
|
152
236
|
'refuses unsafe or noncanonical name %s',
|
|
153
237
|
async name => {
|
|
@@ -33,7 +33,7 @@ function writeIntegration({id, name, type = 'block', root = tmpDir}) {
|
|
|
33
33
|
const stem = path.join(root, 'templates', id);
|
|
34
34
|
fs.mkdirSync(path.dirname(stem), {recursive: true});
|
|
35
35
|
fs.writeFileSync(
|
|
36
|
-
`${stem}.
|
|
36
|
+
`${stem}.doc.mjs`,
|
|
37
37
|
`export default {type: '${type}', name: ${JSON.stringify(name)}, description: 'fixture'};\n`,
|
|
38
38
|
);
|
|
39
39
|
fs.writeFileSync(
|
|
@@ -176,7 +176,7 @@ describe('integrationTemplateConflicts', () => {
|
|
|
176
176
|
);
|
|
177
177
|
fs.mkdirSync(path.join(tmpDir, 'templates'), {recursive: true});
|
|
178
178
|
fs.writeFileSync(
|
|
179
|
-
path.join(tmpDir, 'templates', 'broken.
|
|
179
|
+
path.join(tmpDir, 'templates', 'broken.doc.mjs'),
|
|
180
180
|
`throw new Error('broken fixture');\n`,
|
|
181
181
|
);
|
|
182
182
|
fs.writeFileSync(
|
|
@@ -221,7 +221,9 @@ describe('integrationComponentConflicts', () => {
|
|
|
221
221
|
expect(core).toBeDefined();
|
|
222
222
|
writeComponentIntegration(core.name);
|
|
223
223
|
|
|
224
|
-
const result = await integrationComponentConflicts(undefined, {
|
|
224
|
+
const result = await integrationComponentConflicts(undefined, {
|
|
225
|
+
cwd: tmpDir,
|
|
226
|
+
});
|
|
225
227
|
|
|
226
228
|
expect(result.type).toBe('integration.component-conflicts');
|
|
227
229
|
expect(result.data.issues).toEqual([]);
|
|
@@ -240,7 +242,9 @@ describe('integrationComponentConflicts', () => {
|
|
|
240
242
|
it('does not flag an integration-only component name', async () => {
|
|
241
243
|
writeComponentIntegration('AcmeOnlyWidget');
|
|
242
244
|
|
|
243
|
-
const result = await integrationComponentConflicts(undefined, {
|
|
245
|
+
const result = await integrationComponentConflicts(undefined, {
|
|
246
|
+
cwd: tmpDir,
|
|
247
|
+
});
|
|
244
248
|
|
|
245
249
|
expect(result.data.conflicts).toEqual([]);
|
|
246
250
|
expect(result.data.issues).toEqual([]);
|
|
@@ -51,7 +51,7 @@ const ESBUILD_BIN = resolveBin('esbuild/bin/esbuild');
|
|
|
51
51
|
let tmpDir;
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
|
-
* Build an @acme/widgets fixture: a block template (`.template.ts`
|
|
54
|
+
* Build an @acme/widgets fixture: a block template (released `.template.ts` compatibility descriptor +
|
|
55
55
|
* same-stem `.tsx` source) under `templates/`, plus an astryx.integration
|
|
56
56
|
* manifest, plus a caller-supplied `exports` map.
|
|
57
57
|
* @param {Record<string, string> | undefined} exportsMap
|
|
@@ -71,7 +71,7 @@ function makeWidgets(exportsMap) {
|
|
|
71
71
|
path.join(pkgDir, 'astryx.integration.mjs'),
|
|
72
72
|
`export default { templates: './templates' };\n`,
|
|
73
73
|
);
|
|
74
|
-
// The
|
|
74
|
+
// The released `.template.*` compatibility form remains resolvable.
|
|
75
75
|
fs.writeFileSync(
|
|
76
76
|
path.join(blockDir, 'GaugeShowcase.template.ts'),
|
|
77
77
|
`export default { name: 'Gauge showcase', description: 'A gauge.' };\n`,
|
|
@@ -127,10 +127,14 @@ function writeTsconfig() {
|
|
|
127
127
|
/** @returns {{ok: boolean, out: string}} */
|
|
128
128
|
function runTsc() {
|
|
129
129
|
try {
|
|
130
|
-
execFileSync(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
execFileSync(
|
|
131
|
+
process.execPath,
|
|
132
|
+
[TSC_BIN, '--noEmit', '-p', 'tsconfig.json'],
|
|
133
|
+
{
|
|
134
|
+
cwd: tmpDir,
|
|
135
|
+
stdio: 'pipe',
|
|
136
|
+
},
|
|
137
|
+
);
|
|
134
138
|
return {ok: true, out: ''};
|
|
135
139
|
} catch (e) {
|
|
136
140
|
return {ok: false, out: `${e.stdout ?? ''}${e.stderr ?? ''}`};
|
|
@@ -5,10 +5,11 @@ export const doc = {
|
|
|
5
5
|
type: 'function',
|
|
6
6
|
kind: 'api',
|
|
7
7
|
name: 'integrationAddTheme',
|
|
8
|
+
namespace: 'cli/api',
|
|
8
9
|
displayName: 'integrationAddTheme()',
|
|
9
10
|
summary: 'Add a source theme to an integration package.',
|
|
10
11
|
description:
|
|
11
|
-
'Creates an integration manifest when the package has none, writes a minimal named-export defineTheme source file
|
|
12
|
+
'Creates an integration manifest when the package has none, writes a minimal named-export defineTheme source file plus its strongly typed same-stem ThemeDoc, declares the optional themes root on first use, and includes the manifest and root in package.json files when the package already uses an allowlist. Every path is confined to the package and existing theme directories are never overwritten.',
|
|
12
13
|
importPath: '@astryxdesign/cli/api',
|
|
13
14
|
signature:
|
|
14
15
|
'integrationAddTheme(name: string, options?: IntegrationAddThemeOptions): Promise<IntegrationAddResponse>',
|
|
@@ -17,7 +18,7 @@ export const doc = {
|
|
|
17
18
|
{
|
|
18
19
|
name: 'name',
|
|
19
20
|
type: 'string',
|
|
20
|
-
description: 'Lowercase kebab-case theme name and
|
|
21
|
+
description: 'Lowercase kebab-case theme name and directory slug.',
|
|
21
22
|
required: true,
|
|
22
23
|
},
|
|
23
24
|
{
|
|
@@ -51,7 +52,7 @@ export const doc = {
|
|
|
51
52
|
},
|
|
52
53
|
{
|
|
53
54
|
code: 'ERR_FILE_EXISTS',
|
|
54
|
-
when: 'the theme slug
|
|
55
|
+
when: 'the theme slug directory already exists',
|
|
55
56
|
},
|
|
56
57
|
{
|
|
57
58
|
code: 'ERR_PATH_TRAVERSAL',
|
|
@@ -63,7 +64,7 @@ export const doc = {
|
|
|
63
64
|
},
|
|
64
65
|
{
|
|
65
66
|
code: 'ERR_THEME_INVALID',
|
|
66
|
-
when: 'the package, integration manifest, or theme
|
|
67
|
+
when: 'the package, integration manifest, or theme descriptor is invalid',
|
|
67
68
|
},
|
|
68
69
|
{
|
|
69
70
|
code: 'ERR_WRITE_FAILED',
|
|
@@ -80,6 +81,6 @@ export const doc = {
|
|
|
80
81
|
code: "await integrationAddTheme('ocean', {dryRun: true});",
|
|
81
82
|
},
|
|
82
83
|
],
|
|
83
|
-
command: 'integration add',
|
|
84
|
+
command: 'integration add theme',
|
|
84
85
|
related: ['themeList', 'themeAdd', 'validateIntegration'],
|
|
85
86
|
};
|
|
@@ -53,25 +53,10 @@ function writePackage({
|
|
|
53
53
|
"import {defineTheme} from '@astryxdesign/core/theme';\n\nexport const oceanTheme = defineTheme({name: 'ocean'});\n",
|
|
54
54
|
);
|
|
55
55
|
fs.writeFileSync(
|
|
56
|
-
path.join(root, '
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
themes: [
|
|
61
|
-
{
|
|
62
|
-
slug: 'ocean',
|
|
63
|
-
displayName: 'Ocean',
|
|
64
|
-
description: 'Ocean theme.',
|
|
65
|
-
maintained: true,
|
|
66
|
-
entry: 'oceanTheme.ts',
|
|
67
|
-
exportName: 'oceanTheme',
|
|
68
|
-
files: ['oceanTheme.ts'],
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
},
|
|
72
|
-
null,
|
|
73
|
-
2,
|
|
74
|
-
) + '\n',
|
|
56
|
+
path.join(root, 'ocean', 'oceanTheme.doc.mjs'),
|
|
57
|
+
`/** @type {import('@astryxdesign/cli/authoring').ThemeDoc} */
|
|
58
|
+
export default {type: 'theme', name: 'ocean', displayName: 'Ocean', description: 'Ocean theme.', maintained: true};
|
|
59
|
+
`,
|
|
75
60
|
);
|
|
76
61
|
}
|
|
77
62
|
if (components) {
|
|
@@ -109,7 +94,7 @@ describe('integrationPackCheck', () => {
|
|
|
109
94
|
);
|
|
110
95
|
});
|
|
111
96
|
|
|
112
|
-
it('fails when a theme entry omits its
|
|
97
|
+
it('fails when a theme entry omits its inferred runtime export', async () => {
|
|
113
98
|
writePackage({files: ['astryx.integration.mjs', 'themes']});
|
|
114
99
|
fs.writeFileSync(
|
|
115
100
|
path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.ts'),
|
|
@@ -129,19 +114,12 @@ describe('integrationPackCheck', () => {
|
|
|
129
114
|
);
|
|
130
115
|
});
|
|
131
116
|
|
|
132
|
-
it('fails when a theme imports a
|
|
117
|
+
it('fails when a theme imports a missing local file', async () => {
|
|
133
118
|
writePackage({files: ['astryx.integration.mjs', 'themes']});
|
|
134
|
-
fs.mkdirSync(path.join(tmpDir, 'themes', 'ocean', 'tokens'), {
|
|
135
|
-
recursive: true,
|
|
136
|
-
});
|
|
137
119
|
fs.writeFileSync(
|
|
138
120
|
path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.ts'),
|
|
139
121
|
"import {oceanPalette} from './tokens/ocean.palette';\nexport const oceanTheme = {oceanPalette};\n",
|
|
140
122
|
);
|
|
141
|
-
fs.writeFileSync(
|
|
142
|
-
path.join(tmpDir, 'themes', 'ocean', 'tokens', 'ocean.palette.ts'),
|
|
143
|
-
'export const oceanPalette = {};\n',
|
|
144
|
-
);
|
|
145
123
|
|
|
146
124
|
const result = await integrationPackCheck({cwd: tmpDir});
|
|
147
125
|
|
|
@@ -150,7 +128,7 @@ describe('integrationPackCheck', () => {
|
|
|
150
128
|
expect.objectContaining({
|
|
151
129
|
code: 'invalid_theme',
|
|
152
130
|
message: expect.stringContaining(
|
|
153
|
-
'must resolve to a
|
|
131
|
+
'must resolve to a file inside the theme directory',
|
|
154
132
|
),
|
|
155
133
|
}),
|
|
156
134
|
);
|
|
@@ -231,7 +209,7 @@ describe('integrationPackCheck', () => {
|
|
|
231
209
|
);
|
|
232
210
|
fs.mkdirSync(path.join(tmpDir, 'templates'));
|
|
233
211
|
fs.writeFileSync(
|
|
234
|
-
path.join(tmpDir, 'templates', 'account-page.
|
|
212
|
+
path.join(tmpDir, 'templates', 'account-page.doc.mjs'),
|
|
235
213
|
"export default {type: 'page', name: 'Account page', description: 'Account page.'};\n",
|
|
236
214
|
);
|
|
237
215
|
fs.writeFileSync(
|
|
@@ -314,10 +292,10 @@ describe('integrationPackCheck', () => {
|
|
|
314
292
|
const script = [
|
|
315
293
|
"const fs=require('fs')",
|
|
316
294
|
"fs.renameSync('themes/ocean','themes/storm')",
|
|
317
|
-
"const p='themes/
|
|
318
|
-
|
|
319
|
-
"x.
|
|
320
|
-
'fs.writeFileSync(p,
|
|
295
|
+
"const p='themes/storm/oceanTheme.doc.mjs'",
|
|
296
|
+
"let x=fs.readFileSync(p,'utf8')",
|
|
297
|
+
"x=x.replace(/name: 'ocean'/, 'name: '+String.fromCharCode(39)+'storm'+String.fromCharCode(39))",
|
|
298
|
+
'fs.writeFileSync(p,x)',
|
|
321
299
|
].join(';');
|
|
322
300
|
writePackage({
|
|
323
301
|
files: ['astryx.integration.mjs', 'themes'],
|
|
@@ -513,23 +491,15 @@ describe('integrationPackCheck', () => {
|
|
|
513
491
|
});
|
|
514
492
|
|
|
515
493
|
describe('pack-check mutation tests', () => {
|
|
516
|
-
it('detects when a theme
|
|
494
|
+
it('detects when a theme source is deleted after initial authoring', async () => {
|
|
517
495
|
writePackage({files: ['astryx.integration.mjs', 'themes']});
|
|
518
|
-
|
|
519
|
-
// Write a second theme file then delete it — catalog still references it
|
|
520
|
-
const catalog = JSON.parse(
|
|
521
|
-
fs.readFileSync(path.join(tmpDir, 'themes', 'manifest.json'), 'utf-8'),
|
|
522
|
-
);
|
|
523
|
-
catalog.themes[0].files.push('tokens.ts');
|
|
524
|
-
fs.writeFileSync(
|
|
525
|
-
path.join(tmpDir, 'themes', 'manifest.json'),
|
|
526
|
-
JSON.stringify(catalog, null, 2) + '\n',
|
|
527
|
-
);
|
|
528
|
-
// tokens.ts doesn't exist on disk → will be in inventory but not on disk
|
|
529
|
-
// (Phase 1 catches this; the file won't be in the pack list either)
|
|
496
|
+
fs.rmSync(path.join(tmpDir, 'themes', 'ocean', 'oceanTheme.ts'));
|
|
530
497
|
|
|
531
498
|
const result = await integrationPackCheck({cwd: tmpDir});
|
|
532
499
|
expect(result.data.packable).toBe(false);
|
|
500
|
+
expect(result.data.issues).toContainEqual(
|
|
501
|
+
expect.objectContaining({code: 'invalid_theme'}),
|
|
502
|
+
);
|
|
533
503
|
});
|
|
534
504
|
|
|
535
505
|
it('detects when files[] is narrowed after add removes themes', async () => {
|