Create File class for babel helpers (#10575)

* add test

* fix: pass File to helper traverser

* pass babel.File to helpers.ensure
This commit is contained in:
Huáng Jùnliàng 2020-03-17 04:58:46 -04:00 committed by GitHub
parent 748897be07
commit 4bf36e64da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 61 additions and 10 deletions

View File

@ -2,6 +2,7 @@ import * as helpers from "@babel/helpers";
import generator from "@babel/generator";
import template from "@babel/template";
import * as t from "@babel/types";
import File from "../transformation/file/file";
// Wrapped to avoid wasting time parsing this when almost no-one uses
// build-external-helpers.
@ -136,6 +137,7 @@ function buildHelpers(body, namespace, whitelist) {
const ref = (refs[name] = getHelperReference(name));
helpers.ensure(name, File);
const { nodes } = helpers.get(name, getHelperReference, ref);
body.push(...nodes);

View File

@ -174,7 +174,7 @@ export default class File {
}
// make sure that the helper exists
helpers.ensure(name);
helpers.ensure(name, File);
const uid = (this.declarations[name] = this.scope.generateUidIdentifier(
name,

View File

@ -13,6 +13,7 @@ function makePath(path) {
return parts.reverse().join(".");
}
let fileClass = undefined;
/**
* Given a file AST for a given helper, get a bunch of metadata about it so that Babel can quickly render
* the helper is whatever context it is needed in.
@ -29,7 +30,7 @@ function getHelperMetadata(file) {
const importPaths = [];
const importBindingsReferences = [];
traverse(file, {
const dependencyVisitor = {
ImportDeclaration(child) {
const name = child.node.source.value;
if (!helpers[name]) {
@ -72,9 +73,9 @@ function getHelperMetadata(file) {
child.skip();
},
});
};
traverse(file, {
const referenceVisitor = {
Program(path) {
const bindings = path.scope.getAllBindings();
@ -111,7 +112,10 @@ function getHelperMetadata(file) {
exportBindingAssignments.push(makePath(child));
}
},
});
};
traverse(file.ast, dependencyVisitor, file.scope);
traverse(file.ast, referenceVisitor, file.scope);
if (!exportPath) throw new Error("Helpers must default-export something.");
@ -170,7 +174,7 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
toRename[exportName] = id.name;
}
traverse(file, {
const visitor = {
Program(path) {
// We need to compute these in advance because removing nodes would
// invalidate the paths.
@ -223,7 +227,8 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
// actually doing the traversal.
path.stop();
},
});
};
traverse(file.ast, visitor, file.scope);
}
const helperData = Object.create(null);
@ -238,7 +243,16 @@ function loadHelper(name) {
}
const fn = () => {
return t.file(helper.ast());
const file = { ast: t.file(helper.ast()) };
if (fileClass) {
return new fileClass(
{
filename: `babel-helper://${name}`,
},
file,
);
}
return file;
};
const metadata = getHelperMetadata(fn());
@ -249,7 +263,7 @@ function loadHelper(name) {
permuteHelperAST(file, metadata, id, localBindings, getDependency);
return {
nodes: file.program.body,
nodes: file.ast.program.body,
globals: metadata.globals,
};
},
@ -280,7 +294,12 @@ export function getDependencies(name: string): $ReadOnlyArray<string> {
return Array.from(loadHelper(name).dependencies.values());
}
export function ensure(name: string) {
export function ensure(name: string, newFileClass?) {
if (!fileClass) {
// optional fileClass used to wrap helper snippets into File instance,
// offering `path.hub` support during traversal
fileClass = newFileClass;
}
loadHelper(name);
}

View File

@ -0,0 +1 @@
REPLACE_ME;

View File

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

View File

@ -0,0 +1,3 @@
function _$_9496_main_hub_is_found() {}
_$_9496_main_hub_is_found;

View File

@ -0,0 +1,22 @@
const defineHelper = require("../../../helpers/define-helper").default;
const main = defineHelper(__dirname, "main", `
export default function helper() {}
`);
module.exports = function() {
return {
visitor: {
Identifier(path) {
if (path.node.name !== "REPLACE_ME") {
if (path.hub) {
path.node.name += "_hub_is_found";
}
return;
}
const helper = this.addHelper(main);
path.replaceWith(helper);
},
},
};
};

View File

@ -134,6 +134,7 @@ function buildHelper(
if (!esm) {
bindings = [];
helpers.ensure(helperName, babel.File);
for (const dep of helpers.getDependencies(helperName)) {
const id = (dependencies[dep] = t.identifier(t.toIdentifier(dep)));
tree.body.push(template.statement.ast`