Skip to content

Commit

Permalink
convert @babel/helpers to typescript (#13679)
Browse files Browse the repository at this point in the history
Co-authored-by: Federico Ciardi <fed.ciardi@gmail.com>
  • Loading branch information
colinaaa and fedeci committed Aug 16, 2021
1 parent 10640b2 commit b00bd94
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 51 deletions.
2 changes: 1 addition & 1 deletion Gulpfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ async function generateRuntimeHelpers() {
return generateHelpers(
`./packages/babel-helpers/scripts/generate-helpers.js`,
`./packages/babel-helpers/src/`,
"helpers-generated.js",
"helpers-generated.ts",
"@babel/helpers"
);
}
Expand Down
30 changes: 17 additions & 13 deletions packages/babel-core/src/tools/build-external-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import File from "../transformation/file/file";
// Wrapped to avoid wasting time parsing this when almost no-one uses
// build-external-helpers.
const buildUmdWrapper = replacements =>
template`
template.statement`
(function (root, factory) {
if (typeof define === "function" && define.amd) {
define(AMD_ARGUMENTS, factory);
Expand All @@ -21,10 +21,10 @@ const buildUmdWrapper = replacements =>
});
`(replacements);

function buildGlobal(allowlist) {
function buildGlobal(allowlist?: Array<string>) {
const namespace = t.identifier("babelHelpers");

const body = [];
const body: t.Statement[] = [];
const container = t.functionExpression(
null,
[t.identifier("global")],
Expand Down Expand Up @@ -65,8 +65,8 @@ function buildGlobal(allowlist) {
return tree;
}

function buildModule(allowlist) {
const body = [];
function buildModule(allowlist?: Array<string>) {
const body: t.Statement[] = [];
const refs = buildHelpers(body, null, allowlist);

body.unshift(
Expand All @@ -81,10 +81,10 @@ function buildModule(allowlist) {
return t.program(body, [], "module");
}

function buildUmd(allowlist) {
function buildUmd(allowlist?: Array<string>) {
const namespace = t.identifier("babelHelpers");

const body = [];
const body: t.Statement[] = [];
body.push(
t.variableDeclaration("var", [
t.variableDeclarator(namespace, t.identifier("global")),
Expand All @@ -105,14 +105,14 @@ function buildUmd(allowlist) {
AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]),
FACTORY_BODY: body,
UMD_ROOT: t.identifier("this"),
}) as t.Statement,
}),
]);
}

function buildVar(allowlist) {
function buildVar(allowlist?: Array<string>) {
const namespace = t.identifier("babelHelpers");

const body = [];
const body: t.Statement[] = [];
body.push(
t.variableDeclaration("var", [
t.variableDeclarator(namespace, t.objectExpression([])),
Expand All @@ -124,8 +124,12 @@ function buildVar(allowlist) {
return tree;
}

function buildHelpers(body, namespace, allowlist) {
const getHelperReference = name => {
function buildHelpers(
body: t.Statement[],
namespace: t.Expression | null,
allowlist?: Array<string>,
) {
const getHelperReference = (name: string) => {
return namespace
? t.memberExpression(namespace, t.identifier(name))
: t.identifier(`_${name}`);
Expand All @@ -148,7 +152,7 @@ export default function (
allowlist?: Array<string>,
outputType: "global" | "module" | "umd" | "var" = "global",
) {
let tree;
let tree: t.Program;

const build = {
global: buildGlobal,
Expand Down
3 changes: 2 additions & 1 deletion packages/babel-core/src/transformation/file/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export default class File {
);
}

addHelper(name: string): any {
addHelper(name: string): t.Identifier {
const declar = this.declarations[name];
if (declar) return t.cloneNode(declar);

Expand Down Expand Up @@ -209,6 +209,7 @@ export default class File {
});

nodes.forEach(node => {
// @ts-expect-error
node._compact = true;
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
// @flow

import template from "@babel/template";
import type * as t from "@babel/types";

import * as generated from "./helpers-generated";

const helpers = { __proto__: null, ...generated };
interface Helper {
minVersion: string;
ast: () => t.Program;
}

const helpers: Record<string, Helper> = { __proto__: null, ...generated };
export default helpers;

const helper = (minVersion: string) => tpl => ({
const helper = (minVersion: string) => (tpl: TemplateStringsArray) => ({
minVersion,
ast: () => template.program.ast(tpl),
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { File } from "@babel/core";
import type { NodePath, Visitor } from "@babel/traverse";
import traverse from "@babel/traverse";
import * as t from "@babel/types";
import helpers from "./helpers";

function makePath(path) {
function makePath(path: NodePath) {
const parts = [];

for (; path.parentPath; path = path.parentPath) {
Expand All @@ -14,23 +16,35 @@ function makePath(path) {
}

let fileClass = undefined;

interface HelperMetadata {
globals: string[];
localBindingNames: string[];
dependencies: Map<t.Identifier, string>;
exportBindingAssignments: string[];
exportPath: string;
exportName: string;
importBindingsReferences: string[];
importPaths: string[];
}

/**
* 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.
*/
function getHelperMetadata(file) {
const globals = new Set();
const localBindingNames = new Set();
function getHelperMetadata(file: File): HelperMetadata {
const globals = new Set<string>();
const localBindingNames = new Set<string>();
// Maps imported identifier -> helper name
const dependencies = new Map();
const dependencies = new Map<t.Identifier, string>();

let exportName;
let exportPath;
const exportBindingAssignments = [];
const importPaths = [];
const importBindingsReferences = [];
let exportName: string | undefined;
let exportPath: string | undefined;
const exportBindingAssignments: string[] = [];
const importPaths: string[] = [];
const importBindingsReferences: string[] = [];

const dependencyVisitor = {
const dependencyVisitor: Visitor = {
ImportDeclaration(child) {
const name = child.node.source.value;
if (!helpers[name]) {
Expand Down Expand Up @@ -75,7 +89,7 @@ function getHelperMetadata(file) {
},
};

const referenceVisitor = {
const referenceVisitor: Visitor = {
Program(path) {
const bindings = path.scope.getAllBindings();

Expand All @@ -88,7 +102,7 @@ function getHelperMetadata(file) {
},
ReferencedIdentifier(child) {
const name = child.node.name;
const binding = child.scope.getBinding(name, /* noGlobal */ true);
const binding = child.scope.getBinding(name);
if (!binding) {
globals.add(name);
} else if (dependencies.has(binding.identifier)) {
Expand Down Expand Up @@ -135,10 +149,18 @@ function getHelperMetadata(file) {
};
}

type GetDependency = (name: string) => t.Expression;

/**
* Given a helper AST and information about how it will be used, update the AST to match the usage.
*/
function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
function permuteHelperAST(
file: File,
metadata: HelperMetadata,
id?: t.Identifier | t.MemberExpression,
localBindings?: string[],
getDependency?: GetDependency,
) {
if (localBindings && !id) {
throw new Error("Unexpected local bindings for module-based helpers.");
}
Expand All @@ -155,13 +177,13 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
importPaths,
} = metadata;

const dependenciesRefs = {};
const dependenciesRefs: Record<string, t.Expression> = {};
dependencies.forEach((name, id) => {
dependenciesRefs[id.name] =
(typeof getDependency === "function" && getDependency(name)) || id;
});

const toRename = {};
const toRename: Record<string, string> = {};
const bindings = new Set(localBindings || []);
localBindingNames.forEach(name => {
let newName = name;
Expand All @@ -174,27 +196,32 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
toRename[exportName] = id.name;
}

const visitor = {
const visitor: Visitor = {
Program(path) {
// We need to compute these in advance because removing nodes would
// invalidate the paths.
const exp = path.get(exportPath);
const imps = importPaths.map(p => path.get(p));
const impsBindingRefs = importBindingsReferences.map(p => path.get(p));
const exp: NodePath<t.ExportDefaultDeclaration> = path.get(exportPath);
const imps: NodePath<t.ImportDeclaration>[] = importPaths.map(p =>
path.get(p),
);
const impsBindingRefs: NodePath<t.Identifier>[] =
importBindingsReferences.map(p => path.get(p));

const decl = exp.get("declaration");
if (id.type === "Identifier") {
if (decl.isFunctionDeclaration()) {
exp.replaceWith(decl);
} else {
exp.replaceWith(
t.variableDeclaration("var", [t.variableDeclarator(id, decl.node)]),
t.variableDeclaration("var", [
t.variableDeclarator(id, decl.node as t.Expression),
]),
);
}
} else if (id.type === "MemberExpression") {
if (decl.isFunctionDeclaration()) {
exportBindingAssignments.forEach(assignPath => {
const assign = path.get(assignPath);
const assign: NodePath<t.Expression> = path.get(assignPath);
assign.replaceWith(t.assignmentExpression("=", id, assign.node));
});
exp.replaceWith(decl);
Expand All @@ -206,7 +233,9 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
);
} else {
exp.replaceWith(
t.expressionStatement(t.assignmentExpression("=", id, decl.node)),
t.expressionStatement(
t.assignmentExpression("=", id, decl.node as t.Expression),
),
);
}
} else {
Expand All @@ -231,8 +260,21 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
traverse(file.ast, visitor, file.scope);
}

const helperData = Object.create(null);
function loadHelper(name) {
interface HelperData {
build: (
getDependency: GetDependency,
id: t.Identifier | t.MemberExpression,
localBindings: string[],
) => {
nodes: t.Program["body"];
globals: string[];
};
minVersion: () => string;
dependencies: Map<t.Identifier, string>;
}

const helperData: Record<string, HelperData> = Object.create(null);
function loadHelper(name: string) {
if (!helperData[name]) {
const helper = helpers[name];
if (!helper) {
Expand All @@ -242,7 +284,7 @@ function loadHelper(name) {
});
}

const fn = () => {
const fn = (): File => {
const file = { ast: t.file(helper.ast()) };
if (fileClass) {
return new fileClass(
Expand All @@ -252,7 +294,7 @@ function loadHelper(name) {
file,
);
}
return file;
return file as File;
};

const metadata = getHelperMetadata(fn());
Expand All @@ -278,9 +320,9 @@ function loadHelper(name) {
}

export function get(
name,
getDependency?: string => ?t.Expression,
id?,
name: string,
getDependency?: GetDependency,
id?: t.Identifier | t.MemberExpression,
localBindings?: string[],
) {
return loadHelper(name).build(getDependency, id, localBindings);
Expand All @@ -290,7 +332,7 @@ export function minVersion(name: string) {
return loadHelper(name).minVersion();
}

export function getDependencies(name: string): $ReadOnlyArray<string> {
export function getDependencies(name: string): ReadonlyArray<string> {
return Array.from(loadHelper(name).dependencies.values());
}

Expand Down
2 changes: 1 addition & 1 deletion packages/babel-traverse/src/scope/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1031,7 +1031,7 @@ export default class Scope {
* Walks the scope tree and gathers **all** bindings.
*/

getAllBindings(): any {
getAllBindings(): Record<string, Binding> {
const ids = Object.create(null);

let scope: Scope = this;
Expand Down
4 changes: 4 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"./packages/babel-helper-transform-fixture-test-runner/src/**/*.ts",
"./packages/babel-helper-validator-identifier/src/**/*.ts",
"./packages/babel-helper-validator-option/src/**/*.ts",
"./packages/babel-helpers/src/**/*.ts",
"./packages/babel-highlight/src/**/*.ts",
"./packages/babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining/src/**/*.ts",
"./packages/babel-plugin-proposal-async-do-expressions/src/**/*.ts",
Expand Down Expand Up @@ -107,6 +108,9 @@
"@babel/helper-validator-option": [
"./packages/babel-helper-validator-option/src"
],
"@babel/helpers": [
"./packages/babel-helpers/src"
],
"@babel/highlight": [
"./packages/babel-highlight/src"
],
Expand Down

0 comments on commit b00bd94

Please sign in to comment.