@strapi/upgrade 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813 → 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 +444 -318
- package/dist/cli.js.map +1 -1
- package/dist/index.js +467 -344
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +463 -341
- 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/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 +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 +8 -8
- 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/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/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/cli.js
CHANGED
|
@@ -5,25 +5,26 @@ const commander = require("commander");
|
|
|
5
5
|
const prompts = require("prompts");
|
|
6
6
|
const semver = require("semver");
|
|
7
7
|
const path$1 = require("node:path");
|
|
8
|
-
const
|
|
9
|
-
const utils = require("@strapi/utils");
|
|
10
|
-
const fp = require("lodash/fp");
|
|
11
|
-
const fse = require("fs-extra");
|
|
8
|
+
const CliTable3 = require("cli-table3");
|
|
12
9
|
const assert = require("node:assert");
|
|
13
|
-
const
|
|
10
|
+
const fse = require("fs-extra");
|
|
11
|
+
const fastglob = require("fast-glob");
|
|
14
12
|
const Runner = require("jscodeshift/src/Runner");
|
|
13
|
+
const fp = require("lodash/fp");
|
|
15
14
|
const node = require("esbuild-register/dist/node");
|
|
16
|
-
const
|
|
15
|
+
const utils = require("@strapi/utils");
|
|
16
|
+
const simpleGit = require("simple-git");
|
|
17
17
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
18
18
|
const os__default = /* @__PURE__ */ _interopDefault(os);
|
|
19
19
|
const chalk__default = /* @__PURE__ */ _interopDefault(chalk);
|
|
20
20
|
const prompts__default = /* @__PURE__ */ _interopDefault(prompts);
|
|
21
21
|
const semver__default = /* @__PURE__ */ _interopDefault(semver);
|
|
22
22
|
const path__default = /* @__PURE__ */ _interopDefault(path$1);
|
|
23
|
-
const simpleGit__default = /* @__PURE__ */ _interopDefault(simpleGit);
|
|
24
|
-
const fse__default = /* @__PURE__ */ _interopDefault(fse);
|
|
25
|
-
const assert__default = /* @__PURE__ */ _interopDefault(assert);
|
|
26
23
|
const CliTable3__default = /* @__PURE__ */ _interopDefault(CliTable3);
|
|
24
|
+
const assert__default = /* @__PURE__ */ _interopDefault(assert);
|
|
25
|
+
const fse__default = /* @__PURE__ */ _interopDefault(fse);
|
|
26
|
+
const fastglob__default = /* @__PURE__ */ _interopDefault(fastglob);
|
|
27
|
+
const simpleGit__default = /* @__PURE__ */ _interopDefault(simpleGit);
|
|
27
28
|
class Logger {
|
|
28
29
|
isDebug;
|
|
29
30
|
isSilent;
|
|
@@ -98,6 +99,7 @@ var ReleaseType = /* @__PURE__ */ ((ReleaseType2) => {
|
|
|
98
99
|
ReleaseType2["Major"] = "major";
|
|
99
100
|
ReleaseType2["Minor"] = "minor";
|
|
100
101
|
ReleaseType2["Patch"] = "patch";
|
|
102
|
+
ReleaseType2["Latest"] = "latest";
|
|
101
103
|
return ReleaseType2;
|
|
102
104
|
})(ReleaseType || {});
|
|
103
105
|
const semVerFactory = (version2) => {
|
|
@@ -119,17 +121,20 @@ const rangeFactory = (range) => {
|
|
|
119
121
|
};
|
|
120
122
|
const rangeFromReleaseType = (current, identifier) => {
|
|
121
123
|
switch (identifier) {
|
|
122
|
-
case ReleaseType.
|
|
123
|
-
|
|
124
|
-
return rangeFactory(`>${current.raw} <=${nextMajor}`);
|
|
124
|
+
case ReleaseType.Latest: {
|
|
125
|
+
return rangeFactory(`>${current.raw}`);
|
|
125
126
|
}
|
|
126
|
-
case ReleaseType.
|
|
127
|
-
const
|
|
128
|
-
return rangeFactory(`>${current.raw}
|
|
127
|
+
case ReleaseType.Major: {
|
|
128
|
+
const nextMajor = semVerFactory(current.raw).inc("major");
|
|
129
|
+
return rangeFactory(`>${current.raw} <=${nextMajor.major}`);
|
|
129
130
|
}
|
|
130
131
|
case ReleaseType.Minor: {
|
|
131
|
-
const
|
|
132
|
-
return rangeFactory(`>${current.raw} <${
|
|
132
|
+
const nextMajor = semVerFactory(current.raw).inc("major");
|
|
133
|
+
return rangeFactory(`>${current.raw} <${nextMajor.raw}`);
|
|
134
|
+
}
|
|
135
|
+
case ReleaseType.Patch: {
|
|
136
|
+
const nextMinor = semVerFactory(current.raw).inc("minor");
|
|
137
|
+
return rangeFactory(`>${current.raw} <${nextMinor.raw}`);
|
|
133
138
|
}
|
|
134
139
|
default: {
|
|
135
140
|
throw new Error("Not implemented");
|
|
@@ -149,7 +154,36 @@ const isValidStringifiedRange = (str) => semver__default.default.validRange(str)
|
|
|
149
154
|
const isRangeInstance = (range) => {
|
|
150
155
|
return range instanceof semver__default.default.Range;
|
|
151
156
|
};
|
|
157
|
+
class UnexpectedError extends Error {
|
|
158
|
+
constructor() {
|
|
159
|
+
super("Unexpected Error");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
class NPMCandidateNotFoundError extends Error {
|
|
163
|
+
target;
|
|
164
|
+
constructor(target, message = `Couldn't find a valid NPM candidate for "${target}"`) {
|
|
165
|
+
super(message);
|
|
166
|
+
this.target = target;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
class AbortedError extends Error {
|
|
170
|
+
constructor(message = "Upgrade aborted") {
|
|
171
|
+
super(message);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const unknownToError = (e) => {
|
|
175
|
+
if (e instanceof Error) {
|
|
176
|
+
return e;
|
|
177
|
+
}
|
|
178
|
+
if (typeof e === "string") {
|
|
179
|
+
return new Error(e);
|
|
180
|
+
}
|
|
181
|
+
return new UnexpectedError();
|
|
182
|
+
};
|
|
152
183
|
const handleError = (err, isSilent) => {
|
|
184
|
+
if (err instanceof AbortedError) {
|
|
185
|
+
process.exit(0);
|
|
186
|
+
}
|
|
153
187
|
if (!isSilent) {
|
|
154
188
|
console.error(
|
|
155
189
|
chalk__default.default.red(`[ERROR] [${(/* @__PURE__ */ new Date()).toISOString()}]`),
|
|
@@ -158,115 +192,6 @@ const handleError = (err, isSilent) => {
|
|
|
158
192
|
}
|
|
159
193
|
process.exit(1);
|
|
160
194
|
};
|
|
161
|
-
class Requirement {
|
|
162
|
-
isRequired;
|
|
163
|
-
name;
|
|
164
|
-
testCallback;
|
|
165
|
-
children;
|
|
166
|
-
constructor(name, testCallback, isRequired) {
|
|
167
|
-
this.name = name;
|
|
168
|
-
this.testCallback = testCallback;
|
|
169
|
-
this.isRequired = isRequired ?? true;
|
|
170
|
-
this.children = [];
|
|
171
|
-
}
|
|
172
|
-
setChildren(children) {
|
|
173
|
-
this.children = children;
|
|
174
|
-
return this;
|
|
175
|
-
}
|
|
176
|
-
addChild(child) {
|
|
177
|
-
this.children.push(child);
|
|
178
|
-
return this;
|
|
179
|
-
}
|
|
180
|
-
asOptional() {
|
|
181
|
-
const newInstance = requirementFactory(this.name, this.testCallback, false);
|
|
182
|
-
newInstance.setChildren(this.children);
|
|
183
|
-
return newInstance;
|
|
184
|
-
}
|
|
185
|
-
asRequired() {
|
|
186
|
-
const newInstance = requirementFactory(this.name, this.testCallback, true);
|
|
187
|
-
newInstance.setChildren(this.children);
|
|
188
|
-
return newInstance;
|
|
189
|
-
}
|
|
190
|
-
async test(context) {
|
|
191
|
-
try {
|
|
192
|
-
await this.testCallback?.(context);
|
|
193
|
-
return ok();
|
|
194
|
-
} catch (e) {
|
|
195
|
-
if (e instanceof Error) {
|
|
196
|
-
return errored(e);
|
|
197
|
-
}
|
|
198
|
-
if (typeof e === "string") {
|
|
199
|
-
return errored(new Error(e));
|
|
200
|
-
}
|
|
201
|
-
return errored(new Error("Unknown error"));
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
const ok = () => ({ pass: true, error: null });
|
|
206
|
-
const errored = (error) => ({ pass: false, error });
|
|
207
|
-
const requirementFactory = (name, testCallback, isRequired) => new Requirement(name, testCallback, isRequired);
|
|
208
|
-
const REQUIRE_AVAILABLE_NEXT_MAJOR = requirementFactory(
|
|
209
|
-
"REQUIRE_AVAILABLE_NEXT_MAJOR",
|
|
210
|
-
(context) => {
|
|
211
|
-
const { project, target } = context;
|
|
212
|
-
const currentMajor = project.strapiVersion.major;
|
|
213
|
-
const targetedMajor = target.major;
|
|
214
|
-
if (targetedMajor === currentMajor) {
|
|
215
|
-
throw new Error(`You're already on the latest major version (v${currentMajor})`);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
);
|
|
219
|
-
const REQUIRE_LATEST_FOR_CURRENT_MAJOR = requirementFactory(
|
|
220
|
-
"REQUIRE_LATEST_FOR_CURRENT_MAJOR",
|
|
221
|
-
(context) => {
|
|
222
|
-
const { project, target, npmVersionsMatches } = context;
|
|
223
|
-
if (npmVersionsMatches.length !== 1) {
|
|
224
|
-
const invalidVersions = npmVersionsMatches.slice(0, -1);
|
|
225
|
-
const invalidVersionsAsSemVer = invalidVersions.map((v) => v.version);
|
|
226
|
-
const nbInvalidVersions = npmVersionsMatches.length;
|
|
227
|
-
const currentMajor = project.strapiVersion.major;
|
|
228
|
-
throw new Error(
|
|
229
|
-
`Doing a major upgrade requires to be on the latest v${currentMajor} version, but found ${nbInvalidVersions} versions between the current one and ${target}: ${invalidVersionsAsSemVer}`
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
);
|
|
234
|
-
const REQUIRE_GIT_CLEAN_REPOSITORY = requirementFactory(
|
|
235
|
-
"REQUIRE_GIT_CLEAN_REPOSITORY",
|
|
236
|
-
async (context) => {
|
|
237
|
-
const git = simpleGit__default.default({ baseDir: context.project.cwd });
|
|
238
|
-
const status = await git.status();
|
|
239
|
-
if (!status.isClean()) {
|
|
240
|
-
throw new Error(
|
|
241
|
-
"Repository is not clean. Please commit or stash any changes before upgrading"
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
);
|
|
246
|
-
const REQUIRE_GIT_REPOSITORY = requirementFactory(
|
|
247
|
-
"REQUIRE_GIT_REPOSITORY",
|
|
248
|
-
async (context) => {
|
|
249
|
-
const git = simpleGit__default.default({ baseDir: context.project.cwd });
|
|
250
|
-
const isRepo = await git.checkIsRepo();
|
|
251
|
-
if (!isRepo) {
|
|
252
|
-
throw new Error("Not a git repository (or any of the parent directories)");
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
).addChild(REQUIRE_GIT_CLEAN_REPOSITORY.asOptional());
|
|
256
|
-
const REQUIRE_GIT_INSTALLED = requirementFactory(
|
|
257
|
-
"REQUIRE_GIT_INSTALLED",
|
|
258
|
-
async (context) => {
|
|
259
|
-
const git = simpleGit__default.default({ baseDir: context.project.cwd });
|
|
260
|
-
try {
|
|
261
|
-
await git.version();
|
|
262
|
-
} catch {
|
|
263
|
-
throw new Error("Git is not installed");
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
).addChild(REQUIRE_GIT_REPOSITORY.asOptional());
|
|
267
|
-
const REQUIRE_GIT = requirementFactory("REQUIRE_GIT", null).addChild(
|
|
268
|
-
REQUIRE_GIT_INSTALLED.asOptional()
|
|
269
|
-
);
|
|
270
195
|
class Timer {
|
|
271
196
|
interval;
|
|
272
197
|
constructor() {
|
|
@@ -293,53 +218,126 @@ class Timer {
|
|
|
293
218
|
}
|
|
294
219
|
const timerFactory = () => new Timer();
|
|
295
220
|
const ONE_SECOND_MS = 1e3;
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
221
|
+
const path = (path2) => chalk__default.default.blue(path2);
|
|
222
|
+
const version$1 = (version2) => {
|
|
223
|
+
return chalk__default.default.italic.yellow(`v${version2}`);
|
|
224
|
+
};
|
|
225
|
+
const codemodUID = (uid) => {
|
|
226
|
+
return chalk__default.default.bold.cyan(uid);
|
|
227
|
+
};
|
|
228
|
+
const projectDetails = (project) => {
|
|
229
|
+
return `Project: TYPE=${projectType(project.type)}; CWD=${path(project.cwd)}; PATHS=${project.paths.map(path)}`;
|
|
230
|
+
};
|
|
231
|
+
const projectType = (type) => chalk__default.default.cyan(type);
|
|
232
|
+
const versionRange = (range) => chalk__default.default.italic.yellow(range.raw);
|
|
233
|
+
const highlight = (arg) => chalk__default.default.bold.underline(arg);
|
|
234
|
+
const upgradeStep = (text, step) => {
|
|
235
|
+
return chalk__default.default.bold(`(${step[0]}/${step[1]}) ${text}...`);
|
|
236
|
+
};
|
|
237
|
+
const reports = (reports2) => {
|
|
238
|
+
const rows = reports2.map(({ codemod, report }, i) => {
|
|
239
|
+
const fIndex = chalk__default.default.grey(i);
|
|
240
|
+
const fVersion = chalk__default.default.magenta(codemod.version);
|
|
241
|
+
const fKind = chalk__default.default.yellow(codemod.kind);
|
|
242
|
+
const fFormattedTransformPath = chalk__default.default.cyan(codemod.format());
|
|
243
|
+
const fTimeElapsed = i === 0 ? `${report.timeElapsed}s ${chalk__default.default.dim.italic("(cold start)")}` : `${report.timeElapsed}s`;
|
|
244
|
+
const fAffected = report.ok > 0 ? chalk__default.default.green(report.ok) : chalk__default.default.grey(0);
|
|
245
|
+
const fUnchanged = report.ok === 0 ? chalk__default.default.red(report.nochange) : chalk__default.default.grey(report.nochange);
|
|
246
|
+
return [fIndex, fVersion, fKind, fFormattedTransformPath, fAffected, fUnchanged, fTimeElapsed];
|
|
247
|
+
});
|
|
248
|
+
const table = new CliTable3__default.default({
|
|
249
|
+
style: { compact: true },
|
|
250
|
+
head: [
|
|
251
|
+
chalk__default.default.bold.grey("N°"),
|
|
252
|
+
chalk__default.default.bold.magenta("Version"),
|
|
253
|
+
chalk__default.default.bold.yellow("Kind"),
|
|
254
|
+
chalk__default.default.bold.cyan("Name"),
|
|
255
|
+
chalk__default.default.bold.green("Affected"),
|
|
256
|
+
chalk__default.default.bold.red("Unchanged"),
|
|
257
|
+
chalk__default.default.bold.blue("Duration")
|
|
258
|
+
]
|
|
259
|
+
});
|
|
260
|
+
table.push(...rows);
|
|
261
|
+
return table.toString();
|
|
262
|
+
};
|
|
263
|
+
const codemodList = (codemods) => {
|
|
264
|
+
const rows = codemods.map((codemod, index) => {
|
|
265
|
+
const fIndex = chalk__default.default.grey(index);
|
|
266
|
+
const fVersion = chalk__default.default.magenta(codemod.version);
|
|
267
|
+
const fKind = chalk__default.default.yellow(codemod.kind);
|
|
268
|
+
const fName = chalk__default.default.blue(codemod.format());
|
|
269
|
+
const fUID = codemodUID(codemod.uid);
|
|
270
|
+
return [fIndex, fVersion, fKind, fName, fUID];
|
|
271
|
+
});
|
|
272
|
+
const table = new CliTable3__default.default({
|
|
273
|
+
style: { compact: true },
|
|
274
|
+
head: [
|
|
275
|
+
chalk__default.default.bold.grey("N°"),
|
|
276
|
+
chalk__default.default.bold.magenta("Version"),
|
|
277
|
+
chalk__default.default.bold.yellow("Kind"),
|
|
278
|
+
chalk__default.default.bold.blue("Name"),
|
|
279
|
+
chalk__default.default.bold.cyan("UID")
|
|
280
|
+
]
|
|
281
|
+
});
|
|
282
|
+
table.push(...rows);
|
|
283
|
+
return table.toString();
|
|
284
|
+
};
|
|
285
|
+
const durationMs = (elapsedMs) => {
|
|
286
|
+
const elapsedSeconds = (elapsedMs / ONE_SECOND_MS).toFixed(3);
|
|
287
|
+
return `${elapsedSeconds}s`;
|
|
288
|
+
};
|
|
289
|
+
const NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
290
|
+
class Package {
|
|
291
|
+
name;
|
|
292
|
+
packageURL;
|
|
293
|
+
npmPackage;
|
|
294
|
+
constructor(name) {
|
|
295
|
+
this.name = name;
|
|
296
|
+
this.packageURL = `${NPM_REGISTRY_URL}/${name}`;
|
|
297
|
+
this.npmPackage = null;
|
|
300
298
|
}
|
|
301
|
-
get(
|
|
302
|
-
|
|
303
|
-
return this.root();
|
|
304
|
-
}
|
|
305
|
-
return fp.cloneDeep(fp.get(path2, this.json) ?? defaultValue);
|
|
299
|
+
get isLoaded() {
|
|
300
|
+
return this.npmPackage !== null;
|
|
306
301
|
}
|
|
307
|
-
|
|
308
|
-
|
|
302
|
+
assertPackageIsLoaded(npmPackage) {
|
|
303
|
+
assert__default.default(this.isLoaded, "The package is not loaded yet");
|
|
309
304
|
}
|
|
310
|
-
|
|
311
|
-
this.
|
|
312
|
-
return this;
|
|
305
|
+
getVersionsDict() {
|
|
306
|
+
this.assertPackageIsLoaded(this.npmPackage);
|
|
307
|
+
return this.npmPackage.versions;
|
|
313
308
|
}
|
|
314
|
-
|
|
315
|
-
|
|
309
|
+
getVersionsAsList() {
|
|
310
|
+
this.assertPackageIsLoaded(this.npmPackage);
|
|
311
|
+
return Object.values(this.npmPackage.versions);
|
|
316
312
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
return
|
|
313
|
+
findVersionsInRange(range) {
|
|
314
|
+
const versions = this.getVersionsAsList();
|
|
315
|
+
return versions.filter((v) => range.test(v.version)).filter((v) => isLiteralSemVer(v.version)).sort((v1, v2) => semver__default.default.compare(v1.version, v2.version));
|
|
320
316
|
}
|
|
321
|
-
|
|
322
|
-
|
|
317
|
+
findVersion(version2) {
|
|
318
|
+
const versions = this.getVersionsAsList();
|
|
319
|
+
return versions.find((npmVersion) => semver__default.default.eq(npmVersion.version, version2));
|
|
320
|
+
}
|
|
321
|
+
async refresh() {
|
|
322
|
+
const response = await fetch(this.packageURL);
|
|
323
|
+
assert__default.default(response.ok, `Request failed for ${this.packageURL}`);
|
|
324
|
+
this.npmPackage = await response.json();
|
|
323
325
|
return this;
|
|
324
326
|
}
|
|
327
|
+
versionExists(version2) {
|
|
328
|
+
return this.findVersion(version2) !== void 0;
|
|
329
|
+
}
|
|
325
330
|
}
|
|
326
|
-
const
|
|
327
|
-
const readJSON = async (path2) => {
|
|
328
|
-
const buffer = await fse__default.default.readFile(path2);
|
|
329
|
-
return JSON.parse(buffer.toString());
|
|
330
|
-
};
|
|
331
|
-
const saveJSON = async (path2, json) => {
|
|
332
|
-
const jsonAsString = `${JSON.stringify(json, null, 2)}
|
|
333
|
-
`;
|
|
334
|
-
await fse__default.default.writeFile(path2, jsonAsString);
|
|
335
|
-
};
|
|
331
|
+
const npmPackageFactory = (name) => new Package(name);
|
|
336
332
|
class FileScanner {
|
|
337
333
|
cwd;
|
|
338
334
|
constructor(cwd) {
|
|
339
335
|
this.cwd = cwd;
|
|
340
336
|
}
|
|
341
337
|
scan(patterns) {
|
|
342
|
-
const filenames =
|
|
338
|
+
const filenames = fastglob__default.default.sync(patterns, {
|
|
339
|
+
cwd: this.cwd
|
|
340
|
+
});
|
|
343
341
|
return filenames.map((filename) => path__default.default.join(this.cwd, filename));
|
|
344
342
|
}
|
|
345
343
|
}
|
|
@@ -369,6 +367,46 @@ class CodeRunner extends AbstractRunner {
|
|
|
369
367
|
const codeRunnerFactory = (paths, configuration) => {
|
|
370
368
|
return new CodeRunner(paths, configuration);
|
|
371
369
|
};
|
|
370
|
+
class JSONTransformAPI {
|
|
371
|
+
json;
|
|
372
|
+
constructor(json) {
|
|
373
|
+
this.json = fp.cloneDeep(json);
|
|
374
|
+
}
|
|
375
|
+
get(path2, defaultValue) {
|
|
376
|
+
if (!path2) {
|
|
377
|
+
return this.root();
|
|
378
|
+
}
|
|
379
|
+
return fp.cloneDeep(fp.get(path2, this.json) ?? defaultValue);
|
|
380
|
+
}
|
|
381
|
+
has(path2) {
|
|
382
|
+
return fp.has(path2, this.json);
|
|
383
|
+
}
|
|
384
|
+
merge(other) {
|
|
385
|
+
this.json = fp.merge(other, this.json);
|
|
386
|
+
return this;
|
|
387
|
+
}
|
|
388
|
+
root() {
|
|
389
|
+
return fp.cloneDeep(this.json);
|
|
390
|
+
}
|
|
391
|
+
set(path2, value) {
|
|
392
|
+
this.json = fp.set(path2, value, this.json);
|
|
393
|
+
return this;
|
|
394
|
+
}
|
|
395
|
+
remove(path2) {
|
|
396
|
+
this.json = fp.omit(path2, this.json);
|
|
397
|
+
return this;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
const createJSONTransformAPI = (object) => new JSONTransformAPI(object);
|
|
401
|
+
const readJSON = async (path2) => {
|
|
402
|
+
const buffer = await fse__default.default.readFile(path2);
|
|
403
|
+
return JSON.parse(buffer.toString());
|
|
404
|
+
};
|
|
405
|
+
const saveJSON = async (path2, json) => {
|
|
406
|
+
const jsonAsString = `${JSON.stringify(json, null, 2)}
|
|
407
|
+
`;
|
|
408
|
+
await fse__default.default.writeFile(path2, jsonAsString);
|
|
409
|
+
};
|
|
372
410
|
const transformJSON = async (codemodPath, paths, config) => {
|
|
373
411
|
const { dry } = config;
|
|
374
412
|
const startTime = process.hrtime();
|
|
@@ -380,7 +418,11 @@ const transformJSON = async (codemodPath, paths, config) => {
|
|
|
380
418
|
timeElapsed: "",
|
|
381
419
|
stats: {}
|
|
382
420
|
};
|
|
383
|
-
const esbuildOptions = {
|
|
421
|
+
const esbuildOptions = {
|
|
422
|
+
extensions: [".js", ".mjs", ".ts"],
|
|
423
|
+
hookIgnoreNodeModules: false,
|
|
424
|
+
hookMatcher: fp.isEqual(codemodPath)
|
|
425
|
+
};
|
|
384
426
|
const { unregister } = node.register(esbuildOptions);
|
|
385
427
|
const module = require(codemodPath);
|
|
386
428
|
unregister();
|
|
@@ -421,8 +463,10 @@ const jsonRunnerFactory = (paths, configuration) => {
|
|
|
421
463
|
return new JSONRunner(paths, configuration);
|
|
422
464
|
};
|
|
423
465
|
const PROJECT_PACKAGE_JSON = "package.json";
|
|
424
|
-
const
|
|
425
|
-
const
|
|
466
|
+
const PROJECT_APP_ALLOWED_ROOT_PATHS = ["src", "config", "public"];
|
|
467
|
+
const PROJECT_PLUGIN_ALLOWED_ROOT_PATHS = ["admin", "server"];
|
|
468
|
+
const PROJECT_PLUGIN_ROOT_FILES = ["strapi-admin.js", "strapi-server.js"];
|
|
469
|
+
const PROJECT_CODE_EXTENSIONS = [
|
|
426
470
|
// Source files
|
|
427
471
|
"js",
|
|
428
472
|
"mjs",
|
|
@@ -431,12 +475,8 @@ const PROJECT_DEFAULT_CODE_EXTENSIONS = [
|
|
|
431
475
|
"jsx",
|
|
432
476
|
"tsx"
|
|
433
477
|
];
|
|
434
|
-
const
|
|
435
|
-
const
|
|
436
|
-
...PROJECT_DEFAULT_CODE_EXTENSIONS,
|
|
437
|
-
...PROJECT_DEFAULT_JSON_EXTENSIONS
|
|
438
|
-
];
|
|
439
|
-
const PROJECT_DEFAULT_PATTERNS = ["package.json"];
|
|
478
|
+
const PROJECT_JSON_EXTENSIONS = ["json"];
|
|
479
|
+
const PROJECT_ALLOWED_EXTENSIONS = [...PROJECT_CODE_EXTENSIONS, ...PROJECT_JSON_EXTENSIONS];
|
|
440
480
|
const SCOPED_STRAPI_PACKAGE_PREFIX = "@strapi/";
|
|
441
481
|
const STRAPI_DEPENDENCY_NAME = `${SCOPED_STRAPI_PACKAGE_PREFIX}strapi`;
|
|
442
482
|
class Project {
|
|
@@ -445,11 +485,13 @@ class Project {
|
|
|
445
485
|
files;
|
|
446
486
|
packageJSONPath;
|
|
447
487
|
packageJSON;
|
|
448
|
-
|
|
488
|
+
paths;
|
|
489
|
+
constructor(cwd, config) {
|
|
449
490
|
if (!fse__default.default.pathExistsSync(cwd)) {
|
|
450
491
|
throw new Error(`ENOENT: no such file or directory, access '${cwd}'`);
|
|
451
492
|
}
|
|
452
493
|
this.cwd = cwd;
|
|
494
|
+
this.paths = config.paths;
|
|
453
495
|
this.refresh();
|
|
454
496
|
}
|
|
455
497
|
getFilesByExtensions(extensions) {
|
|
@@ -477,12 +519,8 @@ class Project {
|
|
|
477
519
|
return reports2;
|
|
478
520
|
}
|
|
479
521
|
createProjectCodemodsRunners(dry = false) {
|
|
480
|
-
const jsonExtensions =
|
|
481
|
-
|
|
482
|
-
);
|
|
483
|
-
const codeExtensions = PROJECT_DEFAULT_CODE_EXTENSIONS.map(
|
|
484
|
-
(ext) => `.${ext}`
|
|
485
|
-
);
|
|
522
|
+
const jsonExtensions = PROJECT_JSON_EXTENSIONS.map((ext) => `.${ext}`);
|
|
523
|
+
const codeExtensions = PROJECT_CODE_EXTENSIONS.map((ext) => `.${ext}`);
|
|
486
524
|
const jsonFiles = this.getFilesByExtensions(jsonExtensions);
|
|
487
525
|
const codeFiles = this.getFilesByExtensions(codeExtensions);
|
|
488
526
|
const codeRunner = codeRunnerFactory(codeFiles, {
|
|
@@ -490,7 +528,7 @@ class Project {
|
|
|
490
528
|
parser: "ts",
|
|
491
529
|
runInBand: true,
|
|
492
530
|
babel: true,
|
|
493
|
-
extensions:
|
|
531
|
+
extensions: PROJECT_CODE_EXTENSIONS.join(","),
|
|
494
532
|
// Don't output any log coming from the runner
|
|
495
533
|
print: false,
|
|
496
534
|
silent: true,
|
|
@@ -511,23 +549,32 @@ class Project {
|
|
|
511
549
|
this.packageJSON = JSON.parse(packageJSONBuffer.toString());
|
|
512
550
|
}
|
|
513
551
|
refreshProjectFiles() {
|
|
514
|
-
const allowedRootPaths = formatGlobCollectionPattern(
|
|
515
|
-
PROJECT_DEFAULT_ALLOWED_ROOT_PATHS
|
|
516
|
-
);
|
|
517
|
-
const allowedExtensions = formatGlobCollectionPattern(
|
|
518
|
-
PROJECT_DEFAULT_ALLOWED_EXTENSIONS
|
|
519
|
-
);
|
|
520
|
-
const projectFilesPattern = `./${allowedRootPaths}/**/*.${allowedExtensions}`;
|
|
521
|
-
const patterns = [projectFilesPattern, ...PROJECT_DEFAULT_PATTERNS];
|
|
522
552
|
const scanner = fileScannerFactory(this.cwd);
|
|
523
|
-
this.files = scanner.scan(
|
|
553
|
+
this.files = scanner.scan(this.paths);
|
|
524
554
|
}
|
|
525
555
|
}
|
|
526
556
|
class AppProject extends Project {
|
|
527
557
|
strapiVersion;
|
|
528
558
|
type = "application";
|
|
559
|
+
/**
|
|
560
|
+
* Returns an array of allowed file paths for a Strapi application
|
|
561
|
+
*
|
|
562
|
+
* The resulting paths include app default files and the root package.json file.
|
|
563
|
+
*/
|
|
564
|
+
static get paths() {
|
|
565
|
+
const allowedRootPaths = formatGlobCollectionPattern(PROJECT_APP_ALLOWED_ROOT_PATHS);
|
|
566
|
+
const allowedExtensions = formatGlobCollectionPattern(PROJECT_ALLOWED_EXTENSIONS);
|
|
567
|
+
return [
|
|
568
|
+
// App default files
|
|
569
|
+
`./${allowedRootPaths}/**/*.${allowedExtensions}`,
|
|
570
|
+
`!./**/node_modules/**/*`,
|
|
571
|
+
`!./**/dist/**/*`,
|
|
572
|
+
// Root package.json file
|
|
573
|
+
PROJECT_PACKAGE_JSON
|
|
574
|
+
];
|
|
575
|
+
}
|
|
529
576
|
constructor(cwd) {
|
|
530
|
-
super(cwd);
|
|
577
|
+
super(cwd, { paths: AppProject.paths });
|
|
531
578
|
this.refreshStrapiVersion();
|
|
532
579
|
}
|
|
533
580
|
refresh() {
|
|
@@ -582,6 +629,30 @@ const formatGlobCollectionPattern = (collection) => {
|
|
|
582
629
|
};
|
|
583
630
|
class PluginProject extends Project {
|
|
584
631
|
type = "plugin";
|
|
632
|
+
/**
|
|
633
|
+
* Returns an array of allowed file paths for a Strapi plugin
|
|
634
|
+
*
|
|
635
|
+
* The resulting paths include plugin default files, the root package.json file, and plugin-specific files.
|
|
636
|
+
*/
|
|
637
|
+
static get paths() {
|
|
638
|
+
const allowedRootPaths = formatGlobCollectionPattern(
|
|
639
|
+
PROJECT_PLUGIN_ALLOWED_ROOT_PATHS
|
|
640
|
+
);
|
|
641
|
+
const allowedExtensions = formatGlobCollectionPattern(PROJECT_ALLOWED_EXTENSIONS);
|
|
642
|
+
return [
|
|
643
|
+
// Plugin default files
|
|
644
|
+
`./${allowedRootPaths}/**/*.${allowedExtensions}`,
|
|
645
|
+
`!./**/node_modules/**/*`,
|
|
646
|
+
`!./**/dist/**/*`,
|
|
647
|
+
// Root package.json file
|
|
648
|
+
PROJECT_PACKAGE_JSON,
|
|
649
|
+
// Plugin root files
|
|
650
|
+
...PROJECT_PLUGIN_ROOT_FILES
|
|
651
|
+
];
|
|
652
|
+
}
|
|
653
|
+
constructor(cwd) {
|
|
654
|
+
super(cwd, { paths: PluginProject.paths });
|
|
655
|
+
}
|
|
585
656
|
}
|
|
586
657
|
const isPlugin = (cwd) => {
|
|
587
658
|
const packageJSONPath = path__default.default.join(cwd, PROJECT_PACKAGE_JSON);
|
|
@@ -596,93 +667,11 @@ const isPlugin = (cwd) => {
|
|
|
596
667
|
};
|
|
597
668
|
const projectFactory = (cwd) => {
|
|
598
669
|
fse__default.default.accessSync(cwd);
|
|
599
|
-
|
|
600
|
-
return new PluginProject(cwd);
|
|
601
|
-
}
|
|
602
|
-
return new AppProject(cwd);
|
|
670
|
+
return isPlugin(cwd) ? new PluginProject(cwd) : new AppProject(cwd);
|
|
603
671
|
};
|
|
604
672
|
const isApplicationProject = (project) => {
|
|
605
673
|
return project instanceof AppProject;
|
|
606
674
|
};
|
|
607
|
-
class UnexpectedError extends Error {
|
|
608
|
-
constructor() {
|
|
609
|
-
super("Unexpected Error");
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
const unknownToError = (e) => {
|
|
613
|
-
if (e instanceof Error) {
|
|
614
|
-
return e;
|
|
615
|
-
}
|
|
616
|
-
if (typeof e === "string") {
|
|
617
|
-
return new Error(e);
|
|
618
|
-
}
|
|
619
|
-
return new UnexpectedError();
|
|
620
|
-
};
|
|
621
|
-
const path = (path2) => chalk__default.default.blue(path2);
|
|
622
|
-
const version$1 = (version2) => {
|
|
623
|
-
return chalk__default.default.italic.yellow(`v${version2}`);
|
|
624
|
-
};
|
|
625
|
-
const codemodUID = (uid) => {
|
|
626
|
-
return chalk__default.default.bold.cyan(uid);
|
|
627
|
-
};
|
|
628
|
-
const projectType = (type) => chalk__default.default.cyan(type);
|
|
629
|
-
const versionRange = (range) => chalk__default.default.italic.yellow(range.raw);
|
|
630
|
-
const highlight = (arg) => chalk__default.default.bold.underline(arg);
|
|
631
|
-
const upgradeStep = (text, step) => {
|
|
632
|
-
return chalk__default.default.bold(`(${step[0]}/${step[1]}) ${text}...`);
|
|
633
|
-
};
|
|
634
|
-
const reports = (reports2) => {
|
|
635
|
-
const rows = reports2.map(({ codemod, report }, i) => {
|
|
636
|
-
const fIndex = chalk__default.default.grey(i);
|
|
637
|
-
const fVersion = chalk__default.default.magenta(codemod.version);
|
|
638
|
-
const fKind = chalk__default.default.yellow(codemod.kind);
|
|
639
|
-
const fFormattedTransformPath = chalk__default.default.cyan(codemod.format());
|
|
640
|
-
const fTimeElapsed = i === 0 ? `${report.timeElapsed}s ${chalk__default.default.dim.italic("(cold start)")}` : `${report.timeElapsed}s`;
|
|
641
|
-
const fAffected = report.ok > 0 ? chalk__default.default.green(report.ok) : chalk__default.default.grey(0);
|
|
642
|
-
const fUnchanged = report.ok === 0 ? chalk__default.default.red(report.nochange) : chalk__default.default.grey(report.nochange);
|
|
643
|
-
return [fIndex, fVersion, fKind, fFormattedTransformPath, fAffected, fUnchanged, fTimeElapsed];
|
|
644
|
-
});
|
|
645
|
-
const table = new CliTable3__default.default({
|
|
646
|
-
style: { compact: true },
|
|
647
|
-
head: [
|
|
648
|
-
chalk__default.default.bold.grey("N°"),
|
|
649
|
-
chalk__default.default.bold.magenta("Version"),
|
|
650
|
-
chalk__default.default.bold.yellow("Kind"),
|
|
651
|
-
chalk__default.default.bold.cyan("Name"),
|
|
652
|
-
chalk__default.default.bold.green("Affected"),
|
|
653
|
-
chalk__default.default.bold.red("Unchanged"),
|
|
654
|
-
chalk__default.default.bold.blue("Duration")
|
|
655
|
-
]
|
|
656
|
-
});
|
|
657
|
-
table.push(...rows);
|
|
658
|
-
return table.toString();
|
|
659
|
-
};
|
|
660
|
-
const codemodList = (codemods) => {
|
|
661
|
-
const rows = codemods.map((codemod, index) => {
|
|
662
|
-
const fIndex = chalk__default.default.grey(index);
|
|
663
|
-
const fVersion = chalk__default.default.magenta(codemod.version);
|
|
664
|
-
const fKind = chalk__default.default.yellow(codemod.kind);
|
|
665
|
-
const fName = chalk__default.default.blue(codemod.format());
|
|
666
|
-
const fUID = codemodUID(codemod.uid);
|
|
667
|
-
return [fIndex, fVersion, fKind, fName, fUID];
|
|
668
|
-
});
|
|
669
|
-
const table = new CliTable3__default.default({
|
|
670
|
-
style: { compact: true },
|
|
671
|
-
head: [
|
|
672
|
-
chalk__default.default.bold.grey("N°"),
|
|
673
|
-
chalk__default.default.bold.magenta("Version"),
|
|
674
|
-
chalk__default.default.bold.yellow("Kind"),
|
|
675
|
-
chalk__default.default.bold.blue("Name"),
|
|
676
|
-
chalk__default.default.bold.cyan("UID")
|
|
677
|
-
]
|
|
678
|
-
});
|
|
679
|
-
table.push(...rows);
|
|
680
|
-
return table.toString();
|
|
681
|
-
};
|
|
682
|
-
const durationMs = (elapsedMs) => {
|
|
683
|
-
const elapsedSeconds = (elapsedMs / ONE_SECOND_MS).toFixed(3);
|
|
684
|
-
return `${elapsedSeconds}s`;
|
|
685
|
-
};
|
|
686
675
|
const CODEMOD_CODE_SUFFIX = "code";
|
|
687
676
|
const CODEMOD_JSON_SUFFIX = "json";
|
|
688
677
|
const CODEMOD_ALLOWED_SUFFIXES = [CODEMOD_CODE_SUFFIX, CODEMOD_JSON_SUFFIX];
|
|
@@ -938,6 +927,15 @@ class Upgrader {
|
|
|
938
927
|
this.logger = null;
|
|
939
928
|
this.confirmationCallback = null;
|
|
940
929
|
}
|
|
930
|
+
getNPMPackage() {
|
|
931
|
+
return this.npmPackage;
|
|
932
|
+
}
|
|
933
|
+
getProject() {
|
|
934
|
+
return this.project;
|
|
935
|
+
}
|
|
936
|
+
getTarget() {
|
|
937
|
+
return semVerFactory(this.target.raw);
|
|
938
|
+
}
|
|
941
939
|
setRequirements(requirements) {
|
|
942
940
|
this.requirements = requirements;
|
|
943
941
|
return this;
|
|
@@ -1019,6 +1017,12 @@ class Upgrader {
|
|
|
1019
1017
|
}
|
|
1020
1018
|
return successReport();
|
|
1021
1019
|
}
|
|
1020
|
+
async confirm(message) {
|
|
1021
|
+
if (typeof this.confirmationCallback !== "function") {
|
|
1022
|
+
return true;
|
|
1023
|
+
}
|
|
1024
|
+
return this.confirmationCallback(message);
|
|
1025
|
+
}
|
|
1022
1026
|
async checkRequirements(requirements, context) {
|
|
1023
1027
|
for (const requirement of requirements) {
|
|
1024
1028
|
const { pass, error } = await requirement.test(context);
|
|
@@ -1090,7 +1094,7 @@ class Upgrader {
|
|
|
1090
1094
|
const packageManagerName = await utils.packageManager.getPreferred(projectPath);
|
|
1091
1095
|
this.logger?.debug?.(`Using ${highlight(packageManagerName)} as package manager`);
|
|
1092
1096
|
if (this.isDry) {
|
|
1093
|
-
this.logger?.debug?.(`Skipping dependencies installation (${chalk__default.default.italic("dry mode")}`);
|
|
1097
|
+
this.logger?.debug?.(`Skipping dependencies installation (${chalk__default.default.italic("dry mode")})`);
|
|
1094
1098
|
return;
|
|
1095
1099
|
}
|
|
1096
1100
|
await utils.packageManager.installDependencies(projectPath, packageManagerName, {
|
|
@@ -1109,98 +1113,214 @@ class Upgrader {
|
|
|
1109
1113
|
}
|
|
1110
1114
|
const resolveNPMTarget = (project, target, npmPackage) => {
|
|
1111
1115
|
if (isSemverInstance(target)) {
|
|
1112
|
-
|
|
1116
|
+
const version2 = npmPackage.findVersion(target);
|
|
1117
|
+
if (!version2) {
|
|
1118
|
+
throw new NPMCandidateNotFoundError(target);
|
|
1119
|
+
}
|
|
1120
|
+
return version2;
|
|
1113
1121
|
}
|
|
1114
1122
|
if (isSemVerReleaseType(target)) {
|
|
1115
1123
|
const range = rangeFromVersions(project.strapiVersion, target);
|
|
1116
1124
|
const npmVersionsMatches = npmPackage.findVersionsInRange(range);
|
|
1117
|
-
|
|
1125
|
+
const version2 = npmVersionsMatches.at(-1);
|
|
1126
|
+
if (!version2) {
|
|
1127
|
+
throw new NPMCandidateNotFoundError(range, `The project is already up-to-date (${target})`);
|
|
1128
|
+
}
|
|
1129
|
+
return version2;
|
|
1118
1130
|
}
|
|
1119
|
-
|
|
1131
|
+
throw new NPMCandidateNotFoundError(target);
|
|
1120
1132
|
};
|
|
1121
1133
|
const upgraderFactory = (project, target, npmPackage) => {
|
|
1122
|
-
const
|
|
1123
|
-
|
|
1124
|
-
throw new Error(`Couldn't find a matching version in the NPM registry for "${target}"`);
|
|
1125
|
-
}
|
|
1126
|
-
const semverTarget = semVerFactory(targetedNPMVersion.version);
|
|
1134
|
+
const npmTarget = resolveNPMTarget(project, target, npmPackage);
|
|
1135
|
+
const semverTarget = semVerFactory(npmTarget.version);
|
|
1127
1136
|
if (semver__default.default.eq(semverTarget, project.strapiVersion)) {
|
|
1128
|
-
throw new Error(`The project is already
|
|
1137
|
+
throw new Error(`The project is already using v${semverTarget}`);
|
|
1129
1138
|
}
|
|
1130
1139
|
return new Upgrader(project, semverTarget, npmPackage);
|
|
1131
1140
|
};
|
|
1132
1141
|
const successReport = () => ({ success: true, error: null });
|
|
1133
1142
|
const erroredReport = (error) => ({ success: false, error });
|
|
1134
1143
|
const STRAPI_PACKAGE_NAME = "@strapi/strapi";
|
|
1135
|
-
|
|
1136
|
-
|
|
1144
|
+
class Requirement {
|
|
1145
|
+
isRequired;
|
|
1137
1146
|
name;
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
constructor(name) {
|
|
1147
|
+
testCallback;
|
|
1148
|
+
children;
|
|
1149
|
+
constructor(name, testCallback, isRequired) {
|
|
1141
1150
|
this.name = name;
|
|
1142
|
-
this.
|
|
1143
|
-
this.
|
|
1151
|
+
this.testCallback = testCallback;
|
|
1152
|
+
this.isRequired = isRequired ?? true;
|
|
1153
|
+
this.children = [];
|
|
1144
1154
|
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1155
|
+
setChildren(children) {
|
|
1156
|
+
this.children = children;
|
|
1157
|
+
return this;
|
|
1147
1158
|
}
|
|
1148
|
-
|
|
1149
|
-
|
|
1159
|
+
addChild(child) {
|
|
1160
|
+
this.children.push(child);
|
|
1161
|
+
return this;
|
|
1150
1162
|
}
|
|
1151
|
-
|
|
1152
|
-
this.
|
|
1153
|
-
|
|
1163
|
+
asOptional() {
|
|
1164
|
+
const newInstance = requirementFactory(this.name, this.testCallback, false);
|
|
1165
|
+
newInstance.setChildren(this.children);
|
|
1166
|
+
return newInstance;
|
|
1154
1167
|
}
|
|
1155
|
-
|
|
1156
|
-
this.
|
|
1157
|
-
|
|
1168
|
+
asRequired() {
|
|
1169
|
+
const newInstance = requirementFactory(this.name, this.testCallback, true);
|
|
1170
|
+
newInstance.setChildren(this.children);
|
|
1171
|
+
return newInstance;
|
|
1158
1172
|
}
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1173
|
+
async test(context) {
|
|
1174
|
+
try {
|
|
1175
|
+
await this.testCallback?.(context);
|
|
1176
|
+
return ok();
|
|
1177
|
+
} catch (e) {
|
|
1178
|
+
if (e instanceof Error) {
|
|
1179
|
+
return errored(e);
|
|
1180
|
+
}
|
|
1181
|
+
if (typeof e === "string") {
|
|
1182
|
+
return errored(new Error(e));
|
|
1183
|
+
}
|
|
1184
|
+
return errored(new Error("Unknown error"));
|
|
1185
|
+
}
|
|
1162
1186
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1187
|
+
}
|
|
1188
|
+
const ok = () => ({ pass: true, error: null });
|
|
1189
|
+
const errored = (error) => ({ pass: false, error });
|
|
1190
|
+
const requirementFactory = (name, testCallback, isRequired) => new Requirement(name, testCallback, isRequired);
|
|
1191
|
+
const REQUIRE_AVAILABLE_NEXT_MAJOR = requirementFactory(
|
|
1192
|
+
"REQUIRE_AVAILABLE_NEXT_MAJOR",
|
|
1193
|
+
(context) => {
|
|
1194
|
+
const { project, target } = context;
|
|
1195
|
+
const currentMajor = project.strapiVersion.major;
|
|
1196
|
+
const targetedMajor = target.major;
|
|
1197
|
+
if (targetedMajor === currentMajor) {
|
|
1198
|
+
throw new Error(`You're already on the latest major version (v${currentMajor})`);
|
|
1199
|
+
}
|
|
1166
1200
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1201
|
+
);
|
|
1202
|
+
const REQUIRE_LATEST_FOR_CURRENT_MAJOR = requirementFactory(
|
|
1203
|
+
"REQUIRE_LATEST_FOR_CURRENT_MAJOR",
|
|
1204
|
+
(context) => {
|
|
1205
|
+
const { project, target, npmVersionsMatches } = context;
|
|
1206
|
+
const { major: currentMajor } = project.strapiVersion;
|
|
1207
|
+
const invalidMatches = npmVersionsMatches.filter(
|
|
1208
|
+
(match) => semVerFactory(match.version).major === currentMajor
|
|
1209
|
+
);
|
|
1210
|
+
if (invalidMatches.length > 0) {
|
|
1211
|
+
const invalidVersions = invalidMatches.map((match) => match.version);
|
|
1212
|
+
const invalidVersionsCount = invalidVersions.length;
|
|
1213
|
+
throw new Error(
|
|
1214
|
+
`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.`
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1172
1217
|
}
|
|
1173
|
-
|
|
1174
|
-
|
|
1218
|
+
);
|
|
1219
|
+
const REQUIRE_GIT_CLEAN_REPOSITORY = requirementFactory(
|
|
1220
|
+
"REQUIRE_GIT_CLEAN_REPOSITORY",
|
|
1221
|
+
async (context) => {
|
|
1222
|
+
const git = simpleGit__default.default({ baseDir: context.project.cwd });
|
|
1223
|
+
const status = await git.status();
|
|
1224
|
+
if (!status.isClean()) {
|
|
1225
|
+
throw new Error(
|
|
1226
|
+
"Repository is not clean. Please commit or stash any changes before upgrading"
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1175
1229
|
}
|
|
1176
|
-
|
|
1177
|
-
const
|
|
1230
|
+
);
|
|
1231
|
+
const REQUIRE_GIT_REPOSITORY = requirementFactory(
|
|
1232
|
+
"REQUIRE_GIT_REPOSITORY",
|
|
1233
|
+
async (context) => {
|
|
1234
|
+
const git = simpleGit__default.default({ baseDir: context.project.cwd });
|
|
1235
|
+
const isRepo = await git.checkIsRepo();
|
|
1236
|
+
if (!isRepo) {
|
|
1237
|
+
throw new Error("Not a git repository (or any of the parent directories)");
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
).addChild(REQUIRE_GIT_CLEAN_REPOSITORY.asOptional());
|
|
1241
|
+
const REQUIRE_GIT_INSTALLED = requirementFactory(
|
|
1242
|
+
"REQUIRE_GIT_INSTALLED",
|
|
1243
|
+
async (context) => {
|
|
1244
|
+
const git = simpleGit__default.default({ baseDir: context.project.cwd });
|
|
1245
|
+
try {
|
|
1246
|
+
await git.version();
|
|
1247
|
+
} catch {
|
|
1248
|
+
throw new Error("Git is not installed");
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
).addChild(REQUIRE_GIT_REPOSITORY.asOptional());
|
|
1252
|
+
const REQUIRE_GIT = requirementFactory("REQUIRE_GIT", null).addChild(
|
|
1253
|
+
REQUIRE_GIT_INSTALLED.asOptional()
|
|
1254
|
+
);
|
|
1255
|
+
const latest = async (upgrader, options) => {
|
|
1256
|
+
if (options.target !== ReleaseType.Latest) {
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
const npmPackage = upgrader.getNPMPackage();
|
|
1260
|
+
const target = upgrader.getTarget();
|
|
1261
|
+
const project = upgrader.getProject();
|
|
1262
|
+
const { strapiVersion: current } = project;
|
|
1263
|
+
const fTargetMajor = highlight(`v${target.major}`);
|
|
1264
|
+
const fCurrentMajor = highlight(`v${current.major}`);
|
|
1265
|
+
const fTarget = version$1(target);
|
|
1266
|
+
const fCurrent = version$1(current);
|
|
1267
|
+
const isMajorUpgrade = target.major > current.major;
|
|
1268
|
+
if (isMajorUpgrade) {
|
|
1269
|
+
options.logger.warn(
|
|
1270
|
+
`Detected a major upgrade for the "${highlight(ReleaseType.Latest)}" tag: ${fCurrent} > ${fTarget}`
|
|
1271
|
+
);
|
|
1272
|
+
const newerPackageRelease = npmPackage.findVersionsInRange(rangeFactory(`>${current.raw} <${target.major}`)).at(-1);
|
|
1273
|
+
if (newerPackageRelease) {
|
|
1274
|
+
const fLatest = version$1(semVerFactory(newerPackageRelease.version));
|
|
1275
|
+
options.logger.warn(
|
|
1276
|
+
`It's recommended to first upgrade to the latest version of ${fCurrentMajor} (${fLatest}) before upgrading to ${fTargetMajor}.`
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
const proceedAnyway = await upgrader.confirm(`I know what I'm doing. Proceed anyway!`);
|
|
1280
|
+
if (!proceedAnyway) {
|
|
1281
|
+
throw new AbortedError();
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1178
1285
|
const upgrade$1 = async (options) => {
|
|
1179
1286
|
const timer = timerFactory();
|
|
1180
1287
|
const { logger, codemodsTarget } = options;
|
|
1181
1288
|
const cwd = path__default.default.resolve(options.cwd ?? process.cwd());
|
|
1182
1289
|
const project = projectFactory(cwd);
|
|
1290
|
+
logger.debug(projectDetails(project));
|
|
1183
1291
|
if (!isApplicationProject(project)) {
|
|
1184
1292
|
throw new Error(
|
|
1185
1293
|
`The "${options.target}" upgrade can only be run on a Strapi project; for plugins, please use "codemods".`
|
|
1186
1294
|
);
|
|
1187
1295
|
}
|
|
1296
|
+
logger.debug(
|
|
1297
|
+
`Application: VERSION=${version$1(project.packageJSON.version)}; STRAPI_VERSION=${version$1(project.strapiVersion)}`
|
|
1298
|
+
);
|
|
1188
1299
|
const npmPackage = npmPackageFactory(STRAPI_PACKAGE_NAME);
|
|
1189
1300
|
await npmPackage.refresh();
|
|
1190
1301
|
const upgrader = upgraderFactory(project, options.target, npmPackage).dry(options.dry ?? false).onConfirm(options.confirm ?? null).setLogger(logger);
|
|
1191
1302
|
if (codemodsTarget !== void 0) {
|
|
1192
1303
|
upgrader.overrideCodemodsTarget(codemodsTarget);
|
|
1193
1304
|
}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
}
|
|
1197
|
-
upgrader.addRequirement(REQUIRE_GIT.asOptional());
|
|
1305
|
+
await runUpgradePrompts(upgrader, options);
|
|
1306
|
+
addUpgradeRequirements(upgrader, options);
|
|
1198
1307
|
const upgradeReport = await upgrader.upgrade();
|
|
1199
1308
|
if (!upgradeReport.success) {
|
|
1200
1309
|
throw upgradeReport.error;
|
|
1201
1310
|
}
|
|
1202
1311
|
timer.stop();
|
|
1203
|
-
logger.info(`Completed in ${durationMs(timer.elapsedMs)}`);
|
|
1312
|
+
logger.info(`Completed in ${durationMs(timer.elapsedMs)}ms`);
|
|
1313
|
+
};
|
|
1314
|
+
const runUpgradePrompts = async (upgrader, options) => {
|
|
1315
|
+
if (options.target === ReleaseType.Latest) {
|
|
1316
|
+
await latest(upgrader, options);
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
1319
|
+
const addUpgradeRequirements = (upgrader, options) => {
|
|
1320
|
+
if (options.target === ReleaseType.Major) {
|
|
1321
|
+
upgrader.addRequirement(REQUIRE_AVAILABLE_NEXT_MAJOR).addRequirement(REQUIRE_LATEST_FOR_CURRENT_MAJOR);
|
|
1322
|
+
}
|
|
1323
|
+
upgrader.addRequirement(REQUIRE_GIT.asOptional());
|
|
1204
1324
|
};
|
|
1205
1325
|
const resolvePath = (cwd) => path__default.default.resolve(cwd ?? process.cwd());
|
|
1206
1326
|
const getRangeFromTarget = (currentVersion, target) => {
|
|
@@ -1209,6 +1329,8 @@ const getRangeFromTarget = (currentVersion, target) => {
|
|
|
1209
1329
|
}
|
|
1210
1330
|
const { major, minor, patch } = currentVersion;
|
|
1211
1331
|
switch (target) {
|
|
1332
|
+
case ReleaseType.Latest:
|
|
1333
|
+
throw new Error("Can't use <latest> to create a codemods range: not implemented");
|
|
1212
1334
|
case ReleaseType.Major:
|
|
1213
1335
|
return rangeFactory(`${major}`);
|
|
1214
1336
|
case ReleaseType.Minor:
|
|
@@ -1234,7 +1356,7 @@ const runCodemods$1 = async (options) => {
|
|
|
1234
1356
|
const cwd = resolvePath(options.cwd);
|
|
1235
1357
|
const project = projectFactory(cwd);
|
|
1236
1358
|
const range = findRangeFromTarget(project, options.target);
|
|
1237
|
-
logger.debug(
|
|
1359
|
+
logger.debug(projectDetails(project));
|
|
1238
1360
|
logger.debug(`Range: set to ${versionRange(range)}`);
|
|
1239
1361
|
const codemodRunner = codemodRunnerFactory(project, range).dry(options.dry ?? false).onSelectCodemods(options.selectCodemods ?? null).setLogger(logger);
|
|
1240
1362
|
let report;
|
|
@@ -1255,7 +1377,7 @@ const listCodemods$1 = async (options) => {
|
|
|
1255
1377
|
const cwd = resolvePath(options.cwd);
|
|
1256
1378
|
const project = projectFactory(cwd);
|
|
1257
1379
|
const range = findRangeFromTarget(project, target);
|
|
1258
|
-
logger.debug(
|
|
1380
|
+
logger.debug(projectDetails(project));
|
|
1259
1381
|
logger.debug(`Range: set to ${versionRange(range)}`);
|
|
1260
1382
|
const repo = codemodRepositoryFactory();
|
|
1261
1383
|
repo.refresh();
|
|
@@ -1328,6 +1450,10 @@ const register$1 = (program) => {
|
|
|
1328
1450
|
return upgrade({ ...options, target: releaseType });
|
|
1329
1451
|
});
|
|
1330
1452
|
};
|
|
1453
|
+
addReleaseUpgradeCommand(
|
|
1454
|
+
ReleaseType.Latest,
|
|
1455
|
+
"Upgrade to the latest available version of Strapi"
|
|
1456
|
+
);
|
|
1331
1457
|
addReleaseUpgradeCommand(
|
|
1332
1458
|
ReleaseType.Major,
|
|
1333
1459
|
"Upgrade to the next available major version of Strapi"
|
|
@@ -1440,7 +1566,7 @@ When executed on a Strapi plugin project, it shows every codemods.
|
|
|
1440
1566
|
return listCodemods(options);
|
|
1441
1567
|
});
|
|
1442
1568
|
};
|
|
1443
|
-
const version = "0.0.0-experimental.
|
|
1569
|
+
const version = "0.0.0-experimental.e8d8fc824d0f6a695b2a9ebaa4680ed21c3645ca";
|
|
1444
1570
|
register$1(commander.program);
|
|
1445
1571
|
register(commander.program);
|
|
1446
1572
|
commander.program.usage("<command> [options]").on("command:*", ([invalidCmd]) => {
|