@flint.fyi/ts 0.14.2 → 0.14.3

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 (209) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/lib/index.d.ts +1 -0
  3. package/lib/index.js +1 -0
  4. package/lib/nodes.d.ts +1 -0
  5. package/lib/plugin.d.ts +121 -1
  6. package/lib/plugin.js +60 -0
  7. package/lib/rules/asyncPromiseExecutors.d.ts +6 -0
  8. package/lib/rules/asyncPromiseExecutors.js +51 -0
  9. package/lib/rules/asyncPromiseExecutors.test.d.ts +1 -0
  10. package/lib/rules/asyncPromiseExecutors.test.js +71 -0
  11. package/lib/rules/caseDeclarations.d.ts +6 -0
  12. package/lib/rules/caseDeclarations.js +53 -0
  13. package/lib/rules/caseDeclarations.test.d.ts +1 -0
  14. package/lib/rules/caseDeclarations.test.js +227 -0
  15. package/lib/rules/chainedAssignments.d.ts +6 -0
  16. package/lib/rules/chainedAssignments.js +48 -0
  17. package/lib/rules/chainedAssignments.test.d.ts +1 -0
  18. package/lib/rules/chainedAssignments.test.js +238 -0
  19. package/lib/rules/classAssignments.d.ts +6 -0
  20. package/lib/rules/classAssignments.js +42 -0
  21. package/lib/rules/classAssignments.test.d.ts +1 -0
  22. package/lib/rules/classAssignments.test.js +156 -0
  23. package/lib/rules/constantAssignments.d.ts +6 -0
  24. package/lib/rules/constantAssignments.js +61 -0
  25. package/lib/rules/constantAssignments.test.d.ts +1 -0
  26. package/lib/rules/constantAssignments.test.js +221 -0
  27. package/lib/rules/constructorReturns.d.ts +6 -0
  28. package/lib/rules/constructorReturns.js +52 -0
  29. package/lib/rules/constructorReturns.test.d.ts +1 -0
  30. package/lib/rules/constructorReturns.test.js +96 -0
  31. package/lib/rules/defaultCaseLast.d.ts +6 -0
  32. package/lib/rules/defaultCaseLast.js +43 -0
  33. package/lib/rules/defaultCaseLast.test.d.ts +1 -0
  34. package/lib/rules/defaultCaseLast.test.js +195 -0
  35. package/lib/rules/duplicateArguments.d.ts +6 -0
  36. package/lib/rules/duplicateArguments.js +51 -0
  37. package/lib/rules/duplicateArguments.test.d.ts +1 -0
  38. package/lib/rules/duplicateArguments.test.js +139 -0
  39. package/lib/rules/emptyDestructures.d.ts +6 -0
  40. package/lib/rules/emptyDestructures.js +40 -0
  41. package/lib/rules/emptyDestructures.test.d.ts +1 -0
  42. package/lib/rules/emptyDestructures.test.js +186 -0
  43. package/lib/rules/emptyStaticBlocks.d.ts +6 -0
  44. package/lib/rules/emptyStaticBlocks.js +54 -0
  45. package/lib/rules/emptyStaticBlocks.test.d.ts +1 -0
  46. package/lib/rules/emptyStaticBlocks.test.js +167 -0
  47. package/lib/rules/exceptionAssignments.d.ts +6 -0
  48. package/lib/rules/exceptionAssignments.js +61 -0
  49. package/lib/rules/exceptionAssignments.test.d.ts +1 -0
  50. package/lib/rules/exceptionAssignments.test.js +264 -0
  51. package/lib/rules/functionAssignments.d.ts +6 -0
  52. package/lib/rules/functionAssignments.js +42 -0
  53. package/lib/rules/functionAssignments.test.d.ts +1 -0
  54. package/lib/rules/functionAssignments.test.js +209 -0
  55. package/lib/rules/generatorFunctionYields.d.ts +6 -0
  56. package/lib/rules/generatorFunctionYields.js +57 -0
  57. package/lib/rules/generatorFunctionYields.test.d.ts +1 -0
  58. package/lib/rules/generatorFunctionYields.test.js +151 -0
  59. package/lib/rules/globalAssignments.d.ts +6 -0
  60. package/lib/rules/globalAssignments.js +59 -0
  61. package/lib/rules/globalAssignments.test.d.ts +1 -0
  62. package/lib/rules/globalAssignments.test.js +215 -0
  63. package/lib/rules/globalObjectCalls.d.ts +6 -0
  64. package/lib/rules/globalObjectCalls.js +43 -0
  65. package/lib/rules/globalObjectCalls.test.d.ts +1 -0
  66. package/lib/rules/globalObjectCalls.test.js +93 -0
  67. package/lib/rules/negativeZeroComparisons.d.ts +6 -0
  68. package/lib/rules/negativeZeroComparisons.js +83 -0
  69. package/lib/rules/negativeZeroComparisons.test.d.ts +1 -0
  70. package/lib/rules/negativeZeroComparisons.test.js +209 -0
  71. package/lib/rules/newExpressions.d.ts +6 -0
  72. package/lib/rules/newExpressions.js +54 -0
  73. package/lib/rules/newExpressions.test.d.ts +1 -0
  74. package/lib/rules/newExpressions.test.js +79 -0
  75. package/lib/rules/newNativeNonConstructors.d.ts +6 -0
  76. package/lib/rules/newNativeNonConstructors.js +49 -0
  77. package/lib/rules/newNativeNonConstructors.test.d.ts +1 -0
  78. package/lib/rules/newNativeNonConstructors.test.js +94 -0
  79. package/lib/rules/objectProto.d.ts +6 -0
  80. package/lib/rules/objectProto.js +54 -0
  81. package/lib/rules/objectProto.test.d.ts +1 -0
  82. package/lib/rules/objectProto.test.js +96 -0
  83. package/lib/rules/octalNumbers.d.ts +6 -0
  84. package/lib/rules/octalNumbers.js +68 -0
  85. package/lib/rules/octalNumbers.test.d.ts +1 -0
  86. package/lib/rules/octalNumbers.test.js +245 -0
  87. package/lib/rules/returnAssignments.d.ts +6 -0
  88. package/lib/rules/returnAssignments.js +50 -0
  89. package/lib/rules/returnAssignments.test.d.ts +1 -0
  90. package/lib/rules/returnAssignments.test.js +185 -0
  91. package/lib/rules/sparseArrays.d.ts +6 -0
  92. package/lib/rules/sparseArrays.js +54 -0
  93. package/lib/rules/sparseArrays.test.d.ts +1 -0
  94. package/lib/rules/sparseArrays.test.js +110 -0
  95. package/lib/rules/symbolDescriptions.d.ts +6 -0
  96. package/lib/rules/symbolDescriptions.js +41 -0
  97. package/lib/rules/symbolDescriptions.test.d.ts +1 -0
  98. package/lib/rules/symbolDescriptions.test.js +89 -0
  99. package/lib/rules/unassignedVariables.d.ts +6 -0
  100. package/lib/rules/unassignedVariables.js +55 -0
  101. package/lib/rules/unassignedVariables.test.d.ts +1 -0
  102. package/lib/rules/unassignedVariables.test.js +72 -0
  103. package/lib/rules/undefinedVariables.d.ts +6 -0
  104. package/lib/rules/undefinedVariables.js +76 -0
  105. package/lib/rules/undefinedVariables.test.d.ts +1 -0
  106. package/lib/rules/undefinedVariables.test.js +80 -0
  107. package/lib/rules/unicodeBOMs.d.ts +6 -0
  108. package/lib/rules/unicodeBOMs.js +41 -0
  109. package/lib/rules/unicodeBOMs.test.d.ts +1 -0
  110. package/lib/rules/unicodeBOMs.test.js +65 -0
  111. package/lib/rules/unnecessaryCatches.d.ts +6 -0
  112. package/lib/rules/unnecessaryCatches.js +68 -0
  113. package/lib/rules/unnecessaryCatches.test.d.ts +1 -0
  114. package/lib/rules/unnecessaryCatches.test.js +210 -0
  115. package/lib/rules/unsafeNegations.d.ts +6 -0
  116. package/lib/rules/unsafeNegations.js +50 -0
  117. package/lib/rules/unsafeNegations.test.d.ts +1 -0
  118. package/lib/rules/unsafeNegations.test.js +63 -0
  119. package/lib/rules/variableDeletions.d.ts +6 -0
  120. package/lib/rules/variableDeletions.js +39 -0
  121. package/lib/rules/variableDeletions.test.d.ts +1 -0
  122. package/lib/rules/variableDeletions.test.js +75 -0
  123. package/lib/rules/voidOperator.d.ts +6 -0
  124. package/lib/rules/voidOperator.js +36 -0
  125. package/lib/rules/voidOperator.test.d.ts +1 -0
  126. package/lib/rules/voidOperator.test.js +98 -0
  127. package/lib/utils/declarationsIncludeGlobal.d.ts +2 -0
  128. package/lib/utils/declarationsIncludeGlobal.js +7 -0
  129. package/lib/utils/getModifyingReferences.d.ts +8 -0
  130. package/lib/utils/getModifyingReferences.js +42 -0
  131. package/lib/utils/isGlobalDeclaration.d.ts +2 -0
  132. package/lib/utils/isGlobalDeclaration.js +5 -0
  133. package/lib/utils/isGlobalVariable.d.ts +8 -0
  134. package/lib/utils/isGlobalVariable.js +21 -0
  135. package/lib/utils/unwrapParentParenthesizedExpressions.d.ts +2 -0
  136. package/lib/utils/unwrapParentParenthesizedExpressions.js +6 -0
  137. package/lib/utils/unwrapParenthesizedExpression.d.ts +2 -0
  138. package/lib/utils/unwrapParenthesizedExpression.js +6 -0
  139. package/package.json +1 -1
  140. package/src/index.ts +1 -0
  141. package/src/nodes.ts +1 -0
  142. package/src/plugin.ts +60 -0
  143. package/src/rules/asyncPromiseExecutors.test.ts +72 -0
  144. package/src/rules/asyncPromiseExecutors.ts +61 -0
  145. package/src/rules/caseDeclarations.test.ts +228 -0
  146. package/src/rules/caseDeclarations.ts +70 -0
  147. package/src/rules/chainedAssignments.test.ts +239 -0
  148. package/src/rules/chainedAssignments.ts +55 -0
  149. package/src/rules/classAssignments.test.ts +157 -0
  150. package/src/rules/classAssignments.ts +50 -0
  151. package/src/rules/constantAssignments.test.ts +222 -0
  152. package/src/rules/constantAssignments.ts +78 -0
  153. package/src/rules/constructorReturns.test.ts +97 -0
  154. package/src/rules/constructorReturns.ts +59 -0
  155. package/src/rules/defaultCaseLast.test.ts +196 -0
  156. package/src/rules/defaultCaseLast.ts +54 -0
  157. package/src/rules/duplicateArguments.test.ts +140 -0
  158. package/src/rules/duplicateArguments.ts +58 -0
  159. package/src/rules/emptyDestructures.test.ts +187 -0
  160. package/src/rules/emptyDestructures.ts +48 -0
  161. package/src/rules/emptyStaticBlocks.test.ts +168 -0
  162. package/src/rules/emptyStaticBlocks.ts +60 -0
  163. package/src/rules/exceptionAssignments.test.ts +265 -0
  164. package/src/rules/exceptionAssignments.ts +77 -0
  165. package/src/rules/functionAssignments.test.ts +210 -0
  166. package/src/rules/functionAssignments.ts +51 -0
  167. package/src/rules/generatorFunctionYields.test.ts +152 -0
  168. package/src/rules/generatorFunctionYields.ts +71 -0
  169. package/src/rules/globalAssignments.test.ts +216 -0
  170. package/src/rules/globalAssignments.ts +67 -0
  171. package/src/rules/globalObjectCalls.test.ts +94 -0
  172. package/src/rules/globalObjectCalls.ts +52 -0
  173. package/src/rules/negativeZeroComparisons.test.ts +210 -0
  174. package/src/rules/negativeZeroComparisons.ts +106 -0
  175. package/src/rules/newExpressions.test.ts +80 -0
  176. package/src/rules/newExpressions.ts +67 -0
  177. package/src/rules/newNativeNonConstructors.test.ts +95 -0
  178. package/src/rules/newNativeNonConstructors.ts +59 -0
  179. package/src/rules/objectProto.test.ts +97 -0
  180. package/src/rules/objectProto.ts +62 -0
  181. package/src/rules/octalNumbers.test.ts +246 -0
  182. package/src/rules/octalNumbers.ts +75 -0
  183. package/src/rules/returnAssignments.test.ts +186 -0
  184. package/src/rules/returnAssignments.ts +57 -0
  185. package/src/rules/sparseArrays.test.ts +111 -0
  186. package/src/rules/sparseArrays.ts +61 -0
  187. package/src/rules/symbolDescriptions.test.ts +90 -0
  188. package/src/rules/symbolDescriptions.ts +47 -0
  189. package/src/rules/unassignedVariables.test.ts +73 -0
  190. package/src/rules/unassignedVariables.ts +69 -0
  191. package/src/rules/undefinedVariables.test.ts +81 -0
  192. package/src/rules/undefinedVariables.ts +97 -0
  193. package/src/rules/unicodeBOMs.test.ts +66 -0
  194. package/src/rules/unicodeBOMs.ts +44 -0
  195. package/src/rules/unnecessaryCatches.test.ts +211 -0
  196. package/src/rules/unnecessaryCatches.ts +84 -0
  197. package/src/rules/unsafeNegations.test.ts +64 -0
  198. package/src/rules/unsafeNegations.ts +59 -0
  199. package/src/rules/variableDeletions.test.ts +76 -0
  200. package/src/rules/variableDeletions.ts +43 -0
  201. package/src/rules/voidOperator.test.ts +99 -0
  202. package/src/rules/voidOperator.ts +38 -0
  203. package/src/utils/declarationsIncludeGlobal.ts +11 -0
  204. package/src/utils/getModifyingReferences.ts +58 -0
  205. package/src/utils/isGlobalDeclaration.ts +12 -0
  206. package/src/utils/isGlobalVariable.ts +30 -0
  207. package/src/utils/unwrapParentParenthesizedExpressions.ts +7 -0
  208. package/src/utils/unwrapParenthesizedExpression.ts +9 -0
  209. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,76 @@
