@arabasta/eslint-plugin-tsoa
Version:
ESLint plugin for tsoa rules
116 lines (115 loc) • 5.11 kB
JavaScript
;
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 = [];
},
};
},
});