@strapi/upgrade 0.0.0-experimental.a407f3bc8fb79a53cf7975140864526b6ddbac4b → 0.0.0-experimental.baa6cf22298e591b4d52d8e59c60406d7a9f137f

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 -88
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +319 -89
  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 +45 -0
  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-84t8FGQa.js +0 -729
  66. package/dist/_chunks/codemod-runner-84t8FGQa.js.map +0 -1
  67. package/dist/_chunks/codemods-KNF9fcQL.js +0 -108
  68. package/dist/_chunks/codemods-KNF9fcQL.js.map +0 -1
  69. package/dist/_chunks/index-hERDGiiJ.js +0 -103
  70. package/dist/_chunks/index-hERDGiiJ.js.map +0 -1
  71. package/dist/_chunks/upgrade-dU3oQNZk.js +0 -357
  72. package/dist/_chunks/upgrade-dU3oQNZk.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,16 +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,
461
+ parser: "ts",
462
+ runInBand: true,
463
+ babel: true,
464
+ extensions: PROJECT_DEFAULT_CODE_EXTENSIONS.join(","),
465
+ // Don't output any log coming from the runner
436
466
  print: false,
437
467
  silent: true,
438
- extensions: "js,ts",
439
- runInBand: true,
440
- verbose: 0,
441
- babel: true
468
+ verbose: 0
442
469
  });
443
470
  const jsonRunner = jsonRunnerFactory(jsonFiles, { dry, cwd: this.cwd });
444
471
  return [codeRunner, jsonRunner];
@@ -466,6 +493,19 @@ class Project {
466
493
  const scanner = fileScannerFactory(this.cwd);
467
494
  this.files = scanner.scan(patterns);
468
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
+ }
469
509
  refreshStrapiVersion() {
470
510
  this.strapiVersion = // First try to get the strapi version from the package.json dependencies
471
511
  this.findStrapiVersionFromProjectPackageJSON() ?? // If the version found is not a valid SemVer, get the Strapi version from the installed package
@@ -511,10 +551,50 @@ const formatGlobCollectionPattern = (collection) => {
511
551
  );
512
552
  return collection.length === 1 ? collection[0] : `{${collection}}`;
513
553
  };
514
- 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
+ }
515
591
  const index$a = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
516
592
  __proto__: null,
593
+ assertAppProject,
594
+ assertPluginProject,
517
595
  constants: constants$3,
596
+ isApplicationProject,
597
+ isPluginProject,
518
598
  projectFactory
519
599
  }, Symbol.toStringTag, { value: "Module" }));
520
600
  class UnexpectedError extends Error {
@@ -540,7 +620,11 @@ const path = (path2) => chalk__default.default.blue(path2);
540
620
  const version = (version2) => {
541
621
  return chalk__default.default.italic.yellow(`v${version2}`);
542
622
  };
543
- 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);
544
628
  const transform = (transformFilePath) => chalk__default.default.cyan(transformFilePath);
545
629
  const highlight = (arg) => chalk__default.default.bold.underline(arg);
546
630
  const upgradeStep = (text, step) => {
@@ -572,15 +656,40 @@ const reports = (reports2) => {
572
656
  table.push(...rows);
573
657
  return table.toString();
574
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
+ };
575
681
  const durationMs = (elapsedMs) => {
576
682
  const elapsedSeconds = (elapsedMs / ONE_SECOND_MS).toFixed(3);
577
683
  return `${elapsedSeconds}s`;
578
684
  };
579
685
  const index$8 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
580
686
  __proto__: null,
687
+ codemodList,
688
+ codemodUID,
581
689
  durationMs,
582
690
  highlight,
583
691
  path,
692
+ projectType,
584
693
  reports,
585
694
  transform,
586
695
  upgradeStep,
@@ -603,6 +712,7 @@ const constants$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
603
712
  CODEMOD_JSON_SUFFIX
604
713
  }, Symbol.toStringTag, { value: "Module" }));
605
714
  class Codemod {
715
+ uid;
606
716
  kind;
607
717
  version;
608
718
  baseDirectory;
@@ -614,9 +724,27 @@ class Codemod {
614
724
  this.baseDirectory = options.baseDirectory;
615
725
  this.filename = options.filename;
616
726
  this.path = path__default.default.join(this.baseDirectory, this.version.raw, this.filename);
617
- }
618
- format() {
619
- 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;
620
748
  }
621
749
  }
622
750
  const codemodFactory = (options) => new Codemod(options);
@@ -625,6 +753,20 @@ const index$7 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
625
753
  codemodFactory,
626
754
  constants: constants$2
627
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" }));
628
770
  class CodemodRepository {
629
771
  groups;
630
772
  versions;
@@ -643,23 +785,48 @@ class CodemodRepository {
643
785
  count(version2) {
644
786
  return this.findByVersion(version2).length;
645
787
  }
646
- countRange(range) {
647
- return this.findByRange(range).length;
648
- }
649
- exists(version2) {
788
+ versionExists(version2) {
650
789
  return version2.raw in this.groups;
651
790
  }
652
- 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) {
653
800
  const entries = Object.entries(this.groups);
654
- return entries.filter(([version2]) => range.test(version2)).map(([version2, codemods2]) => ({
801
+ return entries.filter(maybeFilterByRange).map(([version2, codemods]) => ({
655
802
  version: semVerFactory(version2),
656
- codemods: codemods2
657
- }));
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
+ }
658
818
  }
659
819
  findByVersion(version2) {
660
820
  const literalVersion = version2.raw;
661
- const codemods2 = this.groups[literalVersion];
662
- 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
+ }));
663
830
  }
664
831
  refreshAvailableVersions() {
665
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);
@@ -690,18 +857,9 @@ const parseCodemodKindFromFilename = (filename) => {
690
857
  assert__default.default(CODEMOD_ALLOWED_SUFFIXES.includes(kind));
691
858
  return kind;
692
859
  };
693
- const codemodRepositoryFactory = (cwd) => new CodemodRepository(cwd);
694
- const INTERNAL_CODEMODS_DIRECTORY = path__default.default.join(
695
- __dirname,
696
- "..",
697
- "..",
698
- "resources",
699
- "codemods"
700
- );
701
- const constants$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
702
- __proto__: null,
703
- INTERNAL_CODEMODS_DIRECTORY
704
- }, Symbol.toStringTag, { value: "Module" }));
860
+ const codemodRepositoryFactory = (cwd = INTERNAL_CODEMODS_DIRECTORY) => {
861
+ return new CodemodRepository(cwd);
862
+ };
705
863
  const index$6 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
706
864
  __proto__: null,
707
865
  codemodRepositoryFactory,
@@ -736,34 +894,59 @@ class CodemodRunner {
736
894
  this.isDry = enabled;
737
895
  return this;
738
896
  }
739
- async run(codemodsDirectory) {
897
+ createRepository(codemodsDirectory) {
740
898
  const repository = codemodRepositoryFactory(
741
899
  codemodsDirectory ?? INTERNAL_CODEMODS_DIRECTORY
742
900
  );
743
901
  repository.refresh();
744
- const allVersionedCodemods = repository.findByRange(this.range);
745
- const versionedCodemods = this.selectCodemodsCallback ? await this.selectCodemodsCallback(allVersionedCodemods) : allVersionedCodemods;
746
- const hasCodemodsToRun = versionedCodemods.length > 0;
747
- if (!hasCodemodsToRun) {
748
- this.logger?.debug(`Found no codemods to run for ${versionRange(this.range)}`);
749
- 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
+ );
750
909
  }
751
- this.logger?.debug(
752
- `Found codemods for ${highlight(
753
- versionedCodemods.length
754
- )} version(s) using ${versionRange(this.range)}`
755
- );
756
- versionedCodemods.forEach(
757
- ({ version: version$1, codemods: codemods22 }) => this.logger?.debug(`- ${version(version$1)} (${codemods22.length})`)
758
- );
759
- const codemods2 = versionedCodemods.map(({ codemods: codemods22 }) => codemods22).flat();
760
910
  try {
761
- const reports$1 = await this.project.runCodemods(codemods2, { dry: this.isDry });
762
- 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();
763
920
  } catch (e) {
764
921
  return erroredReport$1(unknownToError(e));
765
922
  }
766
- 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);
767
950
  }
