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

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 +7 -7
  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 +374 -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.mjs CHANGED
@@ -3,7 +3,7 @@ import simpleGit from "simple-git";
3
3
  import chalk from "chalk";
4
4
  import semver from "semver";
5
5
  import { packageManager } from "@strapi/utils";
6
- import { cloneDeep, get, has, merge, set, omit, isEqual } from "lodash/fp";
6
+ import { cloneDeep, get, has, merge, set, omit, isEqual, groupBy, size } from "lodash/fp";
7
7
  import fse from "fs-extra";
8
8
  import assert from "node:assert";
9
9
  import { glob } from "glob";
@@ -253,13 +253,19 @@ const rangeFromVersions = (currentVersion, target) => {
253
253
  }
254
254
  throw new Error(`Invalid target set: ${target}`);
255
255
  };
256
+ const isValidStringifiedRange = (str) => semver.validRange(str) !== null;
257
+ const isRangeInstance = (range) => {
258
+ return range instanceof semver.Range;
259
+ };
256
260
  const index$e = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
257
261
  __proto__: null,
258
262
  Version: types,
259
263
  isLiteralSemVer,
264
+ isRangeInstance,
260
265
  isSemVerReleaseType,
261
266
  isSemverInstance,
262
267
  isValidSemVer,
268
+ isValidStringifiedRange,
263
269
  rangeFactory,
264
270
  rangeFromReleaseType,
265
271
  rangeFromVersions,
@@ -366,7 +372,20 @@ const index$b = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
366
372
  }, Symbol.toStringTag, { value: "Module" }));
367
373
  const PROJECT_PACKAGE_JSON = "package.json";
368
374
  const PROJECT_DEFAULT_ALLOWED_ROOT_PATHS = ["src", "config", "public"];
369
- const PROJECT_DEFAULT_ALLOWED_EXTENSIONS = ["js", "ts", "json"];
375
+ const PROJECT_DEFAULT_CODE_EXTENSIONS = [
376
+ // Source files
377
+ "js",
378
+ "mjs",
379
+ "ts",
380
+ // React files
381
+ "jsx",
382
+ "tsx"
383
+ ];
384
+ const PROJECT_DEFAULT_JSON_EXTENSIONS = ["json"];
385
+ const PROJECT_DEFAULT_ALLOWED_EXTENSIONS = [
386
+ ...PROJECT_DEFAULT_CODE_EXTENSIONS,
387
+ ...PROJECT_DEFAULT_JSON_EXTENSIONS
388
+ ];
370
389
  const PROJECT_DEFAULT_PATTERNS = ["package.json"];
371
390
  const SCOPED_STRAPI_PACKAGE_PREFIX = "@strapi/";
372
391
  const STRAPI_DEPENDENCY_NAME = `${SCOPED_STRAPI_PACKAGE_PREFIX}strapi`;
@@ -374,6 +393,8 @@ const constants$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
374
393
  __proto__: null,
375
394
  PROJECT_DEFAULT_ALLOWED_EXTENSIONS,
376
395
  PROJECT_DEFAULT_ALLOWED_ROOT_PATHS,
396
+ PROJECT_DEFAULT_CODE_EXTENSIONS,
397
+ PROJECT_DEFAULT_JSON_EXTENSIONS,
377
398
  PROJECT_DEFAULT_PATTERNS,
378
399
  PROJECT_PACKAGE_JSON,
379
400
  SCOPED_STRAPI_PACKAGE_PREFIX,
@@ -385,7 +406,6 @@ class Project {
385
406
  files;
386
407
  packageJSONPath;
387
408
  packageJSON;
388
- strapiVersion;
389
409
  constructor(cwd) {
390
410
  if (!fse.pathExistsSync(cwd)) {
391
411
  throw new Error(`ENOENT: no such file or directory, access '${cwd}'`);
@@ -401,14 +421,13 @@ class Project {
401
421
  }
402
422
  refresh() {
403
423
  this.refreshPackageJSON();
404
- this.refreshStrapiVersion();
405
424
  this.refreshProjectFiles();
406
425
  return this;
407
426
  }
408
- async runCodemods(codemods2, options) {
427
+ async runCodemods(codemods, options) {
409
428
  const runners = this.createProjectCodemodsRunners(options.dry);
410
429
  const reports2 = [];
411
- for (const codemod of codemods2) {
430
+ for (const codemod of codemods) {
412
431
  for (const runner of runners) {
413
432
  if (runner.valid(codemod)) {
414
433
  const report = await runner.run(codemod);
@@ -419,16 +438,24 @@ class Project {
419
438
  return reports2;
420
439
  }
421
440
  createProjectCodemodsRunners(dry = false) {
422
- const jsonFiles = this.getFilesByExtensions([".json"]);
423
- const codeFiles = this.getFilesByExtensions([".js", ".ts", ".mjs"]);
441
+ const jsonExtensions = PROJECT_DEFAULT_JSON_EXTENSIONS.map(
442
+ (ext) => `.${ext}`
443
+ );
444
+ const codeExtensions = PROJECT_DEFAULT_CODE_EXTENSIONS.map(
445
+ (ext) => `.${ext}`
446
+ );
447
+ const jsonFiles = this.getFilesByExtensions(jsonExtensions);
448
+ const codeFiles = this.getFilesByExtensions(codeExtensions);
424
449
  const codeRunner = codeRunnerFactory(codeFiles, {
425
450
  dry,
451
+ parser: "ts",
452
+ runInBand: true,
453
+ babel: true,
454
+ extensions: PROJECT_DEFAULT_CODE_EXTENSIONS.join(","),
455
+ // Don't output any log coming from the runner
426
456
  print: false,
427
457
  silent: true,
428
- extensions: "js,ts",
429
- runInBand: true,
430
- verbose: 0,
431
- babel: true
458
+ verbose: 0
432
459
  });
433
460
  const jsonRunner = jsonRunnerFactory(jsonFiles, { dry, cwd: this.cwd });
434
461
  return [codeRunner, jsonRunner];
@@ -456,6 +483,19 @@ class Project {
456
483
  const scanner = fileScannerFactory(this.cwd);
457
484
  this.files = scanner.scan(patterns);
458
485
  }
486
+ }
487
+ class AppProject extends Project {
488
+ strapiVersion;
489
+ type = "application";
490
+ constructor(cwd) {
491
+ super(cwd);
492
+ this.refreshStrapiVersion();
493
+ }
494
+ refresh() {
495
+ super.refresh();
496
+ this.refreshStrapiVersion();
497
+ return this;
498
+ }
459
499
  refreshStrapiVersion() {
460
500
  this.strapiVersion = // First try to get the strapi version from the package.json dependencies
461
501
  this.findStrapiVersionFromProjectPackageJSON() ?? // If the version found is not a valid SemVer, get the Strapi version from the installed package
@@ -501,10 +541,50 @@ const formatGlobCollectionPattern = (collection) => {
501
541
  );
502
542
  return collection.length === 1 ? collection[0] : `{${collection}}`;
503
543
  };
504
- const projectFactory = (cwd) => new Project(cwd);
544
+ class PluginProject extends Project {
545
+ type = "plugin";
546
+ }
547
+ const isPlugin = (cwd) => {
548
+ const packageJSONPath = path$1.join(cwd, PROJECT_PACKAGE_JSON);
549
+ try {
550
+ fse.accessSync(packageJSONPath);
551
+ } catch {
552
+ throw new Error(`Could not find a ${PROJECT_PACKAGE_JSON} file in ${cwd}`);
553
+ }
554
+ const packageJSONBuffer = fse.readFileSync(packageJSONPath);
555
+ const packageJSON = JSON.parse(packageJSONBuffer.toString());
556
+ return packageJSON?.strapi?.kind === "plugin";
557
+ };
558
+ const projectFactory = (cwd) => {
559
+ fse.accessSync(cwd);
560
+ if (isPlugin(cwd)) {
561
+ return new PluginProject(cwd);
562
+ }
563
+ return new AppProject(cwd);
564
+ };
565
+ const isPluginProject = (project) => {
566
+ return project instanceof PluginProject;
567
+ };
568
+ function assertPluginProject(project) {
569
+ if (!isPluginProject(project)) {
570
+ throw new Error("Project is not a plugin");
571
+ }
572
+ }
573
+ const isApplicationProject = (project) => {
574
+ return project instanceof AppProject;
575
+ };
576
+ function assertAppProject(project) {
577
+ if (!isApplicationProject(project)) {
578
+ throw new Error("Project is not an application");
579
+ }
580
+ }
505
581
  const index$a = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
506
582
  __proto__: null,
583
+ assertAppProject,
584
+ assertPluginProject,
507
585
  constants: constants$3,
586
+ isApplicationProject,
587
+ isPluginProject,
508
588
  projectFactory
509
589
  }, Symbol.toStringTag, { value: "Module" }));
510
590
  class UnexpectedError extends Error {
@@ -530,7 +610,11 @@ const path = (path2) => chalk.blue(path2);
530
610
  const version = (version2) => {
531
611
  return chalk.italic.yellow(`v${version2}`);
532
612
  };
533
- const versionRange = (range) => chalk.italic.yellow(range);
613
+ const codemodUID = (uid) => {
614
+ return chalk.bold.cyan(uid);
615
+ };
616
+ const projectType = (type) => chalk.cyan(type);
617
+ const versionRange = (range) => chalk.italic.yellow(range.raw);
534
618
  const transform = (transformFilePath) => chalk.cyan(transformFilePath);
535
619
  const highlight = (arg) => chalk.bold.underline(arg);
536
620
  const upgradeStep = (text, step) => {
@@ -562,15 +646,40 @@ const reports = (reports2) => {
562
646
  table.push(...rows);
563
647
  return table.toString();
564
648
  };
649
+ const codemodList = (codemods) => {
650
+ const rows = codemods.map((codemod, index2) => {
651
+ const fIndex = chalk.grey(index2);
652
+ const fVersion = chalk.magenta(codemod.version);
653
+ const fKind = chalk.yellow(codemod.kind);
654
+ const fName = chalk.blue(codemod.format());
655
+ const fUID = codemodUID(codemod.uid);
656
+ return [fIndex, fVersion, fKind, fName, fUID];
657
+ });
658
+ const table = new CliTable3({
659
+ style: { compact: true },
660
+ head: [
661
+ chalk.bold.grey("N°"),
662
+ chalk.bold.magenta("Version"),
663
+ chalk.bold.yellow("Kind"),
664
+ chalk.bold.blue("Name"),
665
+ chalk.bold.cyan("UID")
666
+ ]
667
+ });
668
+ table.push(...rows);
669
+ return table.toString();
670
+ };
565
671
  const durationMs = (elapsedMs) => {
566
672
  const elapsedSeconds = (elapsedMs / ONE_SECOND_MS).toFixed(3);
567
673
  return `${elapsedSeconds}s`;
568
674
  };
569
675
  const index$8 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
570
676
  __proto__: null,
677
+ codemodList,
678
+ codemodUID,
571
679
  durationMs,
572
680
  highlight,
573
681
  path,
682
+ projectType,
574
683
  reports,
575
684
  transform,
576
685
  upgradeStep,
@@ -593,6 +702,7 @@ const constants$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
593
702
  CODEMOD_JSON_SUFFIX
594
703
  }, Symbol.toStringTag, { value: "Module" }));
595
704
  class Codemod {
705
+ uid;
596
706
  kind;
597
707
  version;
598
708
  baseDirectory;
@@ -604,9 +714,27 @@ class Codemod {
604
714
  this.baseDirectory = options.baseDirectory;
605
715
  this.filename = options.filename;
606
716
  this.path = path$1.join(this.baseDirectory, this.version.raw, this.filename);
607
- }
608
- format() {
609
- return this.filename.replace(`.${CODEMOD_CODE_SUFFIX}.${CODEMOD_EXTENSION}`, "").replace(`.${CODEMOD_JSON_SUFFIX}.${CODEMOD_EXTENSION}`, "").replaceAll("-", " ");
717
+ this.uid = this.createUID();
718
+ }
719
+ createUID() {
720
+ const name = this.format({ stripExtension: true, stripKind: true, stripHyphens: false });
721
+ const kind = this.kind;
722
+ const version2 = this.version.raw;
723
+ return `${version2}-${name}-${kind}`;
724
+ }
725
+ format(options) {
726
+ const { stripExtension = true, stripKind = true, stripHyphens = true } = options ?? {};
727
+ let formatted = this.filename;
728
+ if (stripExtension) {
729
+ formatted = formatted.replace(new RegExp(`\\.${CODEMOD_EXTENSION}$`, "i"), "");
730
+ }
731
+ if (stripKind) {
732
+ formatted = formatted.replace(`.${CODEMOD_CODE_SUFFIX}`, "").replace(`.${CODEMOD_JSON_SUFFIX}`, "");
733
+ }
734
+ if (stripHyphens) {
735
+ formatted = formatted.replaceAll("-", " ");
736
+ }
737
+ return formatted;
610
738
  }
611
739
  }
612
740
  const codemodFactory = (options) => new Codemod(options);
@@ -615,6 +743,20 @@ const index$7 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
615
743
  codemodFactory,
616
744
  constants: constants$2
617
745
  }, Symbol.toStringTag, { value: "Module" }));
746
+ const INTERNAL_CODEMODS_DIRECTORY = path$1.join(
747
+ __dirname,
748
+ // upgrade/dist
749
+ "..",
750
+ // upgrade
751
+ "resources",
752
+ // upgrade/resources
753
+ "codemods"
754
+ // upgrade/resources/codemods
755
+ );
756
+ const constants$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
757
+ __proto__: null,
758
+ INTERNAL_CODEMODS_DIRECTORY
759
+ }, Symbol.toStringTag, { value: "Module" }));
618
760
  class CodemodRepository {
619
761
  groups;
620
762
  versions;
@@ -633,23 +775,48 @@ class CodemodRepository {
633
775
  count(version2) {
634
776
  return this.findByVersion(version2).length;
635
777
  }
636
- countRange(range) {
637
- return this.findByRange(range).length;
638
- }
639
- exists(version2) {
778
+ versionExists(version2) {
640
779
  return version2.raw in this.groups;
641
780
  }
642
- findByRange(range) {
781
+ has(uid) {
782
+ const result = this.find({ uids: [uid] });
783
+ if (result.length !== 1) {
784
+ return false;
785
+ }
786
+ const { codemods } = result[0];
787
+ return codemods.length === 1 && codemods[0].uid === uid;
788
+ }
789
+ find(q) {
643
790
  const entries = Object.entries(this.groups);
644
- return entries.filter(([version2]) => range.test(version2)).map(([version2, codemods2]) => ({
791
+ return entries.filter(maybeFilterByRange).map(([version2, codemods]) => ({
645
792
  version: semVerFactory(version2),
646
- codemods: codemods2
647
- }));
793
+ // Filter by UID if provided in the query
794
+ codemods: codemods.filter(maybeFilterByUIDs)
795
+ })).filter(({ codemods }) => codemods.length > 0);
796
+ function maybeFilterByRange([version2]) {
797
+ if (!isRangeInstance(q.range)) {
798
+ return true;
799
+ }
800
+ return q.range.test(version2);
801
+ }
802
+ function maybeFilterByUIDs(codemod) {
803
+ if (q.uids === void 0) {
804
+ return true;
805
+ }
806
+ return q.uids.includes(codemod.uid);
807
+ }
648
808
  }
649
809
  findByVersion(version2) {
650
810
  const literalVersion = version2.raw;
651
- const codemods2 = this.groups[literalVersion];
652
- return codemods2 ?? [];
811
+ const codemods = this.groups[literalVersion];
812
+ return codemods ?? [];
813
+ }
814
+ findAll() {
815
+ const entries = Object.entries(this.groups);
816
+ return entries.map(([version2, codemods]) => ({
817
+ version: semVerFactory(version2),
818
+ codemods
819
+ }));
653
820
  }
654
821
  refreshAvailableVersions() {
655
822
  this.versions = fse.readdirSync(this.cwd).filter((filename) => fse.statSync(path$1.join(this.cwd, filename)).isDirectory()).filter((filename) => semver.valid(filename) !== null).map((version2) => semVerFactory(version2)).sort(semver.compare);
@@ -680,18 +847,9 @@ const parseCodemodKindFromFilename = (filename) => {
680
847
  assert(CODEMOD_ALLOWED_SUFFIXES.includes(kind));
681
848
  return kind;
682
849
  };
683
- const codemodRepositoryFactory = (cwd) => new CodemodRepository(cwd);
684
- const INTERNAL_CODEMODS_DIRECTORY = path$1.join(
685
- __dirname,
686
- "..",
687
- "..",
688
- "resources",
689
- "codemods"
690
- );
691
- const constants$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
692
- __proto__: null,
693
- INTERNAL_CODEMODS_DIRECTORY
694
- }, Symbol.toStringTag, { value: "Module" }));
850
+ const codemodRepositoryFactory = (cwd = INTERNAL_CODEMODS_DIRECTORY) => {
851
+ return new CodemodRepository(cwd);
852
+ };
695
853
  const index$6 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
696
854
  __proto__: null,
697
855
  codemodRepositoryFactory,
@@ -726,34 +884,59 @@ class CodemodRunner {
726
884
  this.isDry = enabled;
727
885
  return this;
728
886
  }
729
- async run(codemodsDirectory) {
887
+ createRepository(codemodsDirectory) {
730
888
  const repository = codemodRepositoryFactory(
731
889
  codemodsDirectory ?? INTERNAL_CODEMODS_DIRECTORY
732
890
  );
733
891
  repository.refresh();
734
- const allVersionedCodemods = repository.findByRange(this.range);
735
- const versionedCodemods = this.selectCodemodsCallback ? await this.selectCodemodsCallback(allVersionedCodemods) : allVersionedCodemods;
736
- const hasCodemodsToRun = versionedCodemods.length > 0;
737
- if (!hasCodemodsToRun) {
738
- this.logger?.debug(`Found no codemods to run for ${versionRange(this.range)}`);
739
- return successReport$1();
892
+ return repository;
893
+ }
894
+ async safeRunAndReport(codemods) {
895
+ if (this.isDry) {
896
+ this.logger?.warn?.(
897
+ "Running the codemods in dry mode. No files will be modified during the process."
898
+ );
740
899
  }
741
- this.logger?.debug(
742
- `Found codemods for ${highlight(
743
- versionedCodemods.length
744
- )} version(s) using ${versionRange(this.range)}`
745
- );
746
- versionedCodemods.forEach(
747
- ({ version: version$1, codemods: codemods22 }) => this.logger?.debug(`- ${version(version$1)} (${codemods22.length})`)
748
- );
749
- const codemods2 = versionedCodemods.map(({ codemods: codemods22 }) => codemods22).flat();
750
900
  try {
751
- const reports$1 = await this.project.runCodemods(codemods2, { dry: this.isDry });
752
- this.logger?.raw(reports(reports$1));
901
+ const reports$1 = await this.project.runCodemods(codemods, { dry: this.isDry });
902
+ this.logger?.raw?.(reports(reports$1));
903
+ if (!this.isDry) {
904
+ const nbAffectedTotal = reports$1.flatMap((report) => report.report.ok).reduce((acc, nb) => acc + nb, 0);
905
+ this.logger?.debug?.(
906
+ `Successfully ran ${highlight(codemods.length)} codemod(s), ${highlight(nbAffectedTotal)} change(s) have been detected`
907
+ );
908
+ }
909
+ return successReport$1();
753
910
  } catch (e) {
754
911
  return erroredReport$1(unknownToError(e));
755
912
  }
756
- return successReport$1();
913
+ }
914
+ async runByUID(uid, codemodsDirectory) {
915
+ const repository = this.createRepository(codemodsDirectory);
916
+ if (!repository.has(uid)) {
917
+ throw new Error(`Unknown codemod UID provided: ${uid}`);
918
+ }
919
+ const codemods = repository.find({ uids: [uid] }).flatMap(({ codemods: codemods2 }) => codemods2);
920
+ return this.safeRunAndReport(codemods);
921
+ }
922
+ async run(codemodsDirectory) {
923
+ const repository = this.createRepository(codemodsDirectory);
924
+ const codemodsInRange = repository.find({ range: this.range });
925
+ const selectedCodemods = this.selectCodemodsCallback ? await this.selectCodemodsCallback(codemodsInRange) : codemodsInRange;
926
+ if (selectedCodemods.length === 0) {
927
+ this.logger?.debug?.(`Found no codemods to run for ${versionRange(this.range)}`);
928
+ return successReport$1();
929
+ }
930
+ const codemods = selectedCodemods.flatMap(({ codemods: codemods2 }) => codemods2);
931
+ const codemodsByVersion = groupBy("version", codemods);
932
+ const fRange = versionRange(this.range);
933
+ this.logger?.debug?.(
934
+ `Found ${highlight(codemods.length)} codemods for ${highlight(size(codemodsByVersion))} version(s) using ${fRange}`
935
+ );
936
+ for (const [version$1, codemods2] of Object.entries(codemodsByVersion)) {
937
+ this.logger?.debug?.(`- ${version(semVerFactory(version$1))} (${codemods2.length})`);
938
+ }
939
+ return this.safeRunAndReport(codemods);
757
940
  }
758
941
  }
759
942
  const codemodRunnerFactory = (project, range) => {
@@ -792,7 +975,7 @@ class Upgrader {
792
975
  this.codemodsTarget = semVerFactory(
793
976
  `${this.target.major}.${this.target.minor}.${this.target.patch}`
794
977
  );
795
- this.logger?.debug(
978
+ this.logger?.debug?.(
796
979
  `The codemods target has been synced with the upgrade target. The codemod runner will now look for ${version(
797
980
  this.codemodsTarget
798
981
  )}`
@@ -801,7 +984,7 @@ class Upgrader {
801
984
  }
802
985
  overrideCodemodsTarget(target) {
803
986
  this.codemodsTarget = target;
804
- this.logger?.debug(
987
+ this.logger?.debug?.(
805
988
  `Overriding the codemods target. The codemod runner will now look for ${version(target)}`
806
989
  );
807
990
  return this;
@@ -821,38 +1004,40 @@ class Upgrader {
821
1004
  addRequirement(requirement) {
822
1005
  this.requirements.push(requirement);
823
1006
  const fRequired = requirement.isRequired ? "(required)" : "(optional)";
824
- this.logger?.debug(
1007
+ this.logger?.debug?.(
825
1008
  `Added a new requirement to the upgrade: ${highlight(requirement.name)} ${fRequired}`
826
1009
  );
827
1010
  return this;
828
1011
  }
829
1012
  async upgrade() {
830
- this.logger?.info(
1013
+ this.logger?.info?.(
831
1014
  `Upgrading from ${version(this.project.strapiVersion)} to ${version(this.target)}`
832
1015
  );
833
1016
  if (this.isDry) {
834
- this.logger?.warn(
1017
+ this.logger?.warn?.(
835
1018
  "Running the upgrade in dry mode. No files will be modified during the process."
836
1019
  );
837
1020
  }
838
1021
  const range = rangeFromVersions(this.project.strapiVersion, this.target);
839
1022
  const codemodsRange = rangeFromVersions(this.project.strapiVersion, this.codemodsTarget);
840
1023
  const npmVersionsMatches = this.npmPackage?.findVersionsInRange(range) ?? [];
841
- this.logger?.debug(
1024
+ this.logger?.debug?.(
842
1025
  `Found ${highlight(npmVersionsMatches.length)} versions satisfying ${versionRange(range)}`
843
1026
  );
844
1027
  try {
845
- this.logger?.info(upgradeStep("Checking requirement", [1, 4]));
1028
+ this.logger?.info?.(upgradeStep("Checking requirement", [1, 4]));
846
1029
  await this.checkRequirements(this.requirements, {
847
1030
  npmVersionsMatches,
848
1031
  project: this.project,
849
1032
  target: this.target
850
1033
  });
851
- this.logger?.info(upgradeStep("Applying the latest code modifications", [2, 4]));
1034
+ this.logger?.info?.(upgradeStep("Applying the latest code modifications", [2, 4]));
852
1035
  await this.runCodemods(codemodsRange);
853
- this.logger?.info(upgradeStep("Upgrading Strapi dependencies", [3, 4]));
1036
+ this.logger?.debug?.("Refreshing project information...");
1037
+ this.project.refresh();
1038
+ this.logger?.info?.(upgradeStep("Upgrading Strapi dependencies", [3, 4]));
854
1039
  await this.updateDependencies();
855
- this.logger?.info(upgradeStep("Installing dependencies", [4, 4]));
1040
+ this.logger?.info?.(upgradeStep("Installing dependencies", [4, 4]));
856
1041
  await this.installDependencies();
857
1042
  } catch (e) {
858
1043
  return erroredReport(unknownToError(e));
@@ -885,7 +1070,7 @@ class Upgrader {
885
1070
  if (requirement.isRequired) {
886
1071
  throw error;
887
1072
  }
888
- this.logger?.warn(warningMessage);
1073
+ this.logger?.warn?.(warningMessage);
889
1074
  const response = await this.confirmationCallback?.(confirmationMessage);
890
1075
  if (!response) {
891
1076
  throw error;
@@ -896,9 +1081,11 @@ class Upgrader {
896
1081
  const json = createJSONTransformAPI(packageJSON);
897
1082
  const dependencies = json.get("dependencies", {});
898
1083
  const strapiDependencies = this.getScopedStrapiDependencies(dependencies);
899
- this.logger?.debug(`Found ${highlight(strapiDependencies.length)} dependency(ies) to update`);
1084
+ this.logger?.debug?.(
1085
+ `Found ${highlight(strapiDependencies.length)} dependency(ies) to update`
1086
+ );
900
1087
  strapiDependencies.forEach(
901
- (dependency) => this.logger?.debug(`- ${dependency[0]} (${dependency[1]} -> ${this.target})`)
1088
+ (dependency) => this.logger?.debug?.(`- ${dependency[0]} (${dependency[1]} -> ${this.target})`)
902
1089
  );
903
1090
  if (strapiDependencies.length === 0) {
904
1091
  return;
@@ -906,7 +1093,7 @@ class Upgrader {
906
1093
  strapiDependencies.forEach(([name]) => json.set(`dependencies.${name}`, this.target.raw));
907
1094
  const updatedPackageJSON = json.root();
908
1095
  if (this.isDry) {
909
- this.logger?.debug(`Skipping dependencies update (${chalk.italic("dry mode")})`);
1096
+ this.logger?.debug?.(`Skipping dependencies update (${chalk.italic("dry mode")})`);
910
1097
  return;
911
1098
  }
912
1099
  await saveJSON(packageJSONPath, updatedPackageJSON);
@@ -926,9 +1113,9 @@ class Upgrader {
926
1113
  async installDependencies() {
927
1114
  const projectPath = this.project.cwd;
928
1115
  const packageManagerName = await packageManager.getPreferred(projectPath);
929
- this.logger?.debug(`Using ${highlight(packageManagerName)} as package manager`);
1116
+ this.logger?.debug?.(`Using ${highlight(packageManagerName)} as package manager`);
930
1117
  if (this.isDry) {
931
- this.logger?.debug(`Skipping dependencies installation (${chalk.italic("dry mode")}`);
1118
+ this.logger?.debug?.(`Skipping dependencies installation (${chalk.italic("dry mode")}`);
932
1119
  return;
933
1120
  }
934
1121
  await packageManager.installDependencies(projectPath, packageManagerName, {
@@ -1027,6 +1214,11 @@ const upgrade = async (options) => {
1027
1214
  const { logger, codemodsTarget } = options;
1028
1215
  const cwd = path$1.resolve(options.cwd ?? process.cwd());
1029
1216
  const project = projectFactory(cwd);
1217
+ if (!isApplicationProject(project)) {
1218
+ throw new Error(
1219
+ `The "${options.target}" upgrade can only be run on a Strapi project; for plugins, please use "codemods".`
1220
+ );
1221
+ }
1030
1222
  const npmPackage = npmPackageFactory(STRAPI_PACKAGE_NAME);
1031
1223
  await npmPackage.refresh();
1032
1224
  const upgrader = upgraderFactory(project, options.target, npmPackage).dry(options.dry ?? false).onConfirm(options.confirm ?? null).setLogger(logger);
@@ -1044,20 +1236,7 @@ const upgrade = async (options) => {
1044
1236
  timer.stop();
1045
1237
  logger.info(`Completed in ${durationMs(timer.elapsedMs)}`);
1046
1238
  };
1047
- const codemods = async (options) => {
1048
- const timer = timerFactory();
1049
- const { logger } = options;
1050
- const cwd = path$1.resolve(options.cwd ?? process.cwd());
1051
- const project = projectFactory(cwd);
1052
- const range = getRangeFromTarget(project.strapiVersion, options.target);
1053
- const codemodRunner = codemodRunnerFactory(project, range).dry(options.dry ?? false).onSelectCodemods(options.selectCodemods ?? null).setLogger(logger);
1054
- const executionReport = await codemodRunner.run();
1055
- if (!executionReport.success) {
1056
- throw executionReport.error;
1057
- }
1058
- timer.stop();
1059
- logger.info(`Completed in ${timer.elapsedMs}`);
1060
- };
1239
+ const resolvePath = (cwd) => path$1.resolve(cwd ?? process.cwd());
1061
1240
  const getRangeFromTarget = (currentVersion, target) => {
1062
1241
  if (isSemverInstance(target)) {
1063
1242
  return rangeFactory(target);
@@ -1074,9 +1253,60 @@ const getRangeFromTarget = (currentVersion, target) => {
1074
1253
  throw new Error(`Invalid target set: ${target}`);
1075
1254
  }
1076
1255
  };
1256
+ const findRangeFromTarget = (project, target) => {
1257
+ if (isRangeInstance(target)) {
1258
+ return target;
1259
+ }
1260
+ if (isApplicationProject(project)) {
1261
+ return getRangeFromTarget(project.strapiVersion, target);
1262
+ }
1263
+ return rangeFactory("*");
1264
+ };
1265
+ const runCodemods = async (options) => {
1266
+ const timer = timerFactory();
1267
+ const { logger, uid } = options;
1268
+ const cwd = resolvePath(options.cwd);
1269
+ const project = projectFactory(cwd);
1270
+ const range = findRangeFromTarget(project, options.target);
1271
+ logger.debug(`Project: ${projectType(project.type)} found in ${path(cwd)}`);
1272
+ logger.debug(`Range: set to ${versionRange(range)}`);
1273
+ const codemodRunner = codemodRunnerFactory(project, range).dry(options.dry ?? false).onSelectCodemods(options.selectCodemods ?? null).setLogger(logger);
1274
+ let report;
1275
+ if (uid !== void 0) {
1276
+ logger.debug(`Running a single codemod: ${codemodUID(uid)}`);
1277
+ report = await codemodRunner.runByUID(uid);
1278
+ } else {
1279
+ report = await codemodRunner.run();
1280
+ }
1281
+ if (!report.success) {
1282
+ throw report.error;
1283
+ }
1284
+ timer.stop();
1285
+ logger.info(`Completed in ${timer.elapsedMs}`);
1286
+ };
1287
+ const listCodemods = async (options) => {
1288
+ const { logger, target } = options;
1289
+ const cwd = resolvePath(options.cwd);
1290
+ const project = projectFactory(cwd);
1291
+ const range = findRangeFromTarget(project, target);
1292
+ logger.debug(`Project: ${projectType(project.type)} found in ${path(cwd)}`);
1293
+ logger.debug(`Range: set to ${versionRange(range)}`);
1294
+ const repo = codemodRepositoryFactory();
1295
+ repo.refresh();
1296
+ const groups = repo.find({ range });
1297
+ const codemods = groups.flatMap((collection) => collection.codemods);
1298
+ logger.debug(`Found ${highlight(codemods.length)} codemods`);
1299
+ if (codemods.length === 0) {
1300
+ logger.info(`Found no codemods matching ${versionRange(range)}`);
1301
+ return;
1302
+ }
1303
+ const fCodemods = codemodList(codemods);
1304
+ logger.raw(fCodemods);
1305
+ };
1077
1306
  const index$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1078
1307
  __proto__: null,
1079
- codemods,
1308
+ listCodemods,
1309
+ runCodemods,
1080
1310
  upgrade
1081
1311
  }, Symbol.toStringTag, { value: "Module" }));
1082
1312
  class Logger {