Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save akx/90344a3f2c950fa819bf4ae037020784 to your computer and use it in GitHub Desktop.

Select an option

Save akx/90344a3f2c950fa819bf4ae037020784 to your computer and use it in GitHub Desktop.
/*
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';
function generateNamedExportDeclaration(jscodeshift, inlineDefaultExport, filePath) {
const declarationType = inlineDefaultExport.node.declaration.type;
const comments = inlineDefaultExport.node.comments;
if (declarationType === 'FunctionDeclaration' || declarationType === 'ClassDeclaration') {
return Object.assign(jscodeshift.exportNamedDeclaration(inlineDefaultExport.node.declaration), {
comments,
});
}
const dynamicExportName = filePath.split('/').pop().split('.')[0];
const exportName = jscodeshift.identifier(dynamicExportName);
return Object.assign(
jscodeshift.exportNamedDeclaration(
jscodeshift.variableDeclaration('const', [
jscodeshift.variableDeclarator(exportName, inlineDefaultExport.node.declaration),
]),
),
{comments},
);
}
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