768
951
  }
769
952
  const codemodRunnerFactory = (project, range) => {
@@ -802,7 +985,7 @@ class Upgrader {
802
985
  this.codemodsTarget = semVerFactory(
803
986
  `${this.target.major}.${this.target.minor}.${this.target.patch}`
804
987
  );
805
- this.logger?.debug(
988
+ this.logger?.debug?.(
806
989
  `The codemods target has been synced with the upgrade target. The codemod runner will now look for ${version(
807
990
  this.codemodsTarget
808
991
  )}`
@@ -811,7 +994,7 @@ class Upgrader {
811
994
  }
812
995
  overrideCodemodsTarget(target) {
813
996
  this.codemodsTarget = target;
814
- this.logger?.debug(
997
+ this.logger?.debug?.(
815
998
  `Overriding the codemods target. The codemod runner will now look for ${version(target)}`
816
999
  );
817
1000
  return this;
@@ -831,38 +1014,40 @@ class Upgrader {
831
1014
  addRequirement(requirement) {
832
1015
  this.requirements.push(requirement);
833
1016
  const fRequired = requirement.isRequired ? "(required)" : "(optional)";
834
- this.logger?.debug(
1017
+ this.logger?.debug?.(
835
1018
  `Added a new requirement to the upgrade: ${highlight(requirement.name)} ${fRequired}`
836
1019
  );
837
1020
  return this;
838
1021
  }
839
1022
  async upgrade() {
840
- this.logger?.info(
1023
+ this.logger?.info?.(
841
1024
  `Upgrading from ${version(this.project.strapiVersion)} to ${version(this.target)}`
842
1025
  );
843
1026
  if (this.isDry) {
844
- this.logger?.warn(
1027
+ this.logger?.warn?.(
845
1028
  "Running the upgrade in dry mode. No files will be modified during the process."
846
1029
  );
847
1030
  }
848
1031
  const range = rangeFromVersions(this.project.strapiVersion, this.target);
849
1032
  const codemodsRange = rangeFromVersions(this.project.strapiVersion, this.codemodsTarget);
850
1033
  const npmVersionsMatches = this.npmPackage?.findVersionsInRange(range) ?? [];
851
- this.logger?.debug(
1034
+ this.logger?.debug?.(
852
1035
  `Found ${highlight(npmVersionsMatches.length)} versions satisfying ${versionRange(range)}`
853
1036
  );
854
1037
  try {
855
- this.logger?.info(upgradeStep("Checking requirement", [1, 4]));
1038
+ this.logger?.info?.(upgradeStep("Checking requirement", [1, 4]));
856
1039
  await this.checkRequirements(this.requirements, {
857
1040
  npmVersionsMatches,
858
1041
  project: this.project,
859
1042
  target: this.target
860
1043
  });
861
- this.logger?.info(upgradeStep("Applying the latest code modifications", [2, 4]));
1044
+ this.logger?.info?.(upgradeStep("Applying the latest code modifications", [2, 4]));
862
1045
  await this.runCodemods(codemodsRange);
863
- 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]));
864
1049
  await this.updateDependencies();
865
- this.logger?.info(upgradeStep("Installing dependencies", [4, 4]));
1050
+ this.logger?.info?.(upgradeStep("Installing dependencies", [4, 4]));
866
1051
  await this.installDependencies();
867
1052
  } catch (e) {
868
1053
  return erroredReport(unknownToError(e));
@@ -895,7 +1080,7 @@ class Upgrader {
895
1080
  if (requirement.isRequired) {
896
1081
  throw error;
897
1082
  }
898
- this.logger?.warn(warningMessage);
1083
+ this.logger?.warn?.(warningMessage);
899
1084
  const response = await this.confirmationCallback?.(confirmationMessage);
900
1085
  if (!response) {
901
1086
  throw error;
@@ -906,9 +1091,11 @@ class Upgrader {
906
1091
  const json = createJSONTransformAPI(packageJSON);
907
1092
  const dependencies = json.get("dependencies", {});
908
1093
  const strapiDependencies = this.getScopedStrapiDependencies(dependencies);
909
- 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
+ );
910
1097
  strapiDependencies.forEach(
911
- (dependency) => this.logger?.debug(`- ${dependency[0]} (${dependency[1]} -> ${this.target})`)
1098
+ (dependency) => this.logger?.debug?.(`- ${dependency[0]} (${dependency[1]} -> ${this.target})`)
912
1099
  );
913
1100
  if (strapiDependencies.length === 0) {
914
1101
  return;
@@ -916,7 +1103,7 @@ class Upgrader {
916
1103
  strapiDependencies.forEach(([name]) => json.set(`dependencies.${name}`, this.target.raw));
917
1104
  const updatedPackageJSON = json.root();
918
1105
  if (this.isDry) {
919
- 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")})`);
920
1107
  return;
921
1108
  }
922
1109
  await saveJSON(packageJSONPath, updatedPackageJSON);
@@ -936,9 +1123,9 @@ class Upgrader {
936
1123
  async installDependencies() {
937
1124
  const projectPath = this.project.cwd;
938
1125
  const packageManagerName = await utils.packageManager.getPreferred(projectPath);
939
- this.logger?.debug(`Using ${highlight(packageManagerName)} as package manager`);
1126
+ this.logger?.debug?.(`Using ${highlight(packageManagerName)} as package manager`);
940
1127
  if (this.isDry) {
941
- 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")}`);
942
1129
  return;
943
1130
  }
944
1131
  await utils.packageManager.installDependencies(projectPath, packageManagerName, {
@@ -1037,6 +1224,11 @@ const upgrade = async (options) => {
1037
1224
  const { logger, codemodsTarget } = options;
1038
1225
  const cwd = path__default.default.resolve(options.cwd ?? process.cwd());
1039
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
+ }
1040
1232
  const npmPackage = npmPackageFactory(STRAPI_PACKAGE_NAME);
1041
1233
  await npmPackage.refresh();
1042
1234
  const upgrader = upgraderFactory(project, options.target, npmPackage).dry(options.dry ?? false).onConfirm(options.confirm ?? null).setLogger(logger);
@@ -1054,20 +1246,7 @@ const upgrade = async (options) => {
1054
1246
  timer.stop();
1055
1247
  logger.info(`Completed in ${durationMs(timer.elapsedMs)}`);
1056
1248
  };
1057
- const codemods = async (options) => {
1058
- const timer = timerFactory();
1059
- const { logger } = options;
1060
- const cwd = path__default.default.resolve(options.cwd ?? process.cwd());
1061
- const project = projectFactory(cwd);
1062
- const range = getRangeFromTarget(project.strapiVersion, options.target);
1063
- const codemodRunner = codemodRunnerFactory(project, range).dry(options.dry ?? false).onSelectCodemods(options.selectCodemods ?? null).setLogger(logger);
1064
- const executionReport = await codemodRunner.run();
1065
- if (!executionReport.success) {
1066
- throw executionReport.error;
1067
- }
1068
- timer.stop();
1069
- logger.info(`Completed in ${timer.elapsedMs}`);
1070
- };
1249
+ const resolvePath = (cwd) => path__default.default.resolve(cwd ?? process.cwd());
1071
1250
  const getRangeFromTarget = (currentVersion, target) => {
1072
1251
  if (isSemverInstance(target)) {
1073
1252
  return rangeFactory(target);
@@ -1084,9 +1263,60 @@ const getRangeFromTarget = (currentVersion, target) => {
1084
1263
  throw new Error(`Invalid target set: ${target}`);
1085
1264
  }
1086
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
+ };
1087
1316
  const index$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1088
1317
  __proto__: null,
1089
- codemods,
1318
+ listCodemods,
1319
+ runCodemods,
1090
1320
  upgrade
1091
1321
  }, Symbol.toStringTag, { value: "Module" }));
1092
1322
  class Logger {