Files
test-repo/scripts/build/transform/transforms/create-method-call-transform.js
T

64 lines
2.0 KiB
JavaScript

import { fileURLToPath } from "node:url";
/**
* @param {import("@babel/types").Node} node
* @returns {boolean}
*/
function isMethodCall(node, { methodName, argumentsLength }) {
return (
(node.type === "CallExpression" ||
node.type === "OptionalCallExpression") &&
!node.optional &&
node.arguments.length === argumentsLength &&
node.arguments.every(({ type }) => type !== "SpreadElement") &&
(node.callee.type === "MemberExpression" ||
node.callee.type === "OptionalMemberExpression") &&
!node.callee.computed &&
node.callee.object.type !== "ThisExpression" &&
node.callee.property.type === "Identifier" &&
node.callee.property.name === methodName
);
}
/**
* `foo.at(index)` -> `__at(false, foo, index)`
* `foo?.at(index)` -> `__at(true, foo, index)`
*
* @param {import("@babel/types").CallExpression | import("@babel/types").OptionalCallExpression} node
* @returns {import("@babel/types").CallExpression}
*/
function transformMethodCallToFunctionCall(node, functionName) {
// `__at(isOptionalObject, object, ...arguments)`
node.arguments.unshift(
{
type: "BooleanLiteral",
value: node.callee.type === "OptionalMemberExpression",
leadingComments: [{ type: "CommentBlock", value: " isOptionalObject" }],
},
node.callee.object
);
node.callee = { type: "Identifier", name: functionName };
}
function createMethodCallTransform({
methodName,
argumentsLength,
functionName = `__${methodName}`,
functionImplementationUrl,
}) {
const functionImplementationPath = fileURLToPath(functionImplementationUrl);
return {
shouldSkip: (text, file) =>
!text.includes(`.${methodName}(`) || file === functionImplementationPath,
test: (node) => isMethodCall(node, { methodName, argumentsLength }),
transform: (node) => transformMethodCallToFunctionCall(node, functionName),
inject: `import ${functionName} from ${JSON.stringify(
functionImplementationPath
)};`,
};
}
export default createMethodCallTransform;