Do not trust Scope when removing TypeScript types (#10174)
* Do not trust Scope when removing TypeScript types * Warn * Update warning message Co-Authored-By: Brian Ng <bng412@gmail.com> * Add test * Node 6
This commit is contained in:
parent
406a65c894
commit
f48b47c1f7
@ -19,6 +19,29 @@ function isInType(path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PARSED_PARAMS = new WeakSet();
|
const PARSED_PARAMS = new WeakSet();
|
||||||
|
const GLOBAL_TYPES = new WeakMap();
|
||||||
|
|
||||||
|
function isGlobalType(path, name) {
|
||||||
|
const program = path.find(path => path.isProgram()).node;
|
||||||
|
if (path.scope.hasOwnBinding(name)) return false;
|
||||||
|
if (GLOBAL_TYPES.get(program).has(name)) return true;
|
||||||
|
|
||||||
|
console.warn(
|
||||||
|
`The exported identifier "${name}" is not declared in Babel's scope tracker\n` +
|
||||||
|
`as a JavaScript value binding, and "@babel/plugin-transform-typescript"\n` +
|
||||||
|
`never encountered it as a TypeScript type declaration.\n` +
|
||||||
|
`It will be treated as a JavaScript value.\n\n` +
|
||||||
|
`This problem is likely caused by another plugin injecting\n` +
|
||||||
|
`"${name}" without registering it in the scope tracker. If you are the author\n` +
|
||||||
|
` of that plugin, please use "scope.registerDeclaration(declarationPath)".`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerGlobalType(programScope, name) {
|
||||||
|
GLOBAL_TYPES.get(programScope.path.node).add(name);
|
||||||
|
}
|
||||||
|
|
||||||
export default declare(
|
export default declare(
|
||||||
(api, { jsxPragma = "React", allowNamespaces = false }) => {
|
(api, { jsxPragma = "React", allowNamespaces = false }) => {
|
||||||
@ -40,6 +63,10 @@ export default declare(
|
|||||||
const { file } = state;
|
const { file } = state;
|
||||||
let fileJsxPragma = null;
|
let fileJsxPragma = null;
|
||||||
|
|
||||||
|
if (!GLOBAL_TYPES.has(path.node)) {
|
||||||
|
GLOBAL_TYPES.set(path.node, new Set());
|
||||||
|
}
|
||||||
|
|
||||||
if (file.ast.comments) {
|
if (file.ast.comments) {
|
||||||
for (const comment of (file.ast.comments: Array<Object>)) {
|
for (const comment of (file.ast.comments: Array<Object>)) {
|
||||||
const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value);
|
const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value);
|
||||||
@ -50,7 +77,7 @@ export default declare(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove type imports
|
// remove type imports
|
||||||
for (const stmt of path.get("body")) {
|
for (let stmt of path.get("body")) {
|
||||||
if (t.isImportDeclaration(stmt)) {
|
if (t.isImportDeclaration(stmt)) {
|
||||||
// Note: this will allow both `import { } from "m"` and `import "m";`.
|
// Note: this will allow both `import { } from "m"` and `import "m";`.
|
||||||
// In TypeScript, the former would be elided.
|
// In TypeScript, the former would be elided.
|
||||||
@ -91,6 +118,28 @@ export default declare(
|
|||||||
importPath.remove();
|
importPath.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stmt.isExportDeclaration()) {
|
||||||
|
stmt = stmt.get("declaration");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stmt.isVariableDeclaration({ declare: true })) {
|
||||||
|
for (const name of Object.keys(stmt.getBindingIdentifiers())) {
|
||||||
|
registerGlobalType(path.scope, name);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
stmt.isTSTypeAliasDeclaration() ||
|
||||||
|
stmt.isTSDeclareFunction() ||
|
||||||
|
stmt.isTSInterfaceDeclaration() ||
|
||||||
|
stmt.isClassDeclaration({ declare: true }) ||
|
||||||
|
stmt.isTSEnumDeclaration({ declare: true }) ||
|
||||||
|
(stmt.isTSModuleDeclaration({ declare: true }) &&
|
||||||
|
stmt.get("id").isIdentifier())
|
||||||
|
) {
|
||||||
|
registerGlobalType(path.scope, stmt.node.id.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -100,8 +149,8 @@ export default declare(
|
|||||||
if (
|
if (
|
||||||
!path.node.source &&
|
!path.node.source &&
|
||||||
path.node.specifiers.length > 0 &&
|
path.node.specifiers.length > 0 &&
|
||||||
!path.node.specifiers.find(exportSpecifier =>
|
path.node.specifiers.every(({ local }) =>
|
||||||
path.scope.hasOwnBinding(exportSpecifier.local.name),
|
isGlobalType(path, local.name),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
path.remove();
|
path.remove();
|
||||||
@ -110,10 +159,7 @@ export default declare(
|
|||||||
|
|
||||||
ExportSpecifier(path) {
|
ExportSpecifier(path) {
|
||||||
// remove type exports
|
// remove type exports
|
||||||
if (
|
if (!path.parent.source && isGlobalType(path, path.node.local.name)) {
|
||||||
!path.parent.source &&
|
|
||||||
!path.scope.hasOwnBinding(path.node.local.name)
|
|
||||||
) {
|
|
||||||
path.remove();
|
path.remove();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -122,7 +168,7 @@ export default declare(
|
|||||||
// 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) &&
|
||||||
!path.scope.hasOwnBinding(path.node.declaration.name)
|
isGlobalType(path, path.node.declaration.name)
|
||||||
) {
|
) {
|
||||||
path.remove();
|
path.remove();
|
||||||
}
|
}
|
||||||
@ -137,7 +183,9 @@ export default declare(
|
|||||||
},
|
},
|
||||||
|
|
||||||
VariableDeclaration(path) {
|
VariableDeclaration(path) {
|
||||||
if (path.node.declare) path.remove();
|
if (path.node.declare) {
|
||||||
|
path.remove();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
VariableDeclarator({ node }) {
|
VariableDeclarator({ node }) {
|
||||||
|
|||||||
1
packages/babel-plugin-transform-typescript/test/fixtures/regression/10162/input.mjs
vendored
Normal file
1
packages/babel-plugin-transform-typescript/test/fixtures/regression/10162/input.mjs
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default 2;
|
||||||
3
packages/babel-plugin-transform-typescript/test/fixtures/regression/10162/options.json
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/regression/10162/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["./plugin.js", "transform-typescript"]
|
||||||
|
}
|
||||||
3
packages/babel-plugin-transform-typescript/test/fixtures/regression/10162/output.mjs
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/regression/10162/output.mjs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const foo = 2;
|
||||||
|
export default foo;
|
||||||
|
["The exported identifier \"foo\" is not declared in Babel's scope tracker\nas a JavaScript value binding, and \"@babel/plugin-transform-typescript\"\nnever encountered it as a TypeScript type declaration.\nIt will be treated as a JavaScript value.\n\nThis problem is likely caused by another plugin injecting\n\"foo\" without registering it in the scope tracker. If you are the author\n of that plugin, please use \"scope.registerDeclaration(declarationPath)\"."];
|
||||||
30
packages/babel-plugin-transform-typescript/test/fixtures/regression/10162/plugin.js
vendored
Normal file
30
packages/babel-plugin-transform-typescript/test/fixtures/regression/10162/plugin.js
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = function({ template, types: t }) {
|
||||||
|
const warnings = [];
|
||||||
|
let consoleWarn;
|
||||||
|
|
||||||
|
return {
|
||||||
|
pre() {
|
||||||
|
consoleWarn = console.warn;
|
||||||
|
console.warn = msg => warnings.push(msg);
|
||||||
|
},
|
||||||
|
|
||||||
|
post({ path }) {
|
||||||
|
console.warn = consoleWarn;
|
||||||
|
|
||||||
|
const stmt = t.expressionStatement(t.valueToNode(warnings));
|
||||||
|
path.pushContainer("body", stmt);
|
||||||
|
},
|
||||||
|
|
||||||
|
visitor: {
|
||||||
|
ExportDefaultDeclaration(path) {
|
||||||
|
path.insertBefore(template.statement.ast`
|
||||||
|
const foo = ${path.node.declaration};
|
||||||
|
`);
|
||||||
|
|
||||||
|
path.node.declaration = t.identifier("foo");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user