From 2886e1e6a353514f90d794bb8f55a054fb73a941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 17 Oct 2019 17:54:35 -0400 Subject: [PATCH] Create File class for babel helpers * add test * fix: pass File to helper traverser * pass babel.File to helpers.ensure --- .../src/tools/build-external-helpers.js | 2 + .../src/transformation/file/file.js | 2 +- packages/babel-helpers/src/index.js | 37 ++++++++++++++----- .../test/fixtures/regression/9496/input.js | 1 + .../fixtures/regression/9496/options.json | 3 ++ .../test/fixtures/regression/9496/output.js | 3 ++ .../test/fixtures/regression/9496/plugin.js | 22 +++++++++++ .../scripts/build-dist.js | 1 + 8 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 packages/babel-helpers/test/fixtures/regression/9496/input.js create mode 100644 packages/babel-helpers/test/fixtures/regression/9496/options.json create mode 100644 packages/babel-helpers/test/fixtures/regression/9496/output.js create mode 100644 packages/babel-helpers/test/fixtures/regression/9496/plugin.js diff --git a/packages/babel-core/src/tools/build-external-helpers.js b/packages/babel-core/src/tools/build-external-helpers.js index c6aa2bf6d21a..914f2baf4e84 100644 --- a/packages/babel-core/src/tools/build-external-helpers.js +++ b/packages/babel-core/src/tools/build-external-helpers.js @@ -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); diff --git a/packages/babel-core/src/transformation/file/file.js b/packages/babel-core/src/transformation/file/file.js index 2e7b66f3a64c..4187151a973a 100644 --- a/packages/babel-core/src/transformation/file/file.js +++ b/packages/babel-core/src/transformation/file/file.js @@ -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, diff --git a/packages/babel-helpers/src/index.js b/packages/babel-helpers/src/index.js index 9dc87ce58916..b7aa97dff1ae 100644 --- a/packages/babel-helpers/src/index.js +++ b/packages/babel-helpers/src/index.js @@ -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 { 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); } diff --git a/packages/babel-helpers/test/fixtures/regression/9496/input.js b/packages/babel-helpers/test/fixtures/regression/9496/input.js new file mode 100644 index 000000000000..087837e3f442 --- /dev/null +++ b/packages/babel-helpers/test/fixtures/regression/9496/input.js @@ -0,0 +1 @@ +REPLACE_ME; \ No newline at end of file diff --git a/packages/babel-helpers/test/fixtures/regression/9496/options.json b/packages/babel-helpers/test/fixtures/regression/9496/options.json new file mode 100644 index 000000000000..14af0e5feac8 --- /dev/null +++ b/packages/babel-helpers/test/fixtures/regression/9496/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["./plugin"] +} diff --git a/packages/babel-helpers/test/fixtures/regression/9496/output.js b/packages/babel-helpers/test/fixtures/regression/9496/output.js new file mode 100644 index 000000000000..a1a37645acd7 --- /dev/null +++ b/packages/babel-helpers/test/fixtures/regression/9496/output.js @@ -0,0 +1,3 @@ +function _$_9496_main_hub_is_found() {} + +_$_9496_main_hub_is_found; diff --git a/packages/babel-helpers/test/fixtures/regression/9496/plugin.js b/packages/babel-helpers/test/fixtures/regression/9496/plugin.js new file mode 100644 index 000000000000..4c25ad746fc6 --- /dev/null +++ b/packages/babel-helpers/test/fixtures/regression/9496/plugin.js @@ -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); + }, + }, + }; +}; diff --git a/packages/babel-plugin-transform-runtime/scripts/build-dist.js b/packages/babel-plugin-transform-runtime/scripts/build-dist.js index a107bbea1fa2..a5ee8f16da6f 100644 --- a/packages/babel-plugin-transform-runtime/scripts/build-dist.js +++ b/packages/babel-plugin-transform-runtime/scripts/build-dist.js @@ -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`