Use scope for typescript export removals. Fixes #10033 (#10034)

This also fixes enum not adding the respective declaration to the scope
during the typescript visitation.

Rewrites:

2080042808b18b005fb54aeaf9ab708f64cb1005 #9944

a6392bd636d07c41579ea5ab443152a09943e096 #10019
This commit is contained in:
Wesley Wolfe 2019-05-29 01:36:04 -05:00 committed by Nicolò Ribaudo
parent b4c9cb0222
commit 8d492b159b
12 changed files with 114 additions and 121 deletions

View File

@ -24,7 +24,9 @@ export default function transpileEnum(path, t) {
path.remove(); path.remove();
} else { } else {
const isGlobal = t.isProgram(path.parent); // && !path.parent.body.some(t.isModuleDeclaration); const isGlobal = t.isProgram(path.parent); // && !path.parent.body.some(t.isModuleDeclaration);
path.replaceWith(makeVar(node.id, t, isGlobal ? "var" : "let")); path.scope.registerDeclaration(
path.replaceWith(makeVar(node.id, t, isGlobal ? "var" : "let"))[0],
);
} }
break; break;
} }

View File

@ -17,22 +17,8 @@ function isInType(path) {
} }
} }
function isTSExportableDeclaration(node) {
// all kinds of type exports that transpile to nothing
// exception is enums, since they transpile to JS values
return (
t.isTSInterfaceDeclaration(node) ||
t.isTSTypeAliasDeclaration(node) ||
t.isTSModuleDeclaration(node) ||
(t.isVariableDeclaration(node) && node.declare) ||
(t.isClassDeclaration(node) && node.declare) ||
t.isTSDeclareFunction(node)
);
}
interface State { interface State {
programPath: any; programPath: any;
exportableTSNames: Set<string>;
} }
const PARSED_PARAMS = new WeakSet(); const PARSED_PARAMS = new WeakSet();
@ -55,7 +41,6 @@ export default declare((api, { jsxPragma = "React" }) => {
Program(path, state: State) { Program(path, state: State) {
state.programPath = path; state.programPath = path;
state.exportableTSNames = new Set();
const { file } = state; const { file } = state;
@ -68,32 +53,6 @@ export default declare((api, { jsxPragma = "React" }) => {
} }
} }
// find exportable top level type declarations
for (const stmt of path.get("body")) {
if (isTSExportableDeclaration(stmt.node)) {
if (stmt.node.id && stmt.node.id.name) {
state.exportableTSNames.add(stmt.node.id.name);
} else if (
stmt.node.declarations &&
stmt.node.declarations.length > 0
) {
for (const declaration of stmt.node.declarations) {
if (declaration.id && declaration.id.name) {
state.exportableTSNames.add(declaration.id.name);
}
}
}
} else if (
t.isExportNamedDeclaration(stmt.node) &&
stmt.node.specifiers.length === 0 &&
isTSExportableDeclaration(stmt.node.declaration) &&
stmt.node.declaration.id &&
stmt.node.declaration.id.name
) {
state.exportableTSNames.add(stmt.node.declaration.id.name);
}
}
// remove type imports // remove type imports
for (const stmt of path.get("body")) { for (const stmt of path.get("body")) {
if (t.isImportDeclaration(stmt)) { if (t.isImportDeclaration(stmt)) {
@ -136,31 +95,30 @@ export default declare((api, { jsxPragma = "React" }) => {
} }
}, },
ExportNamedDeclaration(path, { exportableTSNames }) { ExportNamedDeclaration(path) {
// remove export declaration if it's exporting only types // remove export declaration if it's exporting only types
if ( if (
path.node.specifiers.length > 0 && path.node.specifiers.length > 0 &&
!path.node.specifiers.find( !path.node.specifiers.find(exportSpecifier =>
exportSpecifier => path.scope.hasOwnBinding(exportSpecifier.local.name),
!exportableTSNames.has(exportSpecifier.local.name),
) )
) { ) {
path.remove(); path.remove();
} }
}, },
ExportSpecifier(path, { exportableTSNames }) { ExportSpecifier(path) {
// remove type exports // remove type exports
if (exportableTSNames.has(path.node.local.name)) { if (!path.scope.hasOwnBinding(path.node.local.name)) {
path.remove(); path.remove();
} }
}, },
ExportDefaultDeclaration(path, { exportableTSNames }) { ExportDefaultDeclaration(path) {
// remove whole declaration if it's exporting a TS type // remove whole declaration if it's exporting a TS type
if ( if (
t.isIdentifier(path.node.declaration) && t.isIdentifier(path.node.declaration) &&
exportableTSNames.has(path.node.declaration.name) !path.scope.hasOwnBinding(path.node.declaration.name)
) { ) {
path.remove(); path.remove();
} }

View File

@ -1,3 +1,4 @@
; // Otherwise-empty file
declare const x: number; declare const x: number;
declare function f(): void; declare function f(): void;
declare class C {} declare class C {}
@ -7,42 +8,3 @@ declare module M {}
declare namespace N {} declare namespace N {}
export interface I {} export interface I {}
export type T = number; export type T = number;
export class C2 {}
export { x, f, E, C }; // only E
export { M, N, I as I1, T as T1 }; // everything removed
export {
x as x2,
f as f2,
C as CC2,
E as E2,
M as M2,
N as N2,
I as I2,
T as T2,
C2 as C3
}; // only E and C2
interface II2 {}
type AA = {};
enum BB {
K
}
enum BB {
L = "LL"
}
export { II2, AA, BB }; // only BB
export { II2 as II3, AA as AA2 }; // everything removed
export { BB as BB1 }; // as-is
interface II3 {}
type AA2 = {};
enum BB2 {}
function foo() {}
export { II3 as default, AA2 as A, BB2 as BB3, foo }; // only BB2 and foo
// export an interface before declaration
export default Bar;
export { Bar } // everything removed
export { Bar as Bar2, C2 as C4 } // only C4
interface Bar {}

View File

@ -1,32 +1 @@
export class C2 {} ; // Otherwise-empty file
export { E }; // only E
// everything removed
export { E as E2, C2 as C3 }; // only E and C2
var BB;
(function (BB) {
BB[BB["K"] = 0] = "K";
})(BB || (BB = {}));
(function (BB) {
BB["L"] = "LL";
})(BB || (BB = {}));
export { BB }; // only BB
// everything removed
export { BB as BB1 }; // as-is
var BB2;
(function (BB2) {})(BB2 || (BB2 = {}));
function foo() {}
export { BB2 as BB3, foo }; // only BB2 and foo
// export an interface before declaration
// everything removed
export { C2 as C4 }; // only C4

View File

@ -0,0 +1,11 @@
export class N {
f1(value: N.I) {
value.f2();
}
}
export declare namespace N {
export interface I {
f2();
}
}
export default N;

View File

@ -0,0 +1,7 @@
export class N {
f1(value) {
value.f2();
}
}
export default N;

View File

@ -0,0 +1,48 @@
declare const x: number;
declare function f(): void;
declare class C {}
declare enum E {}
declare module "m" {}
declare module M {}
declare namespace N {}
export interface I {}
export type T = number;
export class C2 {}
export { x, f, E, C }; // Not-even E
export { M, N, I as I1, T as T1 }; // everything removed
export {
x as x2,
f as f2,
C as CC2,
E as E2,
M as M2,
N as N2,
I as I2,
T as T2,
C2 as C3
}; // only C2->C3
interface II2 {}
type AA = {};
enum BB {
K
}
enum BB {
L = "LL"
}
export { II2, AA, BB }; // only BB
export { II2 as II3, AA as AA2 }; // everything removed
export { BB as BB1 }; // BB->BB1
interface II3 {}
type AA2 = {};
enum BB2 {}
function foo() {}
export { II3 as default, AA2 as A, BB2 as BB3, foo }; // only BB2->BB3 and foo
// export an interface before declaration
export default Bar;
export { Bar } // everything removed
export { Bar as Bar2, C2 as C4 } // only C2->C4
interface Bar {}

View File

@ -0,0 +1,30 @@
export class C2 {}
// everything removed
export { C2 as C3 }; // only C2->C3
var BB;
(function (BB) {
BB[BB["K"] = 0] = "K";
})(BB || (BB = {}));
(function (BB) {
BB["L"] = "LL";
})(BB || (BB = {}));
export { BB }; // only BB
// everything removed
export { BB as BB1 }; // BB->BB1
var BB2;
(function (BB2) {})(BB2 || (BB2 = {}));
function foo() {}
export { BB2 as BB3, foo }; // only BB2->BB3 and foo
// export an interface before declaration
// everything removed
export { C2 as C4 }; // only C2->C4

View File

@ -1,2 +1,3 @@
; // Otherwise-empty file
export interface I {} export interface I {}
export default interface A {} export default interface A {}

View File

@ -0,0 +1 @@
; // Otherwise-empty file

View File

@ -0,0 +1,2 @@
export class N {}
export default N;

View File

@ -0,0 +1,2 @@
export class N {}
export default N;