Created
August 16, 2019 17:03
-
-
Save michaelmang/f6b4f5f15646745f44e35deda9bfc131 to your computer and use it in GitHub Desktop.
Remove Unused Imports
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
export default function transformer(file, api, options) { | |
const j = api.jscodeshift; | |
const root = j(file.source); | |
const removeIfUnused = (importSpecifier, importDeclaration) => { | |
const varName = importSpecifier.value.local.name; | |
if (varName === "React") { | |
return false; | |
} | |
const isUsedInScopes = () => { | |
return j(importDeclaration) | |
.closestScope() | |
.find(j.Identifier, { name: varName }) | |
.filter((p) => { | |
if (p.value.start === importSpecifier.value.local.start) return false; | |
if ((p.parentPath.value.type === "Property" && p.name === "key")) return false; | |
if (p.name === "property") return false; | |
return true; | |
}) | |
.size() > 0; | |
}; | |
// Caveat, this doesn't work with annonymously exported class declarations. | |
const isUsedInDecorators = () => { // one could probably cache these, but I'm lazy. | |
let used = false; | |
root.find(j.ClassDeclaration) | |
.forEach((klass) => { | |
used = used || (klass.node.decorators && j(klass.node.decorators) | |
.find(j.Identifier, { name: varName }) | |
.filter((p) => { | |
if ((p.parentPath.value.type === "Property" && p.name === "key")) return false; | |
if (p.name === "property") return false; | |
return true; | |
}) | |
.size() > 0); | |
}); | |
return used; | |
}; | |
if (!(isUsedInScopes() || isUsedInDecorators())) { | |
j(importSpecifier).remove(); | |
return true; | |
} | |
return false; | |
}; | |
const removeUnusedDefaultImport = (importDeclaration) => { | |
return j(importDeclaration).find(j.ImportDefaultSpecifier).filter((s) => removeIfUnused(s, importDeclaration)).size() > 0; | |
}; | |
const removeUnusedNonDefaultImports = (importDeclaration) => { | |
return j(importDeclaration).find(j.ImportSpecifier).filter((s) => removeIfUnused(s, importDeclaration)).size() > 0; | |
}; | |
// Return True if somethin was transformed. | |
const processImportDeclaration = (importDeclaration) => { | |
// e.g. import 'styles.css'; // please Don't Touch these imports! | |
if (importDeclaration.value.specifiers.length === 0) return false; | |
const hadUnusedDefaultImport = removeUnusedDefaultImport(importDeclaration); | |
const hadUnusedNonDefaultImports = removeUnusedNonDefaultImports(importDeclaration); | |
if (importDeclaration.value.specifiers.length === 0) { | |
j(importDeclaration).remove(); | |
return true; | |
} | |
return hadUnusedDefaultImport || hadUnusedNonDefaultImports; | |
}; | |
return root.find(j.ImportDeclaration) | |
.filter(processImportDeclaration) | |
.size() > 0 ? root.toSource(options.printOptions || { quote: "single" }) : null; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment