@addon24/eslint-config
Version:
ESLint configuration rules for WorldOfTextcraft projects - Centralized configuration for all project types
163 lines (146 loc) • 5.63 kB
JavaScript
/**
* @fileoverview Enforce that Entities can only be initialized in DTO fromEntity methods
* @author WorldOfTextcraft Team
*/
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('eslint').Rule.RuleModule} */
export default {
meta: {
type: "problem",
docs: {
description: "Entities dürfen nur in DTO fromEntity-Methoden manuell initialisiert werden",
category: "Architecture",
recommended: true,
},
fixable: null,
schema: [],
messages: {
entityInitializationForbidden: "Manuelle Entity-Initialisierung 'new {{entityName}}()' ist nur in DTO fromEntity, fromEntityArray und toEntity-Methoden erlaubt",
entityPropertyAssignmentForbidden: "Manuelle Property-Zuweisung an Entity '{{entityName}}' ist nur in DTO fromEntity, fromEntityArray und toEntity-Methoden erlaubt",
useRepositoryCreate: "Verwende repository.create() oder DTO.fromEntity() statt manueller Entity-Initialisierung",
},
},
create(context) {
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
const filename = context.getFilename();
const isServiceFile = (filename.includes("/service/") && filename.endsWith(".ts") && !filename.includes("test")) || filename.includes("test-fixtures");
const isDtoFile = filename.includes("/dto/") && filename.endsWith(".ts");
const isEntityFile = filename.includes("/entity/") && filename.endsWith(".ts");
const isTestFixture = filename.includes("test-fixtures");
const isInvalidTestFixture = filename.includes("InvalidEntityFactoryPattern");
/**
* Check if we are in a fromEntity method
* @param {ASTNode} node - The current node
* @returns {boolean} True if in fromEntity method
*/
function isInFromEntityMethod(node) {
let current = node;
while (current && current.parent) {
if (current.type === "MethodDefinition" &&
current.static === true &&
current.key?.name === "fromEntity") {
return true;
}
current = current.parent;
}
return false;
}
/**
* Check if we are in a fromEntityArray method
* @param {ASTNode} node - The current node
* @returns {boolean} True if in fromEntityArray method
*/
function isInFromEntityArrayMethod(node) {
let current = node;
while (current && current.parent) {
if (current.type === "MethodDefinition" &&
current.static === true &&
current.key?.name === "fromEntityArray") {
return true;
}
current = current.parent;
}
return false;
}
/**
* Check if we are in a toEntity method
* @param {ASTNode} node - The current node
* @returns {boolean} True if in toEntity method
*/
function isInToEntityMethod(node) {
let current = node;
while (current && current.parent) {
if (current.type === "MethodDefinition" &&
current.static === true &&
current.key?.name === "toEntity") {
return true;
}
current = current.parent;
}
return false;
}
/**
* Check if we are in a DTO fromEntity method
* @param {ASTNode} node - The current node
* @returns {boolean} True if in DTO fromEntity method
*/
function isInDtoFromEntityMethod(node) {
return isDtoFile && (isInFromEntityMethod(node) || isInFromEntityArrayMethod(node) || isInToEntityMethod(node));
}
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
return {
// Überwache new Entity() Aufrufe
NewExpression(node) {
// Ignoriere Test-Fixtures, außer für InvalidEntityFactoryPattern
if (isTestFixture && !isInvalidTestFixture) {
return;
}
const entityName = node.callee?.name;
// Prüfe ob es eine Entity ist (Name endet mit "Entity")
if (entityName && entityName.endsWith("Entity")) {
// Erlaube nur in DTO fromEntity-Methoden
if (!isInDtoFromEntityMethod(node)) {
context.report({
node,
messageId: "entityInitializationForbidden",
data: {
entityName,
},
});
}
}
},
// Überwache Property-Zuweisungen an Entities
AssignmentExpression(node) {
// Ignoriere Test-Fixtures, außer für InvalidEntityFactoryPattern
if (isTestFixture && !isInvalidTestFixture) {
return;
}
if (isServiceFile || isEntityFile) {
// Prüfe ob links eine Entity-Variable ist (kann auch camelCase sein)
if (node.left.type === "MemberExpression" &&
node.left.object?.name &&
(node.left.object.name.endsWith("Entity") ||
node.left.object.name.match(/^[a-z][a-zA-Z]*Entity$/))) {
// Erlaube nur in DTO fromEntity-Methoden
if (!isInDtoFromEntityMethod(node)) {
context.report({
node,
messageId: "entityPropertyAssignmentForbidden",
data: {
entityName: node.left.object.name,
},
});
}
}
}
},
};
},
};