1
+ import * as ts from "typescript";
2
+ import { typescriptLanguage } from "../language.js";
3
+ export default typescriptLanguage.createRule({
4
+ about: {
5
+ description: "Reports using variables that are not defined.",
6
+ id: "undefinedVariables",
7
+ preset: "untyped",
8
+ },
9
+ messages: {
10
+ undefinedVariable: {
11
+ primary: "Variable '{{ name }}' is used but was never defined.",
12
+ secondary: [
13
+ "Variables must be declared before they can be used.",
14
+ "Using undefined variables will cause a ReferenceError at runtime.",
15
+ ],
16
+ suggestions: [
17
+ "Declare the variable before using it, or check if the variable name is spelled correctly.",
18
+ ],
19
+ },
20
+ },
21
+ setup(context) {
22
+ return {
23
+ visitors: {
24
+ Identifier: (node) => {
25
+ if (ts.isVariableDeclaration(node.parent) &&
26
+ node.parent.name === node) {
27
+ return;
28
+ }
29
+ if (ts.isParameter(node.parent) && node.parent.name === node) {
30
+ return;
31
+ }
32
+ if ((ts.isFunctionDeclaration(node.parent) ||
33
+ ts.isClassDeclaration(node.parent) ||
34
+ ts.isInterfaceDeclaration(node.parent) ||
35
+ ts.isTypeAliasDeclaration(node.parent) ||
36
+ ts.isEnumDeclaration(node.parent) ||
37
+ ts.isModuleDeclaration(node.parent)) &&
38
+ node.parent.name === node) {
39
+ return;
40
+ }
41
+ if (ts.isImportSpecifier(node.parent) ||
42
+ ts.isImportClause(node.parent) ||
43
+ ts.isNamespaceImport(node.parent)) {
44
+ return;
45
+ }
46
+ if (ts.isPropertyAccessExpression(node.parent) &&
47
+ node.parent.name === node) {
48
+ return;
49
+ }
50
+ if (ts.isPropertyAssignment(node.parent) &&
51
+ node.parent.name === node) {
52
+ return;
53
+ }
54
+ if (ts.isTypeOfExpression(node.parent) &&
55
+ node.parent.expression === node) {
56
+ return;
57
+ }
58
+ // TODO: This rule is untyped, so it should use scope analysis
59
+ // https://github.com/JoshuaKGoldberg/flint/issues/400
60
+ if (!context.typeChecker.getSymbolAtLocation(node)) {
61
+ context.report({
62
+ data: {
63
+ name: node.text,
64
+ },
65
+ message: "undefinedVariable",
66
+ range: {
67
+ begin: node.getStart(context.sourceFile),
68
+ end: node.getEnd(),
69
+ },
70
+ });
71
+ }
72
+ },
73
+ },
74
+ };
75
+ },
76
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,80 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./undefinedVariables.js";
3
+ ruleTester.describe(rule, {
4
+ invalid: [
5
+ {
6
+ code: `
7
+ console.log(undefinedVar);
8
+ `,
9
+ snapshot: `
10
+ console.log(undefinedVar);
11
+ ~~~~~~~~~~~~
12
+ Variable 'undefinedVar' is used but was never defined.
13
+ `,
14
+ },
15
+ {
16
+ code: `
17
+ function test() {
18
+ return notDefined;
19
+ }
20
+ `,
21
+ snapshot: `
22
+ function test() {
23
+ return notDefined;
24
+ ~~~~~~~~~~
25
+ Variable 'notDefined' is used but was never defined.
26
+ }
27
+ `,
28
+ },
29
+ {
30
+ code: `
31
+ const value = unknownVariable;
32
+ `,
33
+ snapshot: `
34
+ const value = unknownVariable;
35
+ ~~~~~~~~~~~~~~~
36
+ Variable 'unknownVariable' is used but was never defined.
37
+ `,
38
+ },
39
+ {
40
+ code: `
41
+ if (condition) {
42
+ doSomething();
43
+ }
44
+ `,
45
+ snapshot: `
46
+ if (condition) {
47
+ ~~~~~~~~~
48
+ Variable 'condition' is used but was never defined.
49
+ doSomething();
50
+ ~~~~~~~~~~~
51
+ Variable 'doSomething' is used but was never defined.
52
+ }
53
+ `,
54
+ },
55
+ {
56
+ code: `
57
+ const result = first + second;
58
+ `,
59
+ snapshot: `
60
+ const result = first + second;
61
+ ~~~~~
62
+ Variable 'first' is used but was never defined.
63
+ ~~~~~~
64
+ Variable 'second' is used but was never defined.
65
+ `,
66
+ },
67
+ ],
68
+ valid: [
69
+ `const value = 5; console.log(value);`,
70
+ `function test(parameter: number) { return parameter; }`,
71
+ `let count = 0; count++;`,
72
+ `const obj = { prop: 1 }; console.log(obj.prop);`,
73
+ `typeof undefinedVar === "undefined"`,
74
+ `const obj = {}; const { prop } = obj;`,
75
+ `function fn() { return 1; } fn();`,
76
+ `class MyClass {} const instance = new MyClass();`,
77
+ `import { value } from "module"; console.log(value);`,
78
+ `const array = [1, 2, 3]; array.forEach(item => console.log(item));`,
79
+ ],
80
+ });
@@ -0,0 +1,6 @@
1
+ declare const _default: import("@flint.fyi/core").Rule<{
2
+ readonly description: "Reports files with Unicode Byte Order Marks (BOMs).";
3
+ readonly id: "unicodeBOMs";
4
+ readonly preset: "stylistic";
5
+ }, import("../nodes.js").TSNodesByName, import("../language.js").TypeScriptServices, "noBOM", undefined>;
6
+ export default _default;
@@ -0,0 +1,41 @@
1
+ import { typescriptLanguage } from "../language.js";
2
+ export default typescriptLanguage.createRule({
3
+ about: {
4
+ description: "Reports files with Unicode Byte Order Marks (BOMs).",
5
+ id: "unicodeBOMs",
6
+ preset: "stylistic",
7
+ },
8
+ messages: {
9
+ noBOM: {
10
+ primary: "This Unicode Byte Order Mark (BOM) is unnecessary and can cause issues with some tools.",
11
+ secondary: [
12
+ "The Unicode BOM is a special character (U+FEFF) that can appear at the start of a file to indicate its byte order and encoding.",
13
+ "While it can be useful in some contexts, it does not improve tooling portability and is not generally helpful for editors.",
14
+ ],
15
+ suggestions: ["Remove the BOM from the beginning of the file."],
16
+ },
17
+ },
18
+ setup(context) {
19
+ const text = context.sourceFile.getFullText();
20
+ if (text.charCodeAt(0) !== 0xfeff) {
21
+ return {};
22
+ }
23
+ context.report({
24
+ message: "noBOM",
25
+ range: {
26
+ begin: 0,
27
+ end: 1,
28
+ },
29
+ suggestions: [
30
+ {
31
+ id: "removeBOM",
32
+ range: {
33
+ begin: 0,
34
+ end: 1,
35
+ },
36
+ text: "",
37
+ },
38
+ ],
39
+ });
40
+ },
41
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,65 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./unicodeBOMs.js";
3
+ ruleTester.describe(rule, {
4
+ invalid: [
5
+ {
6
+ code: `\uFEFFconst value = 1;
7
+ `,
8
+ snapshot: `\uFEFFconst value = 1;
9
+ ~
10
+ This Unicode Byte Order Mark (BOM) is unnecessary and can cause issues with some tools.
11
+ `,
12
+ suggestions: [
13
+ {
14
+ id: "removeBOM",
15
+ updated: `const value = 1;
16
+ `,
17
+ },
18
+ ],
19
+ },
20
+ {
21
+ code: `\uFEFF// Comment
22
+ const value = 1;
23
+ `,
24
+ snapshot: `\uFEFF// Comment
25
+ ~
26
+ This Unicode Byte Order Mark (BOM) is unnecessary and can cause issues with some tools.
27
+ const value = 1;
28
+ `,
29
+ suggestions: [
30
+ {
31
+ id: "removeBOM",
32
+ updated: `// Comment
33
+ const value = 1;
34
+ `,
35
+ },
36
+ ],
37
+ },
38
+ {
39
+ code: `\uFEFF
40
+ const value = 1;
41
+ `,
42
+ snapshot: `\uFEFF
43
+ ~
44
+ This Unicode Byte Order Mark (BOM) is unnecessary and can cause issues with some tools.
45
+ const value = 1;
46
+ `,
47
+ suggestions: [
48
+ {
49
+ id: "removeBOM",
50
+ updated: `
51
+ const value = 1;
52
+ `,
53
+ },
54
+ ],
55
+ },
56
+ ],
57
+ valid: [
58
+ `const value = 1;`,
59
+ `// Comment at the start
60
+ const value = 1;`,
61
+ `
62
+ const value = 1;`,
63
+ `function test() { return 42; }`,
64
+ ],
65
+ });
@@ -0,0 +1,6 @@
1
+ declare const _default: import("@flint.fyi/core").Rule<{
2
+ readonly description: "Reports catch clauses that only rethrow the caught error without modification.";
3
+ readonly id: "unnecessaryCatches";
4
+ readonly preset: "logical";
5
+ }, import("../nodes.js").TSNodesByName, import("../language.js").TypeScriptServices, "unnecessaryCatch", undefined>;
6
+ export default _default;
@@ -0,0 +1,68 @@
1
+ import * as ts from "typescript";
2
+ import { typescriptLanguage } from "../language.js";
3
+ export default typescriptLanguage.createRule({
4
+ about: {
5
+ description: "Reports catch clauses that only rethrow the caught error without modification.",
6
+ id: "unnecessaryCatches",
7
+ preset: "logical",
8
+ },
9
+ messages: {
10
+ unnecessaryCatch: {
11
+ primary: "This catch clause is unnecessary, as it only rethrows the exception without modification.",
12
+ secondary: [
13
+ "A catch clause that only rethrows the caught error adds no value and creates unnecessary code complexity.",
14
+ "Removing such catch clauses allows errors to propagate naturally without the overhead of an unnecessary try-catch block.",
15
+ ],
16
+ suggestions: [
17
+ "Remove the try-catch block if the catch clause only rethrows the error, or add meaningful error handling logic to the catch clause.",
18
+ ],
19
+ },
20
+ },
21
+ setup(context) {
22
+ return {
23
+ visitors: {
24
+ CatchClause: (node) => {
25
+ if (!node.variableDeclaration || !ts.isBlock(node.block)) {
26
+ return;
27
+ }
28
+ const statements = node.block.statements;
29
+ if (statements.length !== 1) {
30
+ return;
31
+ }
32
+ const statement = statements[0];
33
+ if (!ts.isThrowStatement(statement)) {
34
+ return;
35
+ }
36
+ const catchVariable = node.variableDeclaration.name;
37
+ const thrownExpression = statement.expression;
38
+ if (!ts.isIdentifier(catchVariable) ||
39
+ !ts.isIdentifier(thrownExpression)) {
40
+ return;
41
+ }
42
+ if (catchVariable.text !== thrownExpression.text) {
43
+ return;
44
+ }
45
+ const tryStatement = node.parent;
46
+ if (!ts.isTryStatement(tryStatement)) {
47
+ return;
48
+ }
49
+ const range = {
50
+ begin: node.getStart(context.sourceFile),
51
+ end: node.getStart(context.sourceFile) + "catch".length,
52
+ };
53
+ context.report({
54
+ fix: {
55
+ range: {
56
+ begin: tryStatement.tryBlock.getEnd(),
57
+ end: node.getEnd(),
58
+ },
59
+ text: "",
60
+ },
61
+ message: "unnecessaryCatch",
62
+ range,
63
+ });
64
+ },
65
+ },
66
+ };
67
+ },
68
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,210 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./unnecessaryCatches.js";
3
+ ruleTester.describe(rule, {
4
+ invalid: [
5
+ {
6
+ code: `
7
+ try {
8
+ doSomething();
9
+ } catch (error) {
10
+ throw error;
11
+ }
12
+ `,
13
+ output: `
14
+ try {
15
+ doSomething();
16
+ }
17
+ `,
18
+ snapshot: `
19
+ try {
20
+ doSomething();
21
+ } catch (error) {
22
+ ~~~~~
23
+ This catch clause is unnecessary, as it only rethrows the exception without modification.
24
+ throw error;
25
+ }
26
+ `,
27
+ },
28
+ {
29
+ code: `
30
+ async function fetchData() {
31
+ try {
32
+ return await fetch("/api/data");
33
+ } catch (error) {
34
+ throw error;
35
+ }
36
+ }
37
+ `,
38
+ output: `
39
+ async function fetchData() {
40
+ try {
41
+ return await fetch("/api/data");
42
+ }
43
+ }
44
+ `,
45
+ snapshot: `
46
+ async function fetchData() {
47
+ try {
48
+ return await fetch("/api/data");
49
+ } catch (error) {
50
+ ~~~~~
51
+ This catch clause is unnecessary, as it only rethrows the exception without modification.
52
+ throw error;
53
+ }
54
+ }
55
+ `,
56
+ },
57
+ {
58
+ code: `
59
+ try {
60
+ processData();
61
+ } catch (exception) {
62
+ throw exception;
63
+ }
64
+ `,
65
+ output: `
66
+ try {
67
+ processData();
68
+ }
69
+ `,
70
+ snapshot: `
71
+ try {
72
+ processData();
73
+ } catch (exception) {
74
+ ~~~~~
75
+ This catch clause is unnecessary, as it only rethrows the exception without modification.
76
+ throw exception;
77
+ }
78
+ `,
79
+ },
80
+ {
81
+ code: `
82
+ function handleRequest() {
83
+ try {
84
+ const result = performOperation();
85
+ return result;
86
+ } catch (err) {
87
+ throw err;
88
+ }
89
+ }
90
+ `,
91
+ output: `
92
+ function handleRequest() {
93
+ try {
94
+ const result = performOperation();
95
+ return result;
96
+ }
97
+ }
98
+ `,
99
+ snapshot: `
100
+ function handleRequest() {
101
+ try {
102
+ const result = performOperation();
103
+ return result;
104
+ } catch (err) {
105
+ ~~~~~
106
+ This catch clause is unnecessary, as it only rethrows the exception without modification.
107
+ throw err;
108
+ }
109
+ }
110
+ `,
111
+ },
112
+ {
113
+ code: `
114
+ try {
115
+ doSomething();
116
+ } catch (error) {
117
+ throw error;
118
+ } finally {
119
+ cleanup();
120
+ }
121
+ `,
122
+ output: `
123
+ try {
124
+ doSomething();
125
+ } finally {
126
+ cleanup();
127
+ }
128
+ `,
129
+ snapshot: `
130
+ try {
131
+ doSomething();
132
+ } catch (error) {
133
+ ~~~~~
134
+ This catch clause is unnecessary, as it only rethrows the exception without modification.
135
+ throw error;
136
+ } finally {
137
+ cleanup();
138
+ }
139
+ `,
140
+ },
141
+ ],
142
+ valid: [
143
+ `try { doSomething(); } catch (error) { console.error(error); throw error; }`,
144
+ `try { doSomething(); } catch (error) { throw new Error("Failed"); }`,
145
+ `try { doSomething(); } catch (error) { logError(error); throw error; }`,
146
+ `try { doSomething(); } catch { throw new Error("Something went wrong"); }`,
147
+ `
148
+ try {
149
+ doSomething();
150
+ } catch (error) {
151
+ console.error("An error occurred:", error);
152
+ throw error;
153
+ }
154
+ `,
155
+ `
156
+ try {
157
+ doSomething();
158
+ } catch (error) {
159
+ throw new Error("Operation failed: " + error.message);
160
+ }
161
+ `,
162
+ `
163
+ try {
164
+ doSomething();
165
+ } catch (error) {
166
+ cleanup();
167
+ throw error;
168
+ }
169
+ `,
170
+ `
171
+ try {
172
+ doSomething();
173
+ } catch (error) {
174
+ throw error.originalError;
175
+ }
176
+ `,
177
+ `
178
+ async function fetchData() {
179
+ try {
180
+ return await fetch("/api/data");
181
+ } catch (error) {
182
+ await logError(error);
183
+ throw error;
184
+ }
185
+ }
186
+ `,
187
+ `
188
+ try {
189
+ doSomething();
190
+ } catch ({ message }) {
191
+ throw message;
192
+ }
193
+ `,
194
+ `
195
+ try {
196
+ doSomething();
197
+ } catch (error) {
198
+ }
199
+ `,
200
+ `
201
+ try {
202
+ doSomething();
203
+ } catch (error) {
204
+ console.log("error");
205
+ cleanup();
206
+ throw error;
207
+ }
208
+ `,
209
+ ],
210
+ });
@@ -0,0 +1,6 @@
1
+ declare const _default: import("@flint.fyi/core").Rule<{
2
+ readonly description: "Reports negating the left operand of `in` or `instanceof` relations.";
3
+ readonly id: "unsafeNegations";
4
+ readonly preset: "untyped";
5
+ }, import("../nodes.js").TSNodesByName, import("../language.js").TypeScriptServices, "preferNegatingRelation", undefined>;
6
+ export default _default;
@@ -0,0 +1,50 @@
1
+ import * as ts from "typescript";
2
+ import { typescriptLanguage } from "../language.js";
3
+ import { unwrapParenthesizedExpression } from "../utils/unwrapParenthesizedExpression.js";
4
+ const operatorStrings = new Map([
5
+ [ts.SyntaxKind.InKeyword, "in"],
6
+ [ts.SyntaxKind.InstanceOfKeyword, "instanceof"],
7
+ ]);
8
+ export default typescriptLanguage.createRule({
9
+ about: {
10
+ description: "Reports negating the left operand of `in` or `instanceof` relations.",
11
+ id: "unsafeNegations",
12
+ preset: "untyped",
13
+ },
14
+ messages: {
15
+ preferNegatingRelation: {
16
+ primary: "This negation applies before the `{{ operator }}` operator.",
17
+ secondary: [
18
+ "The logical not operator (!) has higher precedence than `in` and `instanceof`.",
19
+ "Write `!(left in right)` or `!(left instanceof Right)` to negate the relation as intended.",
20
+ ],
21
+ suggestions: ["Wrap the relation in parentheses and negate it."],
22
+ },
23
+ },
24
+ setup(context) {
25
+ return {
26
+ visitors: {
27
+ BinaryExpression: (node) => {
28
+ const operator = operatorStrings.get(node.operatorToken.kind);
29
+ if (!operator) {
30
+ return;
31
+ }
32
+ const left = unwrapParenthesizedExpression(node.left);
33
+ if (!ts.isPrefixUnaryExpression(left) ||
34
+ left.operator !== ts.SyntaxKind.ExclamationToken) {
35
+ return;
36
+ }
37
+ const begin = left.getStart(context.sourceFile);
38
+ context.report({
39
+ data: { operator },
40
+ message: "preferNegatingRelation",
41
+ range: {
42
+ begin,
43
+ end: begin + 1,
44
+ },
45
+ });
46
+ },
47
+ },
48
+ };
49
+ },
50
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,63 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./unsafeNegations.js";
3
+ ruleTester.describe(rule, {
4
+ invalid: [
5
+ {
6
+ code: `
7
+ !key in object;
8
+ `,
9
+ snapshot: `
10
+ !key in object;
11
+ ~
12
+ This negation applies before the \`in\` operator.
13
+ `,
14
+ },
15
+ {
16
+ code: `
17
+ !object instanceof Constructor;
18
+ `,
19
+ snapshot: `
20
+ !object instanceof Constructor;
21
+ ~
22
+ This negation applies before the \`instanceof\` operator.
23
+ `,
24
+ },
25
+ {
26
+ code: `
27
+ (!key) in object;
28
+ `,
29
+ snapshot: `
30
+ (!key) in object;
31
+ ~
32
+ This negation applies before the \`in\` operator.
33
+ `,
34
+ },
35
+ {
36
+ code: `
37
+ (!object) instanceof Constructor;
38
+ `,
39
+ snapshot: `
40
+ (!object) instanceof Constructor;
41
+ ~
42
+ This negation applies before the \`instanceof\` operator.
43
+ `,
44
+ },
45
+ {
46
+ code: `
47
+ const exists = !key in object;
48
+ `,
49
+ snapshot: `
50
+ const exists = !key in object;
51
+ ~
52
+ This negation applies before the \`in\` operator.
53
+ `,
54
+ },
55
+ ],
56
+ valid: [
57
+ `!(key in object);`,
58
+ `!(object instanceof Constructor);`,
59
+ `key in object;`,
60
+ `object instanceof Constructor;`,
61
+ `!flag && key in object;`,
62
+ ],
63
+ });
@@ -0,0 +1,6 @@
1
+ declare const _default: import("@flint.fyi/core").Rule<{
2
+ readonly description: "Reports attempting to delete variables with the delete operator.";
3
+ readonly id: "variableDeletions";
4
+ readonly preset: "untyped";
5
+ }, import("../nodes.js").TSNodesByName, import("../language.js").TypeScriptServices, "noDeleteVar", undefined>;
6
+ export default _default;