@strapi/upgrade 0.0.0-experimental.e3e48deb89bd0a1b6cc69b698696566fa7854a95 → 0.0.0-experimental.edc24aaa3bb5a90fa5fd4fee208167dd4e2e38d4

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.
Files changed (76) hide show
  1. package/LICENSE +19 -4
  2. package/dist/cli.js +1456 -5
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.js +323 -90
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +324 -91
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/modules/codemod/codemod.d.ts +4 -2
  9. package/dist/modules/codemod/codemod.d.ts.map +1 -1
  10. package/dist/modules/codemod/types.d.ts +8 -1
  11. package/dist/modules/codemod/types.d.ts.map +1 -1
  12. package/dist/modules/codemod-repository/constants.d.ts.map +1 -1
  13. package/dist/modules/codemod-repository/repository.d.ts +6 -5
  14. package/dist/modules/codemod-repository/repository.d.ts.map +1 -1
  15. package/dist/modules/codemod-repository/types.d.ts +7 -3
  16. package/dist/modules/codemod-repository/types.d.ts.map +1 -1
  17. package/dist/modules/codemod-runner/codemod-runner.d.ts +3 -0
  18. package/dist/modules/codemod-runner/codemod-runner.d.ts.map +1 -1
  19. package/dist/modules/codemod-runner/index.d.ts +1 -0
  20. package/dist/modules/codemod-runner/index.d.ts.map +1 -1
  21. package/dist/modules/codemod-runner/types.d.ts +1 -0
  22. package/dist/modules/codemod-runner/types.d.ts.map +1 -1
  23. package/dist/modules/format/formats.d.ts +5 -0
  24. package/dist/modules/format/formats.d.ts.map +1 -1
  25. package/dist/modules/project/constants.d.ts +2 -0
  26. package/dist/modules/project/constants.d.ts.map +1 -1
  27. package/dist/modules/project/index.d.ts +2 -0
  28. package/dist/modules/project/index.d.ts.map +1 -1
  29. package/dist/modules/project/project.d.ts +12 -4
  30. package/dist/modules/project/project.d.ts.map +1 -1
  31. package/dist/modules/project/types.d.ts +1 -11
  32. package/dist/modules/project/types.d.ts.map +1 -1
  33. package/dist/modules/project/utils.d.ts +6 -0
  34. package/dist/modules/project/utils.d.ts.map +1 -0
  35. package/dist/modules/report/report.d.ts.map +1 -1
  36. package/dist/modules/requirement/types.d.ts +2 -2
  37. package/dist/modules/requirement/types.d.ts.map +1 -1
  38. package/dist/modules/runner/json/transform.d.ts.map +1 -1
  39. package/dist/modules/upgrader/upgrader.d.ts +3 -3
  40. package/dist/modules/upgrader/upgrader.d.ts.map +1 -1
  41. package/dist/modules/version/range.d.ts +2 -0
  42. package/dist/modules/version/range.d.ts.map +1 -1
  43. package/dist/tasks/codemods/index.d.ts +2 -1
  44. package/dist/tasks/codemods/index.d.ts.map +1 -1
  45. package/dist/tasks/codemods/list-codemods.d.ts +3 -0
  46. package/dist/tasks/codemods/list-codemods.d.ts.map +1 -0
  47. package/dist/tasks/codemods/run-codemods.d.ts +3 -0
  48. package/dist/tasks/codemods/run-codemods.d.ts.map +1 -0
  49. package/dist/tasks/codemods/types.d.ts +9 -3
  50. package/dist/tasks/codemods/types.d.ts.map +1 -1
  51. package/dist/tasks/codemods/utils.d.ts +6 -0
  52. package/dist/tasks/codemods/utils.d.ts.map +1 -0
  53. package/dist/tasks/index.d.ts +1 -1
  54. package/dist/tasks/index.d.ts.map +1 -1
  55. package/dist/tasks/upgrade/upgrade.d.ts.map +1 -1
  56. package/package.json +9 -8
  57. package/resources/codemods/5.0.0/dependency-remove-strapi-plugin-i18n.json.ts +31 -0
  58. package/resources/codemods/5.0.0/dependency-upgrade-react-router-dom.json.ts +59 -0
  59. package/resources/codemods/5.0.0/entity-service-document-service.code.ts +437 -0
  60. package/resources/codemods/5.0.0/s3-keys-wrapped-in-credentials.code.ts +1 -1
  61. package/resources/codemods/5.0.0/sqlite3-to-better-sqlite3.json.ts +5 -2
  62. package/resources/codemods/5.0.0/strapi-public-interface.code.ts +126 -0
  63. package/resources/codemods/5.0.0/use-uid-for-config-namespace.code.ts +1 -1
  64. package/resources/codemods/5.0.0/utils-public-interface.code.ts +320 -0
  65. package/resources/examples/console.log-to-console.info.code.ts +1 -1
  66. package/resources/examples/disable-jsx-buttons.code.ts +42 -0
  67. package/dist/_chunks/codemod-runner-B5OeSMTQ.js +0 -730
  68. package/dist/_chunks/codemod-runner-B5OeSMTQ.js.map +0 -1
  69. package/dist/_chunks/codemods-10ZKewQx.js +0 -108
  70. package/dist/_chunks/codemods-10ZKewQx.js.map +0 -1
  71. package/dist/_chunks/index-uxCwtuH1.js +0 -103
  72. package/dist/_chunks/index-uxCwtuH1.js.map +0 -1
  73. package/dist/_chunks/upgrade-A4T1OWs5.js +0 -357
  74. package/dist/_chunks/upgrade-A4T1OWs5.js.map +0 -1
  75. package/dist/tasks/codemods/codemods.d.ts +0 -3
  76. package/dist/tasks/codemods/codemods.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -263,13 +263,19 @@ const rangeFromVersions = (currentVersion, target) => {
263
263
  }
