@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,186 @@
1
+ import rule from "./returnAssignments.js";
2
+ import { ruleTester } from "./ruleTester.js";
3
+
4
+ ruleTester.describe(rule, {
5
+ invalid: [
6
+ {
7
+ code: `
8
+ function getValue() {
9
+ let value;
10
+ return value = 1;
11
+ }
12
+ `,
13
+ snapshot: `
14
+ function getValue() {
15
+ let value;
16
+ return value = 1;
17
+ ~
18
+ Placing an assignment inside a return statement can be misleading and is often a sign of a logical mistake.
19
+ }
20
+ `,
21
+ },
22
+ {
23
+ code: `
24
+ function process() {
25
+ let result;
26
+ return result = calculate();
27
+ }
28
+ `,
29
+ snapshot: `
30
+ function process() {
31
+ let result;
32
+ return result = calculate();
33
+ ~
34
+ Placing an assignment inside a return statement can be misleading and is often a sign of a logical mistake.
35
+ }
36
+ `,
37
+ },
38
+ {
39
+ code: `
40
+ function update() {
41
+ let status;
42
+ return (status = "updated");
43
+ }
44
+ `,
45
+ snapshot: `
46
+ function update() {
47
+ let status;
48
+ return (status = "updated");
49
+ ~
50
+ Placing an assignment inside a return statement can be misleading and is often a sign of a logical mistake.
51
+ }
52
+ `,
53
+ },
54
+ {
55
+ code: `
56
+ const arrow = () => {
57
+ let value;
58
+ return value = 42;
59
+ };
60
+ `,
61
+ snapshot: `
62
+ const arrow = () => {
63
+ let value;
64
+ return value = 42;
65
+ ~
66
+ Placing an assignment inside a return statement can be misleading and is often a sign of a logical mistake.
67
+ };
68
+ `,
69
+ },
70
+ {
71
+ code: `
72
+ const arrowImplicit = () => (value = 100);
73
+ `,
74
+ snapshot: `
75
+ const arrowImplicit = () => (value = 100);
76
+ ~
77
+ Placing an assignment inside a return statement can be misleading and is often a sign of a logical mistake.
78
+ `,
79
+ },
80
+ {
81
+ code: `
82
+ function multiply(factor: number) {
83
+ let result;
84
+ return result = factor * 2;
85
+ }
86
+ `,
87
+ snapshot: `
88
+ function multiply(factor: number) {
89
+ let result;
90
+ return result = factor * 2;
91
+ ~
92
+ Placing an assignment inside a return statement can be misleading and is often a sign of a logical mistake.
93
+ }
94
+ `,
95
+ },
96
+ {
97
+ code: `
98
+ function compound() {
99
+ let count;
100
+ return count += 5;
101
+ }
102
+ `,
103
+ snapshot: `
104
+ function compound() {
105
+ let count;
106
+ return count += 5;
107
+ ~~
108
+ Placing an assignment inside a return statement can be misleading and is often a sign of a logical mistake.
109
+ }
110
+ `,
111
+ },
112
+ {
113
+ code: `
114
+ function bitwise() {
115
+ let flags;
116
+ return flags |= 0x01;
117
+ }
118
+ `,
119
+ snapshot: `
120
+ function bitwise() {
121
+ let flags;
122
+ return flags |= 0x01;
123
+ ~~
124
+ Placing an assignment inside a return statement can be misleading and is often a sign of a logical mistake.
125
+ }
126
+ `,
127
+ },
128
+ ],
129
+ valid: [
130
+ `function getValue() { return 1; }`,
131
+ `function getValue() { let value = 1; return value; }`,
132
+ `function process() { const result = calculate(); return result; }`,
133
+ `const arrow = () => { let value = 42; return value; };`,
134
+ `const arrowImplicit = () => getValue();`,
135
+ `
136
+ function update() {
137
+ let status = "updated";
138
+ return status;
139
+ }
140
+ `,
141
+ `
142
+ function multiply(factor: number) {
143
+ let result = factor * 2;
144
+ return result;
145
+ }
146
+ `,
147
+ `
148
+ function compound() {
149
+ let count = 0;
150
+ count += 5;
151
+ return count;
152
+ }
153
+ `,
154
+ `
155
+ function calculate() {
156
+ const value = 10;
157
+ return value;
158
+ }
159
+ `,
160
+ `
161
+ const process = (input: number) => {
162
+ const result = input * 2;
163
+ return result;
164
+ };
165
+ `,
166
+ `
167
+ class MyClass {
168
+ method() {
169
+ const value = 42;
170
+ return value;
171
+ }
172
+ }
173
+ `,
174
+ `
175
+ function compare(a: number, b: number) {
176
+ return a === b;
177
+ }
178
+ `,
179
+ `
180
+ function arrowReturn() {
181
+ const fn = () => 42;
182
+ return fn;
183
+ }
184
+ `,
185
+ ],
186
+ });
@@ -0,0 +1,57 @@
1
+ import * as tsutils from "ts-api-utils";
2
+ import * as ts from "typescript";
3
+
4
+ import { getTSNodeRange } from "../getTSNodeRange.js";
5
+ import { typescriptLanguage } from "../language.js";
6
+ import { unwrapParenthesizedExpression } from "../utils/unwrapParenthesizedExpression.js";
7
+
8
+ export default typescriptLanguage.createRule({
9
+ about: {
10
+ description: "Reports using assignment expressions in return statements.",
11
+ id: "returnAssignments",
12
+ preset: "stylistic",
13
+ },
14
+ messages: {
15
+ noReturnAssign: {
16
+ primary:
17
+ "Placing an assignment inside a return statement can be misleading and is often a sign of a logical mistake.",
18
+ secondary: [
19
+ "Using assignments in return statements can make code harder to read and can lead to confusion about whether the assignment or the returned value is the primary intent.",
20
+ "Assignment expressions return the assigned value, but mixing assignment with return makes the control flow less clear.",
21
+ ],
22
+ suggestions: [
23
+ "Perform the assignment on a separate line before the return statement.",
24
+ ],
25
+ },
26
+ },
27
+ setup(context) {
28
+ function checkForAssignment(node: ts.Expression): void {
29
+ const unwrapped = unwrapParenthesizedExpression(node);
30
+
31
+ if (
32
+ ts.isBinaryExpression(unwrapped) &&
33
+ tsutils.isAssignmentKind(unwrapped.operatorToken.kind)
34
+ ) {
35
+ context.report({
36
+ message: "noReturnAssign",
37
+ range: getTSNodeRange(unwrapped.operatorToken, context.sourceFile),
38
+ });
39
+ }
40
+ }
41
+
42
+ return {
43
+ visitors: {
44
+ ArrowFunction: (node) => {
45
+ if (!ts.isBlock(node.body)) {
46
+ checkForAssignment(node.body);
47
+ }
48
+ },
49
+ ReturnStatement: (node) => {
50
+ if (node.expression) {
51
+ checkForAssignment(node.expression);
52
+ }
53
+ },
54
+ },
55
+ };
56
+ },
57
+ });
@@ -0,0 +1,111 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./sparseArrays.js";
3
+
4
+ ruleTester.describe(rule, {
5
+ invalid: [
6
+ {
7
+ code: `
8
+ const array = [1, , 3];
9
+ `,
10
+ snapshot: `
11
+ const array = [1, , 3];
12
+ ~
13
+ Sparse arrays with "holes" (empty slots) are misleading and behave differently from \`undefined\` values.
14
+ `,
15
+ },
16
+ {
17
+ code: `
18
+ const array = [, 2, 3];
19
+ `,
20
+ snapshot: `
21
+ const array = [, 2, 3];
22
+ ~
23
+ Sparse arrays with "holes" (empty slots) are misleading and behave differently from \`undefined\` values.
24
+ `,
25
+ },
26
+ {
27
+ code: `
28
+ const array = [1, , , 4];
29
+ `,
30
+ snapshot: `
31
+ const array = [1, , , 4];
32
+ ~
33
+ Sparse arrays with "holes" (empty slots) are misleading and behave differently from \`undefined\` values.
34
+ ~
35
+ Sparse arrays with "holes" (empty slots) are misleading and behave differently from \`undefined\` values.
36
+ `,
37
+ },
38
+ {
39
+ code: `
40
+ const nested = [[1, , 3], [4, 5, 6]];
41
+ `,
42
+ snapshot: `
43
+ const nested = [[1, , 3], [4, 5, 6]];
44
+ ~
45
+ Sparse arrays with "holes" (empty slots) are misleading and behave differently from \`undefined\` values.
46
+ `,
47
+ },
48
+ {
49
+ code: `
50
+ const result = [
51
+ 1,
52
+ ,
53
+ 3
54
+ ];
55
+ `,
56
+ snapshot: `
57
+ const result = [
58
+ 1,
59
+ ,
60
+ ~
61
+ Sparse arrays with "holes" (empty slots) are misleading and behave differently from \`undefined\` values.
62
+ 3
63
+ ];
64
+ `,
65
+ },
66
+ {
67
+ code: `
68
+ const matrix = [
69
+ [1, 2, 3],
70
+ [4, , 6],
71
+ [7, 8, 9]
72
+ ];
73
+ `,
74
+ snapshot: `
75
+ const matrix = [
76
+ [1, 2, 3],
77
+ [4, , 6],
78
+ ~
79
+ Sparse arrays with "holes" (empty slots) are misleading and behave differently from \`undefined\` values.
80
+ [7, 8, 9]
81
+ ];
82
+ `,
83
+ },
84
+ {
85
+ code: `
86
+ function getArray() {
87
+ return [1, , 3];
88
+ }
89
+ `,
90
+ snapshot: `
91
+ function getArray() {
92
+ return [1, , 3];
93
+ ~
94
+ Sparse arrays with "holes" (empty slots) are misleading and behave differently from \`undefined\` values.
95
+ }
96
+ `,
97
+ },
98
+ ],
99
+ valid: [
100
+ `const array = [1, 2, 3];`,
101
+ `const array = [];`,
102
+ `const array = [1];`,
103
+ `const array = [1, undefined, 3];`,
104
+ `const array = [undefined, 2, 3];`,
105
+ `const array = [1, 2, undefined];`,
106
+ `const array = [1, 2, 3,];`,
107
+ `const nested = [[1, undefined, 3], [4, 5, 6]];`,
108
+ `const matrix = [[1, 2, 3], [4, undefined, 6], [7, 8, 9]];`,
109
+ `const values = [null, undefined, 0, false, ""];`,
110
+ ],
111
+ });
@@ -0,0 +1,61 @@
1
+ import * as ts from "typescript";
2
+
3
+ import { typescriptLanguage } from "../language.js";
4
+
5
+ export default typescriptLanguage.createRule({
6
+ about: {
7
+ description: "Reports array literals with holes (sparse arrays).",
8
+ id: "sparseArrays",
9
+ preset: "logical",
10
+ },
11
+ messages: {
12
+ noSparseArray: {
13
+ primary:
14
+ 'Sparse arrays with "holes" (empty slots) are misleading and behave differently from `undefined` values.',
15
+ secondary: [
16
+ "Array methods treat holes inconsistently, which can lead to unexpected behavior and bugs.",
17
+ "Using explicit `undefined` values makes the intent clear and ensures consistent behavior.",
18
+ ],
19
+ suggestions: [
20
+ "Replace holes with explicit `undefined` values.",
21
+ "Remove unintended commas if the holes are accidental.",
22
+ ],
23
+ },
24
+ },
25
+ setup(context) {
26
+ return {
27
+ visitors: {
28
+ OmittedExpression: (node) => {
29
+ const parent = node.parent;
30
+ if (!ts.isArrayLiteralExpression(parent)) {
31
+ return;
32
+ }
33
+
34
+ const syntaxList = parent
35
+ .getChildren(context.sourceFile)
36
+ .find((child) => child.kind === ts.SyntaxKind.SyntaxList);
37
+
38
+ if (!syntaxList) {
39
+ return;
40
+ }
41
+
42
+ const children = syntaxList.getChildren(context.sourceFile);
43
+ const omittedIndex = children.indexOf(node);
44
+
45
+ for (let i = omittedIndex + 1; i < children.length; i++) {
46
+ if (children[i].kind === ts.SyntaxKind.CommaToken) {
47
+ context.report({
48
+ message: "noSparseArray",
49
+ range: {
50
+ begin: children[i].getStart(context.sourceFile),
51
+ end: children[i].getEnd(),
52
+ },
53
+ });
54
+ break;
55
+ }
56
+ }
57
+ },
58
+ },
59
+ };
60
+ },
61
+ });
@@ -0,0 +1,90 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./symbolDescriptions.js";
3
+
4
+ ruleTester.describe(rule, {
5
+ invalid: [
6
+ {
7
+ code: `
8
+ const symbol = Symbol();
9
+ `,
10
+ snapshot: `
11
+ const symbol = Symbol();
12
+ ~~~~~~~~
13
+ Symbols without descriptions are more difficult to debug or reason about.
14
+ `,
15
+ },
16
+ {
17
+ code: `
18
+ const uniqueKey = Symbol();
19
+ `,
20
+ snapshot: `
21
+ const uniqueKey = Symbol();
22
+ ~~~~~~~~
23
+ Symbols without descriptions are more difficult to debug or reason about.
24
+ `,
25
+ },
26
+ {
27
+ code: `
28
+ const symbols = [Symbol(), Symbol()];
29
+ `,
30
+ snapshot: `
31
+ const symbols = [Symbol(), Symbol()];
32
+ ~~~~~~~~
33
+ Symbols without descriptions are more difficult to debug or reason about.
34
+ ~~~~~~~~
35
+ Symbols without descriptions are more difficult to debug or reason about.
36
+ `,
37
+ },
38
+ {
39
+ code: `
40
+ function createSymbol() {
41
+ return Symbol();
42
+ }
43
+ `,
44
+ snapshot: `
45
+ function createSymbol() {
46
+ return Symbol();
47
+ ~~~~~~~~
48
+ Symbols without descriptions are more difficult to debug or reason about.
49
+ }
50
+ `,
51
+ },
52
+ {
53
+ code: `
54
+ const obj = {
55
+ key: Symbol(),
56
+ };
57
+ `,
58
+ snapshot: `
59
+ const obj = {
60
+ key: Symbol(),
61
+ ~~~~~~~~
62
+ Symbols without descriptions are more difficult to debug or reason about.
63
+ };
64
+ `,
65
+ },
66
+ {
67
+ code: `
68
+ const value = condition ? Symbol() : null;
69
+ `,
70
+ snapshot: `
71
+ const value = condition ? Symbol() : null;
72
+ ~~~~~~~~
73
+ Symbols without descriptions are more difficult to debug or reason about.
74
+ `,
75
+ },
76
+ ],
77
+ valid: [
78
+ `const symbol = Symbol("description");`,
79
+ `const uniqueKey = Symbol("uniqueKey");`,
80
+ `const mySymbol = Symbol("my symbol");`,
81
+ `const symbols = [Symbol("first"), Symbol("second")];`,
82
+ `function createSymbol() { return Symbol("created"); }`,
83
+ `const obj = { key: Symbol("key") };`,
84
+ `const value = Symbol.for("global");`,
85
+ `const iterator = Symbol.iterator;`,
86
+ `const hasInstance = Symbol.hasInstance;`,
87
+ `const primitiveValue = Symbol.toPrimitive;`,
88
+ `Symbol("valid")`,
89
+ ],
90
+ });
@@ -0,0 +1,47 @@
1
+ import * as ts from "typescript";
2
+
3
+ import { typescriptLanguage } from "../language.js";
4
+
5
+ export default typescriptLanguage.createRule({
6
+ about: {
7
+ description: "Reports Symbol() calls without description arguments.",
8
+ id: "symbolDescriptions",
9
+ preset: "stylistic",
10
+ },
11
+ messages: {
12
+ missingDescription: {
13
+ primary:
14
+ "Symbols without descriptions are more difficult to debug or reason about.",
15
+ secondary: [
16
+ "Creating a symbol without a description makes debugging difficult, as the symbol's purpose isn't clear when inspecting it.",
17
+ "While the description doesn't affect the symbol's uniqueness, it appears in the symbol's string representation and can be accessed via `Symbol.prototype.description`.",
18
+ ],
19
+ suggestions: [
20
+ "Add a descriptive string argument to the Symbol constructor that explains the symbol's purpose.",
21
+ ],
22
+ },
23
+ },
24
+ setup(context) {
25
+ return {
26
+ visitors: {
27
+ CallExpression: (node) => {
28
+ if (
29
+ !ts.isIdentifier(node.expression) ||
30
+ node.expression.text !== "Symbol" ||
31
+ node.arguments.length
32
+ ) {
33
+ return;
34
+ }
35
+
36
+ context.report({
37
+ message: "missingDescription",
38
+ range: {
39
+ begin: node.getStart(context.sourceFile),
40
+ end: node.getEnd(),
41
+ },
42
+ });
43
+ },
44
+ },
45
+ };
46
+ },
47
+ });
@@ -0,0 +1,73 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./unassignedVariables.js";
3
+
4
+ ruleTester.describe(rule, {
5
+ invalid: [
6
+ {
7
+ code: `
8
+ let value;
9
+ `,
10
+ snapshot: `
11
+ let value;
12
+ ~~~~~
13
+ Variable 'value' is declared but never assigned a value.
14
+ `,
15
+ },
16
+ {
17
+ code: `
18
+ var variable;
19
+ console.log(variable);
20
+ `,
21
+ snapshot: `
22
+ var variable;
23
+ ~~~~~~~~
24
+ Variable 'variable' is declared but never assigned a value.
25
+ console.log(variable);
26
+ `,
27
+ },
28
+ {
29
+ code: `
30
+ let unassigned: number;
31
+ console.log(unassigned);
32
+ `,
33
+ snapshot: `
34
+ let unassigned: number;
35
+ ~~~~~~~~~~
36
+ Variable 'unassigned' is declared but never assigned a value.
37
+ console.log(unassigned);
38
+ `,
39
+ },
40
+ {
41
+ code: `
42
+ function example() {
43
+ let local;
44
+ return local;
45
+ }
46
+ `,
47
+ snapshot: `
48
+ function example() {
49
+ let local;
50
+ ~~~~~
51
+ Variable 'local' is declared but never assigned a value.
52
+ return local;
53
+ }
54
+ `,
55
+ },
56
+ ],
57
+ valid: [
58
+ `let assigned = 5;`,
59
+ `const constant = 10;`,
60
+ `var variable = "hello";`,
61
+ `let value: number = 42;`,
62
+ `let x; x = 5;`,
63
+ `let y; y = 10; console.log(y);`,
64
+ `var z; z += 1;`,
65
+ `let counter; counter++;`,
66
+ `let value; value--;`,
67
+ `for (let index = 0; index < 10; index++) {}`,
68
+ `for (let item; item < 10; item++) {}`,
69
+ `let result; result ||= "default";`,
70
+ `let data; data &&= "value";`,
71
+ `let nullish; nullish ??= "fallback";`,
72
+ ],
73
+ });
@@ -0,0 +1,69 @@
1
+ import * as ts from "typescript";
2
+
3
+ import { typescriptLanguage } from "../language.js";
4
+ import { getModifyingReferences } from "../utils/getModifyingReferences.js";
5
+
6
+ export default typescriptLanguage.createRule({
7
+ about: {
8
+ description:
9
+ "Reports variables that are declared but never assigned a value.",
10
+ id: "unassignedVariables",
11
+ preset: "untyped",
12
+ },
13
+ messages: {
14
+ noUnassigned: {
15
+ primary: "Variable '{{ name }}' is declared but never assigned a value.",
16
+ secondary: [
17
+ "Declaring a variable without ever assigning it a value means it will always be `undefined`.",
18
+ "This is often a mistake, such as forgetting to initialize the variable or assign to it later.",
19
+ ],
20
+ suggestions: [
21
+ "Assign a value to the variable, either at declaration or before it is used.",
22
+ "If the variable is meant to be `undefined`, consider making that explicit for clarity.",
23
+ ],
24
+ },
25
+ },
26
+ setup(context) {
27
+ function hasAssignments(
28
+ identifier: ts.Identifier,
29
+ sourceFile: ts.SourceFile,
30
+ typeChecker: ts.TypeChecker,
31
+ ): boolean {
32
+ // TODO (#400): Switch to scope analysis
33
+ return !!getModifyingReferences(identifier, sourceFile, typeChecker)
34
+ .length;
35
+ }
36
+
37
+ return {
38
+ visitors: {
39
+ VariableDeclaration: (node) => {
40
+ if (node.initializer || !ts.isIdentifier(node.name)) {
41
+ return;
42
+ }
43
+
44
+ if (
45
+ ts.isVariableDeclarationList(node.parent) &&
46
+ !!(node.parent.flags & ts.NodeFlags.Const)
47
+ ) {
48
+ return;
49
+ }
50
+
51
+ if (
52
+ !hasAssignments(node.name, context.sourceFile, context.typeChecker)
53
+ ) {
54
+ context.report({
55
+ data: {
56
+ name: node.name.text,
57
+ },
58
+ message: "noUnassigned",
59
+ range: {
60
+ begin: node.name.getStart(context.sourceFile),
61
+ end: node.name.getEnd(),
62
+ },
63
+ });
64
+ }
65
+ },
66
+ },
67
+ };
68
+ },
69
+ });