diff --git a/.gitignore b/.gitignore index 7087f6e030..5f5042e700 100644 --- a/.gitignore +++ b/.gitignore @@ -15,12 +15,16 @@ package-lock.json !/packages/babel-runtime/core-js/map.js /packages/babel-runtime/helpers/*.js !/packages/babel-runtime/helpers/toArray.js +!/packages/babel-runtime/helpers/temporalRef.js /packages/babel-runtime/helpers/builtin/*.js !/packages/babel-runtime/helpers/builtin/toArray.js +!/packages/babel-runtime/helpers/builtin/temporalRef.js /packages/babel-runtime/helpers/builtin/es6/*.js !/packages/babel-runtime/helpers/builtin/es6/toArray.js +!/packages/babel-runtime/helpers/builtin/es6/temporalRef.js /packages/babel-runtime/helpers/es6/*.js !/packages/babel-runtime/helpers/es6/toArray.js +!/packages/babel-runtime/helpers/es6/temporalRef.js /packages/babel-register/test/.babel /packages/babel-cli/test/tmp /packages/babel-node/test/tmp diff --git a/packages/babel-core/src/transformation/file/file.js b/packages/babel-core/src/transformation/file/file.js index 795a33b6bf..79ef660161 100644 --- a/packages/babel-core/src/transformation/file/file.js +++ b/packages/babel-core/src/transformation/file/file.js @@ -1,6 +1,6 @@ // @flow -import getHelper from "@babel/helpers"; +import * as helpers from "@babel/helpers"; import { NodePath, Hub, Scope } from "@babel/traverse"; import { codeFrameColumns } from "@babel/code-frame"; import traverse from "@babel/traverse"; @@ -132,11 +132,16 @@ export default class File { name, )); - const { nodes, globals } = getHelper( + const dependencies = {}; + for (const dep of helpers.getDependencies(name)) { + dependencies[dep] = this.addHelper(dep); + } + + const { nodes, globals } = helpers.get( name, - name => this.addHelper(name), + dep => dependencies[dep], uid, - () => Object.keys(this.scope.getAllBindings()), + Object.keys(this.scope.getAllBindings()), ); globals.forEach(name => { diff --git a/packages/babel-helpers/src/helpers.js b/packages/babel-helpers/src/helpers.js index 0329ff4dd0..42e840f056 100644 --- a/packages/babel-helpers/src/helpers.js +++ b/packages/babel-helpers/src/helpers.js @@ -600,7 +600,9 @@ helpers.taggedTemplateLiteralLoose = defineHelper(` `); helpers.temporalRef = defineHelper(` - export default function _temporalRef(val, name, undef) { + import undef from "temporalUndefined"; + + export default function _temporalRef(val, name) { if (val === undef) { throw new ReferenceError(name + " is not defined - temporal dead zone"); } else { diff --git a/packages/babel-helpers/src/index.js b/packages/babel-helpers/src/index.js index 44cd492c07..c44a794f3d 100644 --- a/packages/babel-helpers/src/index.js +++ b/packages/babel-helpers/src/index.js @@ -134,8 +134,8 @@ function getHelperMetadata(file) { /** * Given a helper AST and information about how it will be used, update the AST to match the usage. */ -function permuteHelperAST(file, metadata, id, getLocalBindings, getDependency) { - if (getLocalBindings && !id) { +function permuteHelperAST(file, metadata, id, localBindings, getDependency) { + if (localBindings && !id) { throw new Error("Unexpected local bindings for module-based helpers."); } @@ -154,11 +154,11 @@ function permuteHelperAST(file, metadata, id, getLocalBindings, getDependency) { const dependenciesRefs = {}; dependencies.forEach((name, id) => { dependenciesRefs[id.name] = - typeof getDependency === "function" ? getDependency(name) : id; + (typeof getDependency === "function" && getDependency(name)) || id; }); const toRename = {}; - const bindings = new Set((getLocalBindings && getLocalBindings()) || []); + const bindings = new Set(localBindings || []); localBindingNames.forEach(name => { let newName = name; while (bindings.has(newName)) newName = "_" + newName; @@ -237,17 +237,17 @@ function loadHelper(name) { const metadata = getHelperMetadata(fn()); - // Preload dependencies - metadata.dependencies.forEach(loadHelper); + helperData[name] = { + build(getDependency, id, localBindings) { + const file = fn(); + permuteHelperAST(file, metadata, id, localBindings, getDependency); - helperData[name] = function(getDependency, id, getLocalBindings) { - const file = fn(); - permuteHelperAST(file, metadata, id, getLocalBindings, getDependency); - - return { - nodes: file.program.body, - globals: metadata.globals, - }; + return { + nodes: file.program.body, + globals: metadata.globals, + }; + }, + dependencies: metadata.dependencies, }; } @@ -256,12 +256,15 @@ function loadHelper(name) { export function get( name, - getDependency?: string => t.Expression, + getDependency?: string => ?t.Expression, id?, - getLocalBindings?: () => string[], + localBindings?: string[], ) { - const helper = loadHelper(name); - return helper(getDependency, id, getLocalBindings); + return loadHelper(name).build(getDependency, id, localBindings); +} + +export function getDependencies(name: string): $ReadOnlyArray { + return Array.from(loadHelper(name).dependencies.values()); } export const list = Object.keys(helpers) diff --git a/packages/babel-plugin-transform-es2015-block-scoping/src/tdz.js b/packages/babel-plugin-transform-es2015-block-scoping/src/tdz.js index 457efe58e9..b1da159b80 100644 --- a/packages/babel-plugin-transform-es2015-block-scoping/src/tdz.js +++ b/packages/babel-plugin-transform-es2015-block-scoping/src/tdz.js @@ -16,7 +16,6 @@ function buildTDZAssert(node, file) { return t.callExpression(file.addHelper("temporalRef"), [ node, t.stringLiteral(node.name), - file.addHelper("temporalUndefined"), ]); } diff --git a/packages/babel-runtime/helpers/builtin/es6/temporalRef.js b/packages/babel-runtime/helpers/builtin/es6/temporalRef.js new file mode 100644 index 0000000000..4b0679c64c --- /dev/null +++ b/packages/babel-runtime/helpers/builtin/es6/temporalRef.js @@ -0,0 +1,8 @@ +import undef from "./temporalUndefined"; +export default function _temporalRef(val, name) { + if (val === undef) { + throw new ReferenceError(name + " is not defined - temporal dead zone"); + } else { + return val; + } +} \ No newline at end of file diff --git a/packages/babel-runtime/helpers/builtin/temporalRef.js b/packages/babel-runtime/helpers/builtin/temporalRef.js new file mode 100644 index 0000000000..20b2652a1f --- /dev/null +++ b/packages/babel-runtime/helpers/builtin/temporalRef.js @@ -0,0 +1,11 @@ +var temporalUndefined = require("./temporalUndefined"); + +function _temporalRef(val, name) { + if (val === temporalUndefined) { + throw new ReferenceError(name + " is not defined - temporal dead zone"); + } else { + return val; + } +} + +module.exports = _temporalRef; \ No newline at end of file diff --git a/packages/babel-runtime/helpers/es6/temporalRef.js b/packages/babel-runtime/helpers/es6/temporalRef.js new file mode 100644 index 0000000000..4b0679c64c --- /dev/null +++ b/packages/babel-runtime/helpers/es6/temporalRef.js @@ -0,0 +1,8 @@ +import undef from "./temporalUndefined"; +export default function _temporalRef(val, name) { + if (val === undef) { + throw new ReferenceError(name + " is not defined - temporal dead zone"); + } else { + return val; + } +} \ No newline at end of file diff --git a/packages/babel-runtime/helpers/temporalRef.js b/packages/babel-runtime/helpers/temporalRef.js new file mode 100644 index 0000000000..20b2652a1f --- /dev/null +++ b/packages/babel-runtime/helpers/temporalRef.js @@ -0,0 +1,11 @@ +var temporalUndefined = require("./temporalUndefined"); + +function _temporalRef(val, name) { + if (val === temporalUndefined) { + throw new ReferenceError(name + " is not defined - temporal dead zone"); + } else { + return val; + } +} + +module.exports = _temporalRef; \ No newline at end of file diff --git a/packages/babel-runtime/scripts/build-dist.js b/packages/babel-runtime/scripts/build-dist.js index 54f309907d..8f424f51d6 100644 --- a/packages/babel-runtime/scripts/build-dist.js +++ b/packages/babel-runtime/scripts/build-dist.js @@ -99,6 +99,15 @@ function buildRuntimeRewritePlugin(relativePath, helperName, dependencies) { }; } +function buildRequireCall(id, dep) { + return t.variableDeclaration("var", [ + t.variableDeclarator( + id, + t.callExpression(t.identifier("require"), [t.stringLiteral(dep)]) + ) + ]); +} + function buildHelper(helperName, modules, useBuiltIns) { const id = modules === "commonjs" @@ -106,12 +115,31 @@ function buildHelper(helperName, modules, useBuiltIns) { : null; const sourceType = modules === "commonjs" ? "script" : "module"; - const helper = helpers.get(helperName, null, id); - const tree = t.program(helper.nodes, [], sourceType); + const tree = t.program([], [], sourceType); + const dependencies = {}; + let bindings = null; + + if (modules === "commonjs") { + bindings = []; + for (const dep of helpers.getDependencies(helperName)) { + const id = dependencies[dep] = t.identifier(t.toIdentifier(dep)); + tree.body.push(buildRequireCall(id, dep)); + bindings.push(id.name); + } + } + + const helper = helpers.get( + helperName, + dep => dependencies[dep], + id, + bindings + ); + tree.body.push.apply(tree.body, helper.nodes); + const transformOpts = makeTransformOpts(modules, useBuiltIns); const relative = useBuiltIns ? "../.." : ".."; - + return babel.transformFromAst(tree, null, { presets: transformOpts.presets, plugins: transformOpts.plugins.concat([