|
19 | 19 | */ |
20 | 20 | // https://sonarsource.github.io/rspec/#/rspec/S3699 |
21 | 21 |
|
22 | | -import type { TSESTree, TSESLint } from '@typescript-eslint/experimental-utils'; |
| 22 | +import { TSESTree, TSESLint } from '@typescript-eslint/experimental-utils'; |
23 | 23 | import { isFunctionExpression, isArrowFunctionExpression, isBlockStatement } from '../utils/nodes'; |
24 | 24 | import docsUrl from '../utils/docs-url'; |
25 | 25 |
|
| 26 | +const EMPTY_RETURN_VALUE_KEYWORDS = new Set<TSESTree.AST_NODE_TYPES>([ |
| 27 | + TSESTree.AST_NODE_TYPES.TSVoidKeyword, |
| 28 | + TSESTree.AST_NODE_TYPES.TSNeverKeyword, |
| 29 | + TSESTree.AST_NODE_TYPES.TSUndefinedKeyword, |
| 30 | +]); |
| 31 | + |
26 | 32 | function isReturnValueUsed(callExpr: TSESTree.Node) { |
27 | 33 | const { parent } = callExpr; |
28 | 34 | if (!parent) { |
29 | 35 | return false; |
30 | 36 | } |
31 | 37 |
|
32 | | - if (parent.type === 'LogicalExpression') { |
| 38 | + if (parent.type === TSESTree.AST_NODE_TYPES.LogicalExpression) { |
33 | 39 | return parent.left === callExpr; |
34 | 40 | } |
35 | 41 |
|
36 | | - if (parent.type === 'SequenceExpression') { |
| 42 | + if (parent.type === TSESTree.AST_NODE_TYPES.SequenceExpression) { |
37 | 43 | return parent.expressions[parent.expressions.length - 1] === callExpr; |
38 | 44 | } |
39 | 45 |
|
40 | | - if (parent.type === 'ConditionalExpression') { |
| 46 | + if (parent.type === TSESTree.AST_NODE_TYPES.ConditionalExpression) { |
41 | 47 | return parent.test === callExpr; |
42 | 48 | } |
43 | 49 |
|
44 | 50 | return ( |
45 | | - parent.type !== 'ExpressionStatement' && |
46 | | - parent.type !== 'ArrowFunctionExpression' && |
47 | | - parent.type !== 'UnaryExpression' && |
48 | | - parent.type !== 'AwaitExpression' && |
49 | | - parent.type !== 'ReturnStatement' && |
50 | | - parent.type !== 'ThrowStatement' |
| 51 | + parent.type !== TSESTree.AST_NODE_TYPES.ExpressionStatement && |
| 52 | + parent.type !== TSESTree.AST_NODE_TYPES.ArrowFunctionExpression && |
| 53 | + parent.type !== TSESTree.AST_NODE_TYPES.UnaryExpression && |
| 54 | + parent.type !== TSESTree.AST_NODE_TYPES.AwaitExpression && |
| 55 | + parent.type !== TSESTree.AST_NODE_TYPES.ReturnStatement && |
| 56 | + parent.type !== TSESTree.AST_NODE_TYPES.ThrowStatement |
51 | 57 | ); |
52 | 58 | } |
53 | 59 |
|
@@ -102,9 +108,9 @@ const rule: TSESLint.RuleModule<string, string[]> = { |
102 | 108 | const ancestors = [...context.getAncestors()].reverse(); |
103 | 109 | const functionNode = ancestors.find( |
104 | 110 | node => |
105 | | - node.type === 'FunctionExpression' || |
106 | | - node.type === 'FunctionDeclaration' || |
107 | | - node.type === 'ArrowFunctionExpression', |
| 111 | + node.type === TSESTree.AST_NODE_TYPES.FunctionExpression || |
| 112 | + node.type === TSESTree.AST_NODE_TYPES.FunctionDeclaration || |
| 113 | + node.type === TSESTree.AST_NODE_TYPES.ArrowFunctionExpression, |
108 | 114 | ); |
109 | 115 |
|
110 | 116 | functionsWithReturnValue.add(functionNode as TSESTree.FunctionLike); |
@@ -132,6 +138,16 @@ const rule: TSESLint.RuleModule<string, string[]> = { |
132 | 138 | } |
133 | 139 | }, |
134 | 140 |
|
| 141 | + TSDeclareFunction(node: TSESTree.Node) { |
| 142 | + const declareFunction = node as TSESTree.TSDeclareFunction; |
| 143 | + if ( |
| 144 | + declareFunction.returnType?.typeAnnotation.type && |
| 145 | + !EMPTY_RETURN_VALUE_KEYWORDS.has(declareFunction.returnType?.typeAnnotation.type) |
| 146 | + ) { |
| 147 | + functionsWithReturnValue.add(declareFunction); |
| 148 | + } |
| 149 | + }, |
| 150 | + |
135 | 151 | 'Program:exit'() { |
136 | 152 | callExpressionsToCheck.forEach((functionDeclaration, callee) => { |
137 | 153 | if (!functionsWithReturnValue.has(functionDeclaration)) { |
|
0 commit comments