fix(transform-typescript): do not elide injected imports (#7833)

This commit is contained in:
Tim Seckinger 2018-05-09 17:05:29 +02:00 committed by Brian Ng
parent b42b21f25c
commit fa1547d8f8
5 changed files with 63 additions and 28 deletions

View File

@ -33,39 +33,42 @@ export default declare(api => {
Program(path, state: State) {
state.programPath = path;
},
ImportDeclaration(path, state: State) {
// Note: this will allow both `import { } from "m"` and `import "m";`.
// In TypeScript, the former would be elided.
if (path.node.specifiers.length === 0) {
return;
}
// remove type imports
for (const stmt of path.get("body")) {
if (t.isImportDeclaration(stmt)) {
// Note: this will allow both `import { } from "m"` and `import "m";`.
// In TypeScript, the former would be elided.
if (stmt.node.specifiers.length === 0) {
return;
}
let allElided = true;
const importsToRemove: Path<Node>[] = [];
let allElided = true;
const importsToRemove: Path<Node>[] = [];
for (const specifier of path.node.specifiers) {
const binding = path.scope.getBinding(specifier.local.name);
for (const specifier of stmt.node.specifiers) {
const binding = stmt.scope.getBinding(specifier.local.name);
// The binding may not exist if the import node was explicitly
// injected by another plugin. Currently core does not do a good job
// of keeping scope bindings synchronized with the AST. For now we
// just bail if there is no binding, since chances are good that if
// the import statement was injected then it wasn't a typescript type
// import anyway.
if (binding && isImportTypeOnly(binding, state.programPath)) {
importsToRemove.push(binding.path);
} else {
allElided = false;
}
}
// The binding may not exist if the import node was explicitly
// injected by another plugin. Currently core does not do a good job
// of keeping scope bindings synchronized with the AST. For now we
// just bail if there is no binding, since chances are good that if
// the import statement was injected then it wasn't a typescript type
// import anyway.
if (binding && isImportTypeOnly(binding, state.programPath)) {
importsToRemove.push(binding.path);
} else {
allElided = false;
}
}
if (allElided) {
path.remove();
} else {
for (const importPath of importsToRemove) {
importPath.remove();
if (allElided) {
stmt.remove();
} else {
for (const importPath of importsToRemove) {
importPath.remove();
}
}
}
}
},

View File

@ -0,0 +1,3 @@
{
"plugins": ["transform-typescript", "./plugin"]
}

View File

@ -0,0 +1,2 @@
import local from "source";
local();

View File

@ -0,0 +1,26 @@
module.exports = function({ types: t }) {
return {
visitor: {
CallExpression(path) {
if (path.node.callee.name === "a") {
// the import we add here should not be elided
path.scope
.getProgramParent()
.path.unshiftContainer(
"body",
t.importDeclaration(
[t.importDefaultSpecifier(t.identifier("local"))],
t.stringLiteral("source")
)
);
// with this crawl, babel-plugin-transform-typescript
// used to elide the import we just added
// https://github.com/babel/babel/issues/7592
path.scope.crawl();
path.node.callee = t.identifier("local");
}
},
},
};
};