@addon24/eslint-config
Version:
ESLint configuration rules for WorldOfTextcraft projects - Centralized configuration for all project types
162 lines (142 loc) • 4.98 kB
JavaScript
/**
* 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;
}