@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
|
@@ -104,13 +104,14 @@ export function ensureCodemodDeps({ installDeps }?: {
|
|
|
104
104
|
* Run the CORE registry codemods. Runs BEFORE the config is loaded so a core
|
|
105
105
|
* CONFIG codemod can repair a config the strict loader would otherwise reject.
|
|
106
106
|
* @param {CoreVersionManifest[]} versionManifests
|
|
107
|
-
* @param {{apply: boolean, path: string, codemod?: string, skipCodemods: Set<string
|
|
107
|
+
* @param {{apply: boolean, path: string, codemod?: string, skipCodemods: Set<string>, root?: string}} options
|
|
108
108
|
*/
|
|
109
|
-
export function runCoreCodemods(versionManifests: CoreVersionManifest[], { apply, path: srcPath, codemod, skipCodemods }: {
|
|
109
|
+
export function runCoreCodemods(versionManifests: CoreVersionManifest[], { apply, path: srcPath, codemod, skipCodemods, root }: {
|
|
110
110
|
apply: boolean;
|
|
111
111
|
path: string;
|
|
112
112
|
codemod?: string;
|
|
113
113
|
skipCodemods: Set<string>;
|
|
114
|
+
root?: string;
|
|
114
115
|
}): Promise<{
|
|
115
116
|
totalFilesChanged: number;
|
|
116
117
|
totalTransformsApplied: number;
|
|
@@ -139,13 +140,21 @@ export function runCoreCodemods(versionManifests: CoreVersionManifest[], { apply
|
|
|
139
140
|
/**
|
|
140
141
|
* Load the consumer project's config + integrations. Throws on invalid config;
|
|
141
142
|
* the run leaf decides between the config_fixable preview and a hard abort.
|
|
143
|
+
*
|
|
144
|
+
* Provider identity is resolved by the same resolver Project uses, on top of
|
|
145
|
+
* Project's ledger, under the codemod policy: a package that lists itself runs
|
|
146
|
+
* its installed copy's released codemods, never the work in progress being
|
|
147
|
+
* authored, and autolinked and local packages claim provider IDs without
|
|
148
|
+
* running codemods.
|
|
149
|
+
*
|
|
142
150
|
* @param {string} cwd
|
|
143
151
|
* @param {string[]} [extraIntegrationSpecs] explicit `--integration` specs
|
|
144
|
-
* @returns {Promise<{postCodemodHooks: import('../../authoring/config/type').PostCodemodHook[], integrations: import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]}>}
|
|
152
|
+
* @returns {Promise<{postCodemodHooks: import('../../authoring/config/type').PostCodemodHook[], integrations: import('../../foundation/integrations/integrations.mjs').LoadedIntegration[], ledger: import('../../foundation/integrations/provider-resolution.mjs').ProviderLedger}>}
|
|
145
153
|
*/
|
|
146
154
|
export function loadProjectContext(cwd: string, extraIntegrationSpecs?: string[]): Promise<{
|
|
147
155
|
postCodemodHooks: import("../../authoring/config/type").PostCodemodHook[];
|
|
148
156
|
integrations: import("../../foundation/integrations/integrations.mjs").LoadedIntegration[];
|
|
157
|
+
ledger: import("../../foundation/integrations/provider-resolution.mjs").ProviderLedger;
|
|
149
158
|
}>;
|
|
150
159
|
/**
|
|
151
160
|
* Non-blocking nudge for integration validation issues. Never throws (a broken
|
package/api/upgrade/_adapter.mjs
CHANGED
|
@@ -19,7 +19,10 @@ import * as path from 'node:path';
|
|
|
19
19
|
import {execFile} from 'node:child_process';
|
|
20
20
|
import {promisify} from 'node:util';
|
|
21
21
|
import {ensureJscodeshift} from '../../assets/codemods/ensure-jscodeshift.mjs';
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
getTransformsBetween,
|
|
24
|
+
latestVersion,
|
|
25
|
+
} from '../../assets/codemods/registry.mjs';
|
|
23
26
|
import {runCodemods} from '../../assets/codemods/runner.mjs';
|
|
24
27
|
import {
|
|
25
28
|
discoverIntegrationCodemods,
|
|
@@ -32,17 +35,15 @@ import {
|
|
|
32
35
|
renderAgentDocsBlock,
|
|
33
36
|
} from '../../foundation/agent-docs/agent-docs.mjs';
|
|
34
37
|
import {formatCliCommand} from '../../foundation/env/package-manager.mjs';
|
|
35
|
-
import {Project} from '../../foundation/config/project.mjs';
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
markProviderConflicts,
|
|
39
|
-
} from '../../foundation/integrations/integrations.mjs';
|
|
38
|
+
import {Project, providerLedgerOf} from '../../foundation/config/project.mjs';
|
|
39
|
+
import {loadIntegrations} from '../../foundation/integrations/integrations.mjs';
|
|
40
|
+
import {resolveProviders} from '../../foundation/integrations/provider-resolution.mjs';
|
|
40
41
|
import {warnOnIntegrationIssues} from '../../foundation/integrations/integration-warnings.mjs';
|
|
41
42
|
import {logger} from '../logger.mjs';
|
|
42
43
|
|
|
43
44
|
// Re-exported for the run leaf's lightweight agent-docs inspection path
|
|
44
45
|
// (config_fixable short-circuit, where the full render cannot load config).
|
|
45
|
-
export {
|
|
46
|
+
export {inspectAgentDocs};
|
|
46
47
|
|
|
47
48
|
const execFileAsync = promisify(execFile);
|
|
48
49
|
|
|
@@ -291,7 +292,13 @@ export async function collectAllCodemods() {
|
|
|
291
292
|
);
|
|
292
293
|
for (const {version, transforms} of manifests) {
|
|
293
294
|
for (const {name, meta, optional} of transforms) {
|
|
294
|
-
codemods.push({
|
|
295
|
+
codemods.push({
|
|
296
|
+
name,
|
|
297
|
+
title: meta.title,
|
|
298
|
+
version,
|
|
299
|
+
pr: meta.pr,
|
|
300
|
+
optional: !!optional,
|
|
301
|
+
});
|
|
295
302
|
}
|
|
296
303
|
}
|
|
297
304
|
return codemods;
|
|
@@ -322,33 +329,35 @@ export async function ensureCodemodDeps({installDeps} = {}) {
|
|
|
322
329
|
* Run the CORE registry codemods. Runs BEFORE the config is loaded so a core
|
|
323
330
|
* CONFIG codemod can repair a config the strict loader would otherwise reject.
|
|
324
331
|
* @param {CoreVersionManifest[]} versionManifests
|
|
325
|
-
* @param {{apply: boolean, path: string, codemod?: string, skipCodemods: Set<string
|
|
332
|
+
* @param {{apply: boolean, path: string, codemod?: string, skipCodemods: Set<string>, root?: string}} options
|
|
326
333
|
*/
|
|
327
|
-
export async function runCoreCodemods(
|
|
334
|
+
export async function runCoreCodemods(
|
|
335
|
+
versionManifests,
|
|
336
|
+
{apply, path: srcPath, codemod, skipCodemods, root},
|
|
337
|
+
) {
|
|
328
338
|
return runCodemods(versionManifests, {
|
|
329
339
|
apply,
|
|
330
340
|
path: srcPath,
|
|
331
341
|
codemod,
|
|
332
342
|
skipCodemods,
|
|
333
343
|
silent: logger.silent,
|
|
344
|
+
root,
|
|
334
345
|
});
|
|
335
346
|
}
|
|
336
347
|
|
|
337
|
-
/**
|
|
338
|
-
* One installed package at one version; two specs that reach it share this.
|
|
339
|
-
* @param {{name: string, version?: string}} integration
|
|
340
|
-
* @returns {string}
|
|
341
|
-
*/
|
|
342
|
-
function packageIdentity(integration) {
|
|
343
|
-
return `${integration.name}\u0000${integration.version ?? ''}`;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
348
|
/**
|
|
347
349
|
* Load the consumer project's config + integrations. Throws on invalid config;
|
|
348
350
|
* the run leaf decides between the config_fixable preview and a hard abort.
|
|
351
|
+
*
|
|
352
|
+
* Provider identity is resolved by the same resolver Project uses, on top of
|
|
353
|
+
* Project's ledger, under the codemod policy: a package that lists itself runs
|
|
354
|
+
* its installed copy's released codemods, never the work in progress being
|
|
355
|
+
* authored, and autolinked and local packages claim provider IDs without
|
|
356
|
+
* running codemods.
|
|
357
|
+
*
|
|
349
358
|
* @param {string} cwd
|
|
350
359
|
* @param {string[]} [extraIntegrationSpecs] explicit `--integration` specs
|
|
351
|
-
* @returns {Promise<{postCodemodHooks: import('../../authoring/config/type').PostCodemodHook[], integrations: import('../../foundation/integrations/integrations.mjs').LoadedIntegration[]}>}
|
|
360
|
+
* @returns {Promise<{postCodemodHooks: import('../../authoring/config/type').PostCodemodHook[], integrations: import('../../foundation/integrations/integrations.mjs').LoadedIntegration[], ledger: import('../../foundation/integrations/provider-resolution.mjs').ProviderLedger}>}
|
|
352
361
|
*/
|
|
353
362
|
export async function loadProjectContext(cwd, extraIntegrationSpecs = []) {
|
|
354
363
|
// The CLI debug preflight may already have imported this config before core
|
|
@@ -360,23 +369,38 @@ export async function loadProjectContext(cwd, extraIntegrationSpecs = []) {
|
|
|
360
369
|
// Configured packages come from Project, which has already resolved provider
|
|
361
370
|
// identity over configured, autolinked, and local packages. Loading them
|
|
362
371
|
// again here would let upgrade run codemods from a package Project set aside.
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
372
|
+
// Autolinked packages and the package being authored join only as claimants:
|
|
373
|
+
// every other command uses them for their provider IDs, but upgrade has
|
|
374
|
+
// never run their codemods.
|
|
375
|
+
const candidates = project.loadedIntegrations.flatMap(integration => {
|
|
376
|
+
const source =
|
|
377
|
+
!integration.__autolinked && configuredSpecs.has(integration.__spec)
|
|
378
|
+
? /** @type {const} */ ('configured')
|
|
379
|
+
: integration.__autolinked
|
|
380
|
+
? /** @type {const} */ ('autolinked')
|
|
381
|
+
: integration.__local
|
|
382
|
+
? /** @type {const} */ ('local')
|
|
383
|
+
: null;
|
|
384
|
+
return source == null
|
|
385
|
+
? []
|
|
386
|
+
: [{source, integration, spec: integration.__spec}];
|
|
387
|
+
});
|
|
367
388
|
// A package that lists itself runs its installed copy's released codemods,
|
|
368
|
-
// never the work in progress being authored
|
|
389
|
+
// never the work in progress being authored; the resolver puts that copy in
|
|
390
|
+
// its place. Naming the package being authored with --integration asks for
|
|
391
|
+
// the installed copy too.
|
|
369
392
|
const local = project.loadedIntegrations.find(
|
|
370
393
|
integration => integration.__local,
|
|
371
394
|
);
|
|
372
|
-
const selfListed =
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
395
|
+
const selfListed =
|
|
396
|
+
local != null && !local.__autolinked && configuredSpecs.has(local.__spec);
|
|
397
|
+
const installed =
|
|
398
|
+
local != null && selfListed && project.configPath
|
|
399
|
+
? await loadIntegrations([local.__spec], {
|
|
400
|
+
cwd: path.dirname(project.configPath),
|
|
401
|
+
resolveProviders: false,
|
|
402
|
+
})
|
|
403
|
+
: [];
|
|
380
404
|
const extraSpecs = uniqueFiles(extraIntegrationSpecs ?? []).filter(
|
|
381
405
|
spec => !configuredSpecs.has(spec),
|
|
382
406
|
);
|
|
@@ -384,38 +408,23 @@ export async function loadProjectContext(cwd, extraIntegrationSpecs = []) {
|
|
|
384
408
|
extraSpecs.length === 0
|
|
385
409
|
? []
|
|
386
410
|
: await loadIntegrations(extraSpecs, {resolveProviders: false});
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
const resolved = markProviderConflicts([
|
|
403
|
-
...configured,
|
|
404
|
-
...claimantsOnly,
|
|
405
|
-
...extras,
|
|
406
|
-
]);
|
|
407
|
-
// Claimants leave by package directory, not object identity: the pass can
|
|
408
|
-
// return one as a new conflict entry, and upgrade must not warn that a
|
|
409
|
-
// package every other command uses contributes nothing.
|
|
410
|
-
const claimantDirs = new Set(
|
|
411
|
-
claimantsOnly.map(integration => integration.__packageDir),
|
|
412
|
-
);
|
|
413
|
-
const integrations = resolved.filter(
|
|
414
|
-
integration =>
|
|
415
|
-
integration.__packageDir == null ||
|
|
416
|
-
!claimantDirs.has(integration.__packageDir),
|
|
411
|
+
const {integrations, ledger} = resolveProviders(
|
|
412
|
+
[
|
|
413
|
+
...candidates,
|
|
414
|
+
...installed.map(integration => ({
|
|
415
|
+
source: /** @type {const} */ ('installed'),
|
|
416
|
+
integration,
|
|
417
|
+
spec: integration.__spec,
|
|
418
|
+
})),
|
|
419
|
+
...extras.map(integration => ({
|
|
420
|
+
source: /** @type {const} */ ('extra'),
|
|
421
|
+
integration,
|
|
422
|
+
spec: integration.__spec,
|
|
423
|
+
})),
|
|
424
|
+
],
|
|
425
|
+
{codemods: true, prior: providerLedgerOf(project)},
|
|
417
426
|
);
|
|
418
|
-
return {postCodemodHooks, integrations};
|
|
427
|
+
return {postCodemodHooks, integrations, ledger};
|
|
419
428
|
}
|
|
420
429
|
|
|
421
430
|
/**
|
|
@@ -450,7 +459,10 @@ export async function selectIntegrationCodemodsFor(integrations, from, to) {
|
|
|
450
459
|
try {
|
|
451
460
|
const byVersion = await discoverIntegrationCodemods([integration]);
|
|
452
461
|
for (const [version, rawList] of byVersion) {
|
|
453
|
-
const list =
|
|
462
|
+
const list =
|
|
463
|
+
/** @type {Array<import('../../authoring/codemod/type').CodemodEntry>} */ (
|
|
464
|
+
/** @type {unknown} */ (rawList)
|
|
465
|
+
);
|
|
454
466
|
const existing = integrationCodemodsByVersion.get(version);
|
|
455
467
|
if (existing) existing.push(...list);
|
|
456
468
|
else integrationCodemodsByVersion.set(version, [...list]);
|
|
@@ -469,7 +481,10 @@ export async function selectIntegrationCodemodsFor(integrations, from, to) {
|
|
|
469
481
|
* @param {Array<{version: string, codemods: import('../../authoring/codemod/type').CodemodEntry[]}>} versionGroups
|
|
470
482
|
* @param {{apply: boolean, path: string, codemod?: string, skipCodemods: Set<string>}} options
|
|
471
483
|
*/
|
|
472
|
-
export async function runIntegrationCodemodsStep(
|
|
484
|
+
export async function runIntegrationCodemodsStep(
|
|
485
|
+
versionGroups,
|
|
486
|
+
{apply, path: srcPath, codemod, skipCodemods},
|
|
487
|
+
) {
|
|
473
488
|
const jscodeshift = (await import('jscodeshift')).default;
|
|
474
489
|
return runIntegrationCodemods(versionGroups, {
|
|
475
490
|
apply,
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Where `upgrade` and Project still disagree on a provider ID's winner.
|
|
5
|
+
*
|
|
6
|
+
* Both repros are `it.fails`: each asserts the agreeing result, and fails
|
|
7
|
+
* today. `upgrade` lets an `--integration` extra of the same name@version stand
|
|
8
|
+
* in for an autolinked package, from any directory, and orders that extra with
|
|
9
|
+
* the extras. So another extra can take the provider ID in `upgrade` while
|
|
10
|
+
* every other command gives it to the autolinked package. The provider ledger
|
|
11
|
+
* property test carves out exactly this shape.
|
|
12
|
+
*
|
|
13
|
+
* Fixtures live under a repo-local temp dir, not /tmp, because Vite refuses to
|
|
14
|
+
* dynamically import a module from outside the project root.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {afterEach, beforeEach, describe, expect, it} from 'vitest';
|
|
18
|
+
import * as fs from 'node:fs';
|
|
19
|
+
import * as path from 'node:path';
|
|
20
|
+
import {loadProjectContext} from './_adapter.mjs';
|
|
21
|
+
import {Project, providerLedgerOf} from '../../foundation/config/project.mjs';
|
|
22
|
+
|
|
23
|
+
let tmpDir;
|
|
24
|
+
let originalCwd;
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
originalCwd = process.cwd();
|
|
28
|
+
tmpDir = fs.mkdtempSync(
|
|
29
|
+
path.join(process.cwd(), '.astryx-upgrade-agreement-'),
|
|
30
|
+
);
|
|
31
|
+
process.chdir(tmpDir);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
process.chdir(originalCwd);
|
|
36
|
+
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Install a package under node_modules/<dir>.
|
|
41
|
+
* @param {string} dir
|
|
42
|
+
* @param {{name: string, version: string}} pkg
|
|
43
|
+
* @param {string} manifest manifest module source
|
|
44
|
+
*/
|
|
45
|
+
function install(dir, pkg, manifest) {
|
|
46
|
+
const pkgDir = path.join(tmpDir, 'node_modules', ...dir.split('/'));
|
|
47
|
+
fs.mkdirSync(pkgDir, {recursive: true});
|
|
48
|
+
fs.writeFileSync(path.join(pkgDir, 'package.json'), JSON.stringify(pkg));
|
|
49
|
+
fs.writeFileSync(path.join(pkgDir, 'astryx.integration.mjs'), manifest);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** An autolinked `@acme/a` and an `@acme/other` that claims its provider ID. */
|
|
53
|
+
function autolinkedWithRival() {
|
|
54
|
+
fs.writeFileSync(
|
|
55
|
+
path.join(tmpDir, 'package.json'),
|
|
56
|
+
JSON.stringify({name: 'consumer', dependencies: {'@acme/a': '1.0.0'}}),
|
|
57
|
+
);
|
|
58
|
+
install(
|
|
59
|
+
'@acme/a',
|
|
60
|
+
{name: '@acme/a', version: '1.0.0'},
|
|
61
|
+
'export default {};\n',
|
|
62
|
+
);
|
|
63
|
+
install(
|
|
64
|
+
'@acme/other',
|
|
65
|
+
{name: '@acme/other', version: '1.0.0'},
|
|
66
|
+
"export default {providerId: '@acme/a'};\n",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The package each resolution lets contribute under a provider ID.
|
|
72
|
+
* @param {Map<string, any>} ledger
|
|
73
|
+
* @param {string} providerId
|
|
74
|
+
*/
|
|
75
|
+
function winnerOf(ledger, providerId) {
|
|
76
|
+
return [...ledger.values()].find(
|
|
77
|
+
entry => entry.outcome === 'contributes' && entry.providerId === providerId,
|
|
78
|
+
)?.key;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** @param {Array<import('../../foundation/integrations/integrations.mjs').LoadedIntegration>} integrations */
|
|
82
|
+
function claims(integrations) {
|
|
83
|
+
return integrations.map(integration => [
|
|
84
|
+
integration.name,
|
|
85
|
+
integration.__providerConflict?.claimedBy ?? null,
|
|
86
|
+
]);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
describe('upgrade and Project on an autolinked package named with --integration', () => {
|
|
90
|
+
it('agree when the autolinked package is named first', async () => {
|
|
91
|
+
autolinkedWithRival();
|
|
92
|
+
const project = await Project.load(tmpDir, {fresh: true});
|
|
93
|
+
const upgrade = await loadProjectContext(tmpDir, [
|
|
94
|
+
'@acme/a',
|
|
95
|
+
'@acme/other',
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
expect(claims(upgrade.integrations)).toEqual([
|
|
99
|
+
['@acme/a', null],
|
|
100
|
+
['@acme/other', '@acme/a'],
|
|
101
|
+
]);
|
|
102
|
+
expect(winnerOf(upgrade.ledger, '@acme/a')).toBe(
|
|
103
|
+
winnerOf(providerLedgerOf(project), '@acme/a'),
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it.fails(
|
|
108
|
+
'agree when an extra that claims its ID is named first',
|
|
109
|
+
async () => {
|
|
110
|
+
autolinkedWithRival();
|
|
111
|
+
const project = await Project.load(tmpDir, {fresh: true});
|
|
112
|
+
// Today upgrade runs @acme/other and reports @acme/a, which every other
|
|
113
|
+
// command uses, as contributing nothing.
|
|
114
|
+
const upgrade = await loadProjectContext(tmpDir, [
|
|
115
|
+
'@acme/other',
|
|
116
|
+
'@acme/a',
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
expect(winnerOf(upgrade.ledger, '@acme/a')).toBe(
|
|
120
|
+
winnerOf(providerLedgerOf(project), '@acme/a'),
|
|
121
|
+
);
|
|
122
|
+
expect(claims(upgrade.integrations)).toEqual([
|
|
123
|
+
['@acme/other', '@acme/a'],
|
|
124
|
+
['@acme/a', null],
|
|
125
|
+
]);
|
|
126
|
+
},
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
it.fails(
|
|
130
|
+
'agree when a copy of it in another directory is named',
|
|
131
|
+
async () => {
|
|
132
|
+
autolinkedWithRival();
|
|
133
|
+
// The same name@version in another directory, with a manifest that fails.
|
|
134
|
+
install(
|
|
135
|
+
'@acme/a-copy',
|
|
136
|
+
{name: '@acme/a', version: '1.0.0'},
|
|
137
|
+
"throw new Error('broken copy');\n",
|
|
138
|
+
);
|
|
139
|
+
const project = await Project.load(tmpDir, {fresh: true});
|
|
140
|
+
// Today the broken copy stands in for @acme/a by name@version, so upgrade
|
|
141
|
+
// has no claimant left for the ID and @acme/other takes it.
|
|
142
|
+
const upgrade = await loadProjectContext(tmpDir, [
|
|
143
|
+
'@acme/a-copy',
|
|
144
|
+
'@acme/other',
|
|
145
|
+
]);
|
|
146
|
+
|
|
147
|
+
expect(winnerOf(upgrade.ledger, '@acme/a')).toBe(
|
|
148
|
+
winnerOf(providerLedgerOf(project), '@acme/a'),
|
|
149
|
+
);
|
|
150
|
+
},
|
|
151
|
+
);
|
|
152
|
+
});
|
package/api/upgrade/run/run.mjs
CHANGED
|
@@ -171,6 +171,7 @@ export async function run(options = {}, {cwd = process.cwd()} = {}) {
|
|
|
171
171
|
path: path_,
|
|
172
172
|
codemod: options.codemod,
|
|
173
173
|
skipCodemods,
|
|
174
|
+
root: cwd,
|
|
174
175
|
});
|
|
175
176
|
const coreResult = codemodResult && 'totalFilesChanged' in codemodResult ? codemodResult : null;
|
|
176
177
|
|
|
@@ -106,7 +106,7 @@ function collectCodemodFiles(versionDir) {
|
|
|
106
106
|
/**
|
|
107
107
|
* Discover file-based codemods contributed by configured integrations.
|
|
108
108
|
*
|
|
109
|
-
* @param {Array<{name?: string, codemods?: string, __spec?: string}>} loadedIntegrations
|
|
109
|
+
* @param {Array<{name?: string, codemods?: string, __spec?: string, __packageDir?: string}>} loadedIntegrations
|
|
110
110
|
* @returns {Promise<Map<string, Array<{id: string, type: 'code'|'config', codemod: object, package: string}>>>}
|
|
111
111
|
* Map keyed by version string; each value is the list of discovered codemods
|
|
112
112
|
* for that version (across all integrations).
|
|
@@ -145,7 +145,13 @@ export async function discoverIntegrationCodemods(loadedIntegrations = []) {
|
|
|
145
145
|
const seenInVersion = new Set();
|
|
146
146
|
|
|
147
147
|
for (const {id, file} of files) {
|
|
148
|
-
const
|
|
148
|
+
const shown = integration.__packageDir
|
|
149
|
+
? path
|
|
150
|
+
.relative(integration.__packageDir, file)
|
|
151
|
+
.split(path.sep)
|
|
152
|
+
.join('/')
|
|
153
|
+
: file;
|
|
154
|
+
const label = `Integration "${pkgLabel}" codemod ${version}/${id} (${shown})`;
|
|
149
155
|
|
|
150
156
|
if (seenInVersion.has(id)) {
|
|
151
157
|
throw new Error(
|
|
@@ -163,6 +163,21 @@ describe('integration codemod discovery', () => {
|
|
|
163
163
|
).rejects.toThrow(/is invalid/i);
|
|
164
164
|
});
|
|
165
165
|
|
|
166
|
+
it('names a broken codemod by its path inside the package', async () => {
|
|
167
|
+
scaffold({
|
|
168
|
+
'1.1.0/no-default.mjs': `export const nope = 1;\n`,
|
|
169
|
+
});
|
|
170
|
+
const project = await Project.load(tmpDir);
|
|
171
|
+
const failure = await discoverIntegrationCodemods(
|
|
172
|
+
project.loadedIntegrations,
|
|
173
|
+
).then(
|
|
174
|
+
() => null,
|
|
175
|
+
error => error,
|
|
176
|
+
);
|
|
177
|
+
expect(failure?.message).toContain('(codemods/1.1.0/no-default.mjs)');
|
|
178
|
+
expect(failure?.message).not.toContain(tmpDir);
|
|
179
|
+
});
|
|
180
|
+
|
|
166
181
|
it('fails discovery when default export is not a codemod envelope', async () => {
|
|
167
182
|
scaffold({
|
|
168
183
|
'0.2.0/bad.mjs': `export default { title: 'x', transform: () => null };\n`,
|
|
@@ -194,6 +194,89 @@ function toUnifiedEntry(transformEntry, version) {
|
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
/**
|
|
198
|
+
* What a core PROJECT codemod plans: whole files to write and delete under the
|
|
199
|
+
* project root, or the problems that stop it. Paths in `writes` and `deletes`
|
|
200
|
+
* are absolute; `problems` name package-relative files.
|
|
201
|
+
*
|
|
202
|
+
* @typedef {object} ProjectCodemodPlan
|
|
203
|
+
* @property {Array<{path: string, contents: string}>} writes
|
|
204
|
+
* @property {string[]} deletes
|
|
205
|
+
* @property {Array<{file: string, message: string}>} problems
|
|
206
|
+
*/
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Run one core PROJECT codemod (`meta.codemodType === 'project'`): instead of
|
|
210
|
+
* rewriting the files it is handed, it reads the project and plans whole-file
|
|
211
|
+
* writes and deletions, which this applies (or previews) as one unit. A plan
|
|
212
|
+
* that names a problem changes nothing. Core-only: integration codemods keep
|
|
213
|
+
* the file contract.
|
|
214
|
+
*
|
|
215
|
+
* @param {{name: string, transform: unknown}} transformEntry
|
|
216
|
+
* @param {{apply: boolean, root: string, log: {success: (m: string) => void, warn: (m: string) => void, error: (m: string) => void}}} options
|
|
217
|
+
* @returns {Promise<{filesChanged: number, writtenFiles: string[], errors: Array<{file: string, codemod: string, error: string}>}>}
|
|
218
|
+
*/
|
|
219
|
+
async function runProjectCodemod({name, transform}, {apply, root, log}) {
|
|
220
|
+
/** @param {string} file */
|
|
221
|
+
const rel = file => path.relative(root, file).split(path.sep).join('/');
|
|
222
|
+
/** @type {ProjectCodemodPlan} */
|
|
223
|
+
let plan;
|
|
224
|
+
try {
|
|
225
|
+
plan = await /** @type {(root: string) => Promise<ProjectCodemodPlan>} */ (
|
|
226
|
+
transform
|
|
227
|
+
)(root);
|
|
228
|
+
} catch (err) {
|
|
229
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
230
|
+
log.error(` ✗ ${message}`);
|
|
231
|
+
return {
|
|
232
|
+
filesChanged: 0,
|
|
233
|
+
writtenFiles: [],
|
|
234
|
+
errors: [{file: '.', codemod: name, error: message}],
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
if (plan.problems.length > 0) {
|
|
238
|
+
for (const {file, message} of plan.problems) {
|
|
239
|
+
log.error(` ✗ ${file} — ${message}`);
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
filesChanged: 0,
|
|
243
|
+
writtenFiles: [],
|
|
244
|
+
errors: plan.problems.map(({file, message}) => ({
|
|
245
|
+
file,
|
|
246
|
+
codemod: name,
|
|
247
|
+
error: message,
|
|
248
|
+
})),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/** @type {string[]} */
|
|
252
|
+
const writtenFiles = [];
|
|
253
|
+
for (const write of plan.writes) {
|
|
254
|
+
if (apply) {
|
|
255
|
+
fs.mkdirSync(path.dirname(write.path), {recursive: true});
|
|
256
|
+
fs.writeFileSync(write.path, write.contents, 'utf-8');
|
|
257
|
+
writtenFiles.push(write.path);
|
|
258
|
+
log.success(` ✓ ${rel(write.path)}`);
|
|
259
|
+
} else {
|
|
260
|
+
log.warn(` ~ ${rel(write.path)} (would write)`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Deletions go last, so a failed write leaves a state a rerun completes.
|
|
264
|
+
for (const file of plan.deletes) {
|
|
265
|
+
if (apply) {
|
|
266
|
+
fs.rmSync(file);
|
|
267
|
+
writtenFiles.push(file);
|
|
268
|
+
log.success(` ✓ ${rel(file)} (removed)`);
|
|
269
|
+
} else {
|
|
270
|
+
log.warn(` ~ ${rel(file)} (would remove)`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
filesChanged: plan.writes.length + plan.deletes.length,
|
|
275
|
+
writtenFiles,
|
|
276
|
+
errors: [],
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
197
280
|
/**
|
|
198
281
|
* Run codemods against source files.
|
|
199
282
|
*
|
|
@@ -204,11 +287,19 @@ function toUnifiedEntry(transformEntry, version) {
|
|
|
204
287
|
* @param {string|undefined} options.codemod - Run only this specific transform
|
|
205
288
|
* @param {Set<string>} [options.skipCodemods] - Transform names to exclude
|
|
206
289
|
* @param {boolean} [options.silent] - Suppress all human-facing output (for --json)
|
|
290
|
+
* @param {string} [options.root] - Project root a project codemod reads (default: the process cwd)
|
|
207
291
|
* @returns {Promise<{totalFilesChanged: number, totalTransformsApplied: number, totalValidationBlocked: number, writtenFiles: string[], errors: Array<{file: string, codemod: string, error: string}>, skippedOptional: Array<{name: string, meta: {title: string, description?: string, fileExtensions?: string[], codemodType?: string}, version: string}>} | {ok: false, reason: string, resolvedPath: string}>}
|
|
208
292
|
*/
|
|
209
293
|
export async function runCodemods(
|
|
210
294
|
versionManifests,
|
|
211
|
-
{
|
|
295
|
+
{
|
|
296
|
+
apply,
|
|
297
|
+
path: srcPath,
|
|
298
|
+
codemod,
|
|
299
|
+
skipCodemods,
|
|
300
|
+
silent = false,
|
|
301
|
+
root = process.cwd(),
|
|
302
|
+
},
|
|
212
303
|
) {
|
|
213
304
|
// No-op stub object so silent mode skips log output entirely without
|
|
214
305
|
// littering the body with `if (!silent)` guards.
|
|
@@ -221,11 +312,14 @@ export async function runCodemods(
|
|
|
221
312
|
|
|
222
313
|
const resolvedPath = path.resolve(srcPath);
|
|
223
314
|
|
|
224
|
-
// Config codemods
|
|
225
|
-
//
|
|
226
|
-
//
|
|
315
|
+
// Config and project codemods never read the files under --path, so a
|
|
316
|
+
// missing --path should not block them. Only hard-fail on a missing source
|
|
317
|
+
// path when there is at least one CODE codemod to run.
|
|
227
318
|
const hasCodeCodemod = versionManifests.some(({transforms}) =>
|
|
228
|
-
transforms.some(
|
|
319
|
+
transforms.some(
|
|
320
|
+
t =>
|
|
321
|
+
t.meta?.codemodType !== 'config' && t.meta?.codemodType !== 'project',
|
|
322
|
+
),
|
|
229
323
|
);
|
|
230
324
|
const sourcePathExists = fs.existsSync(resolvedPath);
|
|
231
325
|
|
|
@@ -290,6 +384,22 @@ export async function runCodemods(
|
|
|
290
384
|
// `(file, api)` contract and targets the consumer's astryx.config.*.
|
|
291
385
|
// A core entry signals "config" via `meta.codemodType === 'config'`
|
|
292
386
|
// (see toUnifiedEntry).
|
|
387
|
+
if (meta?.codemodType === 'project') {
|
|
388
|
+
const result = await runProjectCodemod(transformEntry, {
|
|
389
|
+
apply,
|
|
390
|
+
root,
|
|
391
|
+
log,
|
|
392
|
+
});
|
|
393
|
+
if (result.errors.length > 0) {
|
|
394
|
+
errors.push(...result.errors);
|
|
395
|
+
} else if (result.filesChanged > 0) {
|
|
396
|
+
totalFilesChanged += result.filesChanged;
|
|
397
|
+
totalTransformsApplied += 1;
|
|
398
|
+
writtenFiles.push(...result.writtenFiles);
|
|
399
|
+
}
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
|
|
293
403
|
if (meta?.codemodType === 'config') {
|
|
294
404
|
const result = runConfigCodemod(toUnifiedEntry(transformEntry, version), {
|
|
295
405
|
apply,
|