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

70 lines
2.1 KiB
JavaScript

import { fileURLToPath } from "node:url";
import { createIdentifier, isIdentifier } from "./utilities.js";
/**
* @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" &&
isIdentifier(node.callee.property, 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)`
return {
...node,
callee: createIdentifier(functionName),
arguments: [
{
type: "BooleanLiteral",
value: node.callee.type === "OptionalMemberExpression",
leadingComments: [
{ type: "CommentBlock", value: " isOptionalObject " },
],
},
node.callee.object,
...node.arguments,
],
};
}
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;