UNPKG

@addon24/eslint-config

Version:

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

115 lines (97 loc) 3.56 kB
export default { meta: { type: "problem", docs: { description: "Enforce usage of DTOs instead of anonymous objects", category: "Best Practices", recommended: true, }, fixable: null, schema: [], messages: { anonymousObjectForbidden: "Anonymous objects are not allowed. Use a DTO class instead.", anonymousObjectInReturn: "Returning anonymous objects is not allowed. Create a DTO class for the return type.", anonymousObjectInAssignment: "Assigning anonymous objects is not allowed. Use a DTO class instead.", anonymousObjectInFunctionCall: "Passing anonymous objects to functions is not allowed. Use a DTO class instead.", }, }, create(context) { function isTestFile() { const filename = context.getFilename(); return filename.includes('.test.') || filename.includes('.spec.') || filename.includes('__tests__'); } function isExemptFunction(node) { if (!node || !node.callee) return false; // Check for method calls like logger.error if (node.callee.type === "MemberExpression") { const objectName = node.callee.object.name; const propertyName = node.callee.property.name; const fullName = `${objectName}.${propertyName}`; // Allow logger methods if (fullName.startsWith('logger.')) { return true; } // Allow console methods if (fullName.startsWith('console.')) { return true; } // Allow DTO factory methods if (propertyName === "create" && objectName && objectName.endsWith("Dto")) { return true; } } // Check for direct function calls if (node.callee.type === "Identifier") { const exemptFunctions = [ "Object.assign", "JSON.stringify", "JSON.parse", "collectDefaultMetrics" ]; return exemptFunctions.includes(node.callee.name); } return false; } function isInsideExemptFunction(node) { let parent = node.parent; while (parent) { if (parent.type === "CallExpression" && isExemptFunction(parent)) { return true; } parent = parent.parent; } return false; } function checkObjectExpression(node) { // Skip if it's a test file if (isTestFile()) return; // Skip if it's inside an exempt function if (isInsideExemptFunction(node)) return; // Skip if it's a simple object with only basic properties if (node.properties && node.properties.length <= 2) { const propertyNames = node.properties .filter(prop => prop.type === "Property" && prop.key.type === "Identifier") .map(prop => prop.key.name); // Allow simple objects with basic properties if (propertyNames.every(name => ["id", "isActive", "name", "type", "value"].includes(name))) { return; } } // Report the anonymous object let messageId = "anonymousObjectForbidden"; if (node.parent) { if (node.parent.type === "ReturnStatement") { messageId = "anonymousObjectInReturn"; } else if (node.parent.type === "VariableDeclarator") { messageId = "anonymousObjectInAssignment"; } else if (node.parent.type === "CallExpression") { messageId = "anonymousObjectInFunctionCall"; } } context.report({ node, messageId, }); } return { ObjectExpression: checkObjectExpression, }; }, };