@strapi/upgrade 0.0.0-experimental.e3e48deb89bd0a1b6cc69b698696566fa7854a95 → 0.0.0-experimental.e8d8fc824d0f6a695b2a9ebaa4680ed21c3645ca
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/LICENSE +19 -4
- package/README.md +1 -1
- package/dist/cli.js +1578 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.js +739 -387
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +735 -384
- package/dist/index.mjs.map +1 -1
- package/dist/modules/codemod/codemod.d.ts +4 -2
- package/dist/modules/codemod/codemod.d.ts.map +1 -1
- package/dist/modules/codemod/types.d.ts +8 -1
- package/dist/modules/codemod/types.d.ts.map +1 -1
- package/dist/modules/codemod-repository/constants.d.ts.map +1 -1
- package/dist/modules/codemod-repository/repository.d.ts +6 -5
- package/dist/modules/codemod-repository/repository.d.ts.map +1 -1
- package/dist/modules/codemod-repository/types.d.ts +7 -3
- package/dist/modules/codemod-repository/types.d.ts.map +1 -1
- package/dist/modules/codemod-runner/codemod-runner.d.ts +3 -0
- package/dist/modules/codemod-runner/codemod-runner.d.ts.map +1 -1
- package/dist/modules/codemod-runner/index.d.ts +1 -0
- package/dist/modules/codemod-runner/index.d.ts.map +1 -1
- package/dist/modules/codemod-runner/types.d.ts +1 -0
- package/dist/modules/codemod-runner/types.d.ts.map +1 -1
- package/dist/modules/error/utils.d.ts +8 -0
- package/dist/modules/error/utils.d.ts.map +1 -1
- package/dist/modules/file-scanner/scanner.d.ts.map +1 -1
- package/dist/modules/format/formats.d.ts +6 -0
- package/dist/modules/format/formats.d.ts.map +1 -1
- package/dist/modules/project/constants.d.ts +6 -3
- package/dist/modules/project/constants.d.ts.map +1 -1
- package/dist/modules/project/index.d.ts +2 -0
- package/dist/modules/project/index.d.ts.map +1 -1
- package/dist/modules/project/project.d.ts +27 -5
- package/dist/modules/project/project.d.ts.map +1 -1
- package/dist/modules/project/types.d.ts +3 -10
- package/dist/modules/project/types.d.ts.map +1 -1
- package/dist/modules/project/utils.d.ts +6 -0
- package/dist/modules/project/utils.d.ts.map +1 -0
- package/dist/modules/report/report.d.ts.map +1 -1
- package/dist/modules/requirement/types.d.ts +2 -2
- package/dist/modules/requirement/types.d.ts.map +1 -1
- package/dist/modules/runner/json/transform.d.ts.map +1 -1
- package/dist/modules/upgrader/types.d.ts +6 -0
- package/dist/modules/upgrader/types.d.ts.map +1 -1
- package/dist/modules/upgrader/upgrader.d.ts +7 -3
- package/dist/modules/upgrader/upgrader.d.ts.map +1 -1
- package/dist/modules/version/range.d.ts +2 -0
- package/dist/modules/version/range.d.ts.map +1 -1
- package/dist/modules/version/types.d.ts +2 -1
- package/dist/modules/version/types.d.ts.map +1 -1
- package/dist/tasks/codemods/index.d.ts +2 -1
- package/dist/tasks/codemods/index.d.ts.map +1 -1
- package/dist/tasks/codemods/list-codemods.d.ts +3 -0
- package/dist/tasks/codemods/list-codemods.d.ts.map +1 -0
- package/dist/tasks/codemods/run-codemods.d.ts +3 -0
- package/dist/tasks/codemods/run-codemods.d.ts.map +1 -0
- package/dist/tasks/codemods/types.d.ts +9 -3
- package/dist/tasks/codemods/types.d.ts.map +1 -1
- package/dist/tasks/codemods/utils.d.ts +6 -0
- package/dist/tasks/codemods/utils.d.ts.map +1 -0
- package/dist/tasks/index.d.ts +1 -1
- package/dist/tasks/index.d.ts.map +1 -1
- package/dist/tasks/upgrade/prompts/index.d.ts +2 -0
- package/dist/tasks/upgrade/prompts/index.d.ts.map +1 -0
- package/dist/tasks/upgrade/prompts/latest.d.ts +9 -0
- package/dist/tasks/upgrade/prompts/latest.d.ts.map +1 -0
- package/dist/tasks/upgrade/requirements/major.d.ts.map +1 -1
- package/dist/tasks/upgrade/upgrade.d.ts.map +1 -1
- package/package.json +11 -10
- package/resources/codemods/5.0.0/comment-out-lifecycle-files.code.ts +63 -0
- package/resources/codemods/5.0.0/dependency-remove-strapi-plugin-i18n.json.ts +31 -0
- package/resources/codemods/5.0.0/dependency-upgrade-react-and-react-dom.json.ts +67 -0
- package/resources/codemods/5.0.0/dependency-upgrade-react-router-dom.json.ts +59 -0
- package/resources/codemods/5.0.0/dependency-upgrade-styled-components.json.ts +49 -0
- package/resources/codemods/5.0.0/deprecate-helper-plugin.code.ts +192 -0
- package/resources/codemods/5.0.0/entity-service-document-service.code.ts +437 -0
- package/resources/codemods/5.0.0/s3-keys-wrapped-in-credentials.code.ts +1 -1
- package/resources/codemods/5.0.0/sqlite3-to-better-sqlite3.json.ts +5 -3
- package/resources/codemods/5.0.0/strapi-public-interface.code.ts +126 -0
- package/resources/codemods/5.0.0/use-uid-for-config-namespace.code.ts +1 -1
- package/resources/codemods/5.0.0/utils-public-interface.code.ts +320 -0
- package/resources/codemods/5.1.0/dependency-better-sqlite3.json.ts +48 -0
- package/resources/examples/console.log-to-console.info.code.ts +1 -1
- package/resources/examples/disable-jsx-buttons.code.ts +42 -0
- package/resources/utils/change-import.ts +118 -0
- package/resources/utils/replace-jsx.ts +49 -0
- package/dist/_chunks/codemod-runner-B5OeSMTQ.js +0 -730
- package/dist/_chunks/codemod-runner-B5OeSMTQ.js.map +0 -1
- package/dist/_chunks/codemods-10ZKewQx.js +0 -108
- package/dist/_chunks/codemods-10ZKewQx.js.map +0 -1
- package/dist/_chunks/index-uxCwtuH1.js +0 -103
- package/dist/_chunks/index-uxCwtuH1.js.map +0 -1
- package/dist/_chunks/upgrade-A4T1OWs5.js +0 -357
- package/dist/_chunks/upgrade-A4T1OWs5.js.map +0 -1
- package/dist/tasks/codemods/codemods.d.ts +0 -3
- package/dist/tasks/codemods/codemods.d.ts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,128 +1,15 @@
|
|
|
1
1
|
import path$1 from "node:path";
|
|
2
|
-
import
|
|
2
|
+
import CliTable3 from "cli-table3";
|
|
3
3
|
import chalk from "chalk";
|
|
4
|
+
import assert from "node:assert";
|
|
4
5
|
import semver from "semver";
|
|
5
|
-
import { packageManager } from "@strapi/utils";
|
|
6
|
-
import { cloneDeep, get, has, merge, set, omit, isEqual } from "lodash/fp";
|
|
7
6
|
import fse from "fs-extra";
|
|
8
|
-
import
|
|
9
|
-
import { glob } from "glob";
|
|
7
|
+
import fastglob from "fast-glob";
|
|
10
8
|
import { run } from "jscodeshift/src/Runner";
|
|
9
|
+
import { cloneDeep, get, has, merge, set, omit, isEqual, groupBy, size } from "lodash/fp";
|
|
11
10
|
import { register } from "esbuild-register/dist/node";
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
isRequired;
|
|
15
|
-
name;
|
|
16
|
-
testCallback;
|
|
17
|
-
children;
|
|
18
|
-
constructor(name, testCallback, isRequired) {
|
|
19
|
-
this.name = name;
|
|
20
|
-
this.testCallback = testCallback;
|
|
21
|
-
this.isRequired = isRequired ?? true;
|
|
22
|
-
this.children = [];
|
|
23
|
-
}
|
|
24
|
-
setChildren(children) {
|
|
25
|
-
this.children = children;
|
|
26
|
-
return this;
|
|
27
|
-
}
|
|
28
|
-
addChild(child) {
|
|
29
|
-
this.children.push(child);
|
|
30
|
-
return this;
|
|
31
|
-
}
|
|
32
|
-
asOptional() {
|
|
33
|
-
const newInstance = requirementFactory(this.name, this.testCallback, false);
|
|
34
|
-
newInstance.setChildren(this.children);
|
|
35
|
-
return newInstance;
|
|
36
|
-
}
|
|
37
|
-
asRequired() {
|
|
38
|
-
const newInstance = requirementFactory(this.name, this.testCallback, true);
|
|
39
|
-
newInstance.setChildren(this.children);
|
|
40
|
-
return newInstance;
|
|
41
|
-
}
|
|
42
|
-
async test(context) {
|
|
43
|
-
try {
|
|
44
|
-
await this.testCallback?.(context);
|
|
45
|
-
return ok();
|
|
46
|
-
} catch (e) {
|
|
47
|
-
if (e instanceof Error) {
|
|
48
|
-
return errored(e);
|
|
49
|
-
}
|
|
50
|
-
if (typeof e === "string") {
|
|
51
|
-
return errored(new Error(e));
|
|
52
|
-
}
|
|
53
|
-
return errored(new Error("Unknown error"));
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
const ok = () => ({ pass: true, error: null });
|
|
58
|
-
const errored = (error) => ({ pass: false, error });
|
|
59
|
-
const requirementFactory = (name, testCallback, isRequired) => new Requirement(name, testCallback, isRequired);
|
|
60
|
-
const index$g = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
61
|
-
__proto__: null,
|
|
62
|
-
requirementFactory
|
|
63
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
64
|
-
const REQUIRE_AVAILABLE_NEXT_MAJOR = requirementFactory(
|
|
65
|
-
"REQUIRE_AVAILABLE_NEXT_MAJOR",
|
|
66
|
-
(context) => {
|
|
67
|
-
const { project, target } = context;
|
|
68
|
-
const currentMajor = project.strapiVersion.major;
|
|
69
|
-
const targetedMajor = target.major;
|
|
70
|
-
if (targetedMajor === currentMajor) {
|
|
71
|
-
throw new Error(`You're already on the latest major version (v${currentMajor})`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
);
|
|
75
|
-
const REQUIRE_LATEST_FOR_CURRENT_MAJOR = requirementFactory(
|
|
76
|
-
"REQUIRE_LATEST_FOR_CURRENT_MAJOR",
|
|
77
|
-
(context) => {
|
|
78
|
-
const { project, target, npmVersionsMatches } = context;
|
|
79
|
-
if (npmVersionsMatches.length !== 1) {
|
|
80
|
-
const invalidVersions = npmVersionsMatches.slice(0, -1);
|
|
81
|
-
const invalidVersionsAsSemVer = invalidVersions.map((v) => v.version);
|
|
82
|
-
const nbInvalidVersions = npmVersionsMatches.length;
|
|
83
|
-
const currentMajor = project.strapiVersion.major;
|
|
84
|
-
throw new Error(
|
|
85
|
-
`Doing a major upgrade requires to be on the latest v${currentMajor} version, but found ${nbInvalidVersions} versions between the current one and ${target}: ${invalidVersionsAsSemVer}`
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
);
|
|
90
|
-
const REQUIRE_GIT_CLEAN_REPOSITORY = requirementFactory(
|
|
91
|
-
"REQUIRE_GIT_CLEAN_REPOSITORY",
|
|
92
|
-
async (context) => {
|
|
93
|
-
const git = simpleGit({ baseDir: context.project.cwd });
|
|
94
|
-
const status = await git.status();
|
|
95
|
-
if (!status.isClean()) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
"Repository is not clean. Please commit or stash any changes before upgrading"
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
);
|
|
102
|
-
const REQUIRE_GIT_REPOSITORY = requirementFactory(
|
|
103
|
-
"REQUIRE_GIT_REPOSITORY",
|
|
104
|
-
async (context) => {
|
|
105
|
-
const git = simpleGit({ baseDir: context.project.cwd });
|
|
106
|
-
const isRepo = await git.checkIsRepo();
|
|
107
|
-
if (!isRepo) {
|
|
108
|
-
throw new Error("Not a git repository (or any of the parent directories)");
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
).addChild(REQUIRE_GIT_CLEAN_REPOSITORY.asOptional());
|
|
112
|
-
const REQUIRE_GIT_INSTALLED = requirementFactory(
|
|
113
|
-
"REQUIRE_GIT_INSTALLED",
|
|
114
|
-
async (context) => {
|
|
115
|
-
const git = simpleGit({ baseDir: context.project.cwd });
|
|
116
|
-
try {
|
|
117
|
-
await git.version();
|
|
118
|
-
} catch {
|
|
119
|
-
throw new Error("Git is not installed");
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
).addChild(REQUIRE_GIT_REPOSITORY.asOptional());
|
|
123
|
-
const REQUIRE_GIT = requirementFactory("REQUIRE_GIT", null).addChild(
|
|
124
|
-
REQUIRE_GIT_INSTALLED.asOptional()
|
|
125
|
-
);
|
|
11
|
+
import { packageManager } from "@strapi/utils";
|
|
12
|
+
import simpleGit from "simple-git";
|
|
126
13
|
class Timer {
|
|
127
14
|
interval;
|
|
128
15
|
constructor() {
|
|
@@ -153,55 +40,101 @@ const constants$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
|
|
|
153
40
|
__proto__: null,
|
|
154
41
|
ONE_SECOND_MS
|
|
155
42
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
156
|
-
const index$
|
|
43
|
+
const index$g = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
157
44
|
__proto__: null,
|
|
158
45
|
constants: constants$4,
|
|
159
46
|
timerFactory
|
|
160
47
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
this.json = cloneDeep(json);
|
|
165
|
-
}
|
|
166
|
-
get(path2, defaultValue) {
|
|
167
|
-
if (!path2) {
|
|
168
|
-
return this.root();
|
|
169
|
-
}
|
|
170
|
-
return cloneDeep(get(path2, this.json) ?? defaultValue);
|
|
171
|
-
}
|
|
172
|
-
has(path2) {
|
|
173
|
-
return has(path2, this.json);
|
|
174
|
-
}
|
|
175
|
-
merge(other) {
|
|
176
|
-
this.json = merge(other, this.json);
|
|
177
|
-
return this;
|
|
178
|
-
}
|
|
179
|
-
root() {
|
|
180
|
-
return cloneDeep(this.json);
|
|
181
|
-
}
|
|
182
|
-
set(path2, value) {
|
|
183
|
-
this.json = set(path2, value, this.json);
|
|
184
|
-
return this;
|
|
185
|
-
}
|
|
186
|
-
remove(path2) {
|
|
187
|
-
this.json = omit(path2, this.json);
|
|
188
|
-
return this;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
const createJSONTransformAPI = (object) => new JSONTransformAPI(object);
|
|
192
|
-
const readJSON = async (path2) => {
|
|
193
|
-
const buffer = await fse.readFile(path2);
|
|
194
|
-
return JSON.parse(buffer.toString());
|
|
48
|
+
const path = (path2) => chalk.blue(path2);
|
|
49
|
+
const version = (version2) => {
|
|
50
|
+
return chalk.italic.yellow(`v${version2}`);
|
|
195
51
|
};
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
52
|
+
const codemodUID = (uid) => {
|
|
53
|
+
return chalk.bold.cyan(uid);
|
|
54
|
+
};
|
|
55
|
+
const projectDetails = (project) => {
|
|
56
|
+
return `Project: TYPE=${projectType(project.type)}; CWD=${path(project.cwd)}; PATHS=${project.paths.map(path)}`;
|
|
57
|
+
};
|
|
58
|
+
const projectType = (type) => chalk.cyan(type);
|
|
59
|
+
const versionRange = (range) => chalk.italic.yellow(range.raw);
|
|
60
|
+
const transform = (transformFilePath) => chalk.cyan(transformFilePath);
|
|
61
|
+
const highlight = (arg) => chalk.bold.underline(arg);
|
|
62
|
+
const upgradeStep = (text, step) => {
|
|
63
|
+
return chalk.bold(`(${step[0]}/${step[1]}) ${text}...`);
|
|
64
|
+
};
|
|
65
|
+
const reports = (reports2) => {
|
|
66
|
+
const rows = reports2.map(({ codemod, report }, i) => {
|
|
67
|
+
const fIndex = chalk.grey(i);
|
|
68
|
+
const fVersion = chalk.magenta(codemod.version);
|
|
69
|
+
const fKind = chalk.yellow(codemod.kind);
|
|
70
|
+
const fFormattedTransformPath = chalk.cyan(codemod.format());
|
|
71
|
+
const fTimeElapsed = i === 0 ? `${report.timeElapsed}s ${chalk.dim.italic("(cold start)")}` : `${report.timeElapsed}s`;
|
|
72
|
+
const fAffected = report.ok > 0 ? chalk.green(report.ok) : chalk.grey(0);
|
|
73
|
+
const fUnchanged = report.ok === 0 ? chalk.red(report.nochange) : chalk.grey(report.nochange);
|
|
74
|
+
return [fIndex, fVersion, fKind, fFormattedTransformPath, fAffected, fUnchanged, fTimeElapsed];
|
|
75
|
+
});
|
|
76
|
+
const table = new CliTable3({
|
|
77
|
+
style: { compact: true },
|
|
78
|
+
head: [
|
|
79
|
+
chalk.bold.grey("N°"),
|
|
80
|
+
chalk.bold.magenta("Version"),
|
|
81
|
+
chalk.bold.yellow("Kind"),
|
|
82
|
+
chalk.bold.cyan("Name"),
|
|
83
|
+
chalk.bold.green("Affected"),
|
|
84
|
+
chalk.bold.red("Unchanged"),
|
|
85
|
+
chalk.bold.blue("Duration")
|
|
86
|
+
]
|
|
87
|
+
});
|
|
88
|
+
table.push(...rows);
|
|
89
|
+
return table.toString();
|
|
90
|
+
};
|
|
91
|
+
const codemodList = (codemods) => {
|
|
92
|
+
const rows = codemods.map((codemod, index2) => {
|
|
93
|
+
const fIndex = chalk.grey(index2);
|
|
94
|
+
const fVersion = chalk.magenta(codemod.version);
|
|
95
|
+
const fKind = chalk.yellow(codemod.kind);
|
|
96
|
+
const fName = chalk.blue(codemod.format());
|
|
97
|
+
const fUID = codemodUID(codemod.uid);
|
|
98
|
+
return [fIndex, fVersion, fKind, fName, fUID];
|
|
99
|
+
});
|
|
100
|
+
const table = new CliTable3({
|
|
101
|
+
style: { compact: true },
|
|
102
|
+
head: [
|
|
103
|
+
chalk.bold.grey("N°"),
|
|
104
|
+
chalk.bold.magenta("Version"),
|
|
105
|
+
chalk.bold.yellow("Kind"),
|
|
106
|
+
chalk.bold.blue("Name"),
|
|
107
|
+
chalk.bold.cyan("UID")
|
|
108
|
+
]
|
|
109
|
+
});
|
|
110
|
+
table.push(...rows);
|
|
111
|
+
return table.toString();
|
|
200
112
|
};
|
|
113
|
+
const durationMs = (elapsedMs) => {
|
|
114
|
+
const elapsedSeconds = (elapsedMs / ONE_SECOND_MS).toFixed(3);
|
|
115
|
+
return `${elapsedSeconds}s`;
|
|
116
|
+
};
|
|
117
|
+
const index$f = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
118
|
+
__proto__: null,
|
|
119
|
+
codemodList,
|
|
120
|
+
codemodUID,
|
|
121
|
+
durationMs,
|
|
122
|
+
highlight,
|
|
123
|
+
path,
|
|
124
|
+
projectDetails,
|
|
125
|
+
projectType,
|
|
126
|
+
reports,
|
|
127
|
+
transform,
|
|
128
|
+
upgradeStep,
|
|
129
|
+
version,
|
|
130
|
+
versionRange
|
|
131
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
132
|
+
const NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
201
133
|
var ReleaseType = /* @__PURE__ */ ((ReleaseType2) => {
|
|
202
134
|
ReleaseType2["Major"] = "major";
|
|
203
135
|
ReleaseType2["Minor"] = "minor";
|
|
204
136
|
ReleaseType2["Patch"] = "patch";
|
|
137
|
+
ReleaseType2["Latest"] = "latest";
|
|
205
138
|
return ReleaseType2;
|
|
206
139
|
})(ReleaseType || {});
|
|
207
140
|
const types = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -227,17 +160,20 @@ const rangeFactory = (range) => {
|
|
|
227
160
|
};
|
|
228
161
|
const rangeFromReleaseType = (current, identifier) => {
|
|
229
162
|
switch (identifier) {
|
|
230
|
-
case ReleaseType.
|
|
231
|
-
|
|
232
|
-
return rangeFactory(`>${current.raw} <=${nextMajor}`);
|
|
163
|
+
case ReleaseType.Latest: {
|
|
164
|
+
return rangeFactory(`>${current.raw}`);
|
|
233
165
|
}
|
|
234
|
-
case ReleaseType.
|
|
235
|
-
const
|
|
236
|
-
return rangeFactory(`>${current.raw}
|
|
166
|
+
case ReleaseType.Major: {
|
|
167
|
+
const nextMajor = semVerFactory(current.raw).inc("major");
|
|
168
|
+
return rangeFactory(`>${current.raw} <=${nextMajor.major}`);
|
|
237
169
|
}
|
|
238
170
|
case ReleaseType.Minor: {
|
|
239
|
-
const
|
|
240
|
-
return rangeFactory(`>${current.raw} <${
|
|
171
|
+
const nextMajor = semVerFactory(current.raw).inc("major");
|
|
172
|
+
return rangeFactory(`>${current.raw} <${nextMajor.raw}`);
|
|
173
|
+
}
|
|
174
|
+
case ReleaseType.Patch: {
|
|
175
|
+
const nextMinor = semVerFactory(current.raw).inc("minor");
|
|
176
|
+
return rangeFactory(`>${current.raw} <${nextMinor.raw}`);
|
|
241
177
|
}
|
|
242
178
|
default: {
|
|
243
179
|
throw new Error("Not implemented");
|
|
@@ -253,25 +189,75 @@ const rangeFromVersions = (currentVersion, target) => {
|
|
|
253
189
|
}
|
|
254
190
|
throw new Error(`Invalid target set: ${target}`);
|
|
255
191
|
};
|
|
192
|
+
const isValidStringifiedRange = (str) => semver.validRange(str) !== null;
|
|
193
|
+
const isRangeInstance = (range) => {
|
|
194
|
+
return range instanceof semver.Range;
|
|
195
|
+
};
|
|
256
196
|
const index$e = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
257
197
|
__proto__: null,
|
|
258
198
|
Version: types,
|
|
259
199
|
isLiteralSemVer,
|
|
200
|
+
isRangeInstance,
|
|
260
201
|
isSemVerReleaseType,
|
|
261
202
|
isSemverInstance,
|
|
262
203
|
isValidSemVer,
|
|
204
|
+
isValidStringifiedRange,
|
|
263
205
|
rangeFactory,
|
|
264
206
|
rangeFromReleaseType,
|
|
265
207
|
rangeFromVersions,
|
|
266
208
|
semVerFactory
|
|
267
209
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
210
|
+
class Package {
|
|
211
|
+
name;
|
|
212
|
+
packageURL;
|
|
213
|
+
npmPackage;
|
|
214
|
+
constructor(name) {
|
|
215
|
+
this.name = name;
|
|
216
|
+
this.packageURL = `${NPM_REGISTRY_URL}/${name}`;
|
|
217
|
+
this.npmPackage = null;
|
|
218
|
+
}
|
|
219
|
+
get isLoaded() {
|
|
220
|
+
return this.npmPackage !== null;
|
|
221
|
+
}
|
|
222
|
+
assertPackageIsLoaded(npmPackage) {
|
|
223
|
+
assert(this.isLoaded, "The package is not loaded yet");
|
|
224
|
+
}
|
|
225
|
+
getVersionsDict() {
|
|
226
|
+
this.assertPackageIsLoaded(this.npmPackage);
|
|
227
|
+
return this.npmPackage.versions;
|
|
228
|
+
}
|
|
229
|
+
getVersionsAsList() {
|
|
230
|
+
this.assertPackageIsLoaded(this.npmPackage);
|
|
231
|
+
return Object.values(this.npmPackage.versions);
|
|
232
|
+
}
|
|
233
|
+
findVersionsInRange(range) {
|
|
234
|
+
const versions = this.getVersionsAsList();
|
|
235
|
+
return versions.filter((v) => range.test(v.version)).filter((v) => isLiteralSemVer(v.version)).sort((v1, v2) => semver.compare(v1.version, v2.version));
|
|
236
|
+
}
|
|
237
|
+
findVersion(version2) {
|
|
238
|
+
const versions = this.getVersionsAsList();
|
|
239
|
+
return versions.find((npmVersion) => semver.eq(npmVersion.version, version2));
|
|
240
|
+
}
|
|
241
|
+
async refresh() {
|
|
242
|
+
const response = await fetch(this.packageURL);
|
|
243
|
+
assert(response.ok, `Request failed for ${this.packageURL}`);
|
|
244
|
+
this.npmPackage = await response.json();
|
|
245
|
+
return this;
|
|
246
|
+
}
|
|
247
|
+
versionExists(version2) {
|
|
248
|
+
return this.findVersion(version2) !== void 0;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const npmPackageFactory = (name) => new Package(name);
|
|
268
252
|
class FileScanner {
|
|
269
253
|
cwd;
|
|
270
254
|
constructor(cwd) {
|
|
271
255
|
this.cwd = cwd;
|
|
272
256
|
}
|
|
273
257
|
scan(patterns) {
|
|
274
|
-
const filenames =
|
|
258
|
+
const filenames = fastglob.sync(patterns, {
|
|
259
|
+
cwd: this.cwd
|
|
260
|
+
});
|
|
275
261
|
return filenames.map((filename) => path$1.join(this.cwd, filename));
|
|
276
262
|
}
|
|
277
263
|
}
|
|
@@ -309,6 +295,46 @@ const index$c = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
309
295
|
__proto__: null,
|
|
310
296
|
codeRunnerFactory
|
|
311
297
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
298
|
+
class JSONTransformAPI {
|
|
299
|
+
json;
|
|
300
|
+
constructor(json) {
|
|
301
|
+
this.json = cloneDeep(json);
|
|
302
|
+
}
|
|
303
|
+
get(path2, defaultValue) {
|
|
304
|
+
if (!path2) {
|
|
305
|
+
return this.root();
|
|
306
|
+
}
|
|
307
|
+
return cloneDeep(get(path2, this.json) ?? defaultValue);
|
|
308
|
+
}
|
|
309
|
+
has(path2) {
|
|
310
|
+
return has(path2, this.json);
|
|
311
|
+
}
|
|
312
|
+
merge(other) {
|
|
313
|
+
this.json = merge(other, this.json);
|
|
314
|
+
return this;
|
|
315
|
+
}
|
|
316
|
+
root() {
|
|
317
|
+
return cloneDeep(this.json);
|
|
318
|
+
}
|
|
319
|
+
set(path2, value) {
|
|
320
|
+
this.json = set(path2, value, this.json);
|
|
321
|
+
return this;
|
|
322
|
+
}
|
|
323
|
+
remove(path2) {
|
|
324
|
+
this.json = omit(path2, this.json);
|
|
325
|
+
return this;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const createJSONTransformAPI = (object) => new JSONTransformAPI(object);
|
|
329
|
+
const readJSON = async (path2) => {
|
|
330
|
+
const buffer = await fse.readFile(path2);
|
|
331
|
+
return JSON.parse(buffer.toString());
|
|
332
|
+
};
|
|
333
|
+
const saveJSON = async (path2, json) => {
|
|
334
|
+
const jsonAsString = `${JSON.stringify(json, null, 2)}
|
|
335
|
+
`;
|
|
336
|
+
await fse.writeFile(path2, jsonAsString);
|
|
337
|
+
};
|
|
312
338
|
const transformJSON = async (codemodPath, paths, config) => {
|
|
313
339
|
const { dry } = config;
|
|
314
340
|
const startTime = process.hrtime();
|
|
@@ -320,7 +346,11 @@ const transformJSON = async (codemodPath, paths, config) => {
|
|
|
320
346
|
timeElapsed: "",
|
|
321
347
|
stats: {}
|
|
322
348
|
};
|
|
323
|
-
const esbuildOptions = {
|
|
349
|
+
const esbuildOptions = {
|
|
350
|
+
extensions: [".js", ".mjs", ".ts"],
|
|
351
|
+
hookIgnoreNodeModules: false,
|
|
352
|
+
hookMatcher: isEqual(codemodPath)
|
|
353
|
+
};
|
|
324
354
|
const { unregister } = register(esbuildOptions);
|
|
325
355
|
const module = require(codemodPath);
|
|
326
356
|
unregister();
|
|
@@ -365,17 +395,31 @@ const index$b = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
365
395
|
jsonRunnerFactory
|
|
366
396
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
367
397
|
const PROJECT_PACKAGE_JSON = "package.json";
|
|
368
|
-
const
|
|
369
|
-
const
|
|
370
|
-
const
|
|
398
|
+
const PROJECT_APP_ALLOWED_ROOT_PATHS = ["src", "config", "public"];
|
|
399
|
+
const PROJECT_PLUGIN_ALLOWED_ROOT_PATHS = ["admin", "server"];
|
|
400
|
+
const PROJECT_PLUGIN_ROOT_FILES = ["strapi-admin.js", "strapi-server.js"];
|
|
401
|
+
const PROJECT_CODE_EXTENSIONS = [
|
|
402
|
+
// Source files
|
|
403
|
+
"js",
|
|
404
|
+
"mjs",
|
|
405
|
+
"ts",
|
|
406
|
+
// React files
|
|
407
|
+
"jsx",
|
|
408
|
+
"tsx"
|
|
409
|
+
];
|
|
410
|
+
const PROJECT_JSON_EXTENSIONS = ["json"];
|
|
411
|
+
const PROJECT_ALLOWED_EXTENSIONS = [...PROJECT_CODE_EXTENSIONS, ...PROJECT_JSON_EXTENSIONS];
|
|
371
412
|
const SCOPED_STRAPI_PACKAGE_PREFIX = "@strapi/";
|
|
372
413
|
const STRAPI_DEPENDENCY_NAME = `${SCOPED_STRAPI_PACKAGE_PREFIX}strapi`;
|
|
373
414
|
const constants$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
374
415
|
__proto__: null,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
416
|
+
PROJECT_ALLOWED_EXTENSIONS,
|
|
417
|
+
PROJECT_APP_ALLOWED_ROOT_PATHS,
|
|
418
|
+
PROJECT_CODE_EXTENSIONS,
|
|
419
|
+
PROJECT_JSON_EXTENSIONS,
|
|
378
420
|
PROJECT_PACKAGE_JSON,
|
|
421
|
+
PROJECT_PLUGIN_ALLOWED_ROOT_PATHS,
|
|
422
|
+
PROJECT_PLUGIN_ROOT_FILES,
|
|
379
423
|
SCOPED_STRAPI_PACKAGE_PREFIX,
|
|
380
424
|
STRAPI_DEPENDENCY_NAME
|
|
381
425
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
@@ -385,12 +429,13 @@ class Project {
|
|
|
385
429
|
files;
|
|
386
430
|
packageJSONPath;
|
|
387
431
|
packageJSON;
|
|
388
|
-
|
|
389
|
-
constructor(cwd) {
|
|
432
|
+
paths;
|
|
433
|
+
constructor(cwd, config) {
|
|
390
434
|
if (!fse.pathExistsSync(cwd)) {
|
|
391
435
|
throw new Error(`ENOENT: no such file or directory, access '${cwd}'`);
|
|
392
436
|
}
|
|
393
437
|
this.cwd = cwd;
|
|
438
|
+
this.paths = config.paths;
|
|
394
439
|
this.refresh();
|
|
395
440
|
}
|
|
396
441
|
getFilesByExtensions(extensions) {
|
|
@@ -401,14 +446,13 @@ class Project {
|
|
|
401
446
|
}
|
|
402
447
|
refresh() {
|
|
403
448
|
this.refreshPackageJSON();
|
|
404
|
-
this.refreshStrapiVersion();
|
|
405
449
|
this.refreshProjectFiles();
|
|
406
450
|
return this;
|
|
407
451
|
}
|
|
408
|
-
async runCodemods(
|
|
452
|
+
async runCodemods(codemods, options) {
|
|
409
453
|
const runners = this.createProjectCodemodsRunners(options.dry);
|
|
410
454
|
const reports2 = [];
|
|
411
|
-
for (const codemod of
|
|
455
|
+
for (const codemod of codemods) {
|
|
412
456
|
for (const runner of runners) {
|
|
413
457
|
if (runner.valid(codemod)) {
|
|
414
458
|
const report = await runner.run(codemod);
|
|
@@ -419,17 +463,20 @@ class Project {
|
|
|
419
463
|
return reports2;
|
|
420
464
|
}
|
|
421
465
|
createProjectCodemodsRunners(dry = false) {
|
|
422
|
-
const
|
|
423
|
-
const
|
|
466
|
+
const jsonExtensions = PROJECT_JSON_EXTENSIONS.map((ext) => `.${ext}`);
|
|
467
|
+
const codeExtensions = PROJECT_CODE_EXTENSIONS.map((ext) => `.${ext}`);
|
|
468
|
+
const jsonFiles = this.getFilesByExtensions(jsonExtensions);
|
|
469
|
+
const codeFiles = this.getFilesByExtensions(codeExtensions);
|
|
424
470
|
const codeRunner = codeRunnerFactory(codeFiles, {
|
|
425
471
|
dry,
|
|
426
|
-
|
|
427
|
-
silent: true,
|
|
428
|
-
extensions: "js,ts",
|
|
472
|
+
parser: "ts",
|
|
429
473
|
runInBand: true,
|
|
430
|
-
verbose: 0,
|
|
431
474
|
babel: true,
|
|
432
|
-
|
|
475
|
+
extensions: PROJECT_CODE_EXTENSIONS.join(","),
|
|
476
|
+
// Don't output any log coming from the runner
|
|
477
|
+
print: false,
|
|
478
|
+
silent: true,
|
|
479
|
+
verbose: 0
|
|
433
480
|
});
|
|
434
481
|
const jsonRunner = jsonRunnerFactory(jsonFiles, { dry, cwd: this.cwd });
|
|
435
482
|
return [codeRunner, jsonRunner];
|
|
@@ -446,16 +493,38 @@ class Project {
|
|
|
446
493
|
this.packageJSON = JSON.parse(packageJSONBuffer.toString());
|
|
447
494
|
}
|
|
448
495
|
refreshProjectFiles() {
|
|
449
|
-
const allowedRootPaths = formatGlobCollectionPattern(
|
|
450
|
-
PROJECT_DEFAULT_ALLOWED_ROOT_PATHS
|
|
451
|
-
);
|
|
452
|
-
const allowedExtensions = formatGlobCollectionPattern(
|
|
453
|
-
PROJECT_DEFAULT_ALLOWED_EXTENSIONS
|
|
454
|
-
);
|
|
455
|
-
const projectFilesPattern = `./${allowedRootPaths}/**/*.${allowedExtensions}`;
|
|
456
|
-
const patterns = [projectFilesPattern, ...PROJECT_DEFAULT_PATTERNS];
|
|
457
496
|
const scanner = fileScannerFactory(this.cwd);
|
|
458
|
-
this.files = scanner.scan(
|
|
497
|
+
this.files = scanner.scan(this.paths);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
class AppProject extends Project {
|
|
501
|
+
strapiVersion;
|
|
502
|
+
type = "application";
|
|
503
|
+
/**
|
|
504
|
+
* Returns an array of allowed file paths for a Strapi application
|
|
505
|
+
*
|
|
506
|
+
* The resulting paths include app default files and the root package.json file.
|
|
507
|
+
*/
|
|
508
|
+
static get paths() {
|
|
509
|
+
const allowedRootPaths = formatGlobCollectionPattern(PROJECT_APP_ALLOWED_ROOT_PATHS);
|
|
510
|
+
const allowedExtensions = formatGlobCollectionPattern(PROJECT_ALLOWED_EXTENSIONS);
|
|
511
|
+
return [
|
|
512
|
+
// App default files
|
|
513
|
+
`./${allowedRootPaths}/**/*.${allowedExtensions}`,
|
|
514
|
+
`!./**/node_modules/**/*`,
|
|
515
|
+
`!./**/dist/**/*`,
|
|
516
|
+
// Root package.json file
|
|
517
|
+
PROJECT_PACKAGE_JSON
|
|
518
|
+
];
|
|
519
|
+
}
|
|
520
|
+
constructor(cwd) {
|
|
521
|
+
super(cwd, { paths: AppProject.paths });
|
|
522
|
+
this.refreshStrapiVersion();
|
|
523
|
+
}
|
|
524
|
+
refresh() {
|
|
525
|
+
super.refresh();
|
|
526
|
+
this.refreshStrapiVersion();
|
|
527
|
+
return this;
|
|
459
528
|
}
|
|
460
529
|
refreshStrapiVersion() {
|
|
461
530
|
this.strapiVersion = // First try to get the strapi version from the package.json dependencies
|
|
@@ -502,10 +571,71 @@ const formatGlobCollectionPattern = (collection) => {
|
|
|
502
571
|
);
|
|
503
572
|
return collection.length === 1 ? collection[0] : `{${collection}}`;
|
|
504
573
|
};
|
|
505
|
-
|
|
574
|
+
class PluginProject extends Project {
|
|
575
|
+
type = "plugin";
|
|
576
|
+
/**
|
|
577
|
+
* Returns an array of allowed file paths for a Strapi plugin
|
|
578
|
+
*
|
|
579
|
+
* The resulting paths include plugin default files, the root package.json file, and plugin-specific files.
|
|
580
|
+
*/
|
|
581
|
+
static get paths() {
|
|
582
|
+
const allowedRootPaths = formatGlobCollectionPattern(
|
|
583
|
+
PROJECT_PLUGIN_ALLOWED_ROOT_PATHS
|
|
584
|
+
);
|
|
585
|
+
const allowedExtensions = formatGlobCollectionPattern(PROJECT_ALLOWED_EXTENSIONS);
|
|
586
|
+
return [
|
|
587
|
+
// Plugin default files
|
|
588
|
+
`./${allowedRootPaths}/**/*.${allowedExtensions}`,
|
|
589
|
+
`!./**/node_modules/**/*`,
|
|
590
|
+
`!./**/dist/**/*`,
|
|
591
|
+
// Root package.json file
|
|
592
|
+
PROJECT_PACKAGE_JSON,
|
|
593
|
+
// Plugin root files
|
|
594
|
+
...PROJECT_PLUGIN_ROOT_FILES
|
|
595
|
+
];
|
|
596
|
+
}
|
|
597
|
+
constructor(cwd) {
|
|
598
|
+
super(cwd, { paths: PluginProject.paths });
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
const isPlugin = (cwd) => {
|
|
602
|
+
const packageJSONPath = path$1.join(cwd, PROJECT_PACKAGE_JSON);
|
|
603
|
+
try {
|
|
604
|
+
fse.accessSync(packageJSONPath);
|
|
605
|
+
} catch {
|
|
606
|
+
throw new Error(`Could not find a ${PROJECT_PACKAGE_JSON} file in ${cwd}`);
|
|
607
|
+
}
|
|
608
|
+
const packageJSONBuffer = fse.readFileSync(packageJSONPath);
|
|
609
|
+
const packageJSON = JSON.parse(packageJSONBuffer.toString());
|
|
610
|
+
return packageJSON?.strapi?.kind === "plugin";
|
|
611
|
+
};
|
|
612
|
+
const projectFactory = (cwd) => {
|
|
613
|
+
fse.accessSync(cwd);
|
|
614
|
+
return isPlugin(cwd) ? new PluginProject(cwd) : new AppProject(cwd);
|
|
615
|
+
};
|
|
616
|
+
const isPluginProject = (project) => {
|
|
617
|
+
return project instanceof PluginProject;
|
|
618
|
+
};
|
|
619
|
+
function assertPluginProject(project) {
|
|
620
|
+
if (!isPluginProject(project)) {
|
|
621
|
+
throw new Error("Project is not a plugin");
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
const isApplicationProject = (project) => {
|
|
625
|
+
return project instanceof AppProject;
|
|
626
|
+
};
|
|
627
|
+
function assertAppProject(project) {
|
|
628
|
+
if (!isApplicationProject(project)) {
|
|
629
|
+
throw new Error("Project is not an application");
|
|
630
|
+
}
|
|
631
|
+
}
|
|
506
632
|
const index$a = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
507
633
|
__proto__: null,
|
|
634
|
+
assertAppProject,
|
|
635
|
+
assertPluginProject,
|
|
508
636
|
constants: constants$3,
|
|
637
|
+
isApplicationProject,
|
|
638
|
+
isPluginProject,
|
|
509
639
|
projectFactory
|
|
510
640
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
511
641
|
class UnexpectedError extends Error {
|
|
@@ -513,70 +643,33 @@ class UnexpectedError extends Error {
|
|
|
513
643
|
super("Unexpected Error");
|
|
514
644
|
}
|
|
515
645
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
646
|
+
class NPMCandidateNotFoundError extends Error {
|
|
647
|
+
target;
|
|
648
|
+
constructor(target, message = `Couldn't find a valid NPM candidate for "${target}"`) {
|
|
649
|
+
super(message);
|
|
650
|
+
this.target = target;
|
|
519
651
|
}
|
|
520
|
-
|
|
521
|
-
|
|
652
|
+
}
|
|
653
|
+
class AbortedError extends Error {
|
|
654
|
+
constructor(message = "Upgrade aborted") {
|
|
655
|
+
super(message);
|
|
522
656
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
return chalk.italic.yellow(`v${version2}`);
|
|
533
|
-
};
|
|
534
|
-
const versionRange = (range) => chalk.italic.yellow(range);
|
|
535
|
-
const transform = (transformFilePath) => chalk.cyan(transformFilePath);
|
|
536
|
-
const highlight = (arg) => chalk.bold.underline(arg);
|
|
537
|
-
const upgradeStep = (text, step) => {
|
|
538
|
-
return chalk.bold(`(${step[0]}/${step[1]}) ${text}...`);
|
|
539
|
-
};
|
|
540
|
-
const reports = (reports2) => {
|
|
541
|
-
const rows = reports2.map(({ codemod, report }, i) => {
|
|
542
|
-
const fIndex = chalk.grey(i);
|
|
543
|
-
const fVersion = chalk.magenta(codemod.version);
|
|
544
|
-
const fKind = chalk.yellow(codemod.kind);
|
|
545
|
-
const fFormattedTransformPath = chalk.cyan(codemod.format());
|
|
546
|
-
const fTimeElapsed = i === 0 ? `${report.timeElapsed}s ${chalk.dim.italic("(cold start)")}` : `${report.timeElapsed}s`;
|
|
547
|
-
const fAffected = report.ok > 0 ? chalk.green(report.ok) : chalk.grey(0);
|
|
548
|
-
const fUnchanged = report.ok === 0 ? chalk.red(report.nochange) : chalk.grey(report.nochange);
|
|
549
|
-
return [fIndex, fVersion, fKind, fFormattedTransformPath, fAffected, fUnchanged, fTimeElapsed];
|
|
550
|
-
});
|
|
551
|
-
const table = new CliTable3({
|
|
552
|
-
style: { compact: true },
|
|
553
|
-
head: [
|
|
554
|
-
chalk.bold.grey("N°"),
|
|
555
|
-
chalk.bold.magenta("Version"),
|
|
556
|
-
chalk.bold.yellow("Kind"),
|
|
557
|
-
chalk.bold.cyan("Name"),
|
|
558
|
-
chalk.bold.green("Affected"),
|
|
559
|
-
chalk.bold.red("Unchanged"),
|
|
560
|
-
chalk.bold.blue("Duration")
|
|
561
|
-
]
|
|
562
|
-
});
|
|
563
|
-
table.push(...rows);
|
|
564
|
-
return table.toString();
|
|
565
|
-
};
|
|
566
|
-
const durationMs = (elapsedMs) => {
|
|
567
|
-
const elapsedSeconds = (elapsedMs / ONE_SECOND_MS).toFixed(3);
|
|
568
|
-
return `${elapsedSeconds}s`;
|
|
657
|
+
}
|
|
658
|
+
const unknownToError = (e) => {
|
|
659
|
+
if (e instanceof Error) {
|
|
660
|
+
return e;
|
|
661
|
+
}
|
|
662
|
+
if (typeof e === "string") {
|
|
663
|
+
return new Error(e);
|
|
664
|
+
}
|
|
665
|
+
return new UnexpectedError();
|
|
569
666
|
};
|
|
570
|
-
const index$
|
|
667
|
+
const index$9 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
571
668
|
__proto__: null,
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
transform,
|
|
577
|
-
upgradeStep,
|
|
578
|
-
version,
|
|
579
|
-
versionRange
|
|
669
|
+
AbortedError,
|
|
670
|
+
NPMCandidateNotFoundError,
|
|
671
|
+
UnexpectedError,
|
|
672
|
+
unknownToError
|
|
580
673
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
581
674
|
const CODEMOD_CODE_SUFFIX = "code";
|
|
582
675
|
const CODEMOD_JSON_SUFFIX = "json";
|
|
@@ -594,6 +687,7 @@ const constants$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
|
|
|
594
687
|
CODEMOD_JSON_SUFFIX
|
|
595
688
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
596
689
|
class Codemod {
|
|
690
|
+
uid;
|
|
597
691
|
kind;
|
|
598
692
|
version;
|
|
599
693
|
baseDirectory;
|
|
@@ -605,17 +699,49 @@ class Codemod {
|
|
|
605
699
|
this.baseDirectory = options.baseDirectory;
|
|
606
700
|
this.filename = options.filename;
|
|
607
701
|
this.path = path$1.join(this.baseDirectory, this.version.raw, this.filename);
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
702
|
+
this.uid = this.createUID();
|
|
703
|
+
}
|
|
704
|
+
createUID() {
|
|
705
|
+
const name = this.format({ stripExtension: true, stripKind: true, stripHyphens: false });
|
|
706
|
+
const kind = this.kind;
|
|
707
|
+
const version2 = this.version.raw;
|
|
708
|
+
return `${version2}-${name}-${kind}`;
|
|
709
|
+
}
|
|
710
|
+
format(options) {
|
|
711
|
+
const { stripExtension = true, stripKind = true, stripHyphens = true } = options ?? {};
|
|
712
|
+
let formatted = this.filename;
|
|
713
|
+
if (stripExtension) {
|
|
714
|
+
formatted = formatted.replace(new RegExp(`\\.${CODEMOD_EXTENSION}$`, "i"), "");
|
|
715
|
+
}
|
|
716
|
+
if (stripKind) {
|
|
717
|
+
formatted = formatted.replace(`.${CODEMOD_CODE_SUFFIX}`, "").replace(`.${CODEMOD_JSON_SUFFIX}`, "");
|
|
718
|
+
}
|
|
719
|
+
if (stripHyphens) {
|
|
720
|
+
formatted = formatted.replaceAll("-", " ");
|
|
721
|
+
}
|
|
722
|
+
return formatted;
|
|
611
723
|
}
|
|
612
724
|
}
|
|
613
725
|
const codemodFactory = (options) => new Codemod(options);
|
|
614
|
-
const index$
|
|
726
|
+
const index$8 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
615
727
|
__proto__: null,
|
|
616
728
|
codemodFactory,
|
|
617
729
|
constants: constants$2
|
|
618
730
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
731
|
+
const INTERNAL_CODEMODS_DIRECTORY = path$1.join(
|
|
732
|
+
__dirname,
|
|
733
|
+
// upgrade/dist
|
|
734
|
+
"..",
|
|
735
|
+
// upgrade
|
|
736
|
+
"resources",
|
|
737
|
+
// upgrade/resources
|
|
738
|
+
"codemods"
|
|
739
|
+
// upgrade/resources/codemods
|
|
740
|
+
);
|
|
741
|
+
const constants$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
742
|
+
__proto__: null,
|
|
743
|
+
INTERNAL_CODEMODS_DIRECTORY
|
|
744
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
619
745
|
class CodemodRepository {
|
|
620
746
|
groups;
|
|
621
747
|
versions;
|
|
@@ -634,23 +760,48 @@ class CodemodRepository {
|
|
|
634
760
|
count(version2) {
|
|
635
761
|
return this.findByVersion(version2).length;
|
|
636
762
|
}
|
|
637
|
-
|
|
638
|
-
return this.findByRange(range).length;
|
|
639
|
-
}
|
|
640
|
-
exists(version2) {
|
|
763
|
+
versionExists(version2) {
|
|
641
764
|
return version2.raw in this.groups;
|
|
642
765
|
}
|
|
643
|
-
|
|
766
|
+
has(uid) {
|
|
767
|
+
const result = this.find({ uids: [uid] });
|
|
768
|
+
if (result.length !== 1) {
|
|
769
|
+
return false;
|
|
770
|
+
}
|
|
771
|
+
const { codemods } = result[0];
|
|
772
|
+
return codemods.length === 1 && codemods[0].uid === uid;
|
|
773
|
+
}
|
|
774
|
+
find(q) {
|
|
644
775
|
const entries = Object.entries(this.groups);
|
|
645
|
-
return entries.filter(
|
|
776
|
+
return entries.filter(maybeFilterByRange).map(([version2, codemods]) => ({
|
|
646
777
|
version: semVerFactory(version2),
|
|
647
|
-
|
|
648
|
-
|
|
778
|
+
// Filter by UID if provided in the query
|
|
779
|
+
codemods: codemods.filter(maybeFilterByUIDs)
|
|
780
|
+
})).filter(({ codemods }) => codemods.length > 0);
|
|
781
|
+
function maybeFilterByRange([version2]) {
|
|
782
|
+
if (!isRangeInstance(q.range)) {
|
|
783
|
+
return true;
|
|
784
|
+
}
|
|
785
|
+
return q.range.test(version2);
|
|
786
|
+
}
|
|
787
|
+
function maybeFilterByUIDs(codemod) {
|
|
788
|
+
if (q.uids === void 0) {
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
791
|
+
return q.uids.includes(codemod.uid);
|
|
792
|
+
}
|
|
649
793
|
}
|
|
650
794
|
findByVersion(version2) {
|
|
651
795
|
const literalVersion = version2.raw;
|
|
652
|
-
const
|
|
653
|
-
return
|
|
796
|
+
const codemods = this.groups[literalVersion];
|
|
797
|
+
return codemods ?? [];
|
|
798
|
+
}
|
|
799
|
+
findAll() {
|
|
800
|
+
const entries = Object.entries(this.groups);
|
|
801
|
+
return entries.map(([version2, codemods]) => ({
|
|
802
|
+
version: semVerFactory(version2),
|
|
803
|
+
codemods
|
|
804
|
+
}));
|
|
654
805
|
}
|
|
655
806
|
refreshAvailableVersions() {
|
|
656
807
|
this.versions = fse.readdirSync(this.cwd).filter((filename) => fse.statSync(path$1.join(this.cwd, filename)).isDirectory()).filter((filename) => semver.valid(filename) !== null).map((version2) => semVerFactory(version2)).sort(semver.compare);
|
|
@@ -681,19 +832,10 @@ const parseCodemodKindFromFilename = (filename) => {
|
|
|
681
832
|
assert(CODEMOD_ALLOWED_SUFFIXES.includes(kind));
|
|
682
833
|
return kind;
|
|
683
834
|
};
|
|
684
|
-
const codemodRepositoryFactory = (cwd) =>
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
"..",
|
|
689
|
-
"resources",
|
|
690
|
-
"codemods"
|
|
691
|
-
);
|
|
692
|
-
const constants$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
693
|
-
__proto__: null,
|
|
694
|
-
INTERNAL_CODEMODS_DIRECTORY
|
|
695
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
696
|
-
const index$6 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
835
|
+
const codemodRepositoryFactory = (cwd = INTERNAL_CODEMODS_DIRECTORY) => {
|
|
836
|
+
return new CodemodRepository(cwd);
|
|
837
|
+
};
|
|
838
|
+
const index$7 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
697
839
|
__proto__: null,
|
|
698
840
|
codemodRepositoryFactory,
|
|
699
841
|
constants: constants$1
|
|
@@ -727,34 +869,59 @@ class CodemodRunner {
|
|
|
727
869
|
this.isDry = enabled;
|
|
728
870
|
return this;
|
|
729
871
|
}
|
|
730
|
-
|
|
872
|
+
createRepository(codemodsDirectory) {
|
|
731
873
|
const repository = codemodRepositoryFactory(
|
|
732
874
|
codemodsDirectory ?? INTERNAL_CODEMODS_DIRECTORY
|
|
733
875
|
);
|
|
734
876
|
repository.refresh();
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
if (
|
|
739
|
-
this.logger?.
|
|
740
|
-
|
|
877
|
+
return repository;
|
|
878
|
+
}
|
|
879
|
+
async safeRunAndReport(codemods) {
|
|
880
|
+
if (this.isDry) {
|
|
881
|
+
this.logger?.warn?.(
|
|
882
|
+
"Running the codemods in dry mode. No files will be modified during the process."
|
|
883
|
+
);
|
|
741
884
|
}
|
|
742
|
-
this.logger?.debug(
|
|
743
|
-
`Found codemods for ${highlight(
|
|
744
|
-
versionedCodemods.length
|
|
745
|
-
)} version(s) using ${versionRange(this.range)}`
|
|
746
|
-
);
|
|
747
|
-
versionedCodemods.forEach(
|
|
748
|
-
({ version: version$1, codemods: codemods22 }) => this.logger?.debug(`- ${version(version$1)} (${codemods22.length})`)
|
|
749
|
-
);
|
|
750
|
-
const codemods2 = versionedCodemods.map(({ codemods: codemods22 }) => codemods22).flat();
|
|
751
885
|
try {
|
|
752
|
-
const reports$1 = await this.project.runCodemods(
|
|
753
|
-
this.logger?.raw(reports(reports$1));
|
|
886
|
+
const reports$1 = await this.project.runCodemods(codemods, { dry: this.isDry });
|
|
887
|
+
this.logger?.raw?.(reports(reports$1));
|
|
888
|
+
if (!this.isDry) {
|
|
889
|
+
const nbAffectedTotal = reports$1.flatMap((report) => report.report.ok).reduce((acc, nb) => acc + nb, 0);
|
|
890
|
+
this.logger?.debug?.(
|
|
891
|
+
`Successfully ran ${highlight(codemods.length)} codemod(s), ${highlight(nbAffectedTotal)} change(s) have been detected`
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
return successReport$1();
|
|
754
895
|
} catch (e) {
|
|
755
896
|
return erroredReport$1(unknownToError(e));
|
|
756
897
|
}
|
|
757
|
-
|
|
898
|
+
}
|
|
899
|
+
async runByUID(uid, codemodsDirectory) {
|
|
900
|
+
const repository = this.createRepository(codemodsDirectory);
|
|
901
|
+
if (!repository.has(uid)) {
|
|
902
|
+
throw new Error(`Unknown codemod UID provided: ${uid}`);
|
|
903
|
+
}
|
|
904
|
+
const codemods = repository.find({ uids: [uid] }).flatMap(({ codemods: codemods2 }) => codemods2);
|
|
905
|
+
return this.safeRunAndReport(codemods);
|
|
906
|
+
}
|
|
907
|
+
async run(codemodsDirectory) {
|
|
908
|
+
const repository = this.createRepository(codemodsDirectory);
|
|
909
|
+
const codemodsInRange = repository.find({ range: this.range });
|
|
910
|
+
const selectedCodemods = this.selectCodemodsCallback ? await this.selectCodemodsCallback(codemodsInRange) : codemodsInRange;
|
|
911
|
+
if (selectedCodemods.length === 0) {
|
|
912
|
+
this.logger?.debug?.(`Found no codemods to run for ${versionRange(this.range)}`);
|
|
913
|
+
return successReport$1();
|
|
914
|
+
}
|
|
915
|
+
const codemods = selectedCodemods.flatMap(({ codemods: codemods2 }) => codemods2);
|
|
916
|
+
const codemodsByVersion = groupBy("version", codemods);
|
|
917
|
+
const fRange = versionRange(this.range);
|
|
918
|
+
this.logger?.debug?.(
|
|
919
|
+
`Found ${highlight(codemods.length)} codemods for ${highlight(size(codemodsByVersion))} version(s) using ${fRange}`
|
|
920
|
+
);
|
|
921
|
+
for (const [version$1, codemods2] of Object.entries(codemodsByVersion)) {
|
|
922
|
+
this.logger?.debug?.(`- ${version(semVerFactory(version$1))} (${codemods2.length})`);
|
|
923
|
+
}
|
|
924
|
+
return this.safeRunAndReport(codemods);
|
|
758
925
|
}
|
|
759
926
|
}
|
|
760
927
|
const codemodRunnerFactory = (project, range) => {
|
|
@@ -781,6 +948,15 @@ class Upgrader {
|
|
|
781
948
|
this.logger = null;
|
|
782
949
|
this.confirmationCallback = null;
|
|
783
950
|
}
|
|
951
|
+
getNPMPackage() {
|
|
952
|
+
return this.npmPackage;
|
|
953
|
+
}
|
|
954
|
+
getProject() {
|
|
955
|
+
return this.project;
|
|
956
|
+
}
|
|
957
|
+
getTarget() {
|
|
958
|
+
return semVerFactory(this.target.raw);
|
|
959
|
+
}
|
|
784
960
|
setRequirements(requirements) {
|
|
785
961
|
this.requirements = requirements;
|
|
786
962
|
return this;
|
|
@@ -793,7 +969,7 @@ class Upgrader {
|
|
|
793
969
|
this.codemodsTarget = semVerFactory(
|
|
794
970
|
`${this.target.major}.${this.target.minor}.${this.target.patch}`
|
|
795
971
|
);
|
|
796
|
-
this.logger?.debug(
|
|
972
|
+
this.logger?.debug?.(
|
|
797
973
|
`The codemods target has been synced with the upgrade target. The codemod runner will now look for ${version(
|
|
798
974
|
this.codemodsTarget
|
|
799
975
|
)}`
|
|
@@ -802,7 +978,7 @@ class Upgrader {
|
|
|
802
978
|
}
|
|
803
979
|
overrideCodemodsTarget(target) {
|
|
804
980
|
this.codemodsTarget = target;
|
|
805
|
-
this.logger?.debug(
|
|
981
|
+
this.logger?.debug?.(
|
|
806
982
|
`Overriding the codemods target. The codemod runner will now look for ${version(target)}`
|
|
807
983
|
);
|
|
808
984
|
return this;
|
|
@@ -822,44 +998,52 @@ class Upgrader {
|
|
|
822
998
|
addRequirement(requirement) {
|
|
823
999
|
this.requirements.push(requirement);
|
|
824
1000
|
const fRequired = requirement.isRequired ? "(required)" : "(optional)";
|
|
825
|
-
this.logger?.debug(
|
|
1001
|
+
this.logger?.debug?.(
|
|
826
1002
|
`Added a new requirement to the upgrade: ${highlight(requirement.name)} ${fRequired}`
|
|
827
1003
|
);
|
|
828
1004
|
return this;
|
|
829
1005
|
}
|
|
830
1006
|
async upgrade() {
|
|
831
|
-
this.logger?.info(
|
|
1007
|
+
this.logger?.info?.(
|
|
832
1008
|
`Upgrading from ${version(this.project.strapiVersion)} to ${version(this.target)}`
|
|
833
1009
|
);
|
|
834
1010
|
if (this.isDry) {
|
|
835
|
-
this.logger?.warn(
|
|
1011
|
+
this.logger?.warn?.(
|
|
836
1012
|
"Running the upgrade in dry mode. No files will be modified during the process."
|
|
837
1013
|
);
|
|
838
1014
|
}
|
|
839
1015
|
const range = rangeFromVersions(this.project.strapiVersion, this.target);
|
|
840
1016
|
const codemodsRange = rangeFromVersions(this.project.strapiVersion, this.codemodsTarget);
|
|
841
1017
|
const npmVersionsMatches = this.npmPackage?.findVersionsInRange(range) ?? [];
|
|
842
|
-
this.logger?.debug(
|
|
1018
|
+
this.logger?.debug?.(
|
|
843
1019
|
`Found ${highlight(npmVersionsMatches.length)} versions satisfying ${versionRange(range)}`
|
|
844
1020
|
);
|
|
845
1021
|
try {
|
|
846
|
-
this.logger?.info(upgradeStep("Checking requirement", [1, 4]));
|
|
1022
|
+
this.logger?.info?.(upgradeStep("Checking requirement", [1, 4]));
|
|
847
1023
|
await this.checkRequirements(this.requirements, {
|
|
848
1024
|
npmVersionsMatches,
|
|
849
1025
|
project: this.project,
|
|
850
1026
|
target: this.target
|
|
851
1027
|
});
|
|
852
|
-
this.logger?.info(upgradeStep("Applying the latest code modifications", [2, 4]));
|
|
1028
|
+
this.logger?.info?.(upgradeStep("Applying the latest code modifications", [2, 4]));
|
|
853
1029
|
await this.runCodemods(codemodsRange);
|
|
854
|
-
this.logger?.
|
|
1030
|
+
this.logger?.debug?.("Refreshing project information...");
|
|
1031
|
+
this.project.refresh();
|
|
1032
|
+
this.logger?.info?.(upgradeStep("Upgrading Strapi dependencies", [3, 4]));
|
|
855
1033
|
await this.updateDependencies();
|
|
856
|
-
this.logger?.info(upgradeStep("Installing dependencies", [4, 4]));
|
|
1034
|
+
this.logger?.info?.(upgradeStep("Installing dependencies", [4, 4]));
|
|
857
1035
|
await this.installDependencies();
|
|
858
1036
|
} catch (e) {
|
|
859
1037
|
return erroredReport(unknownToError(e));
|
|
860
1038
|
}
|
|
861
1039
|
return successReport();
|
|
862
1040
|
}
|
|
1041
|
+
async confirm(message) {
|
|
1042
|
+
if (typeof this.confirmationCallback !== "function") {
|
|
1043
|
+
return true;
|
|
1044
|
+
}
|
|
1045
|
+
return this.confirmationCallback(message);
|
|
1046
|
+
}
|
|
863
1047
|
async checkRequirements(requirements, context) {
|
|
864
1048
|
for (const requirement of requirements) {
|
|
865
1049
|
const { pass, error } = await requirement.test(context);
|
|
@@ -886,7 +1070,7 @@ class Upgrader {
|
|
|
886
1070
|
if (requirement.isRequired) {
|
|
887
1071
|
throw error;
|
|
888
1072
|
}
|
|
889
|
-
this.logger?.warn(warningMessage);
|
|
1073
|
+
this.logger?.warn?.(warningMessage);
|
|
890
1074
|
const response = await this.confirmationCallback?.(confirmationMessage);
|
|
891
1075
|
if (!response) {
|
|
892
1076
|
throw error;
|
|
@@ -897,9 +1081,11 @@ class Upgrader {
|
|
|
897
1081
|
const json = createJSONTransformAPI(packageJSON);
|
|
898
1082
|
const dependencies = json.get("dependencies", {});
|
|
899
1083
|
const strapiDependencies = this.getScopedStrapiDependencies(dependencies);
|
|
900
|
-
this.logger?.debug(
|
|
1084
|
+
this.logger?.debug?.(
|
|
1085
|
+
`Found ${highlight(strapiDependencies.length)} dependency(ies) to update`
|
|
1086
|
+
);
|
|
901
1087
|
strapiDependencies.forEach(
|
|
902
|
-
(dependency) => this.logger?.debug(`- ${dependency[0]} (${dependency[1]} -> ${this.target})`)
|
|
1088
|
+
(dependency) => this.logger?.debug?.(`- ${dependency[0]} (${dependency[1]} -> ${this.target})`)
|
|
903
1089
|
);
|
|
904
1090
|
if (strapiDependencies.length === 0) {
|
|
905
1091
|
return;
|
|
@@ -907,7 +1093,7 @@ class Upgrader {
|
|
|
907
1093
|
strapiDependencies.forEach(([name]) => json.set(`dependencies.${name}`, this.target.raw));
|
|
908
1094
|
const updatedPackageJSON = json.root();
|
|
909
1095
|
if (this.isDry) {
|
|
910
|
-
this.logger?.debug(`Skipping dependencies update (${chalk.italic("dry mode")})`);
|
|
1096
|
+
this.logger?.debug?.(`Skipping dependencies update (${chalk.italic("dry mode")})`);
|
|
911
1097
|
return;
|
|
912
1098
|
}
|
|
913
1099
|
await saveJSON(packageJSONPath, updatedPackageJSON);
|
|
@@ -927,9 +1113,9 @@ class Upgrader {
|
|
|
927
1113
|
async installDependencies() {
|
|
928
1114
|
const projectPath = this.project.cwd;
|
|
929
1115
|
const packageManagerName = await packageManager.getPreferred(projectPath);
|
|
930
|
-
this.logger?.debug(`Using ${highlight(packageManagerName)} as package manager`);
|
|
1116
|
+
this.logger?.debug?.(`Using ${highlight(packageManagerName)} as package manager`);
|
|
931
1117
|
if (this.isDry) {
|
|
932
|
-
this.logger?.debug(`Skipping dependencies installation (${chalk.italic("dry mode")}`);
|
|
1118
|
+
this.logger?.debug?.(`Skipping dependencies installation (${chalk.italic("dry mode")})`);
|
|
933
1119
|
return;
|
|
934
1120
|
}
|
|
935
1121
|
await packageManager.installDependencies(projectPath, packageManagerName, {
|
|
@@ -948,23 +1134,28 @@ class Upgrader {
|
|
|
948
1134
|
}
|
|
949
1135
|
const resolveNPMTarget = (project, target, npmPackage) => {
|
|
950
1136
|
if (isSemverInstance(target)) {
|
|
951
|
-
|
|
1137
|
+
const version2 = npmPackage.findVersion(target);
|
|
1138
|
+
if (!version2) {
|
|
1139
|
+
throw new NPMCandidateNotFoundError(target);
|
|
1140
|
+
}
|
|
1141
|
+
return version2;
|
|
952
1142
|
}
|
|
953
1143
|
if (isSemVerReleaseType(target)) {
|
|
954
1144
|
const range = rangeFromVersions(project.strapiVersion, target);
|
|
955
1145
|
const npmVersionsMatches = npmPackage.findVersionsInRange(range);
|
|
956
|
-
|
|
1146
|
+
const version2 = npmVersionsMatches.at(-1);
|
|
1147
|
+
if (!version2) {
|
|
1148
|
+
throw new NPMCandidateNotFoundError(range, `The project is already up-to-date (${target})`);
|
|
1149
|
+
}
|
|
1150
|
+
return version2;
|
|
957
1151
|
}
|
|
958
|
-
|
|
1152
|
+
throw new NPMCandidateNotFoundError(target);
|
|
959
1153
|
};
|
|
960
1154
|
const upgraderFactory = (project, target, npmPackage) => {
|
|
961
|
-
const
|
|
962
|
-
|
|
963
|
-
throw new Error(`Couldn't find a matching version in the NPM registry for "${target}"`);
|
|
964
|
-
}
|
|
965
|
-
const semverTarget = semVerFactory(targetedNPMVersion.version);
|
|
1155
|
+
const npmTarget = resolveNPMTarget(project, target, npmPackage);
|
|
1156
|
+
const semverTarget = semVerFactory(npmTarget.version);
|
|
966
1157
|
if (semver.eq(semverTarget, project.strapiVersion)) {
|
|
967
|
-
throw new Error(`The project is already
|
|
1158
|
+
throw new Error(`The project is already using v${semverTarget}`);
|
|
968
1159
|
}
|
|
969
1160
|
return new Upgrader(project, semverTarget, npmPackage);
|
|
970
1161
|
};
|
|
@@ -975,96 +1166,205 @@ const constants = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePro
|
|
|
975
1166
|
__proto__: null,
|
|
976
1167
|
STRAPI_PACKAGE_NAME
|
|
977
1168
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
978
|
-
const index$
|
|
1169
|
+
const index$6 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
979
1170
|
__proto__: null,
|
|
980
1171
|
constants,
|
|
981
1172
|
upgraderFactory
|
|
982
1173
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
983
|
-
|
|
984
|
-
|
|
1174
|
+
class Requirement {
|
|
1175
|
+
isRequired;
|
|
985
1176
|
name;
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
constructor(name) {
|
|
1177
|
+
testCallback;
|
|
1178
|
+
children;
|
|
1179
|
+
constructor(name, testCallback, isRequired) {
|
|
989
1180
|
this.name = name;
|
|
990
|
-
this.
|
|
991
|
-
this.
|
|
1181
|
+
this.testCallback = testCallback;
|
|
1182
|
+
this.isRequired = isRequired ?? true;
|
|
1183
|
+
this.children = [];
|
|
992
1184
|
}
|
|
993
|
-
|
|
994
|
-
|
|
1185
|
+
setChildren(children) {
|
|
1186
|
+
this.children = children;
|
|
1187
|
+
return this;
|
|
995
1188
|
}
|
|
996
|
-
|
|
997
|
-
|
|
1189
|
+
addChild(child) {
|
|
1190
|
+
this.children.push(child);
|
|
1191
|
+
return this;
|
|
998
1192
|
}
|
|
999
|
-
|
|
1000
|
-
this.
|
|
1001
|
-
|
|
1193
|
+
asOptional() {
|
|
1194
|
+
const newInstance = requirementFactory(this.name, this.testCallback, false);
|
|
1195
|
+
newInstance.setChildren(this.children);
|
|
1196
|
+
return newInstance;
|
|
1002
1197
|
}
|
|
1003
|
-
|
|
1004
|
-
this.
|
|
1005
|
-
|
|
1198
|
+
asRequired() {
|
|
1199
|
+
const newInstance = requirementFactory(this.name, this.testCallback, true);
|
|
1200
|
+
newInstance.setChildren(this.children);
|
|
1201
|
+
return newInstance;
|
|
1006
1202
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1203
|
+
async test(context) {
|
|
1204
|
+
try {
|
|
1205
|
+
await this.testCallback?.(context);
|
|
1206
|
+
return ok();
|
|
1207
|
+
} catch (e) {
|
|
1208
|
+
if (e instanceof Error) {
|
|
1209
|
+
return errored(e);
|
|
1210
|
+
}
|
|
1211
|
+
if (typeof e === "string") {
|
|
1212
|
+
return errored(new Error(e));
|
|
1213
|
+
}
|
|
1214
|
+
return errored(new Error("Unknown error"));
|
|
1215
|
+
}
|
|
1010
1216
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1217
|
+
}
|
|
1218
|
+
const ok = () => ({ pass: true, error: null });
|
|
1219
|
+
const errored = (error) => ({ pass: false, error });
|
|
1220
|
+
const requirementFactory = (name, testCallback, isRequired) => new Requirement(name, testCallback, isRequired);
|
|
1221
|
+
const index$5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1222
|
+
__proto__: null,
|
|
1223
|
+
requirementFactory
|
|
1224
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1225
|
+
const REQUIRE_AVAILABLE_NEXT_MAJOR = requirementFactory(
|
|
1226
|
+
"REQUIRE_AVAILABLE_NEXT_MAJOR",
|
|
1227
|
+
(context) => {
|
|
1228
|
+
const { project, target } = context;
|
|
1229
|
+
const currentMajor = project.strapiVersion.major;
|
|
1230
|
+
const targetedMajor = target.major;
|
|
1231
|
+
if (targetedMajor === currentMajor) {
|
|
1232
|
+
throw new Error(`You're already on the latest major version (v${currentMajor})`);
|
|
1233
|
+
}
|
|
1014
1234
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1235
|
+
);
|
|
1236
|
+
const REQUIRE_LATEST_FOR_CURRENT_MAJOR = requirementFactory(
|
|
1237
|
+
"REQUIRE_LATEST_FOR_CURRENT_MAJOR",
|
|
1238
|
+
(context) => {
|
|
1239
|
+
const { project, target, npmVersionsMatches } = context;
|
|
1240
|
+
const { major: currentMajor } = project.strapiVersion;
|
|
1241
|
+
const invalidMatches = npmVersionsMatches.filter(
|
|
1242
|
+
(match) => semVerFactory(match.version).major === currentMajor
|
|
1243
|
+
);
|
|
1244
|
+
if (invalidMatches.length > 0) {
|
|
1245
|
+
const invalidVersions = invalidMatches.map((match) => match.version);
|
|
1246
|
+
const invalidVersionsCount = invalidVersions.length;
|
|
1247
|
+
throw new Error(
|
|
1248
|
+
`Doing a major upgrade requires to be on the latest v${currentMajor} version, but found ${invalidVersionsCount} versions between the current one and ${target}. Please upgrade to ${invalidVersions.at(-1)} and try again.`
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1020
1251
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1252
|
+
);
|
|
1253
|
+
const REQUIRE_GIT_CLEAN_REPOSITORY = requirementFactory(
|
|
1254
|
+
"REQUIRE_GIT_CLEAN_REPOSITORY",
|
|
1255
|
+
async (context) => {
|
|
1256
|
+
const git = simpleGit({ baseDir: context.project.cwd });
|
|
1257
|
+
const status = await git.status();
|
|
1258
|
+
if (!status.isClean()) {
|
|
1259
|
+
throw new Error(
|
|
1260
|
+
"Repository is not clean. Please commit or stash any changes before upgrading"
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1023
1263
|
}
|
|
1024
|
-
|
|
1025
|
-
const
|
|
1264
|
+
);
|
|
1265
|
+
const REQUIRE_GIT_REPOSITORY = requirementFactory(
|
|
1266
|
+
"REQUIRE_GIT_REPOSITORY",
|
|
1267
|
+
async (context) => {
|
|
1268
|
+
const git = simpleGit({ baseDir: context.project.cwd });
|
|
1269
|
+
const isRepo = await git.checkIsRepo();
|
|
1270
|
+
if (!isRepo) {
|
|
1271
|
+
throw new Error("Not a git repository (or any of the parent directories)");
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
).addChild(REQUIRE_GIT_CLEAN_REPOSITORY.asOptional());
|
|
1275
|
+
const REQUIRE_GIT_INSTALLED = requirementFactory(
|
|
1276
|
+
"REQUIRE_GIT_INSTALLED",
|
|
1277
|
+
async (context) => {
|
|
1278
|
+
const git = simpleGit({ baseDir: context.project.cwd });
|
|
1279
|
+
try {
|
|
1280
|
+
await git.version();
|
|
1281
|
+
} catch {
|
|
1282
|
+
throw new Error("Git is not installed");
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
).addChild(REQUIRE_GIT_REPOSITORY.asOptional());
|
|
1286
|
+
const REQUIRE_GIT = requirementFactory("REQUIRE_GIT", null).addChild(
|
|
1287
|
+
REQUIRE_GIT_INSTALLED.asOptional()
|
|
1288
|
+
);
|
|
1289
|
+
const latest = async (upgrader, options) => {
|
|
1290
|
+
if (options.target !== ReleaseType.Latest) {
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
const npmPackage = upgrader.getNPMPackage();
|
|
1294
|
+
const target = upgrader.getTarget();
|
|
1295
|
+
const project = upgrader.getProject();
|
|
1296
|
+
const { strapiVersion: current } = project;
|
|
1297
|
+
const fTargetMajor = highlight(`v${target.major}`);
|
|
1298
|
+
const fCurrentMajor = highlight(`v${current.major}`);
|
|
1299
|
+
const fTarget = version(target);
|
|
1300
|
+
const fCurrent = version(current);
|
|
1301
|
+
const isMajorUpgrade = target.major > current.major;
|
|
1302
|
+
if (isMajorUpgrade) {
|
|
1303
|
+
options.logger.warn(
|
|
1304
|
+
`Detected a major upgrade for the "${highlight(ReleaseType.Latest)}" tag: ${fCurrent} > ${fTarget}`
|
|
1305
|
+
);
|
|
1306
|
+
const newerPackageRelease = npmPackage.findVersionsInRange(rangeFactory(`>${current.raw} <${target.major}`)).at(-1);
|
|
1307
|
+
if (newerPackageRelease) {
|
|
1308
|
+
const fLatest = version(semVerFactory(newerPackageRelease.version));
|
|
1309
|
+
options.logger.warn(
|
|
1310
|
+
`It's recommended to first upgrade to the latest version of ${fCurrentMajor} (${fLatest}) before upgrading to ${fTargetMajor}.`
|
|
1311
|
+
);
|
|
1312
|
+
}
|
|
1313
|
+
const proceedAnyway = await upgrader.confirm(`I know what I'm doing. Proceed anyway!`);
|
|
1314
|
+
if (!proceedAnyway) {
|
|
1315
|
+
throw new AbortedError();
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
1026
1319
|
const upgrade = async (options) => {
|
|
1027
1320
|
const timer = timerFactory();
|
|
1028
1321
|
const { logger, codemodsTarget } = options;
|
|
1029
1322
|
const cwd = path$1.resolve(options.cwd ?? process.cwd());
|
|
1030
1323
|
const project = projectFactory(cwd);
|
|
1324
|
+
logger.debug(projectDetails(project));
|
|
1325
|
+
if (!isApplicationProject(project)) {
|
|
1326
|
+
throw new Error(
|
|
1327
|
+
`The "${options.target}" upgrade can only be run on a Strapi project; for plugins, please use "codemods".`
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
logger.debug(
|
|
1331
|
+
`Application: VERSION=${version(project.packageJSON.version)}; STRAPI_VERSION=${version(project.strapiVersion)}`
|
|
1332
|
+
);
|
|
1031
1333
|
const npmPackage = npmPackageFactory(STRAPI_PACKAGE_NAME);
|
|
1032
1334
|
await npmPackage.refresh();
|
|
1033
1335
|
const upgrader = upgraderFactory(project, options.target, npmPackage).dry(options.dry ?? false).onConfirm(options.confirm ?? null).setLogger(logger);
|
|
1034
1336
|
if (codemodsTarget !== void 0) {
|
|
1035
1337
|
upgrader.overrideCodemodsTarget(codemodsTarget);
|
|
1036
1338
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
}
|
|
1040
|
-
upgrader.addRequirement(REQUIRE_GIT.asOptional());
|
|
1339
|
+
await runUpgradePrompts(upgrader, options);
|
|
1340
|
+
addUpgradeRequirements(upgrader, options);
|
|
1041
1341
|
const upgradeReport = await upgrader.upgrade();
|
|
1042
1342
|
if (!upgradeReport.success) {
|
|
1043
1343
|
throw upgradeReport.error;
|
|
1044
1344
|
}
|
|
1045
1345
|
timer.stop();
|
|
1046
|
-
logger.info(`Completed in ${durationMs(timer.elapsedMs)}`);
|
|
1346
|
+
logger.info(`Completed in ${durationMs(timer.elapsedMs)}ms`);
|
|
1047
1347
|
};
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
const cwd = path$1.resolve(options.cwd ?? process.cwd());
|
|
1052
|
-
const project = projectFactory(cwd);
|
|
1053
|
-
const range = getRangeFromTarget(project.strapiVersion, options.target);
|
|
1054
|
-
const codemodRunner = codemodRunnerFactory(project, range).dry(options.dry ?? false).onSelectCodemods(options.selectCodemods ?? null).setLogger(logger);
|
|
1055
|
-
const executionReport = await codemodRunner.run();
|
|
1056
|
-
if (!executionReport.success) {
|
|
1057
|
-
throw executionReport.error;
|
|
1348
|
+
const runUpgradePrompts = async (upgrader, options) => {
|
|
1349
|
+
if (options.target === ReleaseType.Latest) {
|
|
1350
|
+
await latest(upgrader, options);
|
|
1058
1351
|
}
|
|
1059
|
-
timer.stop();
|
|
1060
|
-
logger.info(`Completed in ${timer.elapsedMs}`);
|
|
1061
1352
|
};
|
|
1353
|
+
const addUpgradeRequirements = (upgrader, options) => {
|
|
1354
|
+
if (options.target === ReleaseType.Major) {
|
|
1355
|
+
upgrader.addRequirement(REQUIRE_AVAILABLE_NEXT_MAJOR).addRequirement(REQUIRE_LATEST_FOR_CURRENT_MAJOR);
|
|
1356
|
+
}
|
|
1357
|
+
upgrader.addRequirement(REQUIRE_GIT.asOptional());
|
|
1358
|
+
};
|
|
1359
|
+
const resolvePath = (cwd) => path$1.resolve(cwd ?? process.cwd());
|
|
1062
1360
|
const getRangeFromTarget = (currentVersion, target) => {
|
|
1063
1361
|
if (isSemverInstance(target)) {
|
|
1064
1362
|
return rangeFactory(target);
|
|
1065
1363
|
}
|
|
1066
1364
|
const { major, minor, patch } = currentVersion;
|
|
1067
1365
|
switch (target) {
|
|
1366
|
+
case ReleaseType.Latest:
|
|
1367
|
+
throw new Error("Can't use <latest> to create a codemods range: not implemented");
|
|
1068
1368
|
case ReleaseType.Major:
|
|
1069
1369
|
return rangeFactory(`${major}`);
|
|
1070
1370
|
case ReleaseType.Minor:
|
|
@@ -1075,9 +1375,60 @@ const getRangeFromTarget = (currentVersion, target) => {
|
|
|
1075
1375
|
throw new Error(`Invalid target set: ${target}`);
|
|
1076
1376
|
}
|
|
1077
1377
|
};
|
|
1378
|
+
const findRangeFromTarget = (project, target) => {
|
|
1379
|
+
if (isRangeInstance(target)) {
|
|
1380
|
+
return target;
|
|
1381
|
+
}
|
|
1382
|
+
if (isApplicationProject(project)) {
|
|
1383
|
+
return getRangeFromTarget(project.strapiVersion, target);
|
|
1384
|
+
}
|
|
1385
|
+
return rangeFactory("*");
|
|
1386
|
+
};
|
|
1387
|
+
const runCodemods = async (options) => {
|
|
1388
|
+
const timer = timerFactory();
|
|
1389
|
+
const { logger, uid } = options;
|
|
1390
|
+
const cwd = resolvePath(options.cwd);
|
|
1391
|
+
const project = projectFactory(cwd);
|
|
1392
|
+
const range = findRangeFromTarget(project, options.target);
|
|
1393
|
+
logger.debug(projectDetails(project));
|
|
1394
|
+
logger.debug(`Range: set to ${versionRange(range)}`);
|
|
1395
|
+
const codemodRunner = codemodRunnerFactory(project, range).dry(options.dry ?? false).onSelectCodemods(options.selectCodemods ?? null).setLogger(logger);
|
|
1396
|
+
let report;
|
|
1397
|
+
if (uid !== void 0) {
|
|
1398
|
+
logger.debug(`Running a single codemod: ${codemodUID(uid)}`);
|
|
1399
|
+
report = await codemodRunner.runByUID(uid);
|
|
1400
|
+
} else {
|
|
1401
|
+
report = await codemodRunner.run();
|
|
1402
|
+
}
|
|
1403
|
+
if (!report.success) {
|
|
1404
|
+
throw report.error;
|
|
1405
|
+
}
|
|
1406
|
+
timer.stop();
|
|
1407
|
+
logger.info(`Completed in ${timer.elapsedMs}`);
|
|
1408
|
+
};
|
|
1409
|
+
const listCodemods = async (options) => {
|
|
1410
|
+
const { logger, target } = options;
|
|
1411
|
+
const cwd = resolvePath(options.cwd);
|
|
1412
|
+
const project = projectFactory(cwd);
|
|
1413
|
+
const range = findRangeFromTarget(project, target);
|
|
1414
|
+
logger.debug(projectDetails(project));
|
|
1415
|
+
logger.debug(`Range: set to ${versionRange(range)}`);
|
|
1416
|
+
const repo = codemodRepositoryFactory();
|
|
1417
|
+
repo.refresh();
|
|
1418
|
+
const groups = repo.find({ range });
|
|
1419
|
+
const codemods = groups.flatMap((collection) => collection.codemods);
|
|
1420
|
+
logger.debug(`Found ${highlight(codemods.length)} codemods`);
|
|
1421
|
+
if (codemods.length === 0) {
|
|
1422
|
+
logger.info(`Found no codemods matching ${versionRange(range)}`);
|
|
1423
|
+
return;
|
|
1424
|
+
}
|
|
1425
|
+
const fCodemods = codemodList(codemods);
|
|
1426
|
+
logger.raw(fCodemods);
|
|
1427
|
+
};
|
|
1078
1428
|
const index$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1079
1429
|
__proto__: null,
|
|
1080
|
-
|
|
1430
|
+
listCodemods,
|
|
1431
|
+
runCodemods,
|
|
1081
1432
|
upgrade
|
|
1082
1433
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1083
1434
|
class Logger {
|
|
@@ -1171,18 +1522,18 @@ const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
1171
1522
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1172
1523
|
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1173
1524
|
__proto__: null,
|
|
1174
|
-
codemod: index$
|
|
1175
|
-
codemodRepository: index$
|
|
1525
|
+
codemod: index$8,
|
|
1526
|
+
codemodRepository: index$7,
|
|
1176
1527
|
error: index$9,
|
|
1177
|
-
f: index$
|
|
1528
|
+
f: index$f,
|
|
1178
1529
|
fileScanner: index$d,
|
|
1179
1530
|
logger: index$3,
|
|
1180
1531
|
project: index$a,
|
|
1181
1532
|
report: index$2,
|
|
1182
|
-
requirement: index$
|
|
1533
|
+
requirement: index$5,
|
|
1183
1534
|
runner: index$1,
|
|
1184
|
-
timer: index$
|
|
1185
|
-
upgrader: index$
|
|
1535
|
+
timer: index$g,
|
|
1536
|
+
upgrader: index$6,
|
|
1186
1537
|
version: index$e
|
|
1187
1538
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1188
1539
|
export {
|