diff --git a/packages/next-codemod/lib/cra-to-next/global-css-transform.ts b/packages/next-codemod/lib/cra-to-next/global-css-transform.ts index 46b539b1ff9e8..f3d209ced9c8c 100644 --- a/packages/next-codemod/lib/cra-to-next/global-css-transform.ts +++ b/packages/next-codemod/lib/cra-to-next/global-css-transform.ts @@ -1,5 +1,6 @@ import nodePath from 'path' import type { API, FileInfo, Options } from 'jscodeshift' +import { createParserFromPath } from '../parser' export const globalCssContext = { cssImports: new Set(), @@ -9,10 +10,10 @@ const globalStylesRegex = /(? plugin !== 'typescript'), + ['typescript', { dts: true }], + ], +} + +function createParserFromPath(filePath: string): j.JSCodeshift { + const isDeclarationFile = /\.d\.(m|c)?ts$/.test(filePath) + if (isDeclarationFile) { + return j.withParser(babylonParse(dtsOptions)) + } + + // jsx is allowed in .js files, feed them into the tsx parser. + // tsx parser :.js, .jsx, .tsx + // ts parser: .ts, .mts, .cts + const isTsFile = /\.(m|c)?.ts$/.test(filePath) + return isTsFile ? j.withParser('ts') : j.withParser('tsx') +} + +export { createParserFromPath } diff --git a/packages/next-codemod/lib/run-jscodeshift.ts b/packages/next-codemod/lib/run-jscodeshift.ts index a02c376b5c8d7..6f25f956ada24 100644 --- a/packages/next-codemod/lib/run-jscodeshift.ts +++ b/packages/next-codemod/lib/run-jscodeshift.ts @@ -13,10 +13,6 @@ export default function runJscodeshift( '**/node_modules/**', '**/.next/**', '**/build/**', - // type files - '**/*.d.ts', - '**/*.d.cts', - '**/*.d.mts', // test files '**/*.test.*', '**/*.spec.*', diff --git a/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-apis/origin-name-03-env.d.input.ts b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-apis/origin-name-03-env.d.input.ts new file mode 100644 index 0000000000000..4106031e5d3a4 --- /dev/null +++ b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-apis/origin-name-03-env.d.input.ts @@ -0,0 +1,5 @@ +import type { cookies } from 'next/headers' + +export { + cookies +} \ No newline at end of file diff --git a/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-apis/origin-name-03-env.d.output.ts b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-apis/origin-name-03-env.d.output.ts new file mode 100644 index 0000000000000..4106031e5d3a4 --- /dev/null +++ b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-apis/origin-name-03-env.d.output.ts @@ -0,0 +1,5 @@ +import type { cookies } from 'next/headers' + +export { + cookies +} \ No newline at end of file diff --git a/packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block.input.js b/packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block-01.input.js similarity index 100% rename from packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block.input.js rename to packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block-01.input.js diff --git a/packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block.output.js b/packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block-01.output.js similarity index 100% rename from packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block.output.js rename to packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block-01.output.js diff --git a/packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block-02.input.tsx b/packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block-02.input.tsx new file mode 100644 index 0000000000000..71ea481c5fe36 --- /dev/null +++ b/packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block-02.input.tsx @@ -0,0 +1,8 @@ +import type { JSX } from 'react' +import dynamic from 'next/dynamic' + +const DynamicComponent = dynamic( + () => import('./component').then(mod => { + return mod.default; + }) +) diff --git a/packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block-02.output.tsx b/packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block-02.output.tsx new file mode 100644 index 0000000000000..ee12603d4f4c6 --- /dev/null +++ b/packages/next-codemod/transforms/__testfixtures__/next-dynamic-access-named-export/access-named-export-block-02.output.tsx @@ -0,0 +1,10 @@ +import type { JSX } from 'react' +import dynamic from 'next/dynamic' + +const DynamicComponent = dynamic( + () => import('./component').then(mod => { + return { + default: mod.default + }; + }) +) diff --git a/packages/next-codemod/transforms/__tests__/next-dynamic-access-named-export.test.js b/packages/next-codemod/transforms/__tests__/next-dynamic-access-named-export.test.js index 82bee2d7d26a4..e45f6c6a61f70 100644 --- a/packages/next-codemod/transforms/__tests__/next-dynamic-access-named-export.test.js +++ b/packages/next-codemod/transforms/__tests__/next-dynamic-access-named-export.test.js @@ -7,11 +7,11 @@ const { join } = require('path') const fixtureDir = 'next-dynamic-access-named-export' const fixtureDirPath = join(__dirname, '..', '__testfixtures__', fixtureDir) const fixtures = readdirSync(fixtureDirPath) - .filter(file => file.endsWith('.input.js')) - .map(file => file.replace('.input.js', '')) + .filter(file => /\.input\.(js|tsx)$/.test(file)) - -for (const fixture of fixtures) { +for (const file of fixtures) { + const fixture = file.replace(/\.input\.(js|tsx)/, ''); + const isTsx = file.endsWith('.tsx') const prefix = `${fixtureDir}/${fixture}`; - defineTest(__dirname, fixtureDir, null, prefix, { parser: 'js' }); + defineTest(__dirname, fixtureDir, null, prefix, { parser: isTsx ? 'tsx' : 'babel' }); } diff --git a/packages/next-codemod/transforms/add-missing-react-import.ts b/packages/next-codemod/transforms/add-missing-react-import.ts index 5e6267ed736c1..bcfc8fe007e90 100644 --- a/packages/next-codemod/transforms/add-missing-react-import.ts +++ b/packages/next-codemod/transforms/add-missing-react-import.ts @@ -5,6 +5,7 @@ import type { JSCodeshift, Options, } from 'jscodeshift' +import { createParserFromPath } from '../lib/parser' function addReactImport(j: JSCodeshift, root: Collection) { // We create an import specifier, this is the value of an import, eg: @@ -49,10 +50,10 @@ function addReactImport(j: JSCodeshift, root: Collection) { export default function transformer( file: FileInfo, - api: API, + _api: API, options: Options ) { - const j = api.jscodeshift.withParser('tsx') + const j = createParserFromPath(file.path) const root = j(file.source) const hasReactImport = (r) => { diff --git a/packages/next-codemod/transforms/app-dir-runtime-config-experimental-edge.ts b/packages/next-codemod/transforms/app-dir-runtime-config-experimental-edge.ts index 0cc45cc55a209..818e14aace0f5 100644 --- a/packages/next-codemod/transforms/app-dir-runtime-config-experimental-edge.ts +++ b/packages/next-codemod/transforms/app-dir-runtime-config-experimental-edge.ts @@ -1,6 +1,7 @@ import type { API, FileInfo } from 'jscodeshift' +import { createParserFromPath } from '../lib/parser' -export default function transformer(file: FileInfo, api: API) { +export default function transformer(file: FileInfo, _api: API) { if ( process.env.NODE_ENV !== 'test' && !/[/\\]app[/\\].*?(page|layout|route)\.[^/\\]+$/.test(file.path) @@ -8,7 +9,7 @@ export default function transformer(file: FileInfo, api: API) { return file.source } - const j = api.jscodeshift.withParser('tsx') + const j = createParserFromPath(file.path) const root = j(file.source) const runtimeExport = root.find(j.ExportNamedDeclaration, { diff --git a/packages/next-codemod/transforms/built-in-next-font.ts b/packages/next-codemod/transforms/built-in-next-font.ts index 3fbcc56202cc0..e7ce6f3a0378e 100644 --- a/packages/next-codemod/transforms/built-in-next-font.ts +++ b/packages/next-codemod/transforms/built-in-next-font.ts @@ -1,11 +1,12 @@ import type { API, FileInfo, Options } from 'jscodeshift' +import { createParserFromPath } from '../lib/parser' export default function transformer( file: FileInfo, - api: API, + _api: API, options: Options ) { - const j = api.jscodeshift.withParser('tsx') + const j = createParserFromPath(file.path) const root = j(file.source) let hasChanges = false diff --git a/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-api.ts b/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-api.ts index c442ac4cc7785..b573cb2cabf98 100644 --- a/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-api.ts +++ b/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-api.ts @@ -11,6 +11,7 @@ import { insertCommentOnce, NEXTJS_ENTRY_FILES, } from './utils' +import { createParserFromPath } from '../../../lib/parser' const DYNAMIC_IMPORT_WARN_COMMENT = ` Next.js Dynamic Async API Codemod: The APIs under 'next/headers' are async now, need to be manually awaited. ` @@ -42,11 +43,11 @@ function findDynamicImportsAndComment(root: Collection, j: API['j']) { export function transformDynamicAPI( source: string, - api: API, + _api: API, filePath: string ) { const isEntryFile = NEXTJS_ENTRY_FILES.test(filePath) - const j = api.jscodeshift.withParser('tsx') + const j = createParserFromPath(filePath) const root = j(source) let modified = false diff --git a/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-prop.ts b/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-prop.ts index 5bb61d7bbf174..3366c554a04c9 100644 --- a/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-prop.ts +++ b/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-prop.ts @@ -21,6 +21,7 @@ import { getVariableDeclaratorId, NEXTJS_ENTRY_FILES, } from './utils' +import { createParserFromPath } from '../../../lib/parser' const PAGE_PROPS = 'props' @@ -348,7 +349,7 @@ function modifyTypes( export function transformDynamicProps( source: string, - api: API, + _api: API, filePath: string ) { const isEntryFile = NEXTJS_ENTRY_FILES.test(filePath) @@ -358,7 +359,7 @@ export function transformDynamicProps( let modified = false let modifiedPropArgument = false - const j = api.jscodeshift.withParser('tsx') + const j = createParserFromPath(filePath) const root = j(source) // Check if 'use' from 'react' needs to be imported let needsReactUseImport = false diff --git a/packages/next-codemod/transforms/metadata-to-viewport-export.ts b/packages/next-codemod/transforms/metadata-to-viewport-export.ts index f047b2c07d03f..202df7706e786 100644 --- a/packages/next-codemod/transforms/metadata-to-viewport-export.ts +++ b/packages/next-codemod/transforms/metadata-to-viewport-export.ts @@ -1,7 +1,8 @@ import type { API, FileInfo } from 'jscodeshift' +import { createParserFromPath } from '../lib/parser' -export default function transformer(file: FileInfo, api: API) { - const j = api.jscodeshift +export default function transformer(file: FileInfo, _api: API) { + const j = createParserFromPath(file.path) const root = j(file.source) // Find the metadata export diff --git a/packages/next-codemod/transforms/name-default-component.ts b/packages/next-codemod/transforms/name-default-component.ts index 6e02b73adfdc7..5f4fc46c1924b 100644 --- a/packages/next-codemod/transforms/name-default-component.ts +++ b/packages/next-codemod/transforms/name-default-component.ts @@ -8,6 +8,7 @@ import type { Options, } from 'jscodeshift' import { basename, extname } from 'path' +import { createParserFromPath } from '../lib/parser' const camelCase = (value: string): string => { const val = value.replace(/[-_\s.]+(.)?/g, (_match, chr) => @@ -21,10 +22,10 @@ const isValidIdentifier = (value: string): boolean => export default function transformer( file: FileInfo, - api: API, + _api: API, options: Options ) { - const j = api.jscodeshift.withParser('tsx') + const j = createParserFromPath(file.path) const root = j(file.source) let hasModifications: boolean diff --git a/packages/next-codemod/transforms/new-link.ts b/packages/next-codemod/transforms/new-link.ts index 56dc61e56bcd3..ef409c92c57dd 100644 --- a/packages/next-codemod/transforms/new-link.ts +++ b/packages/next-codemod/transforms/new-link.ts @@ -2,9 +2,10 @@ // x-ref: https://github.com/facebook/jscodeshift/issues/534 import type { API, FileInfo } from 'jscodeshift' +import { createParserFromPath } from '../lib/parser' -export default function transformer(file: FileInfo, api: API) { - const j = api.jscodeshift.withParser('tsx') +export default function transformer(file: FileInfo, _api: API) { + const j = createParserFromPath(file.path) const $j = j(file.source) diff --git a/packages/next-codemod/transforms/next-dynamic-access-named-export.ts b/packages/next-codemod/transforms/next-dynamic-access-named-export.ts index 0e96b15e3951b..f039e7b8731c2 100644 --- a/packages/next-codemod/transforms/next-dynamic-access-named-export.ts +++ b/packages/next-codemod/transforms/next-dynamic-access-named-export.ts @@ -1,7 +1,8 @@ import type { FileInfo, API, ImportDeclaration } from 'jscodeshift' +import { createParserFromPath } from '../lib/parser' -export default function transformer(file: FileInfo, api: API) { - const j = api.jscodeshift +export default function transformer(file: FileInfo, _api: API) { + const j = createParserFromPath(file.path) const root = j(file.source) // Find the import declaration for 'next/dynamic' diff --git a/packages/next-codemod/transforms/next-image-experimental.ts b/packages/next-codemod/transforms/next-image-experimental.ts index 19f1729d0a3e7..0809b46386885 100644 --- a/packages/next-codemod/transforms/next-image-experimental.ts +++ b/packages/next-codemod/transforms/next-image-experimental.ts @@ -9,6 +9,7 @@ import type { JSXAttribute, Options, } from 'jscodeshift' +import { createParserFromPath } from '../lib/parser' function findAndReplaceProps( j: JSCodeshift, @@ -255,10 +256,10 @@ function nextConfigTransformer( export default function transformer( file: FileInfo, - api: API, + _api: API, options: Options ) { - const j = api.jscodeshift.withParser('tsx') + const j = createParserFromPath(file.path) const root = j(file.source) const parsed = parse(file.path || '/') diff --git a/packages/next-codemod/transforms/next-image-to-legacy-image.ts b/packages/next-codemod/transforms/next-image-to-legacy-image.ts index 1453d594b9a90..7cedd19fbf73d 100644 --- a/packages/next-codemod/transforms/next-image-to-legacy-image.ts +++ b/packages/next-codemod/transforms/next-image-to-legacy-image.ts @@ -1,11 +1,12 @@ import type { API, FileInfo, Options } from 'jscodeshift' +import { createParserFromPath } from '../lib/parser' export default function transformer( file: FileInfo, - api: API, + _api: API, options: Options ) { - const j = api.jscodeshift.withParser('tsx') + const j = createParserFromPath(file.path) const root = j(file.source) // Before: import Image from "next/image" diff --git a/packages/next-codemod/transforms/next-og-import.ts b/packages/next-codemod/transforms/next-og-import.ts index 074fe4e625ad1..7d7bf8dd00c22 100644 --- a/packages/next-codemod/transforms/next-og-import.ts +++ b/packages/next-codemod/transforms/next-og-import.ts @@ -1,9 +1,10 @@ import type { API, FileInfo } from 'jscodeshift' +import { createParserFromPath } from '../lib/parser' const importToChange = 'ImageResponse' -export default function transformer(file: FileInfo, api: API) { - const j = api.jscodeshift +export default function transformer(file: FileInfo, _api: API) { + const j = createParserFromPath(file.path) // Find import declarations that match the pattern file.source = j(file.source) diff --git a/packages/next-codemod/transforms/next-request-geo-ip.ts b/packages/next-codemod/transforms/next-request-geo-ip.ts index 40d38138d3470..477e67c343d2c 100644 --- a/packages/next-codemod/transforms/next-request-geo-ip.ts +++ b/packages/next-codemod/transforms/next-request-geo-ip.ts @@ -8,6 +8,7 @@ import type { ImportSpecifier, Identifier, } from 'jscodeshift' +import { createParserFromPath } from '../lib/parser' const GEO = 'geo' const IP = 'ip' @@ -15,12 +16,12 @@ const GEOLOCATION = 'geolocation' const IP_ADDRESS = 'ipAddress' const GEO_TYPE = 'Geo' -export default function (fileInfo: FileInfo, api: API) { - const j = api.jscodeshift.withParser('tsx') - const root = j(fileInfo.source) +export default function (file: FileInfo, _api: API) { + const j = createParserFromPath(file.path) + const root = j(file.source) if (!root.length) { - return fileInfo.source + return file.source } const nextReqType = root @@ -97,7 +98,7 @@ export default function (fileInfo: FileInfo, api: API) { hasChangedIpType if (!needChanges) { - return fileInfo.source + return file.source } // Even if there was a change above, if there's an existing import,