UNPKG

@arabasta/eslint-plugin-tsoa

Version:
116 lines (115 loc) 5.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_js_1 = require("../utils.js"); const utils_1 = require("@typescript-eslint/utils"); const type_utils_1 = require("@typescript-eslint/type-utils"); exports.default = (0, utils_js_1.createRule)({ name: 'valid-alternative-response-type', meta: { messages: { wrongFirstTypeArg: "The first type argument of '{{ functionName }}' should be the same as method's return type '{{ correctType }}'", }, type: 'problem', fixable: 'code', docs: { description: "require alternative response's first type argument to be the same as its method's return type", recommended: true, requiresTypeChecking: true, }, schema: [ { type: 'object', additionalProperties: false, properties: { functionNames: { type: 'array', items: { type: 'string', }, description: 'The list of functions that are alternative response', }, }, }, ], }, defaultOptions: [ { functionNames: ['this.errorResult', 'this.noContentResult'], }, ], create: (context, [{ functionNames }]) => { const services = utils_1.ESLintUtils.getParserServices(context); const checker = services.program.getTypeChecker(); let usedFunctions = []; function recordUsedFunctions(functionNode) { var _a; const fullFunctionName = (0, utils_js_1.getFullFunctionName)(functionNode.callee); usedFunctions.push({ fullFunctionName, arguments: functionNode.arguments, typeArgumentsParams: (_a = functionNode.typeArguments) === null || _a === void 0 ? void 0 : _a.params, node: functionNode, }); } function getFunctionReturnTypeName(node) { const signatures = services.getTypeAtLocation(node).getCallSignatures(); if (!signatures.length) { return; } const methodReturnType = checker.getReturnTypeOfSignature(signatures[0]); if ((0, type_utils_1.isPromiseLike)(services.program, methodReturnType) && 'resolvedTypeArguments' in methodReturnType && Array.isArray(methodReturnType.resolvedTypeArguments) && methodReturnType.resolvedTypeArguments.length === 1 && methodReturnType.resolvedTypeArguments[0]) { return (0, type_utils_1.getTypeName)(checker, methodReturnType.resolvedTypeArguments[0]); } return (0, type_utils_1.getTypeName)(checker, methodReturnType); } return { 'MethodDefinition FunctionExpression > BlockStatement CallExpression': (node) => { recordUsedFunctions(node); }, 'MethodDefinition:exit': (node) => { const returnTypeName = getFunctionReturnTypeName(node); if (!returnTypeName) { return; } for (const usedFunction of usedFunctions) { if (!functionNames.includes(usedFunction.fullFunctionName)) { continue; } if (!Array.isArray(usedFunction.typeArgumentsParams)) { context.report({ node: usedFunction.node, messageId: 'wrongFirstTypeArg', data: { functionName: usedFunction.fullFunctionName, correctType: returnTypeName, }, fix: (fixer) => { return fixer.replaceText(usedFunction.node.callee, `${usedFunction.fullFunctionName}<${returnTypeName}>`); }, }); continue; } if (usedFunction.typeArgumentsParams.length === 0) { continue; } const usedFunctionTypeArgumentName = (0, type_utils_1.getTypeName)(checker, services.getTypeAtLocation(usedFunction.typeArgumentsParams[0])); if (usedFunctionTypeArgumentName !== returnTypeName) { context.report({ node: usedFunction.node, messageId: 'wrongFirstTypeArg', data: { functionName: usedFunction.fullFunctionName, correctType: returnTypeName, }, }); } } usedFunctions = []; }, }; }, });