export const noEmptyFunction = { meta: { type: "problem", docs: { description: "禁止空函数体,并提供项目约定的修复指引:生产代码使用 () => undefined,测试代码使用 () => {} + eslint-disable", }, messages: { unexpectedProduction: "生产代码中空函数应使用 () => undefined 明确表意(如 noop/voidLog)。如果确需空实现且为接口契约,请添加注释说明原因。", unexpectedTest: "测试代码中空函数使用 () => {} 并在文件顶部添加 /* eslint-disable @typescript-eslint/no-empty-function */。", }, schema: [], }, create(context) { const sourceCode = context.sourceCode ?? context.getSourceCode(); const allowedFunctionTypes = new Set([ "ArrowFunctionExpression", "FunctionDeclaration", "FunctionExpression", ]); function isEmptyBody(body) { return ( body.type === "BlockStatement" && body.body.length === 0 && sourceCode.getCommentsInside(body).length === 0 ); } function hasDecorator(node) { return Array.isArray(node.decorators) && node.decorators.length > 0; } function isPrivateOrProtectedConstructor(node) { if (node.parent?.type !== "MethodDefinition") return false; if (node.parent.kind !== "constructor") return false; const accessibility = node.parent.accessibility; return accessibility === "private" || accessibility === "protected"; } function isOverrideMethod(node) { if (node.parent?.type !== "MethodDefinition") return false; return node.parent.override === true; } function check(node) { if (!allowedFunctionTypes.has(node.type)) return; if (!isEmptyBody(node.body)) return; if (hasDecorator(node)) return; if (isPrivateOrProtectedConstructor(node)) return; if (isOverrideMethod(node)) return; const isTest = /[\\/]tests?[\\/]/.test(context.filename ?? "") || context.filename?.includes("test"); context.report({ node, messageId: isTest ? "unexpectedTest" : "unexpectedProduction", data: { name: node.id?.name ?? node.key?.name ?? "function" }, }); } return { ArrowFunctionExpression: check, FunctionDeclaration: check, FunctionExpression: check, }; }, };