UNPKG

@addon24/eslint-config

Version:

ESLint configuration rules for WorldOfTextcraft projects - Centralized configuration for all project types

153 lines (139 loc) 5.32 kB
/** * ESLint-Regel, die sicherstellt, dass Controller den BaseController erweitern * und dessen Methoden für Response-Strukturen verwenden */ /** @type {import('eslint').Rule.RuleModule} */ const enforceBaseControllerRule = { meta: { type: "problem", docs: { description: "Stellt sicher, dass Controller den BaseController erweitern und dessen Methoden verwenden", category: "Best Practices", recommended: true, }, fixable: null, schema: [ { type: "object", properties: { controllerPattern: { type: "string", description: "Regex pattern for identifying controller files", default: "Controller\\.ts$" }, baseControllerName: { type: "string", description: "Name of the base controller class that all controllers should extend", default: "BaseController" }, allowDirectResponse: { type: "boolean", description: "Whether to allow direct response usage (res.json, res.status)", default: false }, excludePatterns: { type: "array", items: { type: "string" }, description: "File patterns to exclude from the rule", default: ["BaseController.ts"] } }, additionalProperties: false } ], messages: { notExtendingBaseController: "Controller muss BaseController erweitern: '{{controllerName}}'", directResponseUsage: "Verwende die BaseController-Methoden (sendSuccess, sendError, etc.) anstatt direkt res.json/status aufzurufen", }, }, create(context) { const options = context.options[0] || {}; const controllerPattern = new RegExp(options.controllerPattern || "Controller\\.ts$"); const baseControllerName = options.baseControllerName || "BaseController"; const allowDirectResponse = options.allowDirectResponse || false; const excludePatterns = options.excludePatterns || ["BaseController.ts"]; const filename = context.getFilename(); const isExcluded = excludePatterns.some(pattern => filename.includes(pattern)); const isControllerFile = (controllerPattern.test(filename) || filename.includes('/fixtures/')) && !isExcluded; // Speichert, ob die aktuelle Datei ein Controller ist, der BaseController erweitert let extendsBaseController = false; // Speichert den Namen des Controllers für Fehlermeldungen let controllerName = ""; return { // Prüfen, ob ein Controller den BaseController erweitert ClassDeclaration(node) { if (!isControllerFile) return; // Extrahiere den Controller-Namen controllerName = node.id.name; // Ignoriere BaseController selbst if (controllerName === baseControllerName) return; // Prüfe, ob der Controller von BaseController erbt if (node.superClass && node.superClass.type === "Identifier" && node.superClass.name === baseControllerName) { extendsBaseController = true; } else { // Melde einen Fehler, wenn der Controller nicht von BaseController erbt context.report({ node, messageId: "notExtendingBaseController", data: { controllerName: controllerName, }, }); } }, // Prüfen, ob direkte Response-Methoden verwendet werden CallExpression(node) { if (!isControllerFile || !extendsBaseController) return; // Prüfe auf direkte res.json() Aufrufe if ( !allowDirectResponse && node.callee.type === "MemberExpression" && node.callee.object.type === "Identifier" && node.callee.object.name === "res" && node.callee.property.type === "Identifier" && node.callee.property.name === "json" ) { context.report({ node, messageId: "directResponseUsage", }); } // Prüfe auf res.status().json() Aufrufe if ( node.callee.type === "MemberExpression" && node.callee.property.type === "Identifier" && node.callee.property.name === "json" && node.callee.object.type === "CallExpression" && node.callee.object.callee.type === "MemberExpression" && node.callee.object.callee.object.type === "Identifier" && node.callee.object.callee.object.name === "res" && node.callee.object.callee.property.type === "Identifier" && node.callee.object.callee.property.name === "status" ) { context.report({ node, messageId: "directResponseUsage", }); } }, // Prüfen auf Import des BaseController ImportDeclaration(node) { if (!isControllerFile) return; // Prüfe, ob BaseController importiert wird const specifiers = node.specifiers; if (specifiers.some(specifier => specifier.type === "ImportDefaultSpecifier" && specifier.local.name === baseControllerName)) { return; } }, }; }, }; export default { rules: { "enforce-basecontroller": enforceBaseControllerRule, }, };