Last active
October 7, 2024 08:44
-
-
Save walkerdb/08187fff6d2defee0891923c0b97c332 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This codemod migrates usage of default exports to named exports instead | |
See migrate-default-exports-to-named-exports.test.js for before/after examples. | |
*/ | |
export const parser = 'tsx'; | |
const generateNamedExportDeclaration = (jscodeshift, inlineDefaultExport, filePath) => { | |
const declarationType = inlineDefaultExport.node.declaration.type; | |
if (declarationType === 'FunctionDeclaration' || declarationType === 'ClassDeclaration') { | |
return jscodeshift.exportNamedDeclaration(inlineDefaultExport.node.declaration); | |
} | |
const dynamicExportName = filePath.split('/').pop().split('.')[0]; | |
const exportName = jscodeshift.identifier(dynamicExportName); | |
return jscodeshift.exportNamedDeclaration( | |
jscodeshift.variableDeclaration('const', [ | |
jscodeshift.variableDeclarator(exportName, inlineDefaultExport.node.declaration), | |
]) | |
); | |
}; | |
function migrateDefaultExports(source, jscodeshift, filePath) { | |
if (filePath.includes('.story.') || filePath.includes('.stories.')) { | |
return; | |
} | |
// migrate inline default exports, giving them an export name of the filename | |
source | |
.find(jscodeshift.ExportDefaultDeclaration, (t) => t.declaration.type !== 'Identifier') | |
.replaceWith((inlineDefaultExport) => generateNamedExportDeclaration(jscodeshift, inlineDefaultExport, filePath)); | |
// migrate default exports that just reference a variable | |
source | |
.find(jscodeshift.ExportDefaultDeclaration, { declaration: { type: 'Identifier' } }) | |
.forEach((defaultExport) => { | |
const constThatWasBeingDefaultExported = defaultExport.value.declaration.name; | |
const filter = { id: { name: constThatWasBeingDefaultExported } }; | |
// remove the old default export | |
defaultExport.get().prune(); | |
// check if it's already being exported as a const | |
if (source.find(jscodeshift.ExportNamedDeclaration, { declaration: { declarations: [filter] } }).length) { | |
return; | |
} | |
// check if it's already being exported as a function or a class | |
if (source.find(jscodeshift.ExportNamedDeclaration, { declaration: filter }).length) { | |
return; | |
} | |
// update original declarations with export keyword | |
const namedExportGenerator = (original) => jscodeshift.exportNamedDeclaration(original.node); | |
source.find(jscodeshift.VariableDeclaration, { declarations: [filter] }).replaceWith(namedExportGenerator); | |
source.find(jscodeshift.FunctionDeclaration, filter).replaceWith(namedExportGenerator); | |
}); | |
} | |
function migrateExportDefaultAsStatements(source, jscodeshift) { | |
// delete manual type exports since they'll be covered by next change in this chain | |
source | |
.find(jscodeshift.ExportNamedDeclaration, { | |
exportKind: 'type', | |
source: { type: 'StringLiteral' }, | |
}) | |
.forEach((typeExport) => typeExport.prune()); | |
// migrate "export { default as SomeName } from './thing'" to "export * from './thing'" | |
source | |
.find(jscodeshift.ExportNamedDeclaration, { | |
specifiers: [{ type: 'ExportSpecifier', local: { name: 'default' } }], | |
}) | |
.forEach((t) => t.replace(jscodeshift.exportAllDeclaration(t.value.source, null))); | |
} | |
const filetypesToIgnore = ['.png', '.jpg', '.jpeg', '.md']; | |
function migrateDefaultImports(source, jscodeshift) { | |
source.find(jscodeshift.ImportDefaultSpecifier).forEach((defaultImport) => { | |
const importPath = defaultImport.parent.value.source.value; | |
if (importPath.includes('./') && !filetypesToIgnore.some((filetype) => importPath.endsWith(filetype))) { | |
defaultImport.replace(jscodeshift.importSpecifier(defaultImport.value.local, null)); | |
} | |
}); | |
} | |
export default function transformer(file, api) { | |
const { jscodeshift } = api; | |
const source = jscodeshift.withParser(parser)(file.source); | |
migrateDefaultExports(source, jscodeshift, file.path); | |
migrateDefaultImports(source, jscodeshift); | |
migrateExportDefaultAsStatements(source, jscodeshift); | |
return source.toSource(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment