@flint.fyi/ts 0.14.2 → 0.14.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/lib/createTypeScriptFileFromProgram.js +1 -0
  3. package/lib/index.d.ts +1 -0
  4. package/lib/index.js +1 -0
  5. package/lib/language.d.ts +1 -0
  6. package/lib/nodes.d.ts +1 -0
  7. package/lib/plugin.d.ts +165 -1
  8. package/lib/plugin.js +82 -0
  9. package/lib/rules/anyReturns.d.ts +6 -0
  10. package/lib/rules/anyReturns.js +187 -0
  11. package/lib/rules/anyReturns.test.d.ts +1 -0
  12. package/lib/rules/anyReturns.test.js +647 -0
  13. package/lib/rules/asyncPromiseExecutors.d.ts +6 -0
  14. package/lib/rules/asyncPromiseExecutors.js +51 -0
  15. package/lib/rules/asyncPromiseExecutors.test.d.ts +1 -0
  16. package/lib/rules/asyncPromiseExecutors.test.js +71 -0
  17. package/lib/rules/caseDeclarations.d.ts +6 -0
  18. package/lib/rules/caseDeclarations.js +53 -0
  19. package/lib/rules/caseDeclarations.test.d.ts +1 -0
  20. package/lib/rules/caseDeclarations.test.js +227 -0
  21. package/lib/rules/caseDuplicates.d.ts +6 -0
  22. package/lib/rules/caseDuplicates.js +49 -0
  23. package/lib/rules/caseDuplicates.test.d.ts +1 -0
  24. package/lib/rules/caseDuplicates.test.js +307 -0
  25. package/lib/rules/chainedAssignments.d.ts +6 -0
  26. package/lib/rules/chainedAssignments.js +48 -0
  27. package/lib/rules/chainedAssignments.test.d.ts +1 -0
  28. package/lib/rules/chainedAssignments.test.js +238 -0
  29. package/lib/rules/classAssignments.d.ts +6 -0
  30. package/lib/rules/classAssignments.js +42 -0
  31. package/lib/rules/classAssignments.test.d.ts +1 -0
  32. package/lib/rules/classAssignments.test.js +156 -0
  33. package/lib/rules/constantAssignments.d.ts +6 -0
  34. package/lib/rules/constantAssignments.js +61 -0
  35. package/lib/rules/constantAssignments.test.d.ts +1 -0
  36. package/lib/rules/constantAssignments.test.js +221 -0
  37. package/lib/rules/constructorReturns.d.ts +6 -0
  38. package/lib/rules/constructorReturns.js +52 -0
  39. package/lib/rules/constructorReturns.test.d.ts +1 -0
  40. package/lib/rules/constructorReturns.test.js +96 -0
  41. package/lib/rules/defaultCaseLast.d.ts +6 -0
  42. package/lib/rules/defaultCaseLast.js +43 -0
  43. package/lib/rules/defaultCaseLast.test.d.ts +1 -0
  44. package/lib/rules/defaultCaseLast.test.js +195 -0
  45. package/lib/rules/duplicateArguments.d.ts +6 -0
  46. package/lib/rules/duplicateArguments.js +51 -0
  47. package/lib/rules/duplicateArguments.test.d.ts +1 -0
  48. package/lib/rules/duplicateArguments.test.js +139 -0
  49. package/lib/rules/elseIfDuplicates.d.ts +6 -0
  50. package/lib/rules/elseIfDuplicates.js +53 -0
  51. package/lib/rules/elseIfDuplicates.test.d.ts +1 -0
  52. package/lib/rules/elseIfDuplicates.test.js +176 -0
  53. package/lib/rules/emptyDestructures.d.ts +6 -0
  54. package/lib/rules/emptyDestructures.js +40 -0
  55. package/lib/rules/emptyDestructures.test.d.ts +1 -0
  56. package/lib/rules/emptyDestructures.test.js +186 -0
  57. package/lib/rules/emptyStaticBlocks.d.ts +6 -0
  58. package/lib/rules/emptyStaticBlocks.js +54 -0
  59. package/lib/rules/emptyStaticBlocks.test.d.ts +1 -0
  60. package/lib/rules/emptyStaticBlocks.test.js +167 -0
  61. package/lib/rules/exceptionAssignments.d.ts +6 -0
  62. package/lib/rules/exceptionAssignments.js +61 -0
  63. package/lib/rules/exceptionAssignments.test.d.ts +1 -0
  64. package/lib/rules/exceptionAssignments.test.js +264 -0
  65. package/lib/rules/forDirections.d.ts +6 -0
  66. package/lib/rules/forDirections.js +124 -0
  67. package/lib/rules/forDirections.test.d.ts +1 -0
  68. package/lib/rules/forDirections.test.js +99 -0
  69. package/lib/rules/functionAssignments.d.ts +6 -0
  70. package/lib/rules/functionAssignments.js +42 -0
  71. package/lib/rules/functionAssignments.test.d.ts +1 -0
  72. package/lib/rules/functionAssignments.test.js +209 -0
  73. package/lib/rules/functionNewCalls.d.ts +6 -0
  74. package/lib/rules/functionNewCalls.js +60 -0
  75. package/lib/rules/functionNewCalls.test.d.ts +1 -0
  76. package/lib/rules/functionNewCalls.test.js +115 -0
  77. package/lib/rules/generatorFunctionYields.d.ts +6 -0
  78. package/lib/rules/generatorFunctionYields.js +57 -0
  79. package/lib/rules/generatorFunctionYields.test.d.ts +1 -0
  80. package/lib/rules/generatorFunctionYields.test.js +151 -0
  81. package/lib/rules/globalAssignments.d.ts +6 -0
  82. package/lib/rules/globalAssignments.js +59 -0
  83. package/lib/rules/globalAssignments.test.d.ts +1 -0
  84. package/lib/rules/globalAssignments.test.js +215 -0
  85. package/lib/rules/globalObjectCalls.d.ts +6 -0
  86. package/lib/rules/globalObjectCalls.js +43 -0
  87. package/lib/rules/globalObjectCalls.test.d.ts +1 -0
  88. package/lib/rules/globalObjectCalls.test.js +93 -0
  89. package/lib/rules/negativeZeroComparisons.d.ts +6 -0
  90. package/lib/rules/negativeZeroComparisons.js +65 -0
  91. package/lib/rules/negativeZeroComparisons.test.d.ts +1 -0
  92. package/lib/rules/negativeZeroComparisons.test.js +209 -0
  93. package/lib/rules/newExpressions.d.ts +6 -0
  94. package/lib/rules/newExpressions.js +54 -0
  95. package/lib/rules/newExpressions.test.d.ts +1 -0
  96. package/lib/rules/newExpressions.test.js +79 -0
  97. package/lib/rules/newNativeNonConstructors.d.ts +6 -0
  98. package/lib/rules/newNativeNonConstructors.js +49 -0
  99. package/lib/rules/newNativeNonConstructors.test.d.ts +1 -0
  100. package/lib/rules/newNativeNonConstructors.test.js +94 -0
  101. package/lib/rules/nonOctalDecimalEscapes.d.ts +6 -0
  102. package/lib/rules/nonOctalDecimalEscapes.js +57 -0
  103. package/lib/rules/nonOctalDecimalEscapes.test.d.ts +1 -0
  104. package/lib/rules/nonOctalDecimalEscapes.test.js +69 -0
  105. package/lib/rules/numericLiteralParsing.d.ts +6 -0
  106. package/lib/rules/numericLiteralParsing.js +97 -0
  107. package/lib/rules/numericLiteralParsing.test.d.ts +1 -0
  108. package/lib/rules/numericLiteralParsing.test.js +99 -0
  109. package/lib/rules/objectProto.d.ts +6 -0
  110. package/lib/rules/objectProto.js +54 -0
  111. package/lib/rules/objectProto.test.d.ts +1 -0
  112. package/lib/rules/objectProto.test.js +96 -0
  113. package/lib/rules/octalNumbers.d.ts +6 -0
  114. package/lib/rules/octalNumbers.js +68 -0
  115. package/lib/rules/octalNumbers.test.d.ts +1 -0
  116. package/lib/rules/octalNumbers.test.js +245 -0
  117. package/lib/rules/returnAssignments.d.ts +6 -0
  118. package/lib/rules/returnAssignments.js +50 -0
  119. package/lib/rules/returnAssignments.test.d.ts +1 -0
  120. package/lib/rules/returnAssignments.test.js +185 -0
  121. package/lib/rules/selfAssignments.d.ts +6 -0
  122. package/lib/rules/selfAssignments.js +44 -0
  123. package/lib/rules/selfAssignments.test.d.ts +1 -0
  124. package/lib/rules/selfAssignments.test.js +66 -0
  125. package/lib/rules/selfComparisons.d.ts +6 -0
  126. package/lib/rules/selfComparisons.js +41 -0
  127. package/lib/rules/selfComparisons.test.d.ts +1 -0
  128. package/lib/rules/selfComparisons.test.js +297 -0
  129. package/lib/rules/sequences.d.ts +6 -0
  130. package/lib/rules/sequences.js +34 -0
  131. package/lib/rules/sequences.test.d.ts +1 -0
  132. package/lib/rules/sequences.test.js +48 -0
  133. package/lib/rules/sparseArrays.d.ts +6 -0
  134. package/lib/rules/sparseArrays.js +54 -0
  135. package/lib/rules/sparseArrays.test.d.ts +1 -0
  136. package/lib/rules/sparseArrays.test.js +110 -0
  137. package/lib/rules/symbolDescriptions.d.ts +6 -0
  138. package/lib/rules/symbolDescriptions.js +41 -0
  139. package/lib/rules/symbolDescriptions.test.d.ts +1 -0
  140. package/lib/rules/symbolDescriptions.test.js +89 -0
  141. package/lib/rules/typeofComparisons.d.ts +6 -0
  142. package/lib/rules/typeofComparisons.js +78 -0
  143. package/lib/rules/typeofComparisons.test.d.ts +1 -0
  144. package/lib/rules/typeofComparisons.test.js +85 -0
  145. package/lib/rules/unassignedVariables.d.ts +6 -0
  146. package/lib/rules/unassignedVariables.js +55 -0
  147. package/lib/rules/unassignedVariables.test.d.ts +1 -0
  148. package/lib/rules/unassignedVariables.test.js +72 -0
  149. package/lib/rules/undefinedVariables.d.ts +6 -0
  150. package/lib/rules/undefinedVariables.js +76 -0
  151. package/lib/rules/undefinedVariables.test.d.ts +1 -0
  152. package/lib/rules/undefinedVariables.test.js +80 -0
  153. package/lib/rules/unicodeBOMs.d.ts +6 -0
  154. package/lib/rules/unicodeBOMs.js +41 -0
  155. package/lib/rules/unicodeBOMs.test.d.ts +1 -0
  156. package/lib/rules/unicodeBOMs.test.js +65 -0
  157. package/lib/rules/unnecessaryCatches.d.ts +6 -0
  158. package/lib/rules/unnecessaryCatches.js +68 -0
  159. package/lib/rules/unnecessaryCatches.test.d.ts +1 -0
  160. package/lib/rules/unnecessaryCatches.test.js +210 -0
  161. package/lib/rules/unsafeNegations.d.ts +6 -0
  162. package/lib/rules/unsafeNegations.js +50 -0
  163. package/lib/rules/unsafeNegations.test.d.ts +1 -0
  164. package/lib/rules/unsafeNegations.test.js +63 -0
  165. package/lib/rules/utils/discriminateAnyType.d.ts +12 -0
  166. package/lib/rules/utils/discriminateAnyType.js +41 -0
  167. package/lib/rules/utils/getThisExpression.d.ts +2 -0
  168. package/lib/rules/utils/getThisExpression.js +23 -0
  169. package/lib/rules/utils/isUnsafeAssignment.d.ts +13 -0
  170. package/lib/rules/utils/isUnsafeAssignment.js +76 -0
  171. package/lib/rules/utils/operators.d.ts +4 -0
  172. package/lib/rules/utils/operators.js +36 -0
  173. package/lib/rules/variableDeletions.d.ts +6 -0
  174. package/lib/rules/variableDeletions.js +39 -0
  175. package/lib/rules/variableDeletions.test.d.ts +1 -0
  176. package/lib/rules/variableDeletions.test.js +75 -0
  177. package/lib/rules/voidOperator.d.ts +6 -0
  178. package/lib/rules/voidOperator.js +36 -0
  179. package/lib/rules/voidOperator.test.d.ts +1 -0
  180. package/lib/rules/voidOperator.test.js +98 -0
  181. package/lib/utils/declarationIncludesGlobal.d.ts +2 -0
  182. package/lib/utils/declarationIncludesGlobal.js +5 -0
  183. package/lib/utils/declarationsIncludeGlobal.d.ts +2 -0
  184. package/lib/utils/declarationsIncludeGlobal.js +4 -0
  185. package/lib/utils/getModifyingReferences.d.ts +8 -0
  186. package/lib/utils/getModifyingReferences.js +42 -0
  187. package/lib/utils/hasSameTokens.d.ts +2 -0
  188. package/lib/utils/hasSameTokens.js +30 -0
  189. package/lib/utils/isGlobalDeclaration.d.ts +2 -0
  190. package/lib/utils/isGlobalDeclaration.js +5 -0
  191. package/lib/utils/isGlobalDeclarationOfName.d.ts +5 -0
  192. package/lib/utils/isGlobalDeclarationOfName.js +31 -0
  193. package/lib/utils/isGlobalVariable.d.ts +8 -0
  194. package/lib/utils/isGlobalVariable.js +21 -0
  195. package/lib/utils/unwrapParentParenthesizedExpressions.d.ts +2 -0
  196. package/lib/utils/unwrapParentParenthesizedExpressions.js +6 -0
  197. package/lib/utils/unwrapParenthesizedExpression.d.ts +2 -0
  198. package/lib/utils/unwrapParenthesizedExpression.js +6 -0
  199. package/package.json +1 -1
  200. package/src/createTypeScriptFileFromProgram.ts +1 -0
  201. package/src/index.ts +1 -0
  202. package/src/language.ts +1 -0
  203. package/src/nodes.ts +1 -0
  204. package/src/plugin.ts +82 -0
  205. package/src/rules/anyReturns.test.ts +649 -0
  206. package/src/rules/anyReturns.ts +263 -0
  207. package/src/rules/asyncPromiseExecutors.test.ts +72 -0
  208. package/src/rules/asyncPromiseExecutors.ts +61 -0
  209. package/src/rules/caseDeclarations.test.ts +228 -0
  210. package/src/rules/caseDeclarations.ts +70 -0
  211. package/src/rules/caseDuplicates.test.ts +308 -0
  212. package/src/rules/caseDuplicates.ts +57 -0
  213. package/src/rules/chainedAssignments.test.ts +239 -0
  214. package/src/rules/chainedAssignments.ts +55 -0
  215. package/src/rules/classAssignments.test.ts +157 -0
  216. package/src/rules/classAssignments.ts +50 -0
  217. package/src/rules/constantAssignments.test.ts +222 -0
  218. package/src/rules/constantAssignments.ts +78 -0
  219. package/src/rules/constructorReturns.test.ts +97 -0
  220. package/src/rules/constructorReturns.ts +59 -0
  221. package/src/rules/defaultCaseLast.test.ts +196 -0
  222. package/src/rules/defaultCaseLast.ts +54 -0
  223. package/src/rules/duplicateArguments.test.ts +140 -0
  224. package/src/rules/duplicateArguments.ts +58 -0
  225. package/src/rules/elseIfDuplicates.test.ts +177 -0
  226. package/src/rules/elseIfDuplicates.ts +69 -0
  227. package/src/rules/emptyDestructures.test.ts +187 -0
  228. package/src/rules/emptyDestructures.ts +48 -0
  229. package/src/rules/emptyStaticBlocks.test.ts +168 -0
  230. package/src/rules/emptyStaticBlocks.ts +60 -0
  231. package/src/rules/exceptionAssignments.test.ts +265 -0
  232. package/src/rules/exceptionAssignments.ts +77 -0
  233. package/src/rules/forDirections.test.ts +100 -0
  234. package/src/rules/forDirections.ts +163 -0
  235. package/src/rules/functionAssignments.test.ts +210 -0
  236. package/src/rules/functionAssignments.ts +51 -0
  237. package/src/rules/functionNewCalls.test.ts +116 -0
  238. package/src/rules/functionNewCalls.ts +75 -0
  239. package/src/rules/generatorFunctionYields.test.ts +152 -0
  240. package/src/rules/generatorFunctionYields.ts +71 -0
  241. package/src/rules/globalAssignments.test.ts +216 -0
  242. package/src/rules/globalAssignments.ts +67 -0
  243. package/src/rules/globalObjectCalls.test.ts +94 -0
  244. package/src/rules/globalObjectCalls.ts +52 -0
  245. package/src/rules/negativeZeroComparisons.test.ts +210 -0
  246. package/src/rules/negativeZeroComparisons.ts +87 -0
  247. package/src/rules/newExpressions.test.ts +80 -0
  248. package/src/rules/newExpressions.ts +67 -0
  249. package/src/rules/newNativeNonConstructors.test.ts +95 -0
  250. package/src/rules/newNativeNonConstructors.ts +59 -0
  251. package/src/rules/nonOctalDecimalEscapes.test.ts +70 -0
  252. package/src/rules/nonOctalDecimalEscapes.ts +70 -0
  253. package/src/rules/numericLiteralParsing.test.ts +100 -0
  254. package/src/rules/numericLiteralParsing.ts +116 -0
  255. package/src/rules/objectProto.test.ts +97 -0
  256. package/src/rules/objectProto.ts +62 -0
  257. package/src/rules/octalNumbers.test.ts +246 -0
  258. package/src/rules/octalNumbers.ts +75 -0
  259. package/src/rules/returnAssignments.test.ts +186 -0
  260. package/src/rules/returnAssignments.ts +57 -0
  261. package/src/rules/selfAssignments.test.ts +67 -0
  262. package/src/rules/selfAssignments.ts +50 -0
  263. package/src/rules/selfComparisons.test.ts +298 -0
  264. package/src/rules/selfComparisons.ts +45 -0
  265. package/src/rules/sequences.test.ts +49 -0
  266. package/src/rules/sequences.ts +37 -0
  267. package/src/rules/sparseArrays.test.ts +111 -0
  268. package/src/rules/sparseArrays.ts +61 -0
  269. package/src/rules/symbolDescriptions.test.ts +90 -0
  270. package/src/rules/symbolDescriptions.ts +47 -0
  271. package/src/rules/typeofComparisons.test.ts +86 -0
  272. package/src/rules/typeofComparisons.ts +88 -0
  273. package/src/rules/unassignedVariables.test.ts +73 -0
  274. package/src/rules/unassignedVariables.ts +69 -0
  275. package/src/rules/undefinedVariables.test.ts +81 -0
  276. package/src/rules/undefinedVariables.ts +97 -0
  277. package/src/rules/unicodeBOMs.test.ts +66 -0
  278. package/src/rules/unicodeBOMs.ts +44 -0
  279. package/src/rules/unnecessaryCatches.test.ts +211 -0
  280. package/src/rules/unnecessaryCatches.ts +84 -0
  281. package/src/rules/unsafeNegations.test.ts +64 -0
  282. package/src/rules/unsafeNegations.ts +59 -0
  283. package/src/rules/utils/discriminateAnyType.ts +66 -0
  284. package/src/rules/utils/getThisExpression.ts +24 -0
  285. package/src/rules/utils/isUnsafeAssignment.ts +113 -0
  286. package/src/rules/utils/operators.ts +39 -0
  287. package/src/rules/variableDeletions.test.ts +76 -0
  288. package/src/rules/variableDeletions.ts +43 -0
  289. package/src/rules/voidOperator.test.ts +99 -0
  290. package/src/rules/voidOperator.ts +38 -0
  291. package/src/utils/declarationIncludesGlobal.ts +9 -0
  292. package/src/utils/declarationsIncludeGlobal.ts +7 -0
  293. package/src/utils/getModifyingReferences.ts +58 -0
  294. package/src/utils/hasSameTokens.ts +45 -0
  295. package/src/utils/isGlobalDeclaration.ts +12 -0
  296. package/src/utils/isGlobalDeclarationOfName.ts +51 -0
  297. package/src/utils/isGlobalVariable.ts +30 -0
  298. package/src/utils/unwrapParentParenthesizedExpressions.ts +7 -0
  299. package/src/utils/unwrapParenthesizedExpression.ts +9 -0
  300. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,211 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./unnecessaryCatches.js";
