UNPKG

@addon24/eslint-config

Version:

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

140 lines (126 loc) 4.74 kB
export default { meta: { type: "problem", docs: { description: "Prevent usage of Entity references in Swagger documentation", category: "Best Practices", recommended: true, }, fixable: null, schema: [], messages: { entityInSwaggerSchema: "Swagger schema reference '{{reference}}' should use DTO instead of Entity. Replace '{{entityName}}' with '{{dtoName}}'", entityInApiProperty: "ApiProperty type '{{type}}' should use DTO instead of Entity. Replace '{{entityName}}' with '{{dtoName}}'", entityInApiBody: "ApiBody type '{{type}}' should use DTO instead of Entity. Replace '{{entityName}}' with '{{dtoName}}'", }, }, create(context) { const entityPattern = /Entity$/; const dtoPattern = /Dto$/; function getEntityName(reference) { const match = reference.match(/#\/components\/schemas\/(.+)/); return match ? match[1] : reference; } function getDtoName(entityName) { return entityName.replace(/Entity$/, "Dto"); } function checkStringLiteral(node, messageId) { if (node.type === "Literal" && typeof node.value === "string") { const value = node.value; // Check for schema references like "#/components/schemas/AbilityEntity" if (value.includes("#/components/schemas/") && value.includes("Entity")) { const entityName = getEntityName(value); if (entityPattern.test(entityName)) { const dtoName = getDtoName(entityName); context.report({ node, messageId, data: { reference: value, entityName, dtoName, }, }); } } } } function checkTypeReference(node, messageId) { // Check for type references in ApiProperty, ApiBody decorators if (node.type === "Identifier" && entityPattern.test(node.name)) { const dtoName = getDtoName(node.name); context.report({ node, messageId, data: { type: node.name, entityName: node.name, dtoName, }, }); } } function checkObjectExpression(node) { if (node.type === "ObjectExpression") { node.properties.forEach((prop) => { if (prop.type === "Property") { // Check schema references in object properties if (prop.key && prop.key.name === "$ref") { checkStringLiteral(prop.value, "entityInSwaggerSchema"); } // Check items property in arrays if (prop.key && prop.key.name === "items" && prop.value.type === "ObjectExpression") { prop.value.properties.forEach((itemProp) => { if (itemProp.key && itemProp.key.name === "$ref") { checkStringLiteral(itemProp.value, "entityInSwaggerSchema"); } }); } } }); } } return { Decorator(node) { if (node.expression && node.expression.type === "CallExpression") { const callee = node.expression.callee; // Check ApiResponse, ApiBody, ApiProperty decorators if (callee.type === "Identifier") { const decoratorName = callee.name; if (["ApiResponse", "ApiBody", "ApiProperty"].includes(decoratorName)) { node.expression.arguments.forEach((arg) => { if (arg.type === "ObjectExpression") { arg.properties.forEach((prop) => { if (prop.type === "Property") { // Check type property if (prop.key && prop.key.name === "type") { checkTypeReference(prop.value, "entityInApiProperty"); } // Check schema property if (prop.key && prop.key.name === "schema") { checkObjectExpression(prop.value); } } }); } }); } } } }, // Check for $ref in any string literal Literal(node) { if (typeof node.value === "string" && node.value.includes("Entity")) { const parent = node.parent; // Check if this is in a swagger context if (parent && parent.type === "Property" && parent.key) { if (parent.key.name === "$ref" || (parent.key.type === "Literal" && parent.key.value === "$ref")) { checkStringLiteral(node, "entityInSwaggerSchema"); } } } }, }; }, };