264
264
  throw new Error(`Invalid target set: ${target}`);
265
265
  };
266
+ const isValidStringifiedRange = (str) => semver__default.default.validRange(str) !== null;
267
+ const isRangeInstance = (range) => {
268
+ return range instanceof semver__default.default.Range;
269
+ };
266
270
  const index$e = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
267
271
  __proto__: null,
268
272
  Version: types,
269
273
  isLiteralSemVer,
274
+ isRangeInstance,
270
275
  isSemVerReleaseType,
271
276
  isSemverInstance,
272
277
  isValidSemVer,
278
+ isValidStringifiedRange,
273
279
  rangeFactory,
274
280
  rangeFromReleaseType,
275
281
  rangeFromVersions,
@@ -330,7 +336,11 @@ const transformJSON = async (codemodPath, paths, config) => {
330
336
  timeElapsed: "",
331
337
  stats: {}
332
338
  };
333
- const esbuildOptions = { extensions: [".js", ".mjs", ".ts"] };
339
+ const esbuildOptions = {
340
+ extensions: [".js", ".mjs", ".ts"],
341
+ hookIgnoreNodeModules: false,
342
+ hookMatcher: fp.isEqual(codemodPath)
343
+ };
334
344
  const { unregister } = node.register(esbuildOptions);
335
345
  const module2 = require(codemodPath);
336
346
  unregister();
@@ -376,7 +386,20 @@ const index$b = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
376
386
  }, Symbol.toStringTag, { value: "Module" }));
377
387
  const PROJECT_PACKAGE_JSON = "package.json";
378
388
  const PROJECT_DEFAULT_ALLOWED_ROOT_PATHS = ["src", "config", "public"];
379
- const PROJECT_DEFAULT_ALLOWED_EXTENSIONS = ["js", "ts", "json"];
389
+ const PROJECT_DEFAULT_CODE_EXTENSIONS = [
390
+ // Source files
391
+ "js",
392
+ "mjs",
393
+ "ts",
394
+ // React files
395
+ "jsx",
396
+ "tsx"
397
+ ];
398
+ const PROJECT_DEFAULT_JSON_EXTENSIONS = ["json"];
399
+ const PROJECT_DEFAULT_ALLOWED_EXTENSIONS = [
400
+ ...PROJECT_DEFAULT_CODE_EXTENSIONS,
401
+ ...PROJECT_DEFAULT_JSON_EXTENSIONS
402
+ ];
380
403
  const PROJECT_DEFAULT_PATTERNS = ["package.json"];
381
404
  const SCOPED_STRAPI_PACKAGE_PREFIX = "@strapi/";
382
405
  const STRAPI_DEPENDENCY_NAME = `${SCOPED_STRAPI_PACKAGE_PREFIX}strapi`;
@@ -384,6 +407,8 @@ const constants$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
384
407
  __proto__: null,
385
408
  PROJECT_DEFAULT_ALLOWED_EXTENSIONS,
386
409
  PROJECT_DEFAULT_ALLOWED_ROOT_PATHS,
410
+ PROJECT_DEFAULT_CODE_EXTENSIONS,
411
+ PROJECT_DEFAULT_JSON_EXTENSIONS,
387
412
  PROJECT_DEFAULT_PATTERNS,
388
413
  PROJECT_PACKAGE_JSON,
389
414
  SCOPED_STRAPI_PACKAGE_PREFIX,
