@strapi/upgrade 5.0.0-beta.0 → 5.0.0-beta.10

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