@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,13 @@
1
+ import * as ts from "typescript";
2
+ /**
3
+ * Does a simple check to see if there is an any being assigned to a non-any type.
4
+ *
5
+ * This also checks generic positions to ensure there's no unsafe sub-assignments.
6
+ * Note: in the case of generic positions, it makes the assumption that the two types are the same.
7
+ * @example See tests for examples
8
+ * @returns false if it's safe, or an object with the two types if it's unsafe
9
+ */
10
+ export declare function isUnsafeAssignment(type: ts.Type, receiver: ts.Type, checker: ts.TypeChecker, senderNode: null | ts.Node): false | {
11
+ receiver: ts.Type;
12
+ sender: ts.Type;
13
+ };
@@ -0,0 +1,76 @@
1
+ import * as tsutils from "ts-api-utils";
2
+ import * as ts from "typescript";
3
+ /**
4
+ * Does a simple check to see if there is an any being assigned to a non-any type.
5
+ *
6
+ * This also checks generic positions to ensure there's no unsafe sub-assignments.
7
+ * Note: in the case of generic positions, it makes the assumption that the two types are the same.
8
+ * @example See tests for examples
9
+ * @returns false if it's safe, or an object with the two types if it's unsafe
10
+ */
11
+ export function isUnsafeAssignment(type, receiver, checker, senderNode) {
12
+ return isUnsafeAssignmentWorker(type, receiver, checker, senderNode, new Map());
13
+ }
14
+ function isUnsafeAssignmentWorker(type, receiver, checker, senderNode, visited) {
15
+ if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Any)) {
16
+ // Allow assignment of any ==> unknown.
17
+ if (tsutils.isTypeFlagSet(receiver, ts.TypeFlags.Unknown)) {
18
+ return false;
19
+ }
20
+ if (!tsutils.isTypeFlagSet(receiver, ts.TypeFlags.Any)) {
21
+ return { receiver, sender: type };
22
+ }
23
+ }
24
+ const typeAlreadyVisited = visited.get(type);
25
+ if (typeAlreadyVisited) {
26
+ if (typeAlreadyVisited.has(receiver)) {
27
+ return false;
28
+ }
29
+ typeAlreadyVisited.add(receiver);
30
+ }
31
+ else {
32
+ visited.set(type, new Set([receiver]));
33
+ }
34
+ if (tsutils.isTypeReference(type) && tsutils.isTypeReference(receiver)) {
35
+ // TODO - figure out how to handle cases like this,
36
+ // where the types are assignable, but not the same type
37
+ /*
38
+ function foo(): ReadonlySet<number> { return new Set<any>(); }
39
+
40
+ // and
41
+
42
+ type Test<T> = { prop: T }
43
+ type Test2 = { prop: string }
44
+ declare const a: Test<any>;
45
+ const b: Test2 = a;
46
+ */
47
+ if (type.target !== receiver.target) {
48
+ // if the type references are different, assume safe, as we won't know how to compare the two types
49
+ // the generic positions might not be equivalent for both types
50
+ return false;
51
+ }
52
+ if (senderNode != null &&
53
+ ts.isNewExpression(senderNode) &&
54
+ ts.isIdentifier(senderNode.expression) &&
55
+ senderNode.expression.text === "Map" &&
56
+ (senderNode.arguments == null || senderNode.arguments.length === 0) &&
57
+ senderNode.typeArguments == null) {
58
+ // special case to handle `new Map()`
59
+ // unfortunately Map's default empty constructor is typed to return `Map<any, any>` :(
60
+ // https://github.com/typescript-eslint/typescript-eslint/issues/2109#issuecomment-634144396
61
+ return false;
62
+ }
63
+ const typeArguments = type.typeArguments ?? [];
64
+ const receiverTypeArguments = receiver.typeArguments ?? [];
65
+ for (let i = 0; i < typeArguments.length; i += 1) {
66
+ const arg = typeArguments[i];
67
+ const receiverArg = receiverTypeArguments[i];
68
+ const unsafe = isUnsafeAssignmentWorker(arg, receiverArg, checker, senderNode, visited);
69
+ if (unsafe) {
70
+ return { receiver, sender: type };
71
+ }
72
+ }
73
+ return false;
74
+ }
75
+ return false;
76
+ }
@@ -0,0 +1,4 @@
1
+ import * as ts from "typescript";
2
+ export declare function isComparisonOperator(token: ts.BinaryOperatorToken): boolean;
3
+ export declare function isEqualityOperator(token: ts.BinaryOperatorToken): boolean;
4
+ export declare function isNegatedEqualityOperator(token: ts.BinaryOperatorToken): boolean;
@@ -0,0 +1,36 @@
1
+ import * as ts from "typescript";
2
+ export function isComparisonOperator(token) {
3
+ switch (token.kind) {
4
+ case ts.SyntaxKind.EqualsEqualsEqualsToken:
5
+ case ts.SyntaxKind.EqualsEqualsToken:
6
+ case ts.SyntaxKind.ExclamationEqualsEqualsToken:
7
+ case ts.SyntaxKind.ExclamationEqualsToken:
8
+ case ts.SyntaxKind.GreaterThanEqualsToken:
9
+ case ts.SyntaxKind.GreaterThanToken:
10
+ case ts.SyntaxKind.LessThanEqualsToken:
11
+ case ts.SyntaxKind.LessThanToken:
12
+ return true;
13
+ default:
14
+ return false;
15
+ }
16
+ }
17
+ export function isEqualityOperator(token) {
18
+ switch (token.kind) {
19
+ case ts.SyntaxKind.EqualsEqualsEqualsToken:
20
+ case ts.SyntaxKind.EqualsEqualsToken:
21
+ case ts.SyntaxKind.ExclamationEqualsEqualsToken:
22
+ case ts.SyntaxKind.ExclamationEqualsToken:
23
+ return true;
24
+ default:
25
+ return false;
26
+ }
27
+ }
28
+ export function isNegatedEqualityOperator(token) {
29
+ switch (token.kind) {
30
+ case ts.SyntaxKind.ExclamationEqualsEqualsToken:
31
+ case ts.SyntaxKind.ExclamationEqualsToken:
32
+ return true;
33
+ default:
34
+ return false;
35
+ }
36
+ }
@@ -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;
@@ -0,0 +1,39 @@
1
+ import * as ts from "typescript";
2
+ import { typescriptLanguage } from "../language.js";
3
+ export default typescriptLanguage.createRule({
4
+ about: {
5
+ description: "Reports attempting to delete variables with the delete operator.",
6
+ id: "variableDeletions",
7
+ preset: "untyped",
8
+ },
9
+ messages: {
10
+ noDeleteVar: {
11
+ primary: "Deleting a variable with the delete operator outside of strict mode will silently fail and return false.",
12
+ secondary: [
13
+ "The delete operator is only meant to remove properties from objects, not variables.",
14
+ "Attempting to delete a variable in strict mode will cause a syntax error.",
15
+ "In non-strict mode, it will silently fail and return false without actually deleting the variable.",
16
+ ],
17
+ suggestions: [
18
+ "Remove the delete statement, or if you need to unset the value, assign undefined instead.",
19
+ ],
20
+ },
21
+ },
22
+ setup(context) {
23
+ return {
24
+ visitors: {
25
+ DeleteExpression: (node) => {
26
+ if (node.expression.kind === ts.SyntaxKind.Identifier) {
27
+ context.report({
28
+ message: "noDeleteVar",
29
+ range: {
30
+ begin: node.getStart(context.sourceFile),
31
+ end: node.getEnd(),
32
+ },
33
+ });
34
+ }
35
+ },
36
+ },
37
+ };
38
+ },
39
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,75 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./variableDeletions.js";
3
+ ruleTester.describe(rule, {
4
+ invalid: [
5
+ {
6
+ code: `
7
+ delete value;
8
+ `,
9
+ snapshot: `
10
+ delete value;
11
+ ~~~~~~~~~~~~
12
+ Deleting a variable with the delete operator outside of strict mode will silently fail and return false.
13
+ `,
14
+ },
15
+ {
16
+ code: `
17
+ let x = 5;
18
+ delete x;
19
+ `,
20
+ snapshot: `
21
+ let x = 5;
22
+ delete x;
23
+ ~~~~~~~~
24
+ Deleting a variable with the delete operator outside of strict mode will silently fail and return false.
25
+ `,
26
+ },
27
+ {
28
+ code: `
29
+ const variable = 10;
30
+ delete variable;
31
+ `,
32
+ snapshot: `
33
+ const variable = 10;
34
+ delete variable;
35
+ ~~~~~~~~~~~~~~~
36
+ Deleting a variable with the delete operator outside of strict mode will silently fail and return false.
37
+ `,
38
+ },
39
+ {
40
+ code: `
41
+ function test(parameter: number) {
42
+ delete parameter;
43
+ }
44
+ `,
45
+ snapshot: `
46
+ function test(parameter: number) {
47
+ delete parameter;
48
+ ~~~~~~~~~~~~~~~~
49
+ Deleting a variable with the delete operator outside of strict mode will silently fail and return false.
50
+ }
51
+ `,
52
+ },
53
+ {
54
+ code: `
55
+ for (let index = 0; index < 10; index++) {
56
+ delete index;
57
+ }
58
+ `,
59
+ snapshot: `
60
+ for (let index = 0; index < 10; index++) {
61
+ delete index;
62
+ ~~~~~~~~~~~~
63
+ Deleting a variable with the delete operator outside of strict mode will silently fail and return false.
64
+ }
65
+ `,
66
+ },
67
+ ],
68
+ valid: [
69
+ `const obj = { prop: 1 }; delete obj.prop;`,
70
+ `delete obj.property;`,
71
+ `delete obj["property"];`,
72
+ `const obj = { nested: { prop: 1 } }; delete obj.nested.prop;`,
73
+ `const array = [1, 2, 3]; delete array[0];`,
74
+ ],
75
+ });
@@ -0,0 +1,6 @@
1
+ declare const _default: import("@flint.fyi/core").Rule<{
2
+ readonly description: "Reports using the void operator.";
3
+ readonly id: "voidOperator";
4
+ readonly preset: "stylistic";
5
+ }, import("../nodes.js").TSNodesByName, import("../language.js").TypeScriptServices, "noVoid", undefined>;
6
+ export default _default;
@@ -0,0 +1,36 @@
1
+ import { typescriptLanguage } from "../language.js";
2
+ export default typescriptLanguage.createRule({
3
+ about: {
4
+ description: "Reports using the void operator.",
5
+ id: "voidOperator",
6
+ preset: "stylistic",
7
+ },
8
+ messages: {
9
+ noVoid: {
10
+ primary: "Prefer an explicit value over using the void operator to produce undefined.",
11
+ secondary: [
12
+ "The void operator evaluates an expression and returns undefined, regardless of the expression's value.",
13
+ "This is often confusing and can be replaced with more explicit code.",
14
+ "Instead of using void, return or assign undefined directly.",
15
+ ],
16
+ suggestions: [
17
+ "Replace void expressions with undefined or restructure the code to be more explicit.",
18
+ ],
19
+ },
20
+ },
21
+ setup(context) {
22
+ return {
23
+ visitors: {
24
+ VoidExpression: (node) => {
25
+ context.report({
26
+ message: "noVoid",
27
+ range: {
28
+ begin: node.getStart(context.sourceFile),
29
+ end: node.getEnd(),
30
+ },
31
+ });
32
+ },
33
+ },
34
+ };
35
+ },
36
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,98 @@
1
+ import { ruleTester } from "./ruleTester.js";
2
+ import rule from "./voidOperator.js";
3
+ ruleTester.describe(rule, {
4
+ invalid: [
5
+ {
6
+ code: `
7
+ void 0;
8
+ `,
9
+ snapshot: `
10
+ void 0;
11
+ ~~~~~~
12
+ Prefer an explicit value over using the void operator to produce undefined.
13
+ `,
14
+ },
15
+ {
16
+ code: `
17
+ const value = void 0;
18
+ `,
19
+ snapshot: `
20
+ const value = void 0;
21
+ ~~~~~~
22
+ Prefer an explicit value over using the void operator to produce undefined.
23
+ `,
24
+ },
25
+ {
26
+ code: `
27
+ void someFunction();
28
+ `,
29
+ snapshot: `
30
+ void someFunction();
31
+ ~~~~~~~~~~~~~~~~~~~
32
+ Prefer an explicit value over using the void operator to produce undefined.
33
+ `,
34
+ },
35
+ {
36
+ code: `
37
+ return void calculate();
38
+ `,
39
+ snapshot: `
40
+ return void calculate();
41
+ ~~~~~~~~~~~~~~~~
42
+ Prefer an explicit value over using the void operator to produce undefined.
43
+ `,
44
+ },
45
+ {
46
+ code: `
47
+ const result = void (a + b);
48
+ `,
49
+ snapshot: `
50
+ const result = void (a + b);
51
+ ~~~~~~~~~~~~
52
+ Prefer an explicit value over using the void operator to produce undefined.
53
+ `,
54
+ },
55
+ {
56
+ code: `
57
+ void expression, anotherExpression;
58
+ `,
59
+ snapshot: `
60
+ void expression, anotherExpression;
61
+ ~~~~~~~~~~~~~~~
62
+ Prefer an explicit value over using the void operator to produce undefined.
63
+ `,
64
+ },
65
+ {
66
+ code: `
67
+ function process() {
68
+ void doSomething();
69
+ }
70
+ `,
71
+ snapshot: `
72
+ function process() {
73
+ void doSomething();
74
+ ~~~~~~~~~~~~~~~~~~
75
+ Prefer an explicit value over using the void operator to produce undefined.
76
+ }
77
+ `,
78
+ },
79
+ {
80
+ code: `
81
+ const callback = () => void action();
82
+ `,
83
+ snapshot: `
84
+ const callback = () => void action();
85
+ ~~~~~~~~~~~~~
86
+ Prefer an explicit value over using the void operator to produce undefined.
87
+ `,
88
+ },
89
+ ],
90
+ valid: [
91
+ `const value = undefined;`,
92
+ `return undefined;`,
93
+ `someFunction();`,
94
+ `const result = doSomething();`,
95
+ `if (value === undefined) {}`,
96
+ `function returns() { return; }`,
97
+ ],
98
+ });
@@ -0,0 +1,2 @@
1
+ import * as ts from "typescript";
2
+ export declare function declarationIncludesGlobal(declaration: ts.Declaration): boolean;
@@ -0,0 +1,5 @@
1
+ export function declarationIncludesGlobal(declaration) {
2
+ const sourceFile = declaration.getSourceFile();
3
+ return (sourceFile.hasNoDefaultLib ||
4
+ /\/lib\.[^/]*\.d\.ts$/.test(sourceFile.fileName));
5
+ }
@@ -0,0 +1,2 @@
1
+ import * as ts from "typescript";
2
+ export declare function declarationsIncludeGlobal(declarations: ts.Declaration[]): boolean;
@@ -0,0 +1,4 @@
1
+ import { declarationIncludesGlobal } from "./declarationIncludesGlobal.js";
2
+ export function declarationsIncludeGlobal(declarations) {
3
+ return declarations.some(declarationIncludesGlobal);
4
+ }
@@ -0,0 +1,8 @@
1
+ import * as ts from "typescript";
2
+ /**
3
+ * Gets all references to a variable that modify it (assignments, increments, decrements).
4
+ *
5
+ * TODO: Replace with a proper scope manager when available (see #400).
6
+ * @returns An array of identifier nodes that modify the variable.
7
+ */
8
+ export declare function getModifyingReferences(identifier: ts.Identifier, sourceFile: ts.SourceFile, typeChecker: ts.TypeChecker): ts.Identifier[];
@@ -0,0 +1,42 @@
1
+ import * as tsutils from "ts-api-utils";
2
+ import * as ts from "typescript";
3
+ /**
4
+ * Gets all references to a variable that modify it (assignments, increments, decrements).
5
+ *
6
+ * TODO: Replace with a proper scope manager when available (see #400).
7
+ * @returns An array of identifier nodes that modify the variable.
8
+ */
9
+ export function getModifyingReferences(identifier, sourceFile, typeChecker) {
10
+ const symbol = typeChecker.getSymbolAtLocation(identifier);
11
+ if (!symbol?.valueDeclaration) {
12
+ return [];
13
+ }
14
+ const valueDeclaration = symbol.valueDeclaration;
15
+ const modifyingReferences = [];
16
+ function visit(node) {
17
+ // Check if this is an identifier that refers to the same symbol
18
+ if (ts.isIdentifier(node)) {
19
+ const nodeSymbol = typeChecker.getSymbolAtLocation(node);
20
+ if (nodeSymbol?.valueDeclaration &&
21
+ nodeSymbol.valueDeclaration === valueDeclaration) {
22
+ // Check if this identifier is being modified
23
+ const parent = node.parent;
24
+ // Assignment expressions (=, +=, -=, etc.)
25
+ if (ts.isBinaryExpression(parent) &&
26
+ tsutils.isAssignmentKind(parent.operatorToken.kind) &&
27
+ parent.left === node) {
28
+ modifyingReferences.push(node);
29
+ }
30
+ // Unary expressions (++, --)
31
+ else if ((ts.isPostfixUnaryExpression(parent) ||
32
+ ts.isPrefixUnaryExpression(parent)) &&
33
+ parent.operand === node) {
34
+ modifyingReferences.push(node);
35
+ }
36
+ }
37
+ }
38
+ ts.forEachChild(node, visit);
39
+ }
40
+ visit(sourceFile);
41
+ return modifyingReferences;
42
+ }
@@ -0,0 +1,2 @@
1
+ import * as ts from "typescript";
2
+ export declare function hasSameTokens(nodeA: ts.Node, nodeB: ts.Node, sourceFile: ts.SourceFile): boolean;
@@ -0,0 +1,30 @@
1
+ import * as ts from "typescript";
2
+ export function hasSameTokens(nodeA, nodeB, sourceFile) {
3
+ const queueA = [nodeA];
4
+ const queueB = [nodeB];
5
+ while (true) {
6
+ const currentA = queueA.shift();
7
+ const currentB = queueB.shift();
8
+ if (!currentA || !currentB) {
9
+ break;
10
+ }
11
+ if (currentA.kind !== currentB.kind) {
12
+ return false;
13
+ }
14
+ if (currentA.kind >= ts.SyntaxKind.FirstToken &&
15
+ currentA.kind <= ts.SyntaxKind.LastToken) {
16
+ if (currentA.getText(sourceFile) !== currentB.getText(sourceFile)) {
17
+ return false;
18
+ }
19
+ continue;
20
+ }
21
+ const childrenA = currentA.getChildren(sourceFile);
22
+ const childrenB = currentB.getChildren(sourceFile);
23
+ if (childrenA.length !== childrenB.length) {
24
+ return false;
25
+ }
26
+ queueA.push(...childrenA);
27
+ queueB.push(...childrenB);
28
+ }
29
+ return queueA.length === queueB.length;
30
+ }
@@ -0,0 +1,2 @@
1
+ import * as ts from "typescript";
2
+ export declare function isGlobalDeclaration(node: ts.Expression, typeChecker: ts.TypeChecker): boolean;
@@ -0,0 +1,5 @@
1
+ import { declarationsIncludeGlobal } from "./declarationsIncludeGlobal.js";
2
+ export function isGlobalDeclaration(node, typeChecker) {
3
+ const declarations = typeChecker.getSymbolAtLocation(node)?.getDeclarations();
4
+ return !!declarations && declarationsIncludeGlobal(declarations);
5
+ }
@@ -0,0 +1,5 @@
1
+ import * as ts from "typescript";
2
+ /**
3
+ * TODO: Use a scope analyzer (#400).
4
+ */
5
+ export declare function isGlobalDeclarationOfName(node: ts.Expression, name: string, typeChecker: ts.TypeChecker): boolean;
@@ -0,0 +1,31 @@
1
+ import * as ts from "typescript";
2
+ import { declarationIncludesGlobal } from "./declarationIncludesGlobal.js";
3
+ /**
4
+ * TODO: Use a scope analyzer (#400).
5
+ */
6
+ export function isGlobalDeclarationOfName(node, name, typeChecker) {
7
+ const declarations = typeChecker.getSymbolAtLocation(node)?.getDeclarations();
8
+ if (!declarations) {
9
+ return false;
10
+ }
11
+ return declarations.every((declaration) => {
12
+ // Special case: a variable set to a known identifier. E.g.:
13
+ // const CustomFunction = Function;
14
+ if (ts.isVariableDeclaration(declaration) &&
15
+ declaration.initializer &&
16
+ declaration.initializer.kind === ts.SyntaxKind.Identifier) {
17
+ return isGlobalDeclarationOfName(declaration.initializer, name, typeChecker);
18
+ }
19
+ return (isDeclarationOfName(declaration, name) &&
20
+ declarationIncludesGlobal(declaration));
21
+ });
22
+ }
23
+ function isDeclarationOfName(node, name) {
24
+ if (ts.isClassDeclaration(node) ||
25
+ ts.isFunctionDeclaration(node) ||
26
+ ts.isInterfaceDeclaration(node) ||
27
+ ts.isVariableDeclaration(node)) {
28
+ return node.name && ts.isIdentifier(node.name) && node.name.text === name;
29
+ }
30
+ return false;
31
+ }
@@ -0,0 +1,8 @@
1
+ import * as ts from "typescript";
2
+ /**
3
+ * Checks if a node is a reference to a global variable (e.g., Object, undefined, NaN).
4
+ * Global variables are those declared in TypeScript's lib files or are global identifiers
5
+ * like undefined which have symbols but no user-defined declarations.
6
+ * TODO: Use a scope manager (#400).
7
+ */
8
+ export declare function isGlobalVariable(node: ts.Expression, typeChecker: ts.TypeChecker): boolean;
@@ -0,0 +1,21 @@
1
+ import { declarationsIncludeGlobal } from "./declarationsIncludeGlobal.js";
2
+ /**
3
+ * Checks if a node is a reference to a global variable (e.g., Object, undefined, NaN).
4
+ * Global variables are those declared in TypeScript's lib files or are global identifiers
5
+ * like undefined which have symbols but no user-defined declarations.
6
+ * TODO: Use a scope manager (#400).
7
+ */
8
+ export function isGlobalVariable(node, typeChecker) {
9
+ const symbol = typeChecker.getSymbolAtLocation(node);
10
+ if (!symbol) {
11
+ return false;
12
+ }
13
+ const declarations = symbol.getDeclarations();
14
+ // undefined, NaN, Infinity etc. may have no declarations in some contexts
15
+ // but are still global identifiers. Check if they're global scope symbols.
16
+ if (!declarations?.length) {
17
+ // If there are no declarations, it's likely a built-in global like undefined
18
+ return true;
19
+ }
20
+ return declarationsIncludeGlobal(declarations);
21
+ }
@@ -0,0 +1,2 @@
1
+ import * as ts from "typescript";
2
+ export declare function unwrapParenthesizedExpressionsParent(node: ts.Node): ts.Node;
@@ -0,0 +1,6 @@
1
+ import * as ts from "typescript";
2
+ export function unwrapParenthesizedExpressionsParent(node) {
3
+ return ts.isParenthesizedExpression(node.parent)
4
+ ? unwrapParenthesizedExpressionsParent(node.parent)
5
+ : node.parent;
6
+ }
@@ -0,0 +1,2 @@
1
+ import * as ts from "typescript";
2
+ export declare function unwrapParenthesizedExpression(expression: ts.Expression): ts.Expression;
@@ -0,0 +1,6 @@
1
+ import * as ts from "typescript";
2
+ export function unwrapParenthesizedExpression(expression) {
3
+ return ts.isParenthesizedExpression(expression)
4
+ ? unwrapParenthesizedExpression(expression.expression)
5
+ : expression;
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flint.fyi/ts",
3
- "version": "0.14.2",
3
+ "version": "0.14.4",
4
4
  "description": "[Experimental] TypeScript language plugin for Flint.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -49,6 +49,7 @@ export function createTypeScriptFileFromProgram(
49
49
  const reports: NormalizedReport[] = [];
50
50
 
51
51
  const context = {
52
+ program,
52
53
  report: (report: RuleReport) => {
53
54
  reports.push({
54
55
  ...report,
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { getTSNodeRange } from "./getTSNodeRange.js";
2
2
  export * from "./language.js";
3
3
  export { ts } from "./plugin.js";
4
+ export { isGlobalDeclaration } from "./utils/isGlobalDeclaration.js";
package/src/language.ts CHANGED
@@ -19,6 +19,7 @@ const log = debugForFile(import.meta.filename);
19
19
  const projectRoot = path.join(import.meta.dirname, "../..");
20
20
 
21
21
  export interface TypeScriptServices {
22
+ program: ts.Program;
22
23
  sourceFile: ts.SourceFile;
23
24
  typeChecker: ts.TypeChecker;
24
25
  }
package/src/nodes.ts CHANGED
@@ -26,6 +26,7 @@ export interface TSNodesByName {
26
26
  ComputedPropertyName: ts.ComputedPropertyName;
27
27
  ConditionalExpression: ts.ConditionalExpression;
28
28
  ConditionalType: ts.ConditionalType;
29
+ Constructor: ts.ConstructorDeclaration;
29
30
  ContinueStatement: ts.ContinueStatement;
30
31
  DebuggerStatement: ts.DebuggerStatement;
31
32
  Decorator: ts.Decorator;