@@ -395,7 +420,6 @@ class Project {
395
420
  files;
396
421
  packageJSONPath;
397
422
  packageJSON;
398
- strapiVersion;
399
423
  constructor(cwd) {
400
424
  if (!fse__default.default.pathExistsSync(cwd)) {
401
425
  throw new Error(`ENOENT: no such file or directory, access '${cwd}'`);
@@ -411,14 +435,13 @@ class Project {
411
435
  }
412
436
  refresh() {
413
437
  this.refreshPackageJSON();
414
- this.refreshStrapiVersion();
415
438
  this.refreshProjectFiles();
416
439
  return this;
417
440
  }
418
- async runCodemods(codemods2, options) {
441
+ async runCodemods(codemods, options) {
419
442
  const runners = this.createProjectCodemodsRunners(options.dry);
420
443
  const reports2 = [];
421
- for (const codemod of codemods2) {
444
+ for (const codemod of codemods) {
422
445
  for (const runner of runners) {
423
446
  if (runner.valid(codemod)) {
424
447
  const report = await runner.run(codemod);
@@ -429,17 +452,24 @@ class Project {
429
452
  return reports2;
430
453
  }
431
454
  createProjectCodemodsRunners(dry = false) {
432
- const jsonFiles = this.getFilesByExtensions([".json"]);
433
- const codeFiles = this.getFilesByExtensions([".js", ".ts", ".mjs"]);
455
+ const jsonExtensions = PROJECT_DEFAULT_JSON_EXTENSIONS.map(
456
+ (ext) => `.${ext}`
457
+ );
458
+ const codeExtensions = PROJECT_DEFAULT_CODE_EXTENSIONS.map(
459
+ (ext) => `.${ext}`
460
+ );
461
+ const jsonFiles = this.getFilesByExtensions(jsonExtensions);
462
+ const codeFiles = this.getFilesByExtensions(codeExtensions);
434
463
  const codeRunner = codeRunnerFactory(codeFiles, {
435
464
  dry,
436
- print: false,
437
- silent: true,
438
- extensions: "js,ts",
465
+ parser: "ts",
439
466
  runInBand: true,
440
- verbose: 0,
441
467
  babel: true,
442
- parser: "ts"
468
+ extensions: PROJECT_DEFAULT_CODE_EXTENSIONS.join(","),
469
+ // Don't output any log coming from the runner
470
+ print: false,
471
+ silent: true,
472
+ verbose: 0
443
473
  });
444
474
  const jsonRunner = jsonRunnerFactory(jsonFiles, { dry, cwd: this.cwd });
445
475
  return [codeRunner, jsonRunner];
@@ -467,6 +497,19 @@ class Project {
467
497
  const scanner = fileScannerFactory(this.cwd);
468
498
  this.files = scanner.scan(patterns);
469
499
  }
500
+ }
501
+ class AppProject extends Project {
502
+ strapiVersion;
503
+ type = "application";
504
+ constructor(cwd) {
505
+ super(cwd);
506
+ this.refreshStrapiVersion();
507
+ }
508
+ refresh() {
509
+ super.refresh();
510
+ this.refreshStrapiVersion();
511
+ return this;
512
+ }
470
513
  refreshStrapiVersion() {
471
514
  this.strapiVersion = // First try to get the strapi version from the package.json dependencies
472
515
  this.findStrapiVersionFromProjectPackageJSON() ?? // If the version found is not a valid SemVer, get the Strapi version from the installed package
@@ -512,10 +555,50 @@ const formatGlobCollectionPattern = (collection) => {
512
555
  );
513
556
  return collection.length === 1 ? collection[0] : `{${collection}}`;
514
557
  };
515
- const projectFactory = (cwd) => new Project(cwd);
558
+ class PluginProject extends Project {
559
+ type = "plugin";
560
+ }
561
+ const isPlugin = (cwd) => {
562
+ const packageJSONPath = path__default.default.join(cwd, PROJECT_PACKAGE_JSON);
563
+ try {
564
+ fse__default.default.accessSync(packageJSONPath);
565
+ } catch {
566
+ throw new Error(`Could not find a ${PROJECT_PACKAGE_JSON} file in ${cwd}`);
567
+ }
568
+ const packageJSONBuffer = fse__default.default.readFileSync(packageJSONPath);
569
+ const packageJSON = JSON.parse(packageJSONBuffer.toString());
570
+ return packageJSON?.strapi?.kind === "plugin";
571
+ };
572
+ const projectFactory = (cwd) => {
573
+ fse__default.default.accessSync(cwd);
574
+ if (isPlugin(cwd)) {
575
+ return new PluginProject(cwd);
576
+ }
577
+ return new AppProject(cwd);
578
+ };
579
+ const isPluginProject = (project) => {
580
+ return project instanceof PluginProject;
581
+ };
582
+ function assertPluginProject(project) {
583
+ if (!isPluginProject(project)) {
584
+ throw new Error("Project is not a plugin");
585
+ }
586
+ }
587
+ const isApplicationProject = (project) => {
588
+ return project instanceof AppProject;
589
+ };
590
+ function assertAppProject(project) {
591
+ if (!isApplicationProject(project)) {
592
+ throw new Error("Project is not an application");
593
+ }
594
+ }
516
595
  const index$a = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
517
596
  __proto__: null,
597
+ assertAppProject,
598
+ assertPluginProject,
518
599
  constants: constants$3,
600
+ isApplicationProject,
601
+ isPluginProject,
519
602
  projectFactory
520
603
  }, Symbol.toStringTag, { value: "Module" }));
521
604
  class UnexpectedError extends Error {
@@ -541,7 +624,11 @@ const path = (path2) => chalk__default.default.blue(path2);
541
624
  const version = (version2) => {
542
625
  return chalk__default.default.italic.yellow(`v${version2}`);
543
626
  };
544
- const versionRange = (range) => chalk__default.default.italic.yellow(range);
627
+ const codemodUID = (uid) => {
628
+ return chalk__default.default.bold.cyan(uid);
629
+ };
630
+ const projectType = (type) => chalk__default.default.cyan(type);
631
+ const versionRange = (range) => chalk__default.default.italic.yellow(range.raw);
545
632
  const transform = (transformFilePath) => chalk__default.default.cyan(transformFilePath);
546
633
  const highlight = (arg) => chalk__default.default.bold.underline(arg);
547
634
  const upgradeStep = (text, step) => {
@@ -573,15 +660,40 @@ const reports = (reports2) => {
573
660
  table.push(...rows);
574
661
  return table.toString();
575
662
  };
663
+ const codemodList = (codemods) => {
664
+ const rows = codemods.map((codemod, index2) => {
665
+ const fIndex = chalk__default.default.grey(index2);
666
+ const fVersion = chalk__default.default.magenta(codemod.version);
667
+ const fKind = chalk__default.default.yellow(codemod.kind);
668
+ const fName = chalk__default.default.blue(codemod.format());
669
+ const fUID = codemodUID(codemod.uid);
670
+ return [fIndex, fVersion, fKind, fName, fUID];
671
+ });
672
+ const table = new CliTable3__default.default({
673
+ style: { compact: true },
674
+ head: [
675
+ chalk__default.default.bold.grey("N°"),
676
+ chalk__default.default.bold.magenta("Version"),
677
+ chalk__default.default.bold.yellow("Kind"),
678
+ chalk__default.default.bold.blue("Name"),
679
+ chalk__default.default.bold.cyan("UID")
680
+ ]
681
+ });
682
+ table.push(...rows);
683
+ return table.toString();
684
+ };
576
685
  const durationMs = (elapsedMs) => {
577
686
  const elapsedSeconds = (elapsedMs / ONE_SECOND_MS).toFixed(3);
578
687
  return `${elapsedSeconds}s`;
579
688
  };
580
689
  const index$8 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
581
690
  __proto__: null,
691
+ codemodList,
692
+ codemodUID,
582
693
  durationMs,
583
694
  highlight,
584
695
  path,
696
+ projectType,
585
697
  reports,
586
698
  transform,
587
699
  upgradeStep,
@@ -604,6 +716,7 @@ const constants$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
604
716
  CODEMOD_JSON_SUFFIX
605
717
  }, Symbol.toStringTag, { value: "Module" }));
606
718
  class Codemod {
719
+ uid;
607
720
  kind;
608
721
  version;
609
722
  baseDirectory;
@@ -615,9 +728,27 @@ class Codemod {
615
728
  this.baseDirectory = options.baseDirectory;
616
729
  this.filename = options.filename;
617
730
  this.path = path__default.default.join(this.baseDirectory, this.version.raw, this.filename);
618
- }
619
- format() {
620
- return this.filename.replace(`.${CODEMOD_CODE_SUFFIX}.${CODEMOD_EXTENSION}`, "").replace(`.${CODEMOD_JSON_SUFFIX}.${CODEMOD_EXTENSION}`, "").replaceAll("-", " ");
731
+ this.uid = this.createUID();
732
+ }
733
+ createUID() {
734
+ const name = this.format({ stripExtension: true, stripKind: true, stripHyphens: false });
735
+ const kind = this.kind;
736
+ const version2 = this.version.raw;
737
+ return `${version2}-${name}-${kind}`;
738
+ }
739
+ format(options) {
740
+ const { stripExtension = true, stripKind = true, stripHyphens = true } = options ?? {};
741
+ let formatted = this.filename;
742
+ if (stripExtension) {
743
+ formatted = formatted.replace(new RegExp(`\\.${CODEMOD_EXTENSION}$`, "i"), "");
744
+ }
745
+ if (stripKind) {
746
+ formatted = formatted.replace(`.${CODEMOD_CODE_SUFFIX}`, "").replace(`.${CODEMOD_JSON_SUFFIX}`, "");
747
+ }
748
+ if (stripHyphens) {
749
+ formatted = formatted.replaceAll("-", " ");
750
+ }
751
+ return formatted;
621
752
  }
622
753
  }
623
754
  const codemodFactory = (options) => new Codemod(options);
@@ -626,6 +757,20 @@ const index$7 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
626
757
  codemodFactory,
627
758
  constants: constants$2
628
759
  }, Symbol.toStringTag, { value: "Module" }));
760
+ const INTERNAL_CODEMODS_DIRECTORY = path__default.default.join(
761
+ __dirname,
762
+ // upgrade/dist
763
+ "..",
764
+ // upgrade
765
+ "resources",
766
+ // upgrade/resources
767
+ "codemods"
768
+ // upgrade/resources/codemods
769
+ );
770
+ const constants$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
771
+ __proto__: null,
772
+ INTERNAL_CODEMODS_DIRECTORY
773
+ }, Symbol.toStringTag, { value: "Module" }));
629
774
  class CodemodRepository {
630
775
  groups;
631
776
  versions;
@@ -644,23 +789,48 @@ class CodemodRepository {
644
789
  count(version2) {
645
790
  return this.findByVersion(version2).length;
646
791
  }
647
- countRange(range) {
648
- return this.findByRange(range).length;
649
- }
650
- exists(version2) {
792
+ versionExists(version2) {
651
793
  return version2.raw in this.groups;
652
794
  }
653
- findByRange(range) {
795
+ has(uid) {
796
+ const result = this.find({ uids: [uid] });
797
+ if (result.length !== 1) {
798
+ return false;
799
+ }
800
+ const { codemods } = result[0];
801
+ return codemods.length === 1 && codemods[0].uid === uid;
802
+ }
803
+ find(q) {
654
804
  const entries = Object.entries(this.groups);
655
- return entries.filter(([version2]) => range.test(version2)).map(([version2, codemods2]) => ({
805
+ return entries.filter(maybeFilterByRange).map(([version2, codemods]) => ({
656
806
  version: semVerFactory(version2),
657
- codemods: codemods2
658
- }));
807
+ // Filter by UID if provided in the query
808
+ codemods: codemods.filter(maybeFilterByUIDs)
809
+ })).filter(({ codemods }) => codemods.length > 0);
810
+ function maybeFilterByRange([version2]) {
811
+ if (!isRangeInstance(q.range)) {
812
+ return true;
813
+ }
814
+ return q.range.test(version2);
815
+ }
816
+ function maybeFilterByUIDs(codemod) {
817
+ if (q.uids === void 0) {
818
+ return true;
819
+ }
820
+ return q.uids.includes(codemod.uid);
821
+ }
659
822
  }
660
823
  findByVersion(version2) {
661
824
  const literalVersion = version2.raw;
662
- const codemods2 = this.groups[literalVersion];
663
- return codemods2 ?? [];
825
+ const codemods = this.groups[literalVersion];
826
+ return codemods ?? [];
827
+ }
828
+ findAll() {
829
+ const entries = Object.entries(this.groups);
830
+ return entries.map(([version2, codemods]) => ({
831
+ version: semVerFactory(version2),
832
+ codemods
833
+ }));
664
834
  }
665
835
  refreshAvailableVersions() {
666
836
  this.versions = fse__default.default.readdirSync(this.cwd).filter((filename) => fse__default.default.statSync(path__default.default.join(this.cwd, filename)).isDirectory()).filter((filename) => semver__default.default.valid(filename) !== null).map((version2) => semVerFactory(version2)).sort(semver__default.default.compare);
@@ -691,18 +861,9 @@ const parseCodemodKindFromFilename = (filename) => {
691
861
  assert__default.default(CODEMOD_ALLOWED_SUFFIXES.includes(kind));
692
862
  return kind;
693
863
  };
694
- const codemodRepositoryFactory = (cwd) => new CodemodRepository(cwd);
695
- const INTERNAL_CODEMODS_DIRECTORY = path__default.default.join(
696
- __dirname,
697
- "..",
698
- "..",
699
- "resources",
700
- "codemods"
701
- );
702
- const constants$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
703
- __proto__: null,
704
- INTERNAL_CODEMODS_DIRECTORY
705
- }, Symbol.toStringTag, { value: "Module" }));
864
+ const codemodRepositoryFactory = (cwd = INTERNAL_CODEMODS_DIRECTORY) => {
865
+ return new CodemodRepository(cwd);
866
+ };
706
867
  const index$6 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
707
868
  __proto__: null,
708
869
  codemodRepositoryFactory,
@@ -737,34 +898,59 @@ class CodemodRunner {
737
898
  this.isDry = enabled;
738
899
  return this;
739
900
  }
740
- async run(codemodsDirectory) {
901
+ createRepository(codemodsDirectory) {
741
902
  const repository = codemodRepositoryFactory(
742
903
  codemodsDirectory ?? INTERNAL_CODEMODS_DIRECTORY
743
904
  );
744
905
  repository.refresh();
745
- const allVersionedCodemods = repository.findByRange(this.range);
746
- const versionedCodemods = this.selectCodemodsCallback ? await this.selectCodemodsCallback(allVersionedCodemods) : allVersionedCodemods;
747
- const hasCodemodsToRun = versionedCodemods.length > 0;
748
- if (!hasCodemodsToRun) {
749
- this.logger?.debug(`Found no codemods to run for ${versionRange(this.range)}`);
750
- return successReport$1();
906
+ return repository;
907
+ }
908
+ async safeRunAndReport(codemods) {
909
+ if (this.isDry) {
910
+ this.logger?.warn?.(
911
+ "Running the codemods in dry mode. No files will be modified during the process."
912
+ );
751
913
  }
752
- this.logger?.debug(
753
- `Found codemods for ${highlight(
754
- versionedCodemods.length
755
- )} version(s) using ${versionRange(this.range)}`
756
- );
757
- versionedCodemods.forEach(
758
- ({ version: version$1, codemods: codemods22 }) => this.logger?.debug(`- ${version(version$1)} (${codemods22.length})`)
759
- );
760
- const codemods2 = versionedCodemods.map(({ codemods: codemods22 }) => codemods22).flat();
761
914
  try {
762
- const reports$1 = await this.project.runCodemods(codemods2, { dry: this.isDry });
763
- this.logger?.raw(reports(reports$1));
915
+ const reports$1 = await this.project.runCodemods(codemods, { dry: this.isDry });
916
+ this.logger?.raw?.(reports(reports$1));
917
+ if (!this.isDry) {
918
+ const nbAffectedTotal = reports$1.flatMap((report) => report.report.ok).reduce((acc, nb) => acc + nb, 0);
919
+ this.logger?.debug?.(
920
+ `Successfully ran ${highlight(codemods.length)} codemod(s), ${highlight(nbAffectedTotal)} change(s) have been detected`
921
+ );
922
+ }
923
+ return successReport$1();
764
924
  } catch (e) {
765
925
  return erroredReport$1(unknownToError(e));
766
926
  }
767
- return successReport$1();
927
+ }
928
+ async runByUID(uid, codemodsDirectory) {
929
+ const repository = this.createRepository(codemodsDirectory);
930
+ if (!repository.has(uid)) {
931
+ throw new Error(`Unknown codemod UID provided: ${uid}`);
932
+ }
933
+ const codemods = repository.find({ uids: [uid] }).flatMap(({ codemods: codemods2 }) => codemods2);
934
+ return this.safeRunAndReport(codemods);
935
+ }
936
+ async run(codemodsDirectory) {
937
+ const repository = this.createRepository(codemodsDirectory);
938
+ const codemodsInRange = repository.find({ range: this.range });
939
+ const selectedCodemods = this.selectCodemodsCallback ? await this.selectCodemodsCallback(codemodsInRange) : codemodsInRange;
940
+ if (selectedCodemods.length === 0) {
941
+ this.logger?.debug?.(`Found no codemods to run for ${versionRange(this.range)}`);
942
+ return successReport$1();
943
+ }
944
+ const codemods = selectedCodemods.flatMap(({ codemods: codemods2 }) => codemods2);
945
+ const codemodsByVersion = fp.groupBy("version", codemods);
946
+ const fRange = versionRange(this.range);
947
+ this.logger?.debug?.(
948
+ `Found ${highlight(codemods.length)} codemods for ${highlight(fp.size(codemodsByVersion))} version(s) using ${fRange}`
949
+ );
950
+ for (const [version$1, codemods2] of Object.entries(codemodsByVersion)) {
951
+ this.logger?.debug?.(`- ${version(semVerFactory(version$1))} (${codemods2.length})`);
952
+ }
953
+ return this.safeRunAndReport(codemods);
768
954
  }
769
955
  }
770
956
  const codemodRunnerFactory = (project, range) => {
@@ -803,7 +989,7 @@ class Upgrader {
803
989
  this.codemodsTarget = semVerFactory(
804
990
  `${this.target.major}.${this.target.minor}.${this.target.patch}`
805
991
  );
806
- this.logger?.debug(
992
+ this.logger?.debug?.(
807
993
  `The codemods target has been synced with the upgrade target. The codemod runner will now look for ${version(
808
994
  this.codemodsTarget
809
995
  )}`
@@ -812,7 +998,7 @@ class Upgrader {
812
998
  }
813
999
  overrideCodemodsTarget(target) {
814
1000
  this.codemodsTarget = target;
815
- this.logger?.debug(
1001
+ this.logger?.debug?.(
816
1002
  `Overriding the codemods target. The codemod runner will now look for ${version(target)}`
817
1003
  );
818
1004
  return this;
@@ -832,38 +1018,40 @@ class Upgrader {
832
1018
  addRequirement(requirement) {
833
1019
  this.requirements.push(requirement);
834
1020
  const fRequired = requirement.isRequired ? "(required)" : "(optional)";
835
- this.logger?.debug(
1021
+ this.logger?.debug?.(
836
1022
  `Added a new requirement to the upgrade: ${highlight(requirement.name)} ${fRequired}`
837
1023
  );
838
1024
  return this;
839
1025
  }
840
1026
  async upgrade() {
841
- this.logger?.info(
1027
+ this.logger?.info?.(
842
1028
  `Upgrading from ${version(this.project.strapiVersion)} to ${version(this.target)}`
843
1029
  );
844
1030
  if (this.isDry) {
845
- this.logger?.warn(
1031
+ this.logger?.warn?.(
846
1032
  "Running the upgrade in dry mode. No files will be modified during the process."
847
1033
  );
848
1034
  }
849
1035
  const range = rangeFromVersions(this.project.strapiVersion, this.target);
850
1036
  const codemodsRange = rangeFromVersions(this.project.strapiVersion, this.codemodsTarget);
851
1037
  const npmVersionsMatches = this.npmPackage?.findVersionsInRange(range) ?? [];
852
- this.logger?.debug(
1038
+ this.logger?.debug?.(
853
1039
  `Found ${highlight(npmVersionsMatches.length)} versions satisfying ${versionRange(range)}`
854
1040
  );
855
1041
  try {
856
- this.logger?.info(upgradeStep("Checking requirement", [1, 4]));
1042
+ this.logger?.info?.(upgradeStep("Checking requirement", [1, 4]));
857
1043
  await this.checkRequirements(this.requirements, {
858
1044
  npmVersionsMatches,
859
1045
  project: this.project,
860
1046
  target: this.target
861
1047
  });
862
- this.logger?.info(upgradeStep("Applying the latest code modifications", [2, 4]));
1048
+ this.logger?.info?.(upgradeStep("Applying the latest code modifications", [2, 4]));
863
1049
  await this.runCodemods(codemodsRange);
864
- this.logger?.info(upgradeStep("Upgrading Strapi dependencies", [3, 4]));
1050
+ this.logger?.debug?.("Refreshing project information...");
1051
+ this.project.refresh();
1052
+ this.logger?.info?.(upgradeStep("Upgrading Strapi dependencies", [3, 4]));
865
1053
  await this.updateDependencies();
866
- this.logger?.info(upgradeStep("Installing dependencies", [4, 4]));
1054
+ this.logger?.info?.(upgradeStep("Installing dependencies", [4, 4]));
867
1055
  await this.installDependencies();
868
1056
  } catch (e) {
869
1057
  return erroredReport(unknownToError(e));
@@ -896,7 +1084,7 @@ class Upgrader {
896
1084
  if (requirement.isRequired) {
897
1085
  throw error;
898
1086
  }
899
- this.logger?.warn(warningMessage);
1087
+ this.logger?.warn?.(warningMessage);
900
1088
  const response = await this.confirmationCallback?.(confirmationMessage);
901
1089
  if (!response) {
902
1090
  throw error;
@@ -907,9 +1095,11 @@ class Upgrader {
907
1095
  const json = createJSONTransformAPI(packageJSON);
908
1096
  const dependencies = json.get("dependencies", {});
909
1097
  const strapiDependencies = this.getScopedStrapiDependencies(dependencies);
910
- this.logger?.debug(`Found ${highlight(strapiDependencies.length)} dependency(ies) to update`);
1098
+ this.logger?.debug?.(
1099
+ `Found ${highlight(strapiDependencies.length)} dependency(ies) to update`
1100
+ );
911
1101
  strapiDependencies.forEach(
912
- (dependency) => this.logger?.debug(`- ${dependency[0]} (${dependency[1]} -> ${this.target})`)
1102
+ (dependency) => this.logger?.debug?.(`- ${dependency[0]} (${dependency[1]} -> ${this.target})`)
913
1103
  );
914
1104
  if (strapiDependencies.length === 0) {
915
1105
  return;
@@ -917,7 +1107,7 @@ class Upgrader {
917
1107
  strapiDependencies.forEach(([name]) => json.set(`dependencies.${name}`, this.target.raw));
918
1108
  const updatedPackageJSON = json.root();
919
1109
  if (this.isDry) {
920
- this.logger?.debug(`Skipping dependencies update (${chalk__default.default.italic("dry mode")})`);
1110
+ this.logger?.debug?.(`Skipping dependencies update (${chalk__default.default.italic("dry mode")})`);
921
1111
  return;
922
1112
  }
923
1113
  await saveJSON(packageJSONPath, updatedPackageJSON);
@@ -937,9 +1127,9 @@ class Upgrader {
937
1127
  async installDependencies() {
938
1128
  const projectPath = this.project.cwd;
939
1129
  const packageManagerName = await utils.packageManager.getPreferred(projectPath);
940
- this.logger?.debug(`Using ${highlight(packageManagerName)} as package manager`);
1130
+ this.logger?.debug?.(`Using ${highlight(packageManagerName)} as package manager`);
941
1131
  if (this.isDry) {
942
- this.logger?.debug(`Skipping dependencies installation (${chalk__default.default.italic("dry mode")}`);
1132
+ this.logger?.debug?.(`Skipping dependencies installation (${chalk__default.default.italic("dry mode")}`);
943
1133
  return;
944
1134
  }
945
1135
  await utils.packageManager.installDependencies(projectPath, packageManagerName, {
@@ -1038,6 +1228,11 @@ const upgrade = async (options) => {
1038
1228
  const { logger, codemodsTarget } = options;
1039
1229
  const cwd = path__default.default.resolve(options.cwd ?? process.cwd());
1040
1230
  const project = projectFactory(cwd);
1231
+ if (!isApplicationProject(project)) {
1232
+ throw new Error(
1233
+ `The "${options.target}" upgrade can only be run on a Strapi project; for plugins, please use "codemods".`
1234
+ );
1235
+ }
1041
1236
  const npmPackage = npmPackageFactory(STRAPI_PACKAGE_NAME);
1042
1237
  await npmPackage.refresh();
1043
1238
  const upgrader = upgraderFactory(project, options.target, npmPackage).dry(options.dry ?? false).onConfirm(options.confirm ?? null).setLogger(logger);
@@ -1055,20 +1250,7 @@ const upgrade = async (options) => {
1055
1250
  timer.stop();
1056
1251
  logger.info(`Completed in ${durationMs(timer.elapsedMs)}`);
1057
1252
  };
1058
- const codemods = async (options) => {
1059
- const timer = timerFactory();
1060
- const { logger } = options;
1061
- const cwd = path__default.default.resolve(options.cwd ?? process.cwd());
1062
- const project = projectFactory(cwd);
1063
- const range = getRangeFromTarget(project.strapiVersion, options.target);
1064
- const codemodRunner = codemodRunnerFactory(project, range).dry(options.dry ?? false).onSelectCodemods(options.selectCodemods ?? null).setLogger(logger);
1065
- const executionReport = await codemodRunner.run();
1066
- if (!executionReport.success) {
1067
- throw executionReport.error;
1068
- }
1069
- timer.stop();
1070
- logger.info(`Completed in ${timer.elapsedMs}`);
1071
- };
1253
+ const resolvePath = (cwd) => path__default.default.resolve(cwd ?? process.cwd());
1072
1254
  const getRangeFromTarget = (currentVersion, target) => {
1073
1255
  if (isSemverInstance(target)) {
1074
1256
  return rangeFactory(target);
@@ -1085,9 +1267,60 @@ const getRangeFromTarget = (currentVersion, target) => {
1085
1267
  throw new Error(`Invalid target set: ${target}`);
1086
1268
  }
1087
1269
  };
1270
+ const findRangeFromTarget = (project, target) => {
1271
+ if (isRangeInstance(target)) {
1272
+ return target;
1273
+ }
1274
+ if (isApplicationProject(project)) {
1275
+ return getRangeFromTarget(project.strapiVersion, target);
1276
+ }
1277
+ return rangeFactory("*");
1278
+ };
1279
+ const runCodemods = async (options) => {
1280
+ const timer = timerFactory();
1281
+ const { logger, uid } = options;
1282
+ const cwd = resolvePath(options.cwd);
1283
+ const project = projectFactory(cwd);
1284
+ const range = findRangeFromTarget(project, options.target);
1285
+ logger.debug(`Project: ${projectType(project.type)} found in ${path(cwd)}`);
1286
+ logger.debug(`Range: set to ${versionRange(range)}`);
1287
+ const codemodRunner = codemodRunnerFactory(project, range).dry(options.dry ?? false).onSelectCodemods(options.selectCodemods ?? null).setLogger(logger);
1288
+ let report;
1289
+ if (uid !== void 0) {
1290
+ logger.debug(`Running a single codemod: ${codemodUID(uid)}`);
1291
+ report = await codemodRunner.runByUID(uid);
1292
+ } else {
1293
+ report = await codemodRunner.run();
1294
+ }
1295
+ if (!report.success) {
1296
+ throw report.error;
1297
+ }
1298
+ timer.stop();
1299
+ logger.info(`Completed in ${timer.elapsedMs}`);
1300
+ };
1301
+ const listCodemods = async (options) => {
1302
+ const { logger, target } = options;
1303
+ const cwd = resolvePath(options.cwd);
1304
+ const project = projectFactory(cwd);
1305
+ const range = findRangeFromTarget(project, target);
1306
+ logger.debug(`Project: ${projectType(project.type)} found in ${path(cwd)}`);
1307
+ logger.debug(`Range: set to ${versionRange(range)}`);
1308
+ const repo = codemodRepositoryFactory();
1309
+ repo.refresh();
1310
+ const groups = repo.find({ range });
1311
+ const codemods = groups.flatMap((collection) => collection.codemods);
1312
+ logger.debug(`Found ${highlight(codemods.length)} codemods`);
1313
+ if (codemods.length === 0) {
1314
+ logger.info(`Found no codemods matching ${versionRange(range)}`);
1315
+ return;
1316
+ }
1317
+ const fCodemods = codemodList(codemods);
1318
+ logger.raw(fCodemods);
1319
+ };
1088
1320
  const index$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1089
1321
  __proto__: null,
1090
- codemods,
1322
+ listCodemods,
1323
+ runCodemods,
1091
1324
  upgrade
1092
1325
  }, Symbol.toStringTag, { value: "Module" }));
1093
1326
  class Logger {