rsnext/packages/next-codemod/lib/cra-to-next/index-to-component.ts
JJ Kasper dde9ad46ad
Add experimental cra-to-next transform in codemod cli (#24969)
Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2021-06-09 16:51:56 +02:00

101 lines
2.6 KiB
TypeScript

import { API, FileInfo, JSXElement, Options } from 'jscodeshift'
export const indexContext = {
multipleRenderRoots: false,
nestedRender: false,
}
export default function transformer(
file: FileInfo,
api: API,
options: Options
) {
const j = api.jscodeshift
const root = j(file.source)
let hasModifications = false
let foundReactRender = 0
let hasRenderImport = false
let defaultReactDomImport: string | undefined
root.find(j.ImportDeclaration).forEach((path) => {
if (path.node.source.value === 'react-dom') {
return path.node.specifiers.forEach((specifier) => {
if (specifier.local.name === 'render') {
hasRenderImport = true
}
if (specifier.type === 'ImportDefaultSpecifier') {
defaultReactDomImport = specifier.local.name
}
})
}
return false
})
root
.find(j.CallExpression)
.filter((path) => {
const { node } = path
let found = false
if (
defaultReactDomImport &&
node.callee.type === 'MemberExpression' &&
(node.callee.object as any).name === defaultReactDomImport &&
(node.callee.property as any).name === 'render'
) {
found = true
}
if (hasRenderImport && (node.callee as any).name === 'render') {
found = true
}
if (found) {
foundReactRender++
hasModifications = true
if (!Array.isArray(path.parentPath?.parentPath?.value)) {
indexContext.nestedRender = true
return false
}
const newNode = j.exportDefaultDeclaration(
j.functionDeclaration(
j.identifier('NextIndexWrapper'),
[],
j.blockStatement([
j.returnStatement(
// TODO: remove React.StrictMode wrapper and use
// next.config.js option instead?
path.node.arguments.find(
(a) => a.type === 'JSXElement'
) as JSXElement
),
])
)
)
path.parentPath.insertBefore(newNode)
return true
}
return false
})
.remove()
indexContext.multipleRenderRoots = foundReactRender > 1
hasModifications =
hasModifications &&
!indexContext.nestedRender &&
!indexContext.multipleRenderRoots
// TODO: move function passed to reportWebVitals if present to
// _app reportWebVitals and massage values to expected shape
// root.find(j.CallExpression, {
// callee: {
// name: 'reportWebVitals'
// }
// }).remove()
return hasModifications ? root.toSource(options) : null
}