From 1bc31e746930dde08f200d0c3015b97671af6090 Mon Sep 17 00:00:00 2001 From: Jiwon Choi Date: Sat, 12 Oct 2024 05:11:57 +0900 Subject: [PATCH] chore(next-codemod): suggest pre-release codemods by their "stable" version (#71158) ### What? Suggest pre-released codemods by their "stable" version. ### Why? It is because if we suggest by the version range `(installed ~ target)`, pre-released codemods for the target version are not suggested when upgrading. Let's say we have a codemod for `v15.0.0-canary.x`, and we're upgrading from `v15.x` -> `v15.x`. Our initial version is higher than the codemod's version, so the codemod **will not be** suggested. This is not ideal as the codemods for pre-releases are also targeting the major version. Also, when the user attempts to run the upgrade command twice, and have installed the target version, the behavior must be **idempotent** and suggest the codemods including the pre-releases of the target version. https://github.com/user-attachments/assets/db1ab0c0-fc4e-4170-bc91-b0a096b04cef --- packages/next-codemod/bin/upgrade.ts | 27 ++++++++++-- packages/next-codemod/lib/utils.ts | 22 +++++----- packages/next-codemod/package.json | 7 ++-- pnpm-lock.yaml | 61 +++++++--------------------- 4 files changed, 54 insertions(+), 63 deletions(-) diff --git a/packages/next-codemod/bin/upgrade.ts b/packages/next-codemod/bin/upgrade.ts index eecd95793eea5..0cb2db5066323 100644 --- a/packages/next-codemod/bin/upgrade.ts +++ b/packages/next-codemod/bin/upgrade.ts @@ -1,8 +1,9 @@ import prompts from 'prompts' import fs from 'fs' +import semver from 'semver' +import compareVersions from 'semver/functions/compare' import { execSync } from 'child_process' import path from 'path' -import { compareVersions } from 'compare-versions' import pc from 'picocolors' import { getPkgManager, installPackages } from '../lib/handle-package' import { runTransform } from './transform' @@ -306,9 +307,29 @@ async function suggestCodemods( initialNextVersion: string, targetNextVersion: string ): Promise { + // Here we suggest pre-released codemods by their "stable" version. + // It is because if we suggest by the version range (installed ~ target), + // pre-released codemods for the target version are not suggested when upgrading. + + // Let's say we have a codemod for v15.0.0-canary.x, and we're upgrading from + // v15.x -> v15.x. Our initial version is higher than the codemod's version, + // so the codemod will not be suggested. + + // This is not ideal as the codemods for pre-releases are also targeting the major version. + // Also, when the user attempts to run the upgrade command twice, and have installed the + // target version, the behavior must be idempotent and suggest the codemods including the + // pre-releases of the target version. + const initial = semver.parse(initialNextVersion) const initialVersionIndex = TRANSFORMER_INQUIRER_CHOICES.findIndex( - (versionCodemods) => - compareVersions(versionCodemods.version, initialNextVersion) > 0 + (versionCodemods) => { + const codemod = semver.parse(versionCodemods.version) + return ( + compareVersions( + `${codemod.major}.${codemod.minor}.${codemod.patch}`, + `${initial.major}.${initial.minor}.${initial.patch}` + ) >= 0 + ) + } ) if (initialVersionIndex === -1) { return [] diff --git a/packages/next-codemod/lib/utils.ts b/packages/next-codemod/lib/utils.ts index c895e5315dd0d..27bb5656ffa30 100644 --- a/packages/next-codemod/lib/utils.ts +++ b/packages/next-codemod/lib/utils.ts @@ -40,64 +40,64 @@ export const TRANSFORMER_INQUIRER_CHOICES = [ title: 'Transform the deprecated automatically injected url property on top level pages to using withRouter', value: 'url-to-withrouter', - version: '6.0', + version: '6.0.0', }, { title: 'Transforms the withAmp HOC into Next.js 9 page configuration', value: 'withamp-to-config', - version: '8.0', + version: '8.0.0', }, { title: 'Transforms anonymous components into named components to make sure they work with Fast Refresh', value: 'name-default-component', - version: '9.0', + version: '9.0.0', }, { title: 'Transforms files that do not import `React` to include the import in order for the new React JSX transform', value: 'add-missing-react-import', - version: '10.0', + version: '10.0.0', }, { title: 'Automatically migrates a Create React App project to Next.js (experimental)', value: 'cra-to-next', - version: '11.0', + version: '11.0.0', }, { title: 'Ensures your usage is backwards compatible', value: 'new-link', - version: '13.0', + version: '13.0.0', }, { title: 'Dangerously migrates from `next/legacy/image` to the new `next/image` by adding inline styles and removing unused props (experimental)', value: 'next-image-experimental', - version: '13.0', + version: '13.0.0', }, { title: 'Safely migrate Next.js 10, 11, 12 applications importing `next/image` to the renamed `next/legacy/image` import in Next.js 13', value: 'next-image-to-legacy-image', - version: '13.0', + version: '13.0.0', }, { title: 'Uninstall `@next/font` and transform imports to `next/font`', value: 'built-in-next-font', - version: '13.2', + version: '13.2.0', }, { title: 'Migrates certain viewport related metadata from the `metadata` export to a new `viewport` export', value: 'metadata-to-viewport-export', - version: '14.0', + version: '14.0.0', }, { title: 'Transforms imports from `next/server` to `next/og` for usage of Dynamic OG Image Generation', value: 'next-og-import', - version: '14.0', + version: '14.0.0', }, { title: diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index c451752cd04a2..025f2dd9c467e 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -10,14 +10,14 @@ "dependencies": { "cheerio": "1.0.0-rc.9", "commander": "12.1.0", - "compare-versions": "6.1.1", "execa": "4.0.3", "find-up": "4.1.0", "globby": "11.0.1", "is-git-clean": "1.1.0", "jscodeshift": "17.0.0", "picocolors": "1.0.0", - "prompts": "2.4.2" + "prompts": "2.4.2", + "semver": "7.6.3" }, "files": [ "transforms/*.js", @@ -36,6 +36,7 @@ "devDependencies": { "@types/find-up": "4.0.0", "@types/jscodeshift": "0.11.0", - "@types/prompts": "2.4.2" + "@types/prompts": "2.4.2", + "@types/semver": "7.3.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bea88e1ed4576..b355e795cb2de 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1511,9 +1511,6 @@ importers: commander: specifier: 12.1.0 version: 12.1.0 - compare-versions: - specifier: 6.1.1 - version: 6.1.1 execa: specifier: 4.0.3 version: 4.0.3 @@ -1535,6 +1532,9 @@ importers: prompts: specifier: 2.4.2 version: 2.4.2 + semver: + specifier: 7.6.3 + version: 7.6.3 devDependencies: '@types/find-up': specifier: 4.0.0 @@ -1545,6 +1545,9 @@ importers: '@types/prompts': specifier: 2.4.2 version: 2.4.2 + '@types/semver': + specifier: 7.3.1 + version: 7.3.1 packages/next-env: devDependencies: @@ -6596,9 +6599,6 @@ packages: compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} - compare-versions@6.1.1: - resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} - component-emitter@1.3.0: resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} @@ -7955,11 +7955,13 @@ packages: eslint@7.24.0: resolution: {integrity: sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==} engines: {node: ^10.12.0 || >=12.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.56.0: resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@9.7.0: @@ -13271,10 +13273,6 @@ packages: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} hasBin: true - semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -13289,21 +13287,6 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.3.8: - resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} - engines: {node: '>=10'} - hasBin: true - - semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - - semver@7.6.2: - resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} - engines: {node: '>=10'} - hasBin: true - semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} @@ -19060,7 +19043,7 @@ snapshots: node-fetch: 2.7.0(encoding@0.1.13) p-map: 4.0.0 query-registry: 2.6.0(encoding@0.1.13) - semver: 7.5.4 + semver: 7.6.3 superstruct: 0.15.5 text-table: 0.2.0 ws: 7.5.3 @@ -19949,7 +19932,7 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.6.2 + semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.5.3) optionalDependencies: typescript: 5.5.3 @@ -21417,8 +21400,6 @@ snapshots: array-ify: 1.0.0 dot-prop: 5.3.0 - compare-versions@6.1.1: {} - component-emitter@1.3.0: {} compressible@2.0.18: @@ -21459,7 +21440,7 @@ snapshots: dot-prop: 9.0.0 env-paths: 3.0.0 json-schema-typed: 8.0.1 - semver: 7.6.2 + semver: 7.6.3 uint8array-extras: 1.1.0 conf@5.0.0: @@ -22242,7 +22223,7 @@ snapshots: path-to-regexp: 0.1.7 protobufjs: 7.2.4 retry: 0.13.1 - semver: 7.5.4 + semver: 7.6.3 debounce-fn@6.0.0: dependencies: @@ -23032,7 +23013,7 @@ snapshots: eslint: 8.56.0 esquery: 1.5.0 is-builtin-module: 3.2.1 - semver: 7.5.4 + semver: 7.6.3 spdx-expression-parse: 4.0.0 transitivePeerDependencies: - supports-color @@ -23055,7 +23036,7 @@ snapshots: minimatch: 3.1.2 object.entries: 1.1.6 object.fromentries: 2.0.6 - semver: 6.3.0 + semver: 6.3.1 eslint-plugin-react-hooks@4.5.0(eslint@8.56.0): dependencies: @@ -25936,7 +25917,7 @@ snapshots: jws: 3.2.2 lodash: 4.17.21 ms: 2.1.3 - semver: 7.3.8 + semver: 7.6.3 jsprim@1.4.1: dependencies: @@ -29857,8 +29838,6 @@ snapshots: semver@5.7.1: {} - semver@6.3.0: {} - semver@6.3.1: {} semver@7.3.2: {} @@ -29867,16 +29846,6 @@ snapshots: dependencies: lru-cache: 6.0.0 - semver@7.3.8: - dependencies: - lru-cache: 6.0.0 - - semver@7.5.4: - dependencies: - lru-cache: 6.0.0 - - semver@7.6.2: {} - semver@7.6.3: {} send@0.17.1: