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:
parent
748897be07
commit
4bf36e64da
@ -2,6 +2,7 @@ import * as helpers from "@babel/helpers";
|
|||||||
import generator from "@babel/generator";
|
import generator from "@babel/generator";
|
||||||
import template from "@babel/template";
|
import template from "@babel/template";
|
||||||
import * as t from "@babel/types";
|
import * as t from "@babel/types";
|
||||||
|
import File from "../transformation/file/file";
|
||||||
|
|
||||||
// Wrapped to avoid wasting time parsing this when almost no-one uses
|
// Wrapped to avoid wasting time parsing this when almost no-one uses
|
||||||
// build-external-helpers.
|
// build-external-helpers.
|
||||||
@ -136,6 +137,7 @@ function buildHelpers(body, namespace, whitelist) {
|
|||||||
|
|
||||||
const ref = (refs[name] = getHelperReference(name));
|
const ref = (refs[name] = getHelperReference(name));
|
||||||
|
|
||||||
|
helpers.ensure(name, File);
|
||||||
const { nodes } = helpers.get(name, getHelperReference, ref);
|
const { nodes } = helpers.get(name, getHelperReference, ref);
|
||||||
|
|
||||||
body.push(...nodes);
|
body.push(...nodes);
|
||||||
|
|||||||
@ -174,7 +174,7 @@ export default class File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure that the helper exists
|
// make sure that the helper exists
|
||||||
helpers.ensure(name);
|
helpers.ensure(name, File);
|
||||||
|
|
||||||
const uid = (this.declarations[name] = this.scope.generateUidIdentifier(
|
const uid = (this.declarations[name] = this.scope.generateUidIdentifier(
|
||||||
name,
|
name,
|
||||||
|
|||||||
@ -13,6 +13,7 @@ function makePath(path) {
|
|||||||
return parts.reverse().join(".");
|
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
|
* 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.
|
* the helper is whatever context it is needed in.
|
||||||
@ -29,7 +30,7 @@ function getHelperMetadata(file) {
|
|||||||
const importPaths = [];
|
const importPaths = [];
|
||||||
const importBindingsReferences = [];
|
const importBindingsReferences = [];
|
||||||
|
|
||||||
traverse(file, {
|
const dependencyVisitor = {
|
||||||
ImportDeclaration(child) {
|
ImportDeclaration(child) {
|
||||||
const name = child.node.source.value;
|
const name = child.node.source.value;
|
||||||
if (!helpers[name]) {
|
if (!helpers[name]) {
|
||||||
@ -72,9 +73,9 @@ function getHelperMetadata(file) {
|
|||||||
|
|
||||||
child.skip();
|
child.skip();
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
|
||||||
traverse(file, {
|
const referenceVisitor = {
|
||||||
Program(path) {
|
Program(path) {
|
||||||
const bindings = path.scope.getAllBindings();
|
const bindings = path.scope.getAllBindings();
|
||||||
|
|
||||||
@ -111,7 +112,10 @@ function getHelperMetadata(file) {
|
|||||||
exportBindingAssignments.push(makePath(child));
|
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.");
|
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;
|
toRename[exportName] = id.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
traverse(file, {
|
const visitor = {
|
||||||
Program(path) {
|
Program(path) {
|
||||||
// We need to compute these in advance because removing nodes would
|
// We need to compute these in advance because removing nodes would
|
||||||
// invalidate the paths.
|
// invalidate the paths.
|
||||||
@ -223,7 +227,8 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
|
|||||||
// actually doing the traversal.
|
// actually doing the traversal.
|
||||||
path.stop();
|
path.stop();
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
traverse(file.ast, visitor, file.scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
const helperData = Object.create(null);
|
const helperData = Object.create(null);
|
||||||
@ -238,7 +243,16 @@ function loadHelper(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fn = () => {
|
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());
|
const metadata = getHelperMetadata(fn());
|
||||||
@ -249,7 +263,7 @@ function loadHelper(name) {
|
|||||||
permuteHelperAST(file, metadata, id, localBindings, getDependency);
|
permuteHelperAST(file, metadata, id, localBindings, getDependency);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nodes: file.program.body,
|
nodes: file.ast.program.body,
|
||||||
globals: metadata.globals,
|
globals: metadata.globals,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -280,7 +294,12 @@ export function getDependencies(name: string): $ReadOnlyArray<string> {
|
|||||||
return Array.from(loadHelper(name).dependencies.values());
|
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);
|
loadHelper(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1
packages/babel-helpers/test/fixtures/regression/9496/input.js
vendored
Normal file
1
packages/babel-helpers/test/fixtures/regression/9496/input.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
REPLACE_ME;
|
||||||
3
packages/babel-helpers/test/fixtures/regression/9496/options.json
vendored
Normal file
3
packages/babel-helpers/test/fixtures/regression/9496/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["./plugin"]
|
||||||
|
}
|
||||||
3
packages/babel-helpers/test/fixtures/regression/9496/output.js
vendored
Normal file
3
packages/babel-helpers/test/fixtures/regression/9496/output.js
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function _$_9496_main_hub_is_found() {}
|
||||||
|
|
||||||
|
_$_9496_main_hub_is_found;
|
||||||
22
packages/babel-helpers/test/fixtures/regression/9496/plugin.js
vendored
Normal file
22
packages/babel-helpers/test/fixtures/regression/9496/plugin.js
vendored
Normal 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);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -134,6 +134,7 @@ function buildHelper(
|
|||||||
|
|
||||||
if (!esm) {
|
if (!esm) {
|
||||||
bindings = [];
|
bindings = [];
|
||||||
|
helpers.ensure(helperName, babel.File);
|
||||||
for (const dep of helpers.getDependencies(helperName)) {
|
for (const dep of helpers.getDependencies(helperName)) {
|
||||||
const id = (dependencies[dep] = t.identifier(t.toIdentifier(dep)));
|
const id = (dependencies[dep] = t.identifier(t.toIdentifier(dep)));
|
||||||
tree.body.push(template.statement.ast`
|
tree.body.push(template.statement.ast`
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user