Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(typescript): erase type exports #9944

Merged
merged 3 commits into from May 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 61 additions & 0 deletions packages/babel-plugin-transform-typescript/src/index.js
Expand Up @@ -16,8 +16,22 @@ 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 {
programPath: any;
exportableTSNames: Set<string>;
}

const PARSED_PARAMS = new WeakSet();
Expand All @@ -40,6 +54,7 @@ export default declare((api, { jsxPragma = "React" }) => {

Program(path, state: State) {
state.programPath = path;
state.exportableTSNames = new Set();

const { file } = state;

Expand All @@ -52,6 +67,32 @@ 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
for (const stmt of path.get("body")) {
if (t.isImportDeclaration(stmt)) {
Expand Down Expand Up @@ -94,6 +135,26 @@ export default declare((api, { jsxPragma = "React" }) => {
}
},

ExportNamedDeclaration(path, { exportableTSNames }) {
// remove export declaration if it's exporting only types
if (
path.node.specifiers.length > 0 &&
!path.node.specifiers.find(
exportSpecifier =>
!exportableTSNames.has(exportSpecifier.local.name),
)
) {
path.remove();
}
},

ExportSpecifier(path, { exportableTSNames }) {
// remove type exports
if (exportableTSNames.has(path.node.local.name)) {
path.remove();
}
},

TSDeclareFunction(path) {
path.remove();
},
Expand Down
Expand Up @@ -8,3 +8,40 @@ declare namespace N {}
export interface I {}
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 { Bar } // everything removed
export { Bar as Bar2, C2 as C4 } // only C4
interface Bar {}
@@ -1 +1,32 @@
export class C2 {}
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