mirror of
https://github.com/hanzoai/babel.git
synced 2026-09-24 16:56:45 +00:00
perf: Improve builders of @babel/types (#16870)
* perf * improve * Update packages/babel-types/src/definitions/index.ts Co-authored-by: Nicolò Ribaudo <[email protected]> * review * review * review --------- Co-authored-by: Nicolò Ribaudo <[email protected]>
This commit is contained in:
committed by
GitHub
co-authored by
Nicolò Ribaudo
parent
737cf3089b
commit
1e5452d448
@@ -0,0 +1,20 @@
|
||||
import { Benchmark, baselineTypes, currentTypes } from "../../util.mjs";
|
||||
|
||||
const bench = new Benchmark();
|
||||
|
||||
function benchCases(implementations, num) {
|
||||
for (const version in implementations) {
|
||||
const t = implementations[version];
|
||||
const blockStatement = t.blockStatement;
|
||||
|
||||
const stmts = new Array(num).fill(t.emptyStatement());
|
||||
bench.add(`${version} builder ${num}`, () => {
|
||||
blockStatement(stmts);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
benchCases({ baselineTypes, currentTypes }, 1);
|
||||
benchCases({ baselineTypes, currentTypes }, 128);
|
||||
|
||||
bench.run();
|
||||
@@ -77,6 +77,7 @@ export default [
|
||||
requireConfigFile: false,
|
||||
babelOptions: {
|
||||
babelrc: false,
|
||||
browserslistConfigFile: false,
|
||||
configFile: false,
|
||||
// Todo: Remove the parserOpts here after the proposal gets stage 4.
|
||||
parserOpts: {
|
||||
|
||||
@@ -545,7 +545,7 @@ defineType("Identifier", {
|
||||
validate:
|
||||
process.env.BABEL_8_BREAKING || process.env.BABEL_TYPES_8_BREAKING
|
||||
? function (parent, key, node) {
|
||||
const match = /\.(\w+)$/.exec(key);
|
||||
const match = /\.(\w+)$/.exec(key.toString());
|
||||
if (!match) return;
|
||||
|
||||
const [, parentKey] = match;
|
||||
@@ -1025,7 +1025,7 @@ defineType("RestElement", {
|
||||
validate:
|
||||
process.env.BABEL_8_BREAKING || process.env.BABEL_TYPES_8_BREAKING
|
||||
? function (parent: t.ArrayPattern | t.ObjectPattern, key) {
|
||||
const match = /(\w+)\[(\d+)\]/.exec(key);
|
||||
const match = /(\w+)\[(\d+)\]/.exec(key.toString());
|
||||
if (!match) throw new Error("Internal Babel error: malformed key.");
|
||||
|
||||
const [, listKey, index] = match as unknown as [
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
BUILDER_KEYS,
|
||||
DEPRECATED_KEYS,
|
||||
NODE_PARENT_VALIDATIONS,
|
||||
allExpandedTypes,
|
||||
} from "./utils.ts";
|
||||
import {
|
||||
PLACEHOLDERS,
|
||||
@@ -27,6 +28,17 @@ import { DEPRECATED_ALIASES } from "./deprecated-aliases.ts";
|
||||
FLIPPED_ALIAS_KEYS[DEPRECATED_ALIASES[deprecatedAlias]];
|
||||
});
|
||||
|
||||
for (const { types, set } of allExpandedTypes) {
|
||||
for (const type of types) {
|
||||
const aliases = FLIPPED_ALIAS_KEYS[type];
|
||||
if (aliases) {
|
||||
aliases.forEach(set.add, set);
|
||||
} else {
|
||||
set.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TYPES: Array<string> = [].concat(
|
||||
Object.keys(VISITOR_KEYS),
|
||||
Object.keys(FLIPPED_ALIAS_KEYS),
|
||||
|
||||
@@ -51,7 +51,7 @@ export type Validator = (
|
||||
| { shapeOf: { [x: string]: FieldOptions } }
|
||||
| object
|
||||
) &
|
||||
((node: t.Node, key: string, val: any) => void);
|
||||
((node: t.Node, key: string | { toString(): string }, val: any) => void);
|
||||
|
||||
export type FieldOptions = {
|
||||
default?: string | number | boolean | [];
|
||||
@@ -96,11 +96,21 @@ export function assertEach(callback: Validator): Validator {
|
||||
function validator(node: t.Node, key: string, val: any) {
|
||||
if (!Array.isArray(val)) return;
|
||||
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
const subkey = `${key}[${i}]`;
|
||||
let i = 0;
|
||||
// We lazily concatenate strings here for performance reasons.
|
||||
// Concatenating the strings is expensive because we are actually concatenating a string and a number,
|
||||
// so V8 cannot just create a "rope string" but has to allocate memory for the string resulting from the number
|
||||
// This string is very rarely used, only in error paths, so we can skip the concatenation cost in most cases
|
||||
const subKey = {
|
||||
toString() {
|
||||
return `${key}[${i}]`;
|
||||
},
|
||||
};
|
||||
|
||||
for (; i < val.length; i++) {
|
||||
const v = val[i];
|
||||
callback(node, subkey, v);
|
||||
childValidator(node, subkey, v);
|
||||
callback(node, subKey, v);
|
||||
childValidator(node, subKey, v);
|
||||
}
|
||||
}
|
||||
validator.each = callback;
|
||||
@@ -123,13 +133,31 @@ export function assertOneOf(...values: Array<any>): Validator {
|
||||
return validate;
|
||||
}
|
||||
|
||||
export const allExpandedTypes: {
|
||||
types: NodeTypes[];
|
||||
set: Set<string>;
|
||||
}[] = [];
|
||||
|
||||
export function assertNodeType(...types: NodeTypes[]): Validator {
|
||||
const expandedTypes = new Set<string>();
|
||||
|
||||
allExpandedTypes.push({ types, set: expandedTypes });
|
||||
|
||||
function validate(node: t.Node, key: string, val: any) {
|
||||
for (const type of types) {
|
||||
if (is(type, val)) {
|
||||
const valType = val?.type;
|
||||
if (valType != null) {
|
||||
if (expandedTypes.has(valType)) {
|
||||
validateChild(node, key, val);
|
||||
return;
|
||||
}
|
||||
if (valType === "Placeholder") {
|
||||
for (const type of types) {
|
||||
if (is(type, val)) {
|
||||
validateChild(node, key, val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
@@ -137,7 +165,7 @@ export function assertNodeType(...types: NodeTypes[]): Validator {
|
||||
node.type
|
||||
} expected node to be of a type ${JSON.stringify(
|
||||
types,
|
||||
)} but instead got ${JSON.stringify(val?.type)}`,
|
||||
)} but instead got ${JSON.stringify(valType)}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -150,8 +178,9 @@ export function assertNodeOrValueType(
|
||||
...types: (NodeTypes | PrimitiveTypes)[]
|
||||
): Validator {
|
||||
function validate(node: t.Node, key: string, val: any) {
|
||||
const primitiveType = getType(val);
|
||||
for (const type of types) {
|
||||
if (getType(val) === type || is(type, val)) {
|
||||
if (primitiveType === type || is(type, val)) {
|
||||
validateChild(node, key, val);
|
||||
return;
|
||||
}
|
||||
@@ -173,13 +202,13 @@ export function assertNodeOrValueType(
|
||||
|
||||
export function assertValueType(type: PrimitiveTypes): Validator {
|
||||
function validate(node: t.Node, key: string, val: any) {
|
||||
const valid = getType(val) === type;
|
||||
|
||||
if (!valid) {
|
||||
throw new TypeError(
|
||||
`Property ${key} expected type of ${type} but got ${getType(val)}`,
|
||||
);
|
||||
if (getType(val) === type) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
`Property ${key} expected type of ${type} but got ${getType(val)}`,
|
||||
);
|
||||
}
|
||||
|
||||
validate.type = type;
|
||||
@@ -188,9 +217,10 @@ export function assertValueType(type: PrimitiveTypes): Validator {
|
||||
}
|
||||
|
||||
export function assertShape(shape: { [x: string]: FieldOptions }): Validator {
|
||||
const keys = Object.keys(shape);
|
||||
function validate(node: t.Node, key: string, val: any) {
|
||||
const errors = [];
|
||||
for (const property of Object.keys(shape)) {
|
||||
for (const property of keys) {
|
||||
try {
|
||||
validateField(node, property, val[property], shape[property]);
|
||||
} catch (error) {
|
||||
|
||||
@@ -11,11 +11,7 @@ export default function isPlaceholderType(
|
||||
|
||||
const aliases: Array<string> | undefined =
|
||||
PLACEHOLDERS_ALIAS[placeholderType];
|
||||
if (aliases) {
|
||||
for (const alias of aliases) {
|
||||
if (targetType === alias) return true;
|
||||
}
|
||||
}
|
||||
if (aliases?.includes(targetType)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -26,13 +26,7 @@ export default function isType(nodeType: string, targetType: string): boolean {
|
||||
if (ALIAS_KEYS[targetType]) return false;
|
||||
|
||||
const aliases: Array<string> | undefined = FLIPPED_ALIAS_KEYS[targetType];
|
||||
if (aliases) {
|
||||
if (aliases[0] === nodeType) return true;
|
||||
|
||||
for (const alias of aliases) {
|
||||
if (nodeType === alias) return true;
|
||||
}
|
||||
}
|
||||
if (aliases?.includes(nodeType)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ export function validateField(
|
||||
|
||||
export function validateChild(
|
||||
node: t.Node | undefined | null,
|
||||
key: string,
|
||||
key: string | { toString(): string },
|
||||
val?: unknown,
|
||||
) {
|
||||
const type = (val as t.Node)?.type;
|
||||
|
||||
Reference in New Issue
Block a user