@addon24/eslint-config
Version:
ESLint configuration rules for WorldOfTextcraft projects - Centralized configuration for all project types
213 lines (200 loc) • 8.67 kB
JavaScript
import path from "path";
export default {
meta: {
type: "problem",
docs: {
description: "Enforces DTO naming and folder conventions",
category: "Architecture",
recommended: true,
},
schema: [],
messages: {
classNameMismatch: "Klassenname '{{className}}' muss mit dem Dateinamen '{{filename}}' übereinstimmen.",
entityDtoWrongSuffix: "Entity-DTO '{{className}}' muss den Suffix 'EntityDto' haben (nicht '{{currentSuffix}}')",
entityDtoDoubleSuffix: "Entity-DTO '{{className}}' hat doppelten Suffix. Verwende '{{correctName}}' statt '{{className}}'",
entityDtoMixedType: "Entity-DTO '{{className}}' darf keine anderen DTO-Typen im Namen haben (z.B. 'Response', 'Request'). Verwende '{{correctName}}' statt '{{className}}'",
responseDtoWrongSuffix: "Response-DTO '{{className}}' muss den Suffix 'ResponseDto' haben (nicht '{{currentSuffix}}')",
requestDtoWrongSuffix: "Request-DTO '{{className}}' muss den Suffix 'RequestDto' haben (nicht '{{currentSuffix}}')",
configDtoWrongSuffix: "Config-DTO '{{className}}' muss den Suffix 'ConfigDto' haben (nicht '{{currentSuffix}}')",
filterDtoWrongSuffix: "Filter-DTO '{{className}}' muss den Suffix 'FilterDto' haben (nicht '{{currentSuffix}}')",
unknownFolderSuffix: "DTO '{{className}}' im unbekannten Ordner '{{folder}}'. Definiere einen passenden Suffix.",
dtoMustBeInSubfolder: "DTO '{{className}}' muss in einem Unterordner von /dto/ liegen (z.B. /dto/Response/, /dto/Request/, etc.).",
},
},
create(context) {
return {
ClassDeclaration(node) {
const filename = context.getFilename();
const dtoClassName = node.id?.name;
if (!dtoClassName) return;
const baseFilename = path.basename(filename, ".ts");
// 1. Klassenname und Dateiname müssen übereinstimmen
if (dtoClassName !== baseFilename) {
context.report({
node: node,
messageId: "classNameMismatch",
data: { className: dtoClassName, filename: baseFilename },
});
}
// 2. Bestimme den Ordner und erwarteten Suffix
const pathParts = filename.split(path.sep);
const dtoIndex = pathParts.findIndex(part => part === "dto");
if (dtoIndex !== -1) {
// Ausnahme für BaseEntityDto (abstrakte Base-Klasse)
if (dtoClassName === "BaseEntityDto" && filename.endsWith("/dto/BaseEntityDto.ts")) {
return;
}
// Prüfe, ob es ein Unterordner gibt (nicht die Datei selbst)
if (dtoIndex + 1 < pathParts.length - 1) {
const folder = pathParts[dtoIndex + 1];
const currentSuffix = dtoClassName.match(/([A-Z][a-z]*Dto)$/)?.[1] || "unbekannt";
const expectedSuffixMap = {
"Entity": "EntityDto",
"Response": "ResponseDto",
"Request": "RequestDto",
"Config": "ConfigDto",
"Filter": "FilterDto",
// Add other common DTO subfolders here if they have a specific suffix
// For example, if you have /dto/Auth/AuthRequestDto, you'd add "Auth": "AuthDto"
// For now, general DTOs in other folders just need to end with "Dto"
"Wot": "Dto",
"Game": "Dto",
"User": "Dto",
"Auth": "Dto",
"Chat": "Dto",
"World": "Dto",
"Asset": "Dto",
"Language": "Dto",
"Log": "Dto",
"Health": "Dto",
"Metrics": "Dto",
"Admin": "Dto",
"Utilities": "Dto",
"Common": "Dto",
"Shared": "Dto",
"Core": "Dto",
"System": "Dto",
"Event": "Dto",
"Notification": "Dto",
"Payment": "Dto",
"Inventory": "Dto",
"Quest": "Dto",
"Skill": "Dto",
"Spell": "Dto",
"Item": "Dto",
"Faction": "Dto",
"Race": "Dto",
"Class": "Dto",
"Ability": "Dto",
"Buff": "Dto",
"Debuff": "Dto",
"Effect": "Dto",
"Stat": "Dto",
"Map": "Dto",
"Zone": "Dto",
"Region": "Dto",
"Server": "Dto",
"Client": "Dto",
"Gateway": "Dto",
"Proxy": "Dto",
"Service": "Dto",
"Module": "Dto",
"Provider": "Dto",
"Repository": "Dto",
"Controller": "Dto",
"Middleware": "Dto",
"Guard": "Dto",
"Interceptor": "Dto",
"Pipe": "Dto",
"Decorator": "Dto",
"Enum": "Dto",
"Interface": "Dto",
"Type": "Dto",
"Util": "Dto",
"Helper": "Dto",
"Constant": "Dto",
"Factory": "Dto",
"Strategy": "Dto",
"Subscriber": "Dto",
"Seeder": "Dto",
"Migration": "Dto",
"Test": "Dto",
"Mock": "Dto",
"Stub": "Dto",
"Fixture": "Dto",
"Seed": "Dto",
"Script": "Dto",
"Tool": "Dto",
"Logger": "Dto", // Added Logger as a recognized folder, but no specific suffix beyond Dto
"Main": "Dto", // Added Main as a recognized folder, but no specific suffix beyond Dto
"OAuth": "Dto", // Added OAuth as a recognized folder, but no specific suffix beyond Dto
"Utility": "Dto", // Added Utility as a recognized folder, but no specific suffix beyond Dto
};
const expectedSuffix = expectedSuffixMap[folder];
if (folder === "Entity") {
if (!dtoClassName.endsWith("EntityDto")) {
context.report({
node: node,
messageId: "entityDtoWrongSuffix",
data: { className: dtoClassName, currentSuffix: currentSuffix },
});
} else if (dtoClassName.endsWith("DtoEntityDto")) {
const correctName = dtoClassName.replace("DtoEntityDto", "EntityDto");
context.report({
node: node,
messageId: "entityDtoDoubleSuffix",
data: { className: dtoClassName, correctName: correctName },
});
} else {
// Prüfe, ob Entity-DTO andere DTO-Typen im Namen hat
const forbiddenTypes = ["Response", "Request", "Config", "Filter"];
const hasForbiddenType = forbiddenTypes.some(type =>
dtoClassName.includes(type)
);
if (hasForbiddenType) {
// Entferne den verbotenen Typ und ersetze durch korrekten Namen
let correctName = dtoClassName;
forbiddenTypes.forEach(type => {
if (correctName.includes(type)) {
correctName = correctName.replace(type, "");
}
});
// Stelle sicher, dass es mit EntityDto endet
if (!correctName.endsWith("EntityDto")) {
correctName = correctName.replace(/Dto$/, "EntityDto");
}
context.report({
node: node,
messageId: "entityDtoMixedType",
data: { className: dtoClassName, correctName: correctName },
});
}
}
} else if (expectedSuffix && expectedSuffix !== "Dto") {
if (!dtoClassName.endsWith(expectedSuffix)) {
context.report({
node: node,
messageId: `${folder.toLowerCase()}DtoWrongSuffix`,
data: { className: dtoClassName, currentSuffix: currentSuffix },
});
}
} else if (!expectedSuffix) {
context.report({
node: node,
messageId: "unknownFolderSuffix",
data: { className: dtoClassName, folder: folder },
});
}
} else {
// DTO direkt im /dto/ Ordner - nicht erlaubt
context.report({
node: node,
messageId: "dtoMustBeInSubfolder",
data: { className: dtoClassName },
});
}
}
},
};
},
};