UNPKG

@addon24/eslint-config

Version:

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

162 lines (142 loc) 4.98 kB
/** * ESLint-Regel: Alle nicht-statischen Klassenmethoden müssen Result<T, Error> zurückgeben * * Diese Regel stellt sicher, dass alle nicht-statischen Methoden einer Klasse * ein Result<T, InfrastructureError | DomainError> Pattern verwenden. */ export default { rules: { "require-result-return-type": { meta: { type: "problem", docs: { description: "Require non-static class methods to return Result<T, Error> type", category: "Best Practices", recommended: true, }, schema: [], messages: { missingResultType: "Nicht-statische Klassenmethode '{{methodName}}' muss Promise<Result<T, InfrastructureError | DomainError>> zurückgeben", }, }, create(context) { return { MethodDefinition(node) { // Ignoriere statische Methoden if (node.static) { return; } // Ignoriere Konstruktoren if (node.kind === "constructor") { return; } // Ignoriere Getter/Setter if (node.kind === "get" || node.kind === "set") { return; } // Prüfe nur Klassen im infrastructure-Verzeichnis const filename = context.getFilename(); if (!filename.includes("/infrastructure/")) { return; } // Prüfe nur TypeScript-Dateien if (!filename.endsWith(".ts") && !filename.endsWith(".tsx")) { return; } const methodNode = node.value; let returnType = null; // Prüfe explizite Rückgabetyp-Annotation if (methodNode.returnType && methodNode.returnType.typeAnnotation) { returnType = methodNode.returnType.typeAnnotation; } // Wenn keine explizite Typ-Annotation vorhanden ist, überspringe if (!returnType) { return; } // Prüfe ob es sich um Promise<Result<T, Error>> handelt const isPromiseResultType = checkIsPromiseResultType(returnType); // Für infrastructure-Verzeichnis: Akzeptiere alle Promise-Typen als gültig // (da Result-Pattern über Type-Aliases schwer zu validieren ist) const isPromiseType = returnType.type === "TSTypeReference" && returnType.typeName && returnType.typeName.name === "Promise"; if (!isPromiseResultType && !isPromiseType) { const methodName = node.key.name || "unknown"; context.report({ node: methodNode, messageId: "missingResultType", data: { methodName, }, }); } }, }; }, }, }, }; /** * Prüft ob der Typ ein Promise<Result<T, Error>> ist */ function checkIsPromiseResultType(typeNode) { // Muss Promise<Result<...>> sein if ( typeNode.type === "TSTypeReference" && typeNode.typeName && typeNode.typeName.name === "Promise" && typeNode.typeParameters && typeNode.typeParameters.params.length > 0 ) { const innerType = typeNode.typeParameters.params[0]; return checkIsResultType(innerType) || checkIsResultTypeAlias(innerType); } return false; } /** * Prüft ob der Typ ein Result<T, Error> ist */ function checkIsResultType(typeNode) { // Result<T, Error> Pattern if ( typeNode.type === "TSTypeReference" && typeNode.typeName && typeNode.typeName.name === "Result" && typeNode.typeParameters && typeNode.typeParameters.params.length === 2 ) { const errorType = typeNode.typeParameters.params[1]; // Prüfe ob der Error-Typ InfrastructureError | DomainError ist if (errorType.type === "TSUnionType") { const errorTypes = errorType.types.map(t => t.type === "TSTypeReference" ? t.typeName.name : null ); return errorTypes.includes("InfrastructureError") && errorTypes.includes("DomainError"); } // Oder nur einer der beiden Error-Typen if (errorType.type === "TSTypeReference") { const errorTypeName = errorType.typeName.name; return errorTypeName === "InfrastructureError" || errorTypeName === "DomainError"; } } return false; } /** * Prüft ob der Typ ein Type-Alias ist, der auf Result endet (z.B. ItemResults, CharacterResult) */ function checkIsResultTypeAlias(typeNode) { if ( typeNode.type === "TSTypeReference" && typeNode.typeName && typeNode.typeName.name ) { const typeName = typeNode.typeName.name; // Akzeptiere alle Typen, die auf "Result" enden (weniger strikt) return typeName.endsWith("Result") || typeName.endsWith("Results") || typeName.includes("Result"); } return false; }