3
+
4
+ ruleTester.describe(rule, {
5
+ invalid: [
6
+ {
7
+ code: `
8
+ try {
9
+ doSomething();
10
+ } catch (error) {
11
+ throw error;
12
+ }
13
+ `,
14
+ output: `
15
+ try {
16
+ doSomething();
17
+ }
18
+ `,
19
+ snapshot: `
20
+ try {
21
+ doSomething();
22
+ } catch (error) {
23
+ ~~~~~
24
+ This catch clause is unnecessary, as it only rethrows the exception without modification.
25
+ throw error;
26
+ }
27
+ `,
28
+ },
29
+ {
30
+ code: `
31
+ async function fetchData() {
32
+ try {
33
+ return await fetch("/api/data");
34
+ } catch (error) {
35
+ throw error;
36
+ }
37
+ }
38
+ `,
39
+ output: `
40
+ async function fetchData() {
41
+ try {
42
+ return await fetch("/api/data");
43
+ }
44
+ }
45
+ `,
46
+ snapshot: `
47
+ async function fetchData() {
48
+ try {
49
+ return await fetch("/api/data");
50
+ } catch (error) {
51
+ ~~~~~
52
+ This catch clause is unnecessary, as it only rethrows the exception without modification.
53
+ throw error;
54
+ }
55
+ }
56
+ `,
57
+ },
58
+ {
59
+ code: `
60
+ try {
61
+ processData();
62
+ } catch (exception) {
63
+ throw exception;
64
+ }
65
+ `,
66
+ output: `
67
+ try {
68
+ processData();
69
+ }
70
+ `,
71
+ snapshot: `
72
+ try {
73
+ processData();
74
+ } catch (exception) {
75
+ ~~~~~
76
+ This catch clause is unnecessary, as it only rethrows the exception without modification.
77
+ throw exception;
78
+ }
79
+ `,
80
+ },
81
+ {
82
+ code: `
83
+ function handleRequest() {
84
+ try {
85
+ const result = performOperation();
86
+ return result;
87
+ } catch (err) {
88
+ throw err;
89
+ }
90
+ }
91
+ `,
92
+ output: `
93
+ function handleRequest() {
94
+ try {
95
+ const result = performOperation();
96
+ return result;
97
+ }
98
+ }
99
+ `,
100
+ snapshot: `
101
+ function handleRequest() {
102
+ try {
103
+ const result = performOperation();
104
+ return result;
105
+ } catch (err) {
106
+ ~~~~~
107
+ This catch clause is unnecessary, as it only rethrows the exception without modification.
108
+ throw err;
109
+ }
110
+ }
111
+ `,
112
+ },
113
+ {
114
+ code: `
115
+ try {
116
+ doSomething();
117
+ } catch (error) {
118
+ throw error;
119
+ } finally {
120
+ cleanup();
121
+ }
122
+ `,
123
+ output: `
124
+ try {
125
+ doSomething();
126
+ } finally {
127
+ cleanup();
128
+ }
129
+ `,
130
+ snapshot: `
131
+ try {
132
+ doSomething();
133
+ } catch (error) {
134
+ ~~~~~
135
+ This catch clause is unnecessary, as it only rethrows the exception without modification.
136
+ throw error;
137
+ } finally {
138
+ cleanup();
139
+ }
140
+ `,
141
+ },
142
+ ],
143
+ valid: [
144
+ `try { doSomething(); } catch (error) { console.error(error); throw error; }`,
145
+ `try { doSomething(); } catch (error) { throw new Error("Failed"); }`,
146
+ `try { doSomething(); } catch (error) { logError(error); throw error; }`,
147
+ `try { doSomething(); } catch { throw new Error("Something went wrong"); }`,
148
+ `
149
+ try {
150
+ doSomething();
151
+ } catch (error) {
152
+ console.error("An error occurred:", error);
153
+ throw error;
154
+ }
155
+ `,
156
+ `
157
+ try {
158
+ doSomething();
159
+ } catch (error) {
160
+ throw new Error("Operation failed: " + error.message);
161
+ }
162
+ `,
163
+ `
164
+ try {
165
+ doSomething();
166
+ } catch (error) {
167
+ cleanup();
168
+ throw error;
169
+ }
170
+ `,
171
+ `
172
+ try {
173
+ doSomething();
174
+ } catch (error) {
175
+ throw error.originalError;
176
+ }
177
+ `,
178
+ `
179
+ async function fetchData() {
180
+ try {
181
+ return await fetch("/api/data");
182
+ } catch (error) {
183
+ await logError(error);
184
+ throw error;
185
+ }
186
+ }
187
+ `,
188
+ `
189
+ try {
190
+ doSomething();
191
+ } catch ({ message }) {
192
+ throw message;
193
+ }
194
+ `,
195
+ `
196
+ try {
197
+ doSomething();
198
+ } catch (error) {
199
+ }
200
+ `,
201
+ `
202
+ try {
203
+ doSomething();
204
+ } catch (error) {
205
+ console.log("error");
206
+ cleanup();
207
+ throw error;
208
+ }
209
+ `,
210
+ ],
211
+ });
@@ -0,0 +1,84 @@
1
+ import * as ts from "typescript";
2
+
3
+ import { typescriptLanguage } from "../language.js";
4
+
5
+ export default typescriptLanguage.createRule({
6
+ about: {
7
+ description:
8
+ "Reports catch clauses that only rethrow the caught error without modification.",
9
+ id: "unnecessaryCatches",
10
+ preset: "logical",
11
+ },
12
+ messages: {
13
+ unnecessaryCatch: {
14
+ primary:
15
+ "This catch clause is unnecessary, as it only rethrows the exception without modification.",
16
+ secondary: [
17
+ "A catch clause that only rethrows the caught error adds no value and creates unnecessary code complexity.",
18
+ "Removing such catch clauses allows errors to propagate naturally without the overhead of an unnecessary try-catch block.",
19
+ ],
20
+ suggestions: [
21
+ "Remove the try-catch block if the catch clause only rethrows the error, or add meaningful error handling logic to the catch clause.",
22
+ ],
23
+ },
24
+ },
25
+ setup(context) {
26
+ return {
27
+ visitors: {
28
+ CatchClause: (node) => {
29
+ if (!node.variableDeclaration || !ts.isBlock(node.block)) {
30
+ return;
31
+ }
32
+
33
+ const statements = node.block.statements;
34
+
35
+ if (statements.length !== 1) {
36
+ return;
37
+ }
38
+
39
+ const statement = statements[0];
40
+
41
+ if (!ts.isThrowStatement(statement)) {
42
+ return;
43
+ }
44
+
45
+ const catchVariable = node.variableDeclaration.name;
46
+ const thrownExpression = statement.expression;
47
+
48
+ if (
49
+ !ts.isIdentifier(catchVariable) ||
50
+ !ts.isIdentifier(thrownExpression)
51
+ ) {
52
+ return;
53
+ }
54
+
55
+ if (catchVariable.text !== thrownExpression.text) {
56
+ return;
57
+ }
58
+
59
+ const tryStatement = node.parent;
60
+ if (!ts.isTryStatement(tryStatement)) {
61
+ return;
62
+ }
63
+
64
+ const range = {
65
+ begin: node.getStart(context.sourceFile),
66
+ end: node.getStart(context.sourceFile) + "catch".length,
67
+ };
68
+
69
+ context.report({
70
+ fix: {
71
+ range: {
72
+ begin: tryStatement.tryBlock.getEnd(),
73
+ end: node.getEnd(),
74
+ },
75
+ text: "",
76
+ },
77
+ message: "unnecessaryCatch",
78
+ range,
79
+ });
80
+ },
81
+ },
82
+ };
83
+ },
84
+ });
@@ -0,0 +1,64 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./unsafeNegations.js";
3
+
4
+ ruleTester.describe(rule, {
5
+ invalid: [
6
+ {
7
+ code: `
8
+ !key in object;
9
+ `,
10
+ snapshot: `
11
+ !key in object;
12
+ ~
13
+ This negation applies before the \`in\` operator.
14
+ `,
15
+ },
16
+ {
17
+ code: `
18
+ !object instanceof Constructor;
19
+ `,
20
+ snapshot: `
21
+ !object instanceof Constructor;
22
+ ~
23
+ This negation applies before the \`instanceof\` operator.
24
+ `,
25
+ },
26
+ {
27
+ code: `
28
+ (!key) in object;
29
+ `,
30
+ snapshot: `
31
+ (!key) in object;
32
+ ~
33
+ This negation applies before the \`in\` operator.
34
+ `,
35
+ },
36
+ {
37
+ code: `
38
+ (!object) instanceof Constructor;
39
+ `,
40
+ snapshot: `
41
+ (!object) instanceof Constructor;
42
+ ~
43
+ This negation applies before the \`instanceof\` operator.
44
+ `,
45
+ },
46
+ {
47
+ code: `
48
+ const exists = !key in object;
49
+ `,
50
+ snapshot: `
51
+ const exists = !key in object;
52
+ ~
53
+ This negation applies before the \`in\` operator.
54
+ `,
55
+ },
56
+ ],
57
+ valid: [
58
+ `!(key in object);`,
59
+ `!(object instanceof Constructor);`,
60
+ `key in object;`,
61
+ `object instanceof Constructor;`,
62
+ `!flag && key in object;`,
63
+ ],
64
+ });
@@ -0,0 +1,59 @@
1
+ import * as ts from "typescript";
2
+
3
+ import { typescriptLanguage } from "../language.js";
4
+ import { unwrapParenthesizedExpression } from "../utils/unwrapParenthesizedExpression.js";
5
+
6
+ const operatorStrings = new Map([
7
+ [ts.SyntaxKind.InKeyword, "in"],
8
+ [ts.SyntaxKind.InstanceOfKeyword, "instanceof"],
9
+ ]);
10
+
11
+ export default typescriptLanguage.createRule({
12
+ about: {
13
+ description:
14
+ "Reports negating the left operand of `in` or `instanceof` relations.",
15
+ id: "unsafeNegations",
16
+ preset: "untyped",
17
+ },
18
+ messages: {
19
+ preferNegatingRelation: {
20
+ primary: "This negation applies before the `{{ operator }}` operator.",
21
+ secondary: [
22
+ "The logical not operator (!) has higher precedence than `in` and `instanceof`.",
23
+ "Write `!(left in right)` or `!(left instanceof Right)` to negate the relation as intended.",
24
+ ],
25
+ suggestions: ["Wrap the relation in parentheses and negate it."],
26
+ },
27
+ },
28
+ setup(context) {
29
+ return {
30
+ visitors: {
31
+ BinaryExpression: (node) => {
32
+ const operator = operatorStrings.get(node.operatorToken.kind);
33
+ if (!operator) {
34
+ return;
35
+ }
36
+
37
+ const left = unwrapParenthesizedExpression(node.left);
38
+ if (
39
+ !ts.isPrefixUnaryExpression(left) ||
40
+ left.operator !== ts.SyntaxKind.ExclamationToken
41
+ ) {
42
+ return;
43
+ }
44
+
45
+ const begin = left.getStart(context.sourceFile);
46
+
47
+ context.report({
48
+ data: { operator },
49
+ message: "preferNegatingRelation",
50
+ range: {
51
+ begin,
52
+ end: begin + 1,
53
+ },
54
+ });
55
+ },
56
+ },
57
+ };
58
+ },
59
+ });
@@ -0,0 +1,66 @@
1
+ import * as tsutils from "ts-api-utils";
2
+ import * as ts from "typescript";
3
+
4
+ export enum AnyType {
5
+ Any,
6
+ PromiseAny,
7
+ AnyArray,
8
+ Safe,
9
+ }
10
+
11
+ /**
12
+ * @returns `AnyType.Any` if the type is `any`, `AnyType.AnyArray` if the type is `any[]` or `readonly any[]`, `AnyType.PromiseAny` if the type is `Promise<any>`,
13
+ * otherwise it returns `AnyType.Safe`.
14
+ */
15
+ export function discriminateAnyType(
16
+ type: ts.Type,
17
+ checker: ts.TypeChecker,
18
+ program: ts.Program,
19
+ tsNode: ts.Node,
20
+ ): AnyType {
21
+ return discriminateAnyTypeWorker(type, checker, program, tsNode, new Set());
22
+ }
23
+
24
+ function discriminateAnyTypeWorker(
25
+ type: ts.Type,
26
+ checker: ts.TypeChecker,
27
+ program: ts.Program,
28
+ tsNode: ts.Node,
29
+ visited: Set<ts.Type>,
30
+ ) {
31
+ if (visited.has(type)) {
32
+ return AnyType.Safe;
33
+ }
34
+ visited.add(type);
35
+ if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Any)) {
36
+ return AnyType.Any;
37
+ }
38
+ if (
39
+ checker.isArrayType(type) &&
40
+ tsutils.isTypeFlagSet(
41
+ checker.getTypeArguments(type as ts.TypeReference)[0],
42
+ ts.TypeFlags.Any,
43
+ )
44
+ ) {
45
+ return AnyType.AnyArray;
46
+ }
47
+ for (const part of tsutils.typeConstituents(type)) {
48
+ if (tsutils.isThenableType(checker, tsNode, part)) {
49
+ const awaitedType = checker.getAwaitedType(part);
50
+ if (awaitedType) {
51
+ const awaitedAnyType = discriminateAnyTypeWorker(
52
+ awaitedType,
53
+ checker,
54
+ program,
55
+ tsNode,
56
+ visited,
57
+ );
58
+ if (awaitedAnyType === AnyType.Any) {
59
+ return AnyType.PromiseAny;
60
+ }
61
+ }
62
+ }
63
+ }
64
+
65
+ return AnyType.Safe;
66
+ }
@@ -0,0 +1,24 @@
1
+ import * as tsutils from "ts-api-utils";
2
+ import * as ts from "typescript";
3
+
4
+ export function getThisExpression(node: ts.Node): null | ts.ThisExpression {
5
+ while (true) {
6
+ node = skipParentheses(node);
7
+ if (ts.isCallExpression(node) || tsutils.isAccessExpression(node)) {
8
+ node = node.expression;
9
+ } else if (tsutils.isThisExpression(node)) {
10
+ return node;
11
+ } else {
12
+ break;
13
+ }
14
+ }
15
+
16
+ return null;
17
+ }
18
+
19
+ function skipParentheses(node: ts.Node): ts.Node {
20
+ while (ts.isParenthesizedExpression(node)) {
21
+ node = node.expression;
22
+ }
23
+ return node;
24
+ }
@@ -0,0 +1,113 @@
1
+ import * as tsutils from "ts-api-utils";
2
+ import * as ts from "typescript";
3
+
4
+ /**
5
+ * Does a simple check to see if there is an any being assigned to a non-any type.
6
+ *
7
+ * This also checks generic positions to ensure there's no unsafe sub-assignments.
8
+ * Note: in the case of generic positions, it makes the assumption that the two types are the same.
9
+ * @example See tests for examples
10
+ * @returns false if it's safe, or an object with the two types if it's unsafe
11
+ */
12
+ export function isUnsafeAssignment(
13
+ type: ts.Type,
14
+ receiver: ts.Type,
15
+ checker: ts.TypeChecker,
16
+ senderNode: null | ts.Node,
17
+ ): false | { receiver: ts.Type; sender: ts.Type } {
18
+ return isUnsafeAssignmentWorker(
19
+ type,
20
+ receiver,
21
+ checker,
22
+ senderNode,
23
+ new Map(),
24
+ );
25
+ }
26
+
27
+ function isUnsafeAssignmentWorker(
28
+ type: ts.Type,
29
+ receiver: ts.Type,
30
+ checker: ts.TypeChecker,
31
+ senderNode: null | ts.Node,
32
+ visited: Map<ts.Type, Set<ts.Type>>,
33
+ ): false | { receiver: ts.Type; sender: ts.Type } {
34
+ if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Any)) {
35
+ // Allow assignment of any ==> unknown.
36
+ if (tsutils.isTypeFlagSet(receiver, ts.TypeFlags.Unknown)) {
37
+ return false;
38
+ }
39
+
40
+ if (!tsutils.isTypeFlagSet(receiver, ts.TypeFlags.Any)) {
41
+ return { receiver, sender: type };
42
+ }
43
+ }
44
+
45
+ const typeAlreadyVisited = visited.get(type);
46
+
47
+ if (typeAlreadyVisited) {
48
+ if (typeAlreadyVisited.has(receiver)) {
49
+ return false;
50
+ }
51
+ typeAlreadyVisited.add(receiver);
52
+ } else {
53
+ visited.set(type, new Set([receiver]));
54
+ }
55
+
56
+ if (tsutils.isTypeReference(type) && tsutils.isTypeReference(receiver)) {
57
+ // TODO - figure out how to handle cases like this,
58
+ // where the types are assignable, but not the same type
59
+ /*
60
+ function foo(): ReadonlySet<number> { return new Set<any>(); }
61
+
62
+ // and
63
+
64
+ type Test<T> = { prop: T }
65
+ type Test2 = { prop: string }
66
+ declare const a: Test<any>;
67
+ const b: Test2 = a;
68
+ */
69
+
70
+ if (type.target !== receiver.target) {
71
+ // if the type references are different, assume safe, as we won't know how to compare the two types
72
+ // the generic positions might not be equivalent for both types
73
+ return false;
74
+ }
75
+
76
+ if (
77
+ senderNode != null &&
78
+ ts.isNewExpression(senderNode) &&
79
+ ts.isIdentifier(senderNode.expression) &&
80
+ senderNode.expression.text === "Map" &&
81
+ (senderNode.arguments == null || senderNode.arguments.length === 0) &&
82
+ senderNode.typeArguments == null
83
+ ) {
84
+ // special case to handle `new Map()`
85
+ // unfortunately Map's default empty constructor is typed to return `Map<any, any>` :(
86
+ // https://github.com/typescript-eslint/typescript-eslint/issues/2109#issuecomment-634144396
87
+ return false;
88
+ }
89
+
90
+ const typeArguments = type.typeArguments ?? [];
91
+ const receiverTypeArguments = receiver.typeArguments ?? [];
92
+
93
+ for (let i = 0; i < typeArguments.length; i += 1) {
94
+ const arg = typeArguments[i];
95
+ const receiverArg = receiverTypeArguments[i];
96
+
97
+ const unsafe = isUnsafeAssignmentWorker(
98
+ arg,
99
+ receiverArg,
100
+ checker,
101
+ senderNode,
102
+ visited,
103
+ );
104
+ if (unsafe) {
105
+ return { receiver, sender: type };
106
+ }
107
+ }
108
+
109
+ return false;
110
+ }
111
+
112
+ return false;
113
+ }
@@ -0,0 +1,39 @@
1
+ import * as ts from "typescript";
2
+
3
+ export function isComparisonOperator(token: ts.BinaryOperatorToken) {
4
+ switch (token.kind) {
5
+ case ts.SyntaxKind.EqualsEqualsEqualsToken:
6
+ case ts.SyntaxKind.EqualsEqualsToken:
7
+ case ts.SyntaxKind.ExclamationEqualsEqualsToken:
8
+ case ts.SyntaxKind.ExclamationEqualsToken:
9
+ case ts.SyntaxKind.GreaterThanEqualsToken:
10
+ case ts.SyntaxKind.GreaterThanToken:
11
+ case ts.SyntaxKind.LessThanEqualsToken:
12
+ case ts.SyntaxKind.LessThanToken:
13
+ return true;
14
+ default:
15
+ return false;
16
+ }
17
+ }
18
+
19
+ export function isEqualityOperator(token: ts.BinaryOperatorToken) {
20
+ switch (token.kind) {
21
+ case ts.SyntaxKind.EqualsEqualsEqualsToken:
22
+ case ts.SyntaxKind.EqualsEqualsToken:
23
+ case ts.SyntaxKind.ExclamationEqualsEqualsToken:
24
+ case ts.SyntaxKind.ExclamationEqualsToken:
25
+ return true;
26
+ default:
27
+ return false;
28
+ }
29
+ }
30
+
31
+ export function isNegatedEqualityOperator(token: ts.BinaryOperatorToken) {
32
+ switch (token.kind) {
33
+ case ts.SyntaxKind.ExclamationEqualsEqualsToken:
34
+ case ts.SyntaxKind.ExclamationEqualsToken:
35
+ return true;
36
+ default:
37
+ return false;
38
+ }
39
+ }