UNPKG

@addon24/eslint-config

Version:

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

127 lines (108 loc) 4.24 kB
/** * @fileoverview Verbietet Konstruktoren in DTO-Klassen * DTOs sind reine Datencontainer und sollten keine Konstruktoren haben. * Sie werden automatisch von class-transformer aus JSON erstellt. */ export default { meta: { type: "error", docs: { description: "Forbid constructors in DTO classes - DTOs should be pure data containers", category: "Best Practices", recommended: true, }, fixable: "code", schema: [], messages: { noDtoConstructor: "DTO class '{{className}}' must not have a constructor. DTOs are pure data containers that are automatically instantiated by class-transformer from JSON. Remove the constructor and let the framework handle object creation.", constructorRemoved: "Constructor removed from DTO class '{{className}}'", }, }, create(context) { const filename = context.getFilename(); // Ignoriere Test-Dateien und Non-DTO-Dateien if (!filename.includes("/dto/") || filename.includes("test") || filename.includes("spec") || filename.includes("__tests__") || filename.endsWith(".test.ts") || filename.endsWith(".spec.ts")) { return {}; } function isDtoClass(className) { return ( className.endsWith("Dto") || className.endsWith("DTO") || className.includes("Request") || className.includes("Response") || className.includes("Create") || className.includes("Update") || className.includes("Delete") ); } function isInDtoClass(node) { let parent = node.parent; // Traverse up to find the class declaration while (parent) { if (parent.type === "ClassDeclaration" || (parent.type === "ExportDefaultDeclaration" && parent.declaration?.type === "ClassDeclaration")) { const classNode = parent.type === "ClassDeclaration" ? parent : parent.declaration; const className = classNode.id?.name; if (className && isDtoClass(className)) { return { isDto: true, className, classNode }; } break; } parent = parent.parent; } return { isDto: false, className: null, classNode: null }; } return { MethodDefinition(node) { // Prüfe nur Konstruktoren if (node.kind !== "constructor") { return; } const { isDto, className } = isInDtoClass(node); if (isDto) { context.report({ node, messageId: "noDtoConstructor", data: { className: className || "unknown" }, fix(fixer) { const sourceCode = context.getSourceCode(); // Finde den Konstruktor-Block const constructorStart = node.range[0]; const constructorEnd = node.range[1]; // Prüfe, ob es Leerzeilen vor/nach dem Konstruktor gibt const beforeConstructor = sourceCode.getText().substring(0, constructorStart); const afterConstructor = sourceCode.getText().substring(constructorEnd); // Entferne auch überflüssige Leerzeilen let startPos = constructorStart; let endPos = constructorEnd; // Prüfe auf Leerzeilen vor dem Konstruktor const lines = beforeConstructor.split('\n'); if (lines.length > 1 && lines[lines.length - 1].trim() === '') { // Finde die Position der letzten nicht-leeren Zeile vor dem Konstruktor for (let i = lines.length - 2; i >= 0; i--) { if (lines[i].trim() !== '') { break; } startPos -= (lines[lines.length - 1 - (lines.length - 2 - i)].length + 1); } } // Prüfe auf Leerzeilen nach dem Konstruktor const afterLines = afterConstructor.split('\n'); if (afterLines.length > 1 && afterLines[0].trim() === '') { endPos += afterLines[0].length + 1; } return fixer.removeRange([startPos, endPos]); }, }); } } }; }, };