90 lines · 3.1 KB · JavaScript
RawDownload
import { isIdentifier } from "../utils.js"; const message =  "Do not add redundant helpers that only construct a tagged error. Construct the tagged error directly. Skill: wrdn-effect-typed-errors."; const isErrorFactoryName = (name) => /^make[A-Z].*Error$/.test(name); const isErrorHelperName = (name) =>  isErrorFactoryName(name) || String(name ?? "").endsWith("Error"); const parameterName = (param) => {  if (isIdentifier(param)) return param.name;  if (param?.type === "AssignmentPattern" && isIdentifier(param.left)) return param.left.name;  if (param?.type === "RestElement" && isIdentifier(param.argument)) return param.argument.name;  return undefined;}; const isNewErrorExpression = (node) =>  node?.type === "NewExpression" && isIdentifier(node.callee) && node.callee.name.endsWith("Error"); const isForwardedValue = (node, parameterNames) => {  if (node?.type === "Literal" || node?.type === "StringLiteral") return true;  if (node?.type === "Identifier") return parameterNames.has(node.name);  return (    node?.type === "MemberExpression" &&    isIdentifier(node.object) &&    parameterNames.has(node.object.name)  );}; const isObjectWithOnlyForwardedFields = (node, parameterNames) => {  if (node?.type !== "ObjectExpression") return true;  return (node.properties ?? []).every((property) => {    if (property.type === "SpreadElement") return false;    return isForwardedValue(property.value, parameterNames);  });}; const isRedundantNewErrorExpression = (node, parameterNames) => {  if (!isNewErrorExpression(node)) return false;  if ((node.arguments ?? []).length === 0) return true;  if (node.arguments.length > 1) return false;  const argument = node.arguments[0];  if (argument?.type === "Identifier") return parameterNames.has(argument.name);  return isObjectWithOnlyForwardedFields(argument, parameterNames);}; const returnsOnlyNewError = (node) => {  const parameterNames = new Set((node?.params ?? []).map(parameterName).filter(Boolean));  if (isRedundantNewErrorExpression(node?.body ?? node, parameterNames)) return true;  if (node?.type !== "BlockStatement") return false;  const statements = node.body ?? [];  return (    statements.length === 1 &&    statements[0]?.type === "ReturnStatement" &&    isRedundantNewErrorExpression(statements[0].argument, parameterNames)  );}; const reportIfRedundantFactory = (context, name, fnNode, reportNode) => {  if (isErrorHelperName(name) && returnsOnlyNewError(fnNode)) {    context.report({ node: reportNode, message });  }}; export default {  meta: {    type: "problem",    docs: {      description: message,    },  },  create(context) {    return {      FunctionDeclaration(node) {        reportIfRedundantFactory(context, node.id?.name, node, node);      },      VariableDeclarator(node) {        if (!isIdentifier(node.id)) return;        if (          node.init?.type !== "ArrowFunctionExpression" &&          node.init?.type !== "FunctionExpression"        ) {          return;        }        reportIfRedundantFactory(context, node.id.name, node.init, node);      },    };  },};