convert @babel/helpers to typescript (#13679)
Co-authored-by: Federico Ciardi <fed.ciardi@gmail.com>
This commit is contained in:
parent
10640b2aad
commit
b00bd94ad8
@ -149,7 +149,7 @@ async function generateRuntimeHelpers() {
|
|||||||
return generateHelpers(
|
return generateHelpers(
|
||||||
`./packages/babel-helpers/scripts/generate-helpers.js`,
|
`./packages/babel-helpers/scripts/generate-helpers.js`,
|
||||||
`./packages/babel-helpers/src/`,
|
`./packages/babel-helpers/src/`,
|
||||||
"helpers-generated.js",
|
"helpers-generated.ts",
|
||||||
"@babel/helpers"
|
"@babel/helpers"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ 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.
|
||||||
const buildUmdWrapper = replacements =>
|
const buildUmdWrapper = replacements =>
|
||||||
template`
|
template.statement`
|
||||||
(function (root, factory) {
|
(function (root, factory) {
|
||||||
if (typeof define === "function" && define.amd) {
|
if (typeof define === "function" && define.amd) {
|
||||||
define(AMD_ARGUMENTS, factory);
|
define(AMD_ARGUMENTS, factory);
|
||||||
@ -21,10 +21,10 @@ const buildUmdWrapper = replacements =>
|
|||||||
});
|
});
|
||||||
`(replacements);
|
`(replacements);
|
||||||
|
|
||||||
function buildGlobal(allowlist) {
|
function buildGlobal(allowlist?: Array<string>) {
|
||||||
const namespace = t.identifier("babelHelpers");
|
const namespace = t.identifier("babelHelpers");
|
||||||
|
|
||||||
const body = [];
|
const body: t.Statement[] = [];
|
||||||
const container = t.functionExpression(
|
const container = t.functionExpression(
|
||||||
null,
|
null,
|
||||||
[t.identifier("global")],
|
[t.identifier("global")],
|
||||||
@ -65,8 +65,8 @@ function buildGlobal(allowlist) {
|
|||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildModule(allowlist) {
|
function buildModule(allowlist?: Array<string>) {
|
||||||
const body = [];
|
const body: t.Statement[] = [];
|
||||||
const refs = buildHelpers(body, null, allowlist);
|
const refs = buildHelpers(body, null, allowlist);
|
||||||
|
|
||||||
body.unshift(
|
body.unshift(
|
||||||
@ -81,10 +81,10 @@ function buildModule(allowlist) {
|
|||||||
return t.program(body, [], "module");
|
return t.program(body, [], "module");
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildUmd(allowlist) {
|
function buildUmd(allowlist?: Array<string>) {
|
||||||
const namespace = t.identifier("babelHelpers");
|
const namespace = t.identifier("babelHelpers");
|
||||||
|
|
||||||
const body = [];
|
const body: t.Statement[] = [];
|
||||||
body.push(
|
body.push(
|
||||||
t.variableDeclaration("var", [
|
t.variableDeclaration("var", [
|
||||||
t.variableDeclarator(namespace, t.identifier("global")),
|
t.variableDeclarator(namespace, t.identifier("global")),
|
||||||
@ -105,14 +105,14 @@ function buildUmd(allowlist) {
|
|||||||
AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]),
|
AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]),
|
||||||
FACTORY_BODY: body,
|
FACTORY_BODY: body,
|
||||||
UMD_ROOT: t.identifier("this"),
|
UMD_ROOT: t.identifier("this"),
|
||||||
}) as t.Statement,
|
}),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildVar(allowlist) {
|
function buildVar(allowlist?: Array<string>) {
|
||||||
const namespace = t.identifier("babelHelpers");
|
const namespace = t.identifier("babelHelpers");
|
||||||
|
|
||||||
const body = [];
|
const body: t.Statement[] = [];
|
||||||
body.push(
|
body.push(
|
||||||
t.variableDeclaration("var", [
|
t.variableDeclaration("var", [
|
||||||
t.variableDeclarator(namespace, t.objectExpression([])),
|
t.variableDeclarator(namespace, t.objectExpression([])),
|
||||||
@ -124,8 +124,12 @@ function buildVar(allowlist) {
|
|||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildHelpers(body, namespace, allowlist) {
|
function buildHelpers(
|
||||||
const getHelperReference = name => {
|
body: t.Statement[],
|
||||||
|
namespace: t.Expression | null,
|
||||||
|
allowlist?: Array<string>,
|
||||||
|
) {
|
||||||
|
const getHelperReference = (name: string) => {
|
||||||
return namespace
|
return namespace
|
||||||
? t.memberExpression(namespace, t.identifier(name))
|
? t.memberExpression(namespace, t.identifier(name))
|
||||||
: t.identifier(`_${name}`);
|
: t.identifier(`_${name}`);
|
||||||
@ -148,7 +152,7 @@ export default function (
|
|||||||
allowlist?: Array<string>,
|
allowlist?: Array<string>,
|
||||||
outputType: "global" | "module" | "umd" | "var" = "global",
|
outputType: "global" | "module" | "umd" | "var" = "global",
|
||||||
) {
|
) {
|
||||||
let tree;
|
let tree: t.Program;
|
||||||
|
|
||||||
const build = {
|
const build = {
|
||||||
global: buildGlobal,
|
global: buildGlobal,
|
||||||
|
|||||||
@ -174,7 +174,7 @@ export default class File {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
addHelper(name: string): any {
|
addHelper(name: string): t.Identifier {
|
||||||
const declar = this.declarations[name];
|
const declar = this.declarations[name];
|
||||||
if (declar) return t.cloneNode(declar);
|
if (declar) return t.cloneNode(declar);
|
||||||
|
|
||||||
@ -209,6 +209,7 @@ export default class File {
|
|||||||
});
|
});
|
||||||
|
|
||||||
nodes.forEach(node => {
|
nodes.forEach(node => {
|
||||||
|
// @ts-expect-error
|
||||||
node._compact = true;
|
node._compact = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,17 @@
|
|||||||
// @flow
|
|
||||||
|
|
||||||
import template from "@babel/template";
|
import template from "@babel/template";
|
||||||
|
import type * as t from "@babel/types";
|
||||||
|
|
||||||
import * as generated from "./helpers-generated";
|
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;
|
export default helpers;
|
||||||
|
|
||||||
const helper = (minVersion: string) => tpl => ({
|
const helper = (minVersion: string) => (tpl: TemplateStringsArray) => ({
|
||||||
minVersion,
|
minVersion,
|
||||||
ast: () => template.program.ast(tpl),
|
ast: () => template.program.ast(tpl),
|
||||||
});
|
});
|
||||||
@ -1,8 +1,10 @@
|
|||||||
|
import type { File } from "@babel/core";
|
||||||
|
import type { NodePath, Visitor } from "@babel/traverse";
|
||||||
import traverse from "@babel/traverse";
|
import traverse from "@babel/traverse";
|
||||||
import * as t from "@babel/types";
|
import * as t from "@babel/types";
|
||||||
import helpers from "./helpers";
|
import helpers from "./helpers";
|
||||||
|
|
||||||
function makePath(path) {
|
function makePath(path: NodePath) {
|
||||||
const parts = [];
|
const parts = [];
|
||||||
|
|
||||||
for (; path.parentPath; path = path.parentPath) {
|
for (; path.parentPath; path = path.parentPath) {
|
||||||
@ -14,23 +16,35 @@ function makePath(path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let fileClass = undefined;
|
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
|
* 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.
|
||||||
*/
|
*/
|
||||||
function getHelperMetadata(file) {
|
function getHelperMetadata(file: File): HelperMetadata {
|
||||||
const globals = new Set();
|
const globals = new Set<string>();
|
||||||
const localBindingNames = new Set();
|
const localBindingNames = new Set<string>();
|
||||||
// Maps imported identifier -> helper name
|
// Maps imported identifier -> helper name
|
||||||
const dependencies = new Map();
|
const dependencies = new Map<t.Identifier, string>();
|
||||||
|
|
||||||
let exportName;
|
let exportName: string | undefined;
|
||||||
let exportPath;
|
let exportPath: string | undefined;
|
||||||
const exportBindingAssignments = [];
|
const exportBindingAssignments: string[] = [];
|
||||||
const importPaths = [];
|
const importPaths: string[] = [];
|
||||||
const importBindingsReferences = [];
|
const importBindingsReferences: string[] = [];
|
||||||
|
|
||||||
const dependencyVisitor = {
|
const dependencyVisitor: Visitor = {
|
||||||
ImportDeclaration(child) {
|
ImportDeclaration(child) {
|
||||||
const name = child.node.source.value;
|
const name = child.node.source.value;
|
||||||
if (!helpers[name]) {
|
if (!helpers[name]) {
|
||||||
@ -75,7 +89,7 @@ function getHelperMetadata(file) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const referenceVisitor = {
|
const referenceVisitor: Visitor = {
|
||||||
Program(path) {
|
Program(path) {
|
||||||
const bindings = path.scope.getAllBindings();
|
const bindings = path.scope.getAllBindings();
|
||||||
|
|
||||||
@ -88,7 +102,7 @@ function getHelperMetadata(file) {
|
|||||||
},
|
},
|
||||||
ReferencedIdentifier(child) {
|
ReferencedIdentifier(child) {
|
||||||
const name = child.node.name;
|
const name = child.node.name;
|
||||||
const binding = child.scope.getBinding(name, /* noGlobal */ true);
|
const binding = child.scope.getBinding(name);
|
||||||
if (!binding) {
|
if (!binding) {
|
||||||
globals.add(name);
|
globals.add(name);
|
||||||
} else if (dependencies.has(binding.identifier)) {
|
} else if (dependencies.has(binding.identifier)) {
|
||||||
@ -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.
|
* 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) {
|
if (localBindings && !id) {
|
||||||
throw new Error("Unexpected local bindings for module-based helpers.");
|
throw new Error("Unexpected local bindings for module-based helpers.");
|
||||||
}
|
}
|
||||||
@ -155,13 +177,13 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
|
|||||||
importPaths,
|
importPaths,
|
||||||
} = metadata;
|
} = metadata;
|
||||||
|
|
||||||
const dependenciesRefs = {};
|
const dependenciesRefs: Record<string, t.Expression> = {};
|
||||||
dependencies.forEach((name, id) => {
|
dependencies.forEach((name, id) => {
|
||||||
dependenciesRefs[id.name] =
|
dependenciesRefs[id.name] =
|
||||||
(typeof getDependency === "function" && getDependency(name)) || id;
|
(typeof getDependency === "function" && getDependency(name)) || id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const toRename = {};
|
const toRename: Record<string, string> = {};
|
||||||
const bindings = new Set(localBindings || []);
|
const bindings = new Set(localBindings || []);
|
||||||
localBindingNames.forEach(name => {
|
localBindingNames.forEach(name => {
|
||||||
let newName = name;
|
let newName = name;
|
||||||
@ -174,13 +196,16 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
|
|||||||
toRename[exportName] = id.name;
|
toRename[exportName] = id.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const visitor = {
|
const visitor: 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.
|
||||||
const exp = path.get(exportPath);
|
const exp: NodePath<t.ExportDefaultDeclaration> = path.get(exportPath);
|
||||||
const imps = importPaths.map(p => path.get(p));
|
const imps: NodePath<t.ImportDeclaration>[] = importPaths.map(p =>
|
||||||
const impsBindingRefs = importBindingsReferences.map(p => path.get(p));
|
path.get(p),
|
||||||
|
);
|
||||||
|
const impsBindingRefs: NodePath<t.Identifier>[] =
|
||||||
|
importBindingsReferences.map(p => path.get(p));
|
||||||
|
|
||||||
const decl = exp.get("declaration");
|
const decl = exp.get("declaration");
|
||||||
if (id.type === "Identifier") {
|
if (id.type === "Identifier") {
|
||||||
@ -188,13 +213,15 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
|
|||||||
exp.replaceWith(decl);
|
exp.replaceWith(decl);
|
||||||
} else {
|
} else {
|
||||||
exp.replaceWith(
|
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") {
|
} else if (id.type === "MemberExpression") {
|
||||||
if (decl.isFunctionDeclaration()) {
|
if (decl.isFunctionDeclaration()) {
|
||||||
exportBindingAssignments.forEach(assignPath => {
|
exportBindingAssignments.forEach(assignPath => {
|
||||||
const assign = path.get(assignPath);
|
const assign: NodePath<t.Expression> = path.get(assignPath);
|
||||||
assign.replaceWith(t.assignmentExpression("=", id, assign.node));
|
assign.replaceWith(t.assignmentExpression("=", id, assign.node));
|
||||||
});
|
});
|
||||||
exp.replaceWith(decl);
|
exp.replaceWith(decl);
|
||||||
@ -206,7 +233,9 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
exp.replaceWith(
|
exp.replaceWith(
|
||||||
t.expressionStatement(t.assignmentExpression("=", id, decl.node)),
|
t.expressionStatement(
|
||||||
|
t.assignmentExpression("=", id, decl.node as t.Expression),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -231,8 +260,21 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
|
|||||||
traverse(file.ast, visitor, file.scope);
|
traverse(file.ast, visitor, file.scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
const helperData = Object.create(null);
|
interface HelperData {
|
||||||
function loadHelper(name) {
|
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]) {
|
if (!helperData[name]) {
|
||||||
const helper = helpers[name];
|
const helper = helpers[name];
|
||||||
if (!helper) {
|
if (!helper) {
|
||||||
@ -242,7 +284,7 @@ function loadHelper(name) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn = () => {
|
const fn = (): File => {
|
||||||
const file = { ast: t.file(helper.ast()) };
|
const file = { ast: t.file(helper.ast()) };
|
||||||
if (fileClass) {
|
if (fileClass) {
|
||||||
return new fileClass(
|
return new fileClass(
|
||||||
@ -252,7 +294,7 @@ function loadHelper(name) {
|
|||||||
file,
|
file,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return file;
|
return file as File;
|
||||||
};
|
};
|
||||||
|
|
||||||
const metadata = getHelperMetadata(fn());
|
const metadata = getHelperMetadata(fn());
|
||||||
@ -278,9 +320,9 @@ function loadHelper(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function get(
|
export function get(
|
||||||
name,
|
name: string,
|
||||||
getDependency?: string => ?t.Expression,
|
getDependency?: GetDependency,
|
||||||
id?,
|
id?: t.Identifier | t.MemberExpression,
|
||||||
localBindings?: string[],
|
localBindings?: string[],
|
||||||
) {
|
) {
|
||||||
return loadHelper(name).build(getDependency, id, localBindings);
|
return loadHelper(name).build(getDependency, id, localBindings);
|
||||||
@ -290,7 +332,7 @@ export function minVersion(name: string) {
|
|||||||
return loadHelper(name).minVersion();
|
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());
|
return Array.from(loadHelper(name).dependencies.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1031,7 +1031,7 @@ export default class Scope {
|
|||||||
* Walks the scope tree and gathers **all** bindings.
|
* Walks the scope tree and gathers **all** bindings.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
getAllBindings(): any {
|
getAllBindings(): Record<string, Binding> {
|
||||||
const ids = Object.create(null);
|
const ids = Object.create(null);
|
||||||
|
|
||||||
let scope: Scope = this;
|
let scope: Scope = this;
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
"./packages/babel-helper-transform-fixture-test-runner/src/**/*.ts",
|
"./packages/babel-helper-transform-fixture-test-runner/src/**/*.ts",
|
||||||
"./packages/babel-helper-validator-identifier/src/**/*.ts",
|
"./packages/babel-helper-validator-identifier/src/**/*.ts",
|
||||||
"./packages/babel-helper-validator-option/src/**/*.ts",
|
"./packages/babel-helper-validator-option/src/**/*.ts",
|
||||||
|
"./packages/babel-helpers/src/**/*.ts",
|
||||||
"./packages/babel-highlight/src/**/*.ts",
|
"./packages/babel-highlight/src/**/*.ts",
|
||||||
"./packages/babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining/src/**/*.ts",
|
"./packages/babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining/src/**/*.ts",
|
||||||
"./packages/babel-plugin-proposal-async-do-expressions/src/**/*.ts",
|
"./packages/babel-plugin-proposal-async-do-expressions/src/**/*.ts",
|
||||||
@ -107,6 +108,9 @@
|
|||||||
"@babel/helper-validator-option": [
|
"@babel/helper-validator-option": [
|
||||||
"./packages/babel-helper-validator-option/src"
|
"./packages/babel-helper-validator-option/src"
|
||||||
],
|
],
|
||||||
|
"@babel/helpers": [
|
||||||
|
"./packages/babel-helpers/src"
|
||||||
|
],
|
||||||
"@babel/highlight": [
|
"@babel/highlight": [
|
||||||
"./packages/babel-highlight/src"
|
"./packages/babel-highlight/src"
|
||||||
],
|
],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user