Skip to content

Commit

Permalink
Move hoistVariables to Scope.prototype (#16644)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo authored Jul 17, 2024
1 parent 054be45 commit 52b21ef
Show file tree
Hide file tree
Showing 14 changed files with 113 additions and 216 deletions.
3 changes: 0 additions & 3 deletions packages/babel-helper-hoist-variables/.npmignore

This file was deleted.

19 changes: 0 additions & 19 deletions packages/babel-helper-hoist-variables/README.md

This file was deleted.

52 changes: 0 additions & 52 deletions packages/babel-helper-hoist-variables/package.json

This file was deleted.

73 changes: 0 additions & 73 deletions packages/babel-helper-hoist-variables/src/index.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/babel-helper-plugin-utils/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"../../packages/babel-helper-compilation-targets/src/**/*.ts",
"../../packages/babel-helper-fixtures/src/**/*.ts",
"../../packages/babel-helper-function-name/src/**/*.ts",
"../../packages/babel-helper-hoist-variables/src/**/*.ts",
"../../packages/babel-helper-module-imports/src/**/*.ts",
"../../packages/babel-helper-module-transforms/src/**/*.ts",
"../../packages/babel-helper-plugin-test-runner/src/**/*.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,16 @@
"babel-plugin"
],
"dependencies": {
"@babel/helper-hoist-variables": "workspace:^",
"@babel/helper-plugin-utils": "workspace:^",
"@babel/plugin-syntax-async-do-expressions": "workspace:^"
"@babel/plugin-syntax-async-do-expressions": "workspace:^",
"@babel/traverse": "condition:BABEL_8_BREAKING ? : workspace:^"
},
"peerDependencies": {
"@babel/core": "^7.13.0"
},
"devDependencies": {
"@babel/core": "workspace:^",
"@babel/helper-plugin-test-runner": "workspace:^",
"@babel/traverse": "workspace:^",
"@babel/types": "workspace:^"
"@babel/helper-plugin-test-runner": "workspace:^"
},
"homepage": "https://babel.dev/docs/en/next/babel-plugin-proposal-async-do-expressions",
"engines": {
Expand Down
19 changes: 8 additions & 11 deletions packages/babel-plugin-proposal-async-do-expressions/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { declare } from "@babel/helper-plugin-utils";
import syntaxAsyncDoExpressions from "@babel/plugin-syntax-async-do-expressions";
import hoistVariables from "@babel/helper-hoist-variables";
import type { types as t } from "@babel/core";

export default declare(({ types: t, assertVersion }) => {
assertVersion(REQUIRED_VERSION("^7.13.0"));
Expand All @@ -16,18 +14,17 @@ export default declare(({ types: t, assertVersion }) => {
// non-async do expressions are handled by proposal-do-expressions
return;
}
const { scope } = path;
// Hoist variable declaration to containing function scope
// `async do { var x = 1; x }` -> `var x; (async() => { x = 1; return x })()`
hoistVariables(
path,
(id: t.Identifier) => {
scope.push({ id: t.cloneNode(id) });
},
"var",
);
const bodyPath = path.get("body");
if (!process.env.BABEL_8_BREAKING && !USE_ESM && !IS_STANDALONE) {
// polyfill when being run by an older Babel version
path.scope.hoistVariables ??=
// eslint-disable-next-line no-restricted-globals
require("@babel/traverse").Scope.prototype.hoistVariables;
}
path.scope.hoistVariables();

const bodyPath = path.get("body");
// add implicit returns to all ending expression statements
const completionRecords = bodyPath.getCompletionRecords();

Expand Down
4 changes: 2 additions & 2 deletions packages/babel-plugin-transform-modules-systemjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
},
"main": "./lib/index.js",
"dependencies": {
"@babel/helper-hoist-variables": "workspace:^",
"@babel/helper-module-transforms": "workspace:^",
"@babel/helper-plugin-utils": "workspace:^",
"@babel/helper-validator-identifier": "workspace:^"
"@babel/helper-validator-identifier": "workspace:^",
"@babel/traverse": "condition:BABEL_8_BREAKING ? : workspace:^"
},
"keywords": [
"babel-plugin"
Expand Down
16 changes: 11 additions & 5 deletions packages/babel-plugin-transform-modules-systemjs/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { declare } from "@babel/helper-plugin-utils";
import hoistVariables from "@babel/helper-hoist-variables";
import { template, types as t } from "@babel/core";
import type { PluginPass, NodePath, Scope, Visitor } from "@babel/core";
import {
Expand Down Expand Up @@ -629,12 +628,19 @@ export default declare<PluginState>((api, options: Options) => {
// @ts-expect-error todo(flow->ts): do not reuse variables
if (moduleName) moduleName = t.stringLiteral(moduleName);

hoistVariables(path, (id, name, hasInit) => {
if (!process.env.BABEL_8_BREAKING && !USE_ESM && !IS_STANDALONE) {
// polyfill when being run by an older Babel version
path.scope.hoistVariables ??=
// eslint-disable-next-line no-restricted-globals
require("@babel/traverse").Scope.prototype.hoistVariables;
}

path.scope.hoistVariables((id, hasInit) => {
variableIds.push(id);
if (!hasInit && name in exportMap) {
for (const exported of exportMap[name]) {
if (!hasInit && id.name in exportMap) {
for (const exported of exportMap[id.name]) {
exportNames.push(exported);
exportValues.push(scope.buildUndefinedNode());
exportValues.push(t.buildUndefinedNode());
}
}
});
Expand Down
1 change: 0 additions & 1 deletion packages/babel-traverse/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"@babel/code-frame": "workspace:^",
"@babel/generator": "workspace:^",
"@babel/helper-function-name": "workspace:^",
"@babel/helper-hoist-variables": "workspace:^",
"@babel/parser": "workspace:^",
"@babel/types": "workspace:^",
"debug": "^4.3.1",
Expand Down
13 changes: 2 additions & 11 deletions packages/babel-traverse/src/path/replacement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import {
yieldExpression,
} from "@babel/types";
import type * as t from "@babel/types";
import hoistVariables from "@babel/helper-hoist-variables";

/**
* Replace a node with an array of multiple. This method performs the following steps:
Expand Down Expand Up @@ -261,18 +260,10 @@ export function replaceExpressionWithStatements(
// hoist variable declaration in do block
// `(do { var x = 1; x;})` -> `var x; (() => { x = 1; return x; })()`
const callee = (this as ThisType).get("callee");
hoistVariables(
callee.get("body"),
(id: t.Identifier) => {
this.scope.push({ id });
},
"var",
);
callee.get("body").scope.hoistVariables(id => this.scope.push({ id }));

// add implicit returns to all ending expression statements
const completionRecords: Array<NodePath> = (this as ThisType)
.get("callee")
.getCompletionRecords();
const completionRecords: Array<NodePath> = callee.getCompletionRecords();
for (const path of completionRecords) {
if (!path.isExpressionStatement()) continue;

Expand Down
60 changes: 60 additions & 0 deletions packages/babel-traverse/src/scope/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { BindingKind } from "./binding.ts";
import globals from "globals";
import {
NOT_LOCAL_BINDING,
assignmentExpression,
callExpression,
cloneNode,
getBindingIdentifiers,
Expand Down Expand Up @@ -38,6 +39,7 @@ import {
isThisExpression,
isUnaryExpression,
isVariableDeclaration,
expressionStatement,
matchesPattern,
memberExpression,
numericLiteral,
Expand All @@ -52,6 +54,7 @@ import {
isPrivateName,
isExportDeclaration,
buildUndefinedNode,
sequenceExpression,
} from "@babel/types";
import * as t from "@babel/types";
import { scope as scopeCache } from "../cache.ts";
Expand Down Expand Up @@ -1375,6 +1378,63 @@ class Scope {
}
} while ((scope = scope.parent));
}

/**
* Hoist all the `var` variable to the beginning of the function/program
* scope where their binding will be actually defined. For exmaple,
* { var x = 2 }
* will be transformed to
* var x; { x = 2 }
*
* @param emit A custom function to emit `var` declarations, for example to
* emit them in a different scope.
*/
hoistVariables(
emit: (id: t.Identifier, hasInit: boolean) => void = id =>
this.push({ id }),
) {
this.crawl();

const seen = new Set();
for (const name of Object.keys(this.bindings)) {
const binding = this.bindings[name];
if (!binding) continue;
const { path } = binding;
if (!path.isVariableDeclarator()) continue;
const { parent, parentPath } = path;

if (parent.kind !== "var" || seen.has(parent)) continue;
seen.add(path.parent);

let firstId;
const init = [];
for (const decl of parent.declarations) {
firstId ??= decl.id;
if (decl.init) {
init.push(assignmentExpression("=", decl.id, decl.init));
}

const ids = Object.keys(getBindingIdentifiers(decl, false, true, true));
for (const name of ids) {
emit(identifier(name), decl.init != null);
}
}

// for (var i in test)
if (parentPath.parentPath.isFor({ left: parent })) {
parentPath.replaceWith(firstId);
} else if (init.length === 0) {
parentPath.remove();
} else {
const expr = init.length === 1 ? init[0] : sequenceExpression(init);
if (parentPath.parentPath.isForStatement({ init: parent })) {
parentPath.replaceWith(expr);
} else {
parentPath.replaceWith(expressionStatement(expr));
}
}
}
}
}

type _Binding = Binding;
Expand Down
3 changes: 0 additions & 3 deletions tsconfig.paths.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@
"@babel/helper-function-name": [
"./packages/babel-helper-function-name/src"
],
"@babel/helper-hoist-variables": [
"./packages/babel-helper-hoist-variables/src"
],
"@babel/helper-import-to-platform-api": [
"./packages/babel-helper-import-to-platform-api/src"
],
Expand Down
Loading

0 comments on commit 52b21ef

Please sign in to comment.