@strapi/upgrade 0.0.0-experimental.f31889311d753b5f7d95198ae84d8fce1d156cd6 → 0.0.0-experimental.f49f46a1c17445a39e8af3f63124bcccf73842e6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +439 -317
- package/dist/cli.js.map +1 -1
- package/dist/index.js +462 -343
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +458 -340
- package/dist/index.mjs.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 +2 -1
- package/dist/modules/format/formats.d.ts.map +1 -1
- package/dist/modules/project/constants.d.ts +6 -5
- package/dist/modules/project/constants.d.ts.map +1 -1
- package/dist/modules/project/project.d.ts +16 -2
- package/dist/modules/project/project.d.ts.map +1 -1
- package/dist/modules/project/types.d.ts +3 -0
- package/dist/modules/project/types.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 +4 -0
- package/dist/modules/upgrader/upgrader.d.ts.map +1 -1
- 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/utils.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 +7 -7
- package/resources/codemods/5.0.0/comment-out-lifecycle-files.code.ts +63 -0
- package/resources/codemods/5.0.0/dependency-upgrade-react-and-react-dom.json.ts +67 -0
- package/resources/codemods/5.0.0/deprecate-helper-plugin.code.ts +192 -0
- package/resources/codemods/5.0.0/sqlite3-to-better-sqlite3.json.ts +0 -1
- package/resources/codemods/5.1.0/dependency-better-sqlite3.json.ts +48 -0
- package/resources/utils/change-import.ts +118 -0
- package/resources/utils/replace-jsx.ts +49 -0
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, groupBy, size } 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
|
-
await fse.writeFile(path2, jsonAsString);
|
|
52
|
+
const codemodUID = (uid) => {
|
|
53
|
+
return chalk.bold.cyan(uid);
|
|
200
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();
|
|
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");
|
|
@@ -271,13 +207,57 @@ const index$e = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
271
207
|
rangeFromVersions,
|
|
272
208
|
semVerFactory
|
|
273
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);
|
|
274
252
|
class FileScanner {
|
|
275
253
|
cwd;
|
|
276
254
|
constructor(cwd) {
|
|
277
255
|
this.cwd = cwd;
|
|
278
256
|
}
|
|
279
257
|
scan(patterns) {
|
|
280
|
-
const filenames =
|
|
258
|
+
const filenames = fastglob.sync(patterns, {
|
|
259
|
+
cwd: this.cwd
|
|
260
|
+
});
|
|
281
261
|
return filenames.map((filename) => path$1.join(this.cwd, filename));
|
|
282
262
|
}
|
|
283
263
|
}
|
|
@@ -315,6 +295,46 @@ const index$c = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
315
295
|
__proto__: null,
|
|
316
296
|
codeRunnerFactory
|
|
317
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
|
+
};
|
|
318
338
|
const transformJSON = async (codemodPath, paths, config) => {
|
|
319
339
|
const { dry } = config;
|
|
320
340
|
const startTime = process.hrtime();
|
|
@@ -375,8 +395,10 @@ const index$b = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
375
395
|
jsonRunnerFactory
|
|
376
396
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
377
397
|
const PROJECT_PACKAGE_JSON = "package.json";
|
|
378
|
-
const
|
|
379
|
-
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 = [
|
|
380
402
|
// Source files
|
|
381
403
|
"js",
|
|
382
404
|
"mjs",
|
|
@@ -385,22 +407,19 @@ const PROJECT_DEFAULT_CODE_EXTENSIONS = [
|
|
|
385
407
|
"jsx",
|
|
386
408
|
"tsx"
|
|
387
409
|
];
|
|
388
|
-
const
|
|
389
|
-
const
|
|
390
|
-
...PROJECT_DEFAULT_CODE_EXTENSIONS,
|
|
391
|
-
...PROJECT_DEFAULT_JSON_EXTENSIONS
|
|
392
|
-
];
|
|
393
|
-
const PROJECT_DEFAULT_PATTERNS = ["package.json"];
|
|
410
|
+
const PROJECT_JSON_EXTENSIONS = ["json"];
|
|
411
|
+
const PROJECT_ALLOWED_EXTENSIONS = [...PROJECT_CODE_EXTENSIONS, ...PROJECT_JSON_EXTENSIONS];
|
|
394
412
|
const SCOPED_STRAPI_PACKAGE_PREFIX = "@strapi/";
|
|
395
413
|
const STRAPI_DEPENDENCY_NAME = `${SCOPED_STRAPI_PACKAGE_PREFIX}strapi`;
|
|
396
414
|
const constants$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
397
415
|
__proto__: null,
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
PROJECT_DEFAULT_PATTERNS,
|
|
416
|
+
PROJECT_ALLOWED_EXTENSIONS,
|
|
417
|
+
PROJECT_APP_ALLOWED_ROOT_PATHS,
|
|
418
|
+
PROJECT_CODE_EXTENSIONS,
|
|
419
|
+
PROJECT_JSON_EXTENSIONS,
|
|
403
420
|
PROJECT_PACKAGE_JSON,
|
|
421
|
+
PROJECT_PLUGIN_ALLOWED_ROOT_PATHS,
|
|
422
|
+
PROJECT_PLUGIN_ROOT_FILES,
|
|
404
423
|
SCOPED_STRAPI_PACKAGE_PREFIX,
|
|
405
424
|
STRAPI_DEPENDENCY_NAME
|
|
406
425
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
@@ -410,11 +429,13 @@ class Project {
|
|
|
410
429
|
files;
|
|
411
430
|
packageJSONPath;
|
|
412
431
|
packageJSON;
|
|
413
|
-
|
|
432
|
+
paths;
|
|
433
|
+
constructor(cwd, config) {
|
|
414
434
|
if (!fse.pathExistsSync(cwd)) {
|
|
415
435
|
throw new Error(`ENOENT: no such file or directory, access '${cwd}'`);
|
|
416
436
|
}
|
|
417
437
|
this.cwd = cwd;
|
|
438
|
+
this.paths = config.paths;
|
|
418
439
|
this.refresh();
|
|
419
440
|
}
|
|
420
441
|
getFilesByExtensions(extensions) {
|
|
@@ -442,12 +463,8 @@ class Project {
|
|
|
442
463
|
return reports2;
|
|
443
464
|
}
|
|
444
465
|
createProjectCodemodsRunners(dry = false) {
|
|
445
|
-
const jsonExtensions =
|
|
446
|
-
|
|
447
|
-
);
|
|
448
|
-
const codeExtensions = PROJECT_DEFAULT_CODE_EXTENSIONS.map(
|
|
449
|
-
(ext) => `.${ext}`
|
|
450
|
-
);
|
|
466
|
+
const jsonExtensions = PROJECT_JSON_EXTENSIONS.map((ext) => `.${ext}`);
|
|
467
|
+
const codeExtensions = PROJECT_CODE_EXTENSIONS.map((ext) => `.${ext}`);
|
|
451
468
|
const jsonFiles = this.getFilesByExtensions(jsonExtensions);
|
|
452
469
|
const codeFiles = this.getFilesByExtensions(codeExtensions);
|
|
453
470
|
const codeRunner = codeRunnerFactory(codeFiles, {
|
|
@@ -455,7 +472,7 @@ class Project {
|
|
|
455
472
|
parser: "ts",
|
|
456
473
|
runInBand: true,
|
|
457
474
|
babel: true,
|
|
458
|
-
extensions:
|
|
475
|
+
extensions: PROJECT_CODE_EXTENSIONS.join(","),
|
|
459
476
|
// Don't output any log coming from the runner
|
|
460
477
|
print: false,
|
|
461
478
|
silent: true,
|
|
@@ -476,23 +493,32 @@ class Project {
|
|
|
476
493
|
this.packageJSON = JSON.parse(packageJSONBuffer.toString());
|
|
477
494
|
}
|
|
478
495
|
refreshProjectFiles() {
|
|
479
|
-
const allowedRootPaths = formatGlobCollectionPattern(
|
|
480
|
-
PROJECT_DEFAULT_ALLOWED_ROOT_PATHS
|
|
481
|
-
);
|
|
482
|
-
const allowedExtensions = formatGlobCollectionPattern(
|
|
483
|
-
PROJECT_DEFAULT_ALLOWED_EXTENSIONS
|
|
484
|
-
);
|
|
485
|
-
const projectFilesPattern = `./${allowedRootPaths}/**/*.${allowedExtensions}`;
|
|
486
|
-
const patterns = [projectFilesPattern, ...PROJECT_DEFAULT_PATTERNS];
|
|
487
496
|
const scanner = fileScannerFactory(this.cwd);
|
|
488
|
-
this.files = scanner.scan(
|
|
497
|
+
this.files = scanner.scan(this.paths);
|
|
489
498
|
}
|
|
490
499
|
}
|
|
491
500
|
class AppProject extends Project {
|
|
492
501
|
strapiVersion;
|
|
493
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
|
+
}
|
|
494
520
|
constructor(cwd) {
|
|
495
|
-
super(cwd);
|
|
521
|
+
super(cwd, { paths: AppProject.paths });
|
|
496
522
|
this.refreshStrapiVersion();
|
|
497
523
|
}
|
|
498
524
|
refresh() {
|
|
@@ -547,6 +573,30 @@ const formatGlobCollectionPattern = (collection) => {
|
|
|
547
573
|
};
|
|
548
574
|
class PluginProject extends Project {
|
|
549
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
|
+
}
|
|
550
600
|
}
|
|
551
601
|
const isPlugin = (cwd) => {
|
|
552
602
|
const packageJSONPath = path$1.join(cwd, PROJECT_PACKAGE_JSON);
|
|
@@ -561,10 +611,7 @@ const isPlugin = (cwd) => {
|
|
|
561
611
|
};
|
|
562
612
|
const projectFactory = (cwd) => {
|
|
563
613
|
fse.accessSync(cwd);
|
|
564
|
-
|
|
565
|
-
return new PluginProject(cwd);
|
|
566
|
-
}
|
|
567
|
-
return new AppProject(cwd);
|
|
614
|
+
return isPlugin(cwd) ? new PluginProject(cwd) : new AppProject(cwd);
|
|
568
615
|
};
|
|
569
616
|
const isPluginProject = (project) => {
|
|
570
617
|
return project instanceof PluginProject;
|
|
@@ -596,6 +643,18 @@ class UnexpectedError extends Error {
|
|
|
596
643
|
super("Unexpected Error");
|
|
597
644
|
}
|
|
598
645
|
}
|
|
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;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
class AbortedError extends Error {
|
|
654
|
+
constructor(message = "Upgrade aborted") {
|
|
655
|
+
super(message);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
599
658
|
const unknownToError = (e) => {
|
|
600
659
|
if (e instanceof Error) {
|
|
601
660
|
return e;
|
|
@@ -607,89 +666,11 @@ const unknownToError = (e) => {
|
|
|
607
666
|
};
|
|
608
667
|
const index$9 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
609
668
|
__proto__: null,
|
|
669
|
+
AbortedError,
|
|
670
|
+
NPMCandidateNotFoundError,
|
|
610
671
|
UnexpectedError,
|
|
611
672
|
unknownToError
|
|
612
673
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
613
|
-
const path = (path2) => chalk.blue(path2);
|
|
614
|
-
const version = (version2) => {
|
|
615
|
-
return chalk.italic.yellow(`v${version2}`);
|
|
616
|
-
};
|
|
617
|
-
const codemodUID = (uid) => {
|
|
618
|
-
return chalk.bold.cyan(uid);
|
|
619
|
-
};
|
|
620
|
-
const projectType = (type) => chalk.cyan(type);
|
|
621
|
-
const versionRange = (range) => chalk.italic.yellow(range.raw);
|
|
622
|
-
const transform = (transformFilePath) => chalk.cyan(transformFilePath);
|
|
623
|
-
const highlight = (arg) => chalk.bold.underline(arg);
|
|
624
|
-
const upgradeStep = (text, step) => {
|
|
625
|
-
return chalk.bold(`(${step[0]}/${step[1]}) ${text}...`);
|
|
626
|
-
};
|
|
627
|
-
const reports = (reports2) => {
|
|
628
|
-
const rows = reports2.map(({ codemod, report }, i) => {
|
|
629
|
-
const fIndex = chalk.grey(i);
|
|
630
|
-
const fVersion = chalk.magenta(codemod.version);
|
|
631
|
-
const fKind = chalk.yellow(codemod.kind);
|
|
632
|
-
const fFormattedTransformPath = chalk.cyan(codemod.format());
|
|
633
|
-
const fTimeElapsed = i === 0 ? `${report.timeElapsed}s ${chalk.dim.italic("(cold start)")}` : `${report.timeElapsed}s`;
|
|
634
|
-
const fAffected = report.ok > 0 ? chalk.green(report.ok) : chalk.grey(0);
|
|
635
|
-
const fUnchanged = report.ok === 0 ? chalk.red(report.nochange) : chalk.grey(report.nochange);
|
|
636
|
-
return [fIndex, fVersion, fKind, fFormattedTransformPath, fAffected, fUnchanged, fTimeElapsed];
|
|
637
|
-
});
|
|
638
|
-
const table = new CliTable3({
|
|
639
|
-
style: { compact: true },
|
|
640
|
-
head: [
|
|
641
|
-
chalk.bold.grey("N°"),
|
|
642
|
-
chalk.bold.magenta("Version"),
|
|
643
|
-
chalk.bold.yellow("Kind"),
|
|
644
|
-
chalk.bold.cyan("Name"),
|
|
645
|
-
chalk.bold.green("Affected"),
|
|
646
|
-
chalk.bold.red("Unchanged"),
|
|
647
|
-
chalk.bold.blue("Duration")
|
|
648
|
-
]
|
|
649
|
-
});
|
|
650
|
-
table.push(...rows);
|
|
651
|
-
return table.toString();
|
|
652
|
-
};
|
|
653
|
-
const codemodList = (codemods) => {
|
|
654
|
-
const rows = codemods.map((codemod, index2) => {
|
|
655
|
-
const fIndex = chalk.grey(index2);
|
|
656
|
-
const fVersion = chalk.magenta(codemod.version);
|
|
657
|
-
const fKind = chalk.yellow(codemod.kind);
|
|
658
|
-
const fName = chalk.blue(codemod.format());
|
|
659
|
-
const fUID = codemodUID(codemod.uid);
|
|
660
|
-
return [fIndex, fVersion, fKind, fName, fUID];
|
|
661
|
-
});
|
|
662
|
-
const table = new CliTable3({
|
|
663
|
-
style: { compact: true },
|
|
664
|
-
head: [
|
|
665
|
-
chalk.bold.grey("N°"),
|
|
666
|
-
chalk.bold.magenta("Version"),
|
|
667
|
-
chalk.bold.yellow("Kind"),
|
|
668
|
-
chalk.bold.blue("Name"),
|
|
669
|
-
chalk.bold.cyan("UID")
|
|
670
|
-
]
|
|
671
|
-
});
|
|
672
|
-
table.push(...rows);
|
|
673
|
-
return table.toString();
|
|
674
|
-
};
|
|
675
|
-
const durationMs = (elapsedMs) => {
|
|
676
|
-
const elapsedSeconds = (elapsedMs / ONE_SECOND_MS).toFixed(3);
|
|
677
|
-
return `${elapsedSeconds}s`;
|
|
678
|
-
};
|
|
679
|
-
const index$8 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
680
|
-
__proto__: null,
|
|
681
|
-
codemodList,
|
|
682
|
-
codemodUID,
|
|
683
|
-
durationMs,
|
|
684
|
-
highlight,
|
|
685
|
-
path,
|
|
686
|
-
projectType,
|
|
687
|
-
reports,
|
|
688
|
-
transform,
|
|
689
|
-
upgradeStep,
|
|
690
|
-
version,
|
|
691
|
-
versionRange
|
|
692
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
693
674
|
const CODEMOD_CODE_SUFFIX = "code";
|
|
694
675
|
const CODEMOD_JSON_SUFFIX = "json";
|
|
695
676
|
const CODEMOD_ALLOWED_SUFFIXES = [CODEMOD_CODE_SUFFIX, CODEMOD_JSON_SUFFIX];
|
|
@@ -742,7 +723,7 @@ class Codemod {
|
|
|
742
723
|
}
|
|
743
724
|
}
|
|
744
725
|
const codemodFactory = (options) => new Codemod(options);
|
|
745
|
-
const index$
|
|
726
|
+
const index$8 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
746
727
|
__proto__: null,
|
|
747
728
|
codemodFactory,
|
|
748
729
|
constants: constants$2
|
|
@@ -854,7 +835,7 @@ const parseCodemodKindFromFilename = (filename) => {
|
|
|
854
835
|
const codemodRepositoryFactory = (cwd = INTERNAL_CODEMODS_DIRECTORY) => {
|
|
855
836
|
return new CodemodRepository(cwd);
|
|
856
837
|
};
|
|
857
|
-
const index$
|
|
838
|
+
const index$7 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
858
839
|
__proto__: null,
|
|
859
840
|
codemodRepositoryFactory,
|
|
860
841
|
constants: constants$1
|
|
@@ -967,6 +948,15 @@ class Upgrader {
|
|
|
967
948
|
this.logger = null;
|
|
968
949
|
this.confirmationCallback = null;
|
|
969
950
|
}
|
|
951
|
+
getNPMPackage() {
|
|
952
|
+
return this.npmPackage;
|
|
953
|
+
}
|
|
954
|
+
getProject() {
|
|
955
|
+
return this.project;
|
|
956
|
+
}
|
|
957
|
+
getTarget() {
|
|
958
|
+
return semVerFactory(this.target.raw);
|
|
959
|
+
}
|
|
970
960
|
setRequirements(requirements) {
|
|
971
961
|
this.requirements = requirements;
|
|
972
962
|
return this;
|
|
@@ -1048,6 +1038,12 @@ class Upgrader {
|
|
|
1048
1038
|
}
|
|
1049
1039
|
return successReport();
|
|
1050
1040
|
}
|
|
1041
|
+
async confirm(message) {
|
|
1042
|
+
if (typeof this.confirmationCallback !== "function") {
|
|
1043
|
+
return true;
|
|
1044
|
+
}
|
|
1045
|
+
return this.confirmationCallback(message);
|
|
1046
|
+
}
|
|
1051
1047
|
async checkRequirements(requirements, context) {
|
|
1052
1048
|
for (const requirement of requirements) {
|
|
1053
1049
|
const { pass, error } = await requirement.test(context);
|
|
@@ -1119,7 +1115,7 @@ class Upgrader {
|
|
|
1119
1115
|
const packageManagerName = await packageManager.getPreferred(projectPath);
|
|
1120
1116
|
this.logger?.debug?.(`Using ${highlight(packageManagerName)} as package manager`);
|
|
1121
1117
|
if (this.isDry) {
|
|
1122
|
-
this.logger?.debug?.(`Skipping dependencies installation (${chalk.italic("dry mode")}`);
|
|
1118
|
+
this.logger?.debug?.(`Skipping dependencies installation (${chalk.italic("dry mode")})`);
|
|
1123
1119
|
return;
|
|
1124
1120
|
}
|
|
1125
1121
|
await packageManager.installDependencies(projectPath, packageManagerName, {
|
|
@@ -1138,23 +1134,28 @@ class Upgrader {
|
|
|
1138
1134
|
}
|
|
1139
1135
|
const resolveNPMTarget = (project, target, npmPackage) => {
|
|
1140
1136
|
if (isSemverInstance(target)) {
|
|
1141
|
-
|
|
1137
|
+
const version2 = npmPackage.findVersion(target);
|
|
1138
|
+
if (!version2) {
|
|
1139
|
+
throw new NPMCandidateNotFoundError(target);
|
|
1140
|
+
}
|
|
1141
|
+
return version2;
|
|
1142
1142
|
}
|
|
1143
1143
|
if (isSemVerReleaseType(target)) {
|
|
1144
1144
|
const range = rangeFromVersions(project.strapiVersion, target);
|
|
1145
1145
|
const npmVersionsMatches = npmPackage.findVersionsInRange(range);
|
|
1146
|
-
|
|
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;
|
|
1147
1151
|
}
|
|
1148
|
-
|
|
1152
|
+
throw new NPMCandidateNotFoundError(target);
|
|
1149
1153
|
};
|
|
1150
1154
|
const upgraderFactory = (project, target, npmPackage) => {
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1153
|
-
throw new Error(`Couldn't find a matching version in the NPM registry for "${target}"`);
|
|
1154
|
-
}
|
|
1155
|
-
const semverTarget = semVerFactory(targetedNPMVersion.version);
|
|
1155
|
+
const npmTarget = resolveNPMTarget(project, target, npmPackage);
|
|
1156
|
+
const semverTarget = semVerFactory(npmTarget.version);
|
|
1156
1157
|
if (semver.eq(semverTarget, project.strapiVersion)) {
|
|
1157
|
-
throw new Error(`The project is already
|
|
1158
|
+
throw new Error(`The project is already using v${semverTarget}`);
|
|
1158
1159
|
}
|
|
1159
1160
|
return new Upgrader(project, semverTarget, npmPackage);
|
|
1160
1161
|
};
|
|
@@ -1165,80 +1166,195 @@ const constants = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePro
|
|
|
1165
1166
|
__proto__: null,
|
|
1166
1167
|
STRAPI_PACKAGE_NAME
|
|
1167
1168
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1168
|
-
const index$
|
|
1169
|
+
const index$6 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1169
1170
|
__proto__: null,
|
|
1170
1171
|
constants,
|
|
1171
1172
|
upgraderFactory
|
|
1172
1173
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1173
|
-
|
|
1174
|
-
|
|
1174
|
+
class Requirement {
|
|
1175
|
+
isRequired;
|
|
1175
1176
|
name;
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
constructor(name) {
|
|
1177
|
+
testCallback;
|
|
1178
|
+
children;
|
|
1179
|
+
constructor(name, testCallback, isRequired) {
|
|
1179
1180
|
this.name = name;
|
|
1180
|
-
this.
|
|
1181
|
-
this.
|
|
1181
|
+
this.testCallback = testCallback;
|
|
1182
|
+
this.isRequired = isRequired ?? true;
|
|
1183
|
+
this.children = [];
|
|
1182
1184
|
}
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
+
setChildren(children) {
|
|
1186
|
+
this.children = children;
|
|
1187
|
+
return this;
|
|
1185
1188
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
1189
|
+
addChild(child) {
|
|
1190
|
+
this.children.push(child);
|
|
1191
|
+
return this;
|
|
1188
1192
|
}
|
|
1189
|
-
|
|
1190
|
-
this.
|
|
1191
|
-
|
|
1193
|
+
asOptional() {
|
|
1194
|
+
const newInstance = requirementFactory(this.name, this.testCallback, false);
|
|
1195
|
+
newInstance.setChildren(this.children);
|
|
1196
|
+
return newInstance;
|
|
1192
1197
|
}
|
|
1193
|
-
|
|
1194
|
-
this.
|
|
1195
|
-
|
|
1198
|
+
asRequired() {
|
|
1199
|
+
const newInstance = requirementFactory(this.name, this.testCallback, true);
|
|
1200
|
+
newInstance.setChildren(this.children);
|
|
1201
|
+
return newInstance;
|
|
1196
1202
|
}
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
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
|
+
}
|
|
1200
1216
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
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
|
+
}
|
|
1204
1234
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
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
|
+
}
|
|
1210
1251
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
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
|
+
}
|
|
1213
1263
|
}
|
|
1214
|
-
|
|
1215
|
-
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
|
+
};
|
|
1216
1319
|
const upgrade = async (options) => {
|
|
1217
1320
|
const timer = timerFactory();
|
|
1218
1321
|
const { logger, codemodsTarget } = options;
|
|
1219
1322
|
const cwd = path$1.resolve(options.cwd ?? process.cwd());
|
|
1220
1323
|
const project = projectFactory(cwd);
|
|
1324
|
+
logger.debug(projectDetails(project));
|
|
1221
1325
|
if (!isApplicationProject(project)) {
|
|
1222
1326
|
throw new Error(
|
|
1223
1327
|
`The "${options.target}" upgrade can only be run on a Strapi project; for plugins, please use "codemods".`
|
|
1224
1328
|
);
|
|
1225
1329
|
}
|
|
1330
|
+
logger.debug(
|
|
1331
|
+
`Application: VERSION=${version(project.packageJSON.version)}; STRAPI_VERSION=${version(project.strapiVersion)}`
|
|
1332
|
+
);
|
|
1226
1333
|
const npmPackage = npmPackageFactory(STRAPI_PACKAGE_NAME);
|
|
1227
1334
|
await npmPackage.refresh();
|
|
1228
1335
|
const upgrader = upgraderFactory(project, options.target, npmPackage).dry(options.dry ?? false).onConfirm(options.confirm ?? null).setLogger(logger);
|
|
1229
1336
|
if (codemodsTarget !== void 0) {
|
|
1230
1337
|
upgrader.overrideCodemodsTarget(codemodsTarget);
|
|
1231
1338
|
}
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
}
|
|
1235
|
-
upgrader.addRequirement(REQUIRE_GIT.asOptional());
|
|
1339
|
+
await runUpgradePrompts(upgrader, options);
|
|
1340
|
+
addUpgradeRequirements(upgrader, options);
|
|
1236
1341
|
const upgradeReport = await upgrader.upgrade();
|
|
1237
1342
|
if (!upgradeReport.success) {
|
|
1238
1343
|
throw upgradeReport.error;
|
|
1239
1344
|
}
|
|
1240
1345
|
timer.stop();
|
|
1241
|
-
logger.info(`Completed in ${durationMs(timer.elapsedMs)}`);
|
|
1346
|
+
logger.info(`Completed in ${durationMs(timer.elapsedMs)}ms`);
|
|
1347
|
+
};
|
|
1348
|
+
const runUpgradePrompts = async (upgrader, options) => {
|
|
1349
|
+
if (options.target === ReleaseType.Latest) {
|
|
1350
|
+
await latest(upgrader, options);
|
|
1351
|
+
}
|
|
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());
|
|
1242
1358
|
};
|
|
1243
1359
|
const resolvePath = (cwd) => path$1.resolve(cwd ?? process.cwd());
|
|
1244
1360
|
const getRangeFromTarget = (currentVersion, target) => {
|
|
@@ -1247,6 +1363,8 @@ const getRangeFromTarget = (currentVersion, target) => {
|
|
|
1247
1363
|
}
|
|
1248
1364
|
const { major, minor, patch } = currentVersion;
|
|
1249
1365
|
switch (target) {
|
|
1366
|
+
case ReleaseType.Latest:
|
|
1367
|
+
throw new Error("Can't use <latest> to create a codemods range: not implemented");
|
|
1250
1368
|
case ReleaseType.Major:
|
|
1251
1369
|
return rangeFactory(`${major}`);
|
|
1252
1370
|
case ReleaseType.Minor:
|
|
@@ -1272,7 +1390,7 @@ const runCodemods = async (options) => {
|
|
|
1272
1390
|
const cwd = resolvePath(options.cwd);
|
|
1273
1391
|
const project = projectFactory(cwd);
|
|
1274
1392
|
const range = findRangeFromTarget(project, options.target);
|
|
1275
|
-
logger.debug(
|
|
1393
|
+
logger.debug(projectDetails(project));
|
|
1276
1394
|
logger.debug(`Range: set to ${versionRange(range)}`);
|
|
1277
1395
|
const codemodRunner = codemodRunnerFactory(project, range).dry(options.dry ?? false).onSelectCodemods(options.selectCodemods ?? null).setLogger(logger);
|
|
1278
1396
|
let report;
|
|
@@ -1293,7 +1411,7 @@ const listCodemods = async (options) => {
|
|
|
1293
1411
|
const cwd = resolvePath(options.cwd);
|
|
1294
1412
|
const project = projectFactory(cwd);
|
|
1295
1413
|
const range = findRangeFromTarget(project, target);
|
|
1296
|
-
logger.debug(
|
|
1414
|
+
logger.debug(projectDetails(project));
|
|
1297
1415
|
logger.debug(`Range: set to ${versionRange(range)}`);
|
|
1298
1416
|
const repo = codemodRepositoryFactory();
|
|
1299
1417
|
repo.refresh();
|
|
@@ -1404,18 +1522,18 @@ const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
1404
1522
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1405
1523
|
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1406
1524
|
__proto__: null,
|
|
1407
|
-
codemod: index$
|
|
1408
|
-
codemodRepository: index$
|
|
1525
|
+
codemod: index$8,
|
|
1526
|
+
codemodRepository: index$7,
|
|
1409
1527
|
error: index$9,
|
|
1410
|
-
f: index$
|
|
1528
|
+
f: index$f,
|
|
1411
1529
|
fileScanner: index$d,
|
|
1412
1530
|
logger: index$3,
|
|
1413
1531
|
project: index$a,
|
|
1414
1532
|
report: index$2,
|
|
1415
|
-
requirement: index$
|
|
1533
|
+
requirement: index$5,
|
|
1416
1534
|
runner: index$1,
|
|
1417
|
-
timer: index$
|
|
1418
|
-
upgrader: index$
|
|
1535
|
+
timer: index$g,
|
|
1536
|
+
upgrader: index$6,
|
|
1419
1537
|
version: index$e
|
|
1420
1538
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1421
1539
|
export {
|