Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the layout of generated validators #15546

Merged
merged 1 commit into from Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
214 changes: 214 additions & 0 deletions benchmark/babel-types/validators/isExpression.mjs
@@ -0,0 +1,214 @@
import Benchmark from "benchmark";
import { report } from "../../util.mjs";

const suite = new Benchmark.Suite();

function isExpressionIf(node) {
if (!node) return false;
const nodeType = node.type;
if (
"ArrayExpression" === nodeType ||
"AssignmentExpression" === nodeType ||
"BinaryExpression" === nodeType ||
"CallExpression" === nodeType ||
"ConditionalExpression" === nodeType ||
"FunctionExpression" === nodeType ||
"Identifier" === nodeType ||
"StringLiteral" === nodeType ||
"NumericLiteral" === nodeType ||
"NullLiteral" === nodeType ||
"BooleanLiteral" === nodeType ||
"RegExpLiteral" === nodeType ||
"LogicalExpression" === nodeType ||
"MemberExpression" === nodeType ||
"NewExpression" === nodeType ||
"ObjectExpression" === nodeType ||
"SequenceExpression" === nodeType ||
"ParenthesizedExpression" === nodeType ||
"ThisExpression" === nodeType ||
"UnaryExpression" === nodeType ||
"UpdateExpression" === nodeType ||
"ArrowFunctionExpression" === nodeType ||
"ClassExpression" === nodeType ||
"MetaProperty" === nodeType ||
"Super" === nodeType ||
"TaggedTemplateExpression" === nodeType ||
"TemplateLiteral" === nodeType ||
"YieldExpression" === nodeType ||
"AwaitExpression" === nodeType ||
"Import" === nodeType ||
"BigIntLiteral" === nodeType ||
"OptionalMemberExpression" === nodeType ||
"OptionalCallExpression" === nodeType ||
"TypeCastExpression" === nodeType ||
"JSXElement" === nodeType ||
"JSXFragment" === nodeType ||
"BindExpression" === nodeType ||
"DoExpression" === nodeType ||
"RecordExpression" === nodeType ||
"TupleExpression" === nodeType ||
"DecimalLiteral" === nodeType ||
"ModuleExpression" === nodeType ||
"TopicReference" === nodeType ||
"PipelineTopicExpression" === nodeType ||
"PipelineBareFunction" === nodeType ||
"PipelinePrimaryTopicReference" === nodeType ||
"TSInstantiationExpression" === nodeType ||
"TSAsExpression" === nodeType ||
"TSSatisfiesExpression" === nodeType ||
"TSTypeAssertion" === nodeType ||
"TSNonNullExpression" === nodeType ||
(nodeType === "Placeholder" &&
("Expression" === node.expectedNode ||
"Identifier" === node.expectedNode ||
"StringLiteral" === node.expectedNode))
) {
return true;
}
}

function isExpressionSwitch(node) {
if (!node) return false;
switch (node.type) {
case "ArrayExpression":
case "AssignmentExpression":
case "BinaryExpression":
case "CallExpression":
case "ConditionalExpression":
case "FunctionExpression":
case "Identifier":
case "StringLiteral":
case "NumericLiteral":
case "NullLiteral":
case "BooleanLiteral":
case "RegExpLiteral":
case "LogicalExpression":
case "MemberExpression":
case "NewExpression":
case "ObjectExpression":
case "SequenceExpression":
case "ParenthesizedExpression":
case "ThisExpression":
case "UnaryExpression":
case "UpdateExpression":
case "ArrowFunctionExpression":
case "ClassExpression":
case "MetaProperty":
case "Super":
case "TaggedTemplateExpression":
case "TemplateLiteral":
case "YieldExpression":
case "AwaitExpression":
case "Import":
case "BigIntLiteral":
case "OptionalMemberExpression":
case "OptionalCallExpression":
case "TypeCastExpression":
case "JSXElement":
case "JSXFragment":
case "BindExpression":
case "DoExpression":
case "RecordExpression":
case "TupleExpression":
case "DecimalLiteral":
case "ModuleExpression":
case "TopicReference":
case "PipelineTopicExpression":
case "PipelineBareFunction":
case "PipelinePrimaryTopicReference":
case "TSInstantiationExpression":
case "TSAsExpression":
case "TSSatisfiesExpression":
case "TSTypeAssertion":
case "TSNonNullExpression":
return true;
case "Placeholder":
if (
"Expression" === node.expectedNode ||
"Identifier" === node.expectedNode ||
"StringLiteral" === node.expectedNode
) {
return true;
}
}
return false;
}

