UNPKG

@arabasta/eslint-plugin-tsoa

Version:
147 lines (146 loc) 6.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_js_1 = require("../utils.js"); exports.default = (0, utils_js_1.createRule)({ name: 'valid-alternative-response', meta: { messages: { noCorrectResponseDecorator: "Using '{{ functionName }}' inside a method requires you to have '@Response({{ status }})' decorator on the method", }, type: 'problem', docs: { description: 'require correct response decorators when using alternative responses', recommended: true, }, fixable: 'code', schema: [ { type: 'object', additionalProperties: false, properties: { functionNames: { items: { type: 'string', }, type: 'array', description: 'The list of functions that are alternative response', }, specialStatuses: { items: { type: 'object', additionalProperties: false, properties: { functionName: { type: 'string', description: 'The alternative response function name', }, statusCode: { oneOf: [ { type: 'string', }, { type: 'number', }, ], description: "The alternative response's status code", }, }, }, type: 'array', description: 'The list of alternative responses function names and special statuses', }, }, }, ], }, defaultOptions: [ { functionNames: ['this.errorResult', 'this.noContentResult'], specialStatuses: [ { functionName: 'this.noContentResult', statusCode: 204, }, ], }, ], create(context, [{ functionNames, specialStatuses }]) { const specialStatusesMap = new Map(); if (specialStatuses) { for (const specialStatus of specialStatuses) { specialStatusesMap.set(specialStatus.functionName, specialStatus.statusCode); } } let usedFunctions = []; function recordUsedFunctions(functionNode) { var _a; const fullFunctionName = (0, utils_js_1.getFullFunctionName)(functionNode.callee); usedFunctions.push({ fullFunctionName, arguments: functionNode.arguments, typeArguments: (_a = functionNode.typeArguments) === null || _a === void 0 ? void 0 : _a.params, node: functionNode, }); } let currentClassDeclarationNode; return { ClassDeclaration(node) { currentClassDeclarationNode = node; }, 'MethodDefinition FunctionExpression > BlockStatement CallExpression': (node) => { recordUsedFunctions(node); }, 'MethodDefinition:exit': (node) => { const responseDecorators = [ ...(0, utils_js_1.getAllDecoratorsWithName)({ node, decoratorName: 'Response', }), ...(0, utils_js_1.getAllDecoratorsWithName)({ node, decoratorName: 'SuccessResponse', }), ...(0, utils_js_1.getAllDecoratorsWithName)({ node: currentClassDeclarationNode, decoratorName: 'Response', }), ]; for (const usedFunction of usedFunctions) { if (!functionNames || !functionNames.includes(usedFunction.fullFunctionName)) { continue; } let status; if (specialStatusesMap.has(usedFunction.fullFunctionName)) { status = specialStatusesMap.get(usedFunction.fullFunctionName); } else { if (!Array.isArray(usedFunction.arguments) || usedFunction.arguments.length === 0 || !('value' in usedFunction.arguments[0]) || typeof usedFunction.arguments[0].value !== 'number') { continue; } status = usedFunction.arguments[0].value; } if (!Array.isArray(responseDecorators) || !(0, utils_js_1.hasResponseDecoratorWithStatus)({ status, decorators: responseDecorators, })) { context.report({ node, messageId: 'noCorrectResponseDecorator', data: { functionName: usedFunction.fullFunctionName, status, }, }); } } usedFunctions = []; }, }; }, });