function isExpressionIncludes(node) {
if (!node) return false;

const nodeType = node.type;
return (
[
"ArrayExpression",
"AssignmentExpression",
"BinaryExpression",
"CallExpression",
"ConditionalExpression",
"FunctionExpression",
"Identifier",
"StringLiteral",
"NumericLiteral",
"NullLiteral",
"BooleanLiteral",
"RegExpLiteral",
"LogicalExpression",
"MemberExpression",
"NewExpression",
"ObjectExpression",
"SequenceExpression",
"ParenthesizedExpression",
"ThisExpression",
"UnaryExpression",
"UpdateExpression",
"ArrowFunctionExpression",
"ClassExpression",
"MetaProperty",
"Super",
"TaggedTemplateExpression",
"TemplateLiteral",
"YieldExpression",
"AwaitExpression",
"Import",
"BigIntLiteral",
"OptionalMemberExpression",
"OptionalCallExpression",
"TypeCastExpression",
"JSXElement",
"JSXFragment",
"BindExpression",
"DoExpression",
"RecordExpression",
"TupleExpression",
"DecimalLiteral",
"ModuleExpression",
"TopicReference",
"PipelineTopicExpression",
"PipelineBareFunction",
"PipelinePrimaryTopicReference",
"TSInstantiationExpression",
"TSAsExpression",
"TSSatisfiesExpression",
"TSTypeAssertion",
"TSNonNullExpression",
].includes(nodeType) ||
(nodeType === "Placeholder" &&
("Expression" === node.expectedNode ||
"Identifier" === node.expectedNode ||
"StringLiteral" === node.expectedNode))
);
}

function benchCases(name, func) {
suite.add(`isExpression ${name}`, () => {
func({ type: "ArrayExpression" }); // first
func({ type: "TSNonNullExpression" }); // last
func({ type: "XXXXXXXXXXXXX" }); // not found
});
}

benchCases("if", isExpressionIf);
benchCases("switch", isExpressionSwitch);
benchCases("includes", isExpressionIncludes);

suite.on("cycle", report).run();
46 changes: 22 additions & 24 deletions packages/babel-types/scripts/generators/validators.js
Expand Up @@ -10,20 +10,17 @@ import {

const has = Function.call.bind(Object.prototype.hasOwnProperty);

function joinComparisons(leftArr, right) {
return (
leftArr.map(JSON.stringify).join(` === ${right} || `) + ` === ${right}`
);
function buildCases(arr) {
return arr.map(key => `case ${JSON.stringify(key)}:`).join("") + "break;";
}

function addIsHelper(type, aliasKeys, deprecated) {
const targetType = JSON.stringify(type);
let aliasSource = "";
let cases = "";
if (aliasKeys) {
aliasSource = joinComparisons(aliasKeys, "nodeType");
cases = buildCases(aliasKeys);
}

let placeholderSource = "";
const placeholderTypes = [];
if (PLACEHOLDERS.includes(type) && has(FLIPPED_ALIAS_KEYS, type)) {
placeholderTypes.push(type);
Expand All @@ -32,13 +29,14 @@ function addIsHelper(type, aliasKeys, deprecated) {
placeholderTypes.push(...PLACEHOLDERS_FLIPPED_ALIAS[type]);
}
if (placeholderTypes.length > 0) {
placeholderSource =
' || nodeType === "Placeholder" && (' +
joinComparisons(
placeholderTypes,
"(node as t.Placeholder).expectedNode"
) +
")";
cases += `
case "Placeholder":
switch ((node as t.Placeholder).expectedNode) {
${buildCases(placeholderTypes)}
default:
return false;
}
break;`;
}

const result =
Expand All @@ -50,18 +48,18 @@ function addIsHelper(type, aliasKeys, deprecated) {
${deprecated || ""}
if (!node) return false;

const nodeType = (node as t.Node).type;
if (${
aliasSource ? aliasSource : `nodeType === ${targetType}`
}${placeholderSource}) {
if (typeof opts === "undefined") {
return true;
} else {
return shallowEqual(node, opts);
}
${
cases
? `
switch((node as t.Node).type){
${cases}
default:
return false;
}`
: `if ((node as t.Node).type !== ${targetType}) return false;`
}

return false;
return opts == null || shallowEqual(node, opts);
}
`;
}
Expand Down