@blumintinc/eslint-plugin-blumint 1.12.6 → 1.14.0

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 (258) hide show
  1. package/README.md +171 -99
  2. package/lib/index.js +300 -17
  3. package/lib/rules/array-methods-this-context.js +20 -2
  4. package/lib/rules/avoid-utils-directory.js +11 -2
  5. package/lib/rules/class-methods-read-top-to-bottom.js +24 -5
  6. package/lib/rules/consistent-callback-naming.js +1 -1
  7. package/lib/rules/dynamic-https-errors.d.ts +3 -1
  8. package/lib/rules/dynamic-https-errors.js +48 -11
  9. package/lib/rules/enforce-assert-safe-object-key.d.ts +8 -0
  10. package/lib/rules/{enforce-assertSafe-object-key.js → enforce-assert-safe-object-key.js} +52 -96
  11. package/lib/rules/enforce-assert-throws.d.ts +3 -1
  12. package/lib/rules/enforce-assert-throws.js +493 -51
  13. package/lib/rules/enforce-boolean-naming-prefixes.d.ts +3 -1
  14. package/lib/rules/enforce-boolean-naming-prefixes.js +820 -39
  15. package/lib/rules/enforce-callable-types.js +4 -4
  16. package/lib/rules/enforce-callback-memo.js +143 -18
  17. package/lib/rules/enforce-centralized-mock-firestore.js +5 -2
  18. package/lib/rules/enforce-console-error.d.ts +3 -0
  19. package/lib/rules/enforce-console-error.js +278 -0
  20. package/lib/rules/enforce-css-media-queries.js +24 -46
  21. package/lib/rules/enforce-dynamic-file-naming.d.ts +2 -0
  22. package/lib/rules/enforce-dynamic-file-naming.js +53 -28
  23. package/lib/rules/enforce-dynamic-firebase-imports.js +100 -19
  24. package/lib/rules/enforce-dynamic-imports.js +1 -1
  25. package/lib/rules/enforce-early-destructuring.d.ts +2 -0
  26. package/lib/rules/enforce-early-destructuring.js +980 -0
  27. package/lib/rules/enforce-empty-object-check.d.ts +11 -0
  28. package/lib/rules/enforce-empty-object-check.js +502 -0
  29. package/lib/rules/enforce-exported-function-types.js +4 -4
  30. package/lib/rules/enforce-fieldpath-syntax-in-docsetter.d.ts +2 -0
  31. package/lib/rules/enforce-fieldpath-syntax-in-docsetter.js +262 -0
  32. package/lib/rules/enforce-firestore-doc-ref-generic.js +350 -3
  33. package/lib/rules/enforce-firestore-facade.js +349 -157
  34. package/lib/rules/enforce-firestore-rules-get-access.d.ts +3 -0
  35. package/lib/rules/enforce-firestore-rules-get-access.js +109 -0
  36. package/lib/rules/enforce-firestore-set-merge.js +3 -4
  37. package/lib/rules/enforce-global-constants.d.ts +4 -1
  38. package/lib/rules/enforce-global-constants.js +240 -12
  39. package/lib/rules/enforce-identifiable-firestore-type.js +108 -58
  40. package/lib/rules/enforce-memoize-async.d.ts +2 -1
  41. package/lib/rules/enforce-memoize-async.js +92 -27
  42. package/lib/rules/enforce-memoize-getters.d.ts +3 -0
  43. package/lib/rules/enforce-memoize-getters.js +147 -0
  44. package/lib/rules/enforce-microdiff.js +3 -2
  45. package/lib/rules/enforce-object-literal-as-const.js +4 -4
  46. package/lib/rules/enforce-positive-naming.js +9 -7
  47. package/lib/rules/enforce-props-argument-name.d.ts +2 -7
  48. package/lib/rules/enforce-props-argument-name.js +165 -151
  49. package/lib/rules/enforce-props-naming-consistency.d.ts +2 -0
  50. package/lib/rules/enforce-props-naming-consistency.js +145 -0
  51. package/lib/rules/enforce-querykey-ts.d.ts +9 -0
  52. package/lib/rules/enforce-querykey-ts.js +274 -0
  53. package/lib/rules/enforce-safe-stringify.js +1 -1
  54. package/lib/rules/enforce-serializable-params.js +3 -3
  55. package/lib/rules/enforce-singular-type-names.js +10 -6
  56. package/lib/rules/enforce-stable-hash-spread-props.d.ts +13 -0
  57. package/lib/rules/enforce-stable-hash-spread-props.js +342 -0
  58. package/lib/rules/enforce-storage-context.d.ts +9 -0
  59. package/lib/rules/enforce-storage-context.js +646 -0
  60. package/lib/rules/enforce-timestamp-now.js +23 -7
  61. package/lib/rules/enforce-transform-memoization.d.ts +4 -0
  62. package/lib/rules/enforce-transform-memoization.js +416 -0
  63. package/lib/rules/enforce-typescript-markdown-code-blocks.d.ts +1 -0
  64. package/lib/rules/enforce-typescript-markdown-code-blocks.js +100 -0
  65. package/lib/rules/enforce-unique-cursor-headers.d.ts +16 -0
  66. package/lib/rules/enforce-unique-cursor-headers.js +365 -0
  67. package/lib/rules/enforce-verb-noun-naming.js +90 -14
  68. package/lib/rules/ensure-pointer-events-none.js +28 -2
  69. package/lib/rules/export-if-in-doubt.js +27 -4
  70. package/lib/rules/extract-global-constants.js +92 -53
  71. package/lib/rules/fast-deep-equal-over-microdiff.d.ts +2 -1
  72. package/lib/rules/fast-deep-equal-over-microdiff.js +351 -83
  73. package/lib/rules/firestore-transaction-reads-before-writes.d.ts +1 -0
  74. package/lib/rules/firestore-transaction-reads-before-writes.js +277 -0
  75. package/lib/rules/flatten-push-calls.d.ts +2 -0
  76. package/lib/rules/flatten-push-calls.js +428 -0
  77. package/lib/rules/generic-starts-with-t.js +8 -2
  78. package/lib/rules/global-const-style.js +50 -19
  79. package/lib/rules/jsdoc-above-field.d.ts +11 -0
  80. package/lib/rules/jsdoc-above-field.js +208 -0
  81. package/lib/rules/key-only-outermost-element.js +21 -3
  82. package/lib/rules/logical-top-to-bottom-grouping.d.ts +5 -0
  83. package/lib/rules/logical-top-to-bottom-grouping.js +1258 -0
  84. package/lib/rules/memo-compare-deeply-complex-props.d.ts +3 -0
  85. package/lib/rules/memo-compare-deeply-complex-props.js +788 -0
  86. package/lib/rules/memo-nested-react-components.d.ts +8 -0
  87. package/lib/rules/memo-nested-react-components.js +410 -0
  88. package/lib/rules/memoize-root-level-hocs.d.ts +7 -0
  89. package/lib/rules/memoize-root-level-hocs.js +242 -0
  90. package/lib/rules/no-always-true-false-conditions.d.ts +2 -1
  91. package/lib/rules/no-always-true-false-conditions.js +68 -8
  92. package/lib/rules/no-array-length-in-deps.d.ts +12 -0
  93. package/lib/rules/no-array-length-in-deps.js +314 -0
  94. package/lib/rules/no-async-array-filter.js +5 -2
  95. package/lib/rules/no-async-foreach.js +210 -12
  96. package/lib/rules/no-circular-references.js +18 -17
  97. package/lib/rules/no-class-instance-destructuring.js +55 -12
  98. package/lib/rules/no-complex-cloud-params.js +22 -5
  99. package/lib/rules/no-compositing-layer-props.js +6 -4
  100. package/lib/rules/no-conditional-literals-in-jsx.js +37 -12
  101. package/lib/rules/no-console-error.d.ts +9 -0
  102. package/lib/rules/no-console-error.js +525 -0
  103. package/lib/rules/no-curly-brackets-around-commented-properties.d.ts +2 -0
  104. package/lib/rules/no-curly-brackets-around-commented-properties.js +258 -0
  105. package/lib/rules/no-empty-dependency-use-callbacks.d.ts +11 -0
  106. package/lib/rules/no-empty-dependency-use-callbacks.js +576 -0
  107. package/lib/rules/no-entire-object-hook-deps.d.ts +3 -1
  108. package/lib/rules/no-entire-object-hook-deps.js +320 -68
  109. package/lib/rules/no-excessive-parent-chain.d.ts +5 -0
  110. package/lib/rules/no-excessive-parent-chain.js +273 -0
  111. package/lib/rules/no-explicit-return-type.d.ts +2 -1
  112. package/lib/rules/no-explicit-return-type.js +215 -26
  113. package/lib/rules/no-filter-without-return.js +5 -1
  114. package/lib/rules/no-firestore-jest-mock.d.ts +2 -1
  115. package/lib/rules/no-firestore-jest-mock.js +126 -8
  116. package/lib/rules/no-firestore-object-arrays.js +398 -28
  117. package/lib/rules/no-handler-suffix.d.ts +12 -0
  118. package/lib/rules/no-handler-suffix.js +305 -0
  119. package/lib/rules/no-hungarian.js +14 -14
  120. package/lib/rules/no-inline-component-prop.d.ts +10 -0
  121. package/lib/rules/no-inline-component-prop.js +456 -0
  122. package/lib/rules/no-jsx-in-hooks.js +6 -1
  123. package/lib/rules/no-jsx-whitespace-literal.js +8 -2
  124. package/lib/rules/no-margin-properties.d.ts +7 -1
  125. package/lib/rules/no-margin-properties.js +22 -9
  126. package/lib/rules/no-memoize-on-static.js +9 -1
  127. package/lib/rules/no-misleading-boolean-prefixes.d.ts +7 -0
  128. package/lib/rules/no-misleading-boolean-prefixes.js +331 -0
  129. package/lib/rules/no-misused-switch-case.js +22 -1
  130. package/lib/rules/no-mixed-firestore-transactions.d.ts +3 -1
  131. package/lib/rules/no-mixed-firestore-transactions.js +296 -34
  132. package/lib/rules/no-mock-firebase-admin.js +5 -2
  133. package/lib/rules/no-object-values-on-strings.js +10 -2
  134. package/lib/rules/no-overridable-method-calls-in-constructor.d.ts +1 -0
  135. package/lib/rules/no-overridable-method-calls-in-constructor.js +272 -0
  136. package/lib/rules/no-passthrough-getters.d.ts +4 -0
  137. package/lib/rules/no-passthrough-getters.js +206 -0
  138. package/lib/rules/no-redundant-annotation-assertion.d.ts +2 -0
  139. package/lib/rules/no-redundant-annotation-assertion.js +402 -0
  140. package/lib/rules/no-redundant-param-types.js +16 -6
  141. package/lib/rules/no-redundant-this-params.d.ts +3 -0
  142. package/lib/rules/no-redundant-this-params.js +459 -0
  143. package/lib/rules/no-redundant-usecallback-wrapper.d.ts +8 -0
  144. package/lib/rules/no-redundant-usecallback-wrapper.js +328 -0
  145. package/lib/rules/no-res-error-status-in-onrequest.d.ts +4 -0
  146. package/lib/rules/no-res-error-status-in-onrequest.js +521 -0
  147. package/lib/rules/no-restricted-properties-fix.d.ts +12 -0
  148. package/lib/rules/no-restricted-properties-fix.js +173 -0
  149. package/lib/rules/no-separate-loading-state.d.ts +8 -0
  150. package/lib/rules/no-separate-loading-state.js +133 -0
  151. package/lib/rules/no-stale-state-across-await.d.ts +1 -0
  152. package/lib/rules/no-stale-state-across-await.js +185 -0
  153. package/lib/rules/no-static-constants-in-dynamic-files.d.ts +3 -0
  154. package/lib/rules/no-static-constants-in-dynamic-files.js +149 -0
  155. package/lib/rules/no-try-catch-already-exists-in-transaction.d.ts +1 -0
  156. package/lib/rules/no-try-catch-already-exists-in-transaction.js +342 -0
  157. package/lib/rules/no-type-assertion-returns.js +49 -49
  158. package/lib/rules/no-undefined-null-passthrough.js +217 -40
  159. package/lib/rules/no-unmemoized-memo-without-props.d.ts +8 -0
  160. package/lib/rules/no-unmemoized-memo-without-props.js +426 -0
  161. package/lib/rules/no-unnecessary-destructuring-rename.d.ts +2 -0
  162. package/lib/rules/no-unnecessary-destructuring-rename.js +347 -0
  163. package/lib/rules/no-unnecessary-destructuring.js +14 -4
  164. package/lib/rules/no-unnecessary-verb-suffix.js +2 -3
  165. package/lib/rules/no-unpinned-dependencies.js +36 -5
  166. package/lib/rules/no-unsafe-firestore-spread.js +8 -5
  167. package/lib/rules/no-unused-props.d.ts +5 -2
  168. package/lib/rules/no-unused-props.js +451 -112
  169. package/lib/rules/no-unused-usestate.js +6 -2
  170. package/lib/rules/no-useless-fragment.js +28 -2
  171. package/lib/rules/no-useless-usememo-primitives.d.ts +9 -0
  172. package/lib/rules/no-useless-usememo-primitives.js +393 -0
  173. package/lib/rules/no-usememo-for-pass-by-value.d.ts +13 -0
  174. package/lib/rules/no-usememo-for-pass-by-value.js +757 -0
  175. package/lib/rules/no-uuidv4-base62-as-key.js +18 -13
  176. package/lib/rules/omit-index-html.d.ts +2 -1
  177. package/lib/rules/omit-index-html.js +62 -7
  178. package/lib/rules/optimize-object-boolean-conditions.d.ts +1 -0
  179. package/lib/rules/optimize-object-boolean-conditions.js +236 -0
  180. package/lib/rules/parallelize-async-operations.d.ts +8 -0
  181. package/lib/rules/parallelize-async-operations.js +394 -0
  182. package/lib/rules/prefer-batch-operations.d.ts +1 -3
  183. package/lib/rules/prefer-batch-operations.js +228 -35
  184. package/lib/rules/prefer-block-comments-for-declarations.js +22 -7
  185. package/lib/rules/prefer-clone-deep.js +3 -3
  186. package/lib/rules/prefer-destructuring-no-class.d.ts +2 -1
  187. package/lib/rules/prefer-destructuring-no-class.js +244 -59
  188. package/lib/rules/prefer-docsetter-setall.d.ts +2 -0
  189. package/lib/rules/prefer-docsetter-setall.js +243 -0
  190. package/lib/rules/prefer-document-flattening.d.ts +4 -0
  191. package/lib/rules/prefer-document-flattening.js +239 -0
  192. package/lib/rules/prefer-field-paths-in-transforms.d.ts +7 -0
  193. package/lib/rules/prefer-field-paths-in-transforms.js +251 -0
  194. package/lib/rules/prefer-fragment-component.js +4 -4
  195. package/lib/rules/prefer-fragment-shorthand.js +2 -1
  196. package/lib/rules/prefer-getter-over-parameterless-method.d.ts +13 -0
  197. package/lib/rules/prefer-getter-over-parameterless-method.js +648 -0
  198. package/lib/rules/prefer-global-router-state-key.d.ts +7 -3
  199. package/lib/rules/prefer-global-router-state-key.js +305 -31
  200. package/lib/rules/prefer-memoized-props.d.ts +3 -0
  201. package/lib/rules/prefer-memoized-props.js +445 -0
  202. package/lib/rules/prefer-next-dynamic.d.ts +9 -0
  203. package/lib/rules/prefer-next-dynamic.js +357 -0
  204. package/lib/rules/prefer-nullish-coalescing-boolean-props.d.ts +1 -0
  205. package/lib/rules/prefer-nullish-coalescing-boolean-props.js +435 -0
  206. package/lib/rules/prefer-nullish-coalescing-override.d.ts +7 -0
  207. package/lib/rules/prefer-nullish-coalescing-override.js +188 -0
  208. package/lib/rules/prefer-params-over-parent-id.d.ts +5 -0
  209. package/lib/rules/prefer-params-over-parent-id.js +277 -0
  210. package/lib/rules/prefer-settings-object.js +23 -15
  211. package/lib/rules/prefer-type-alias-over-typeof-constant.d.ts +3 -0
  212. package/lib/rules/prefer-type-alias-over-typeof-constant.js +259 -0
  213. package/lib/rules/prefer-type-over-interface.js +7 -2
  214. package/lib/rules/prefer-url-tostring-over-tojson.d.ts +2 -0
  215. package/lib/rules/prefer-url-tostring-over-tojson.js +169 -0
  216. package/lib/rules/prefer-use-deep-compare-memo.d.ts +4 -0
  217. package/lib/rules/prefer-use-deep-compare-memo.js +431 -0
  218. package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +25 -2
  219. package/lib/rules/prefer-usememo-over-useeffect-usestate.js +24 -5
  220. package/lib/rules/prefer-utility-function-over-private-static.js +34 -2
  221. package/lib/rules/prevent-children-clobber.d.ts +2 -0
  222. package/lib/rules/prevent-children-clobber.js +536 -0
  223. package/lib/rules/react-memoize-literals.d.ts +4 -0
  224. package/lib/rules/react-memoize-literals.js +495 -0
  225. package/lib/rules/react-usememo-should-be-component.d.ts +2 -1
  226. package/lib/rules/react-usememo-should-be-component.js +144 -78
  227. package/lib/rules/require-dynamic-firebase-imports.js +2 -1
  228. package/lib/rules/require-hooks-default-params.js +17 -16
  229. package/lib/rules/require-https-error-cause.d.ts +4 -0
  230. package/lib/rules/require-https-error-cause.js +136 -0
  231. package/lib/rules/require-https-error.js +43 -21
  232. package/lib/rules/require-image-optimized.js +2 -2
  233. package/lib/rules/require-memo.js +12 -2
  234. package/lib/rules/require-memoize-jsx-returners.d.ts +3 -0
  235. package/lib/rules/require-memoize-jsx-returners.js +485 -0
  236. package/lib/rules/require-usememo-object-literals.js +9 -4
  237. package/lib/rules/semantic-function-prefixes.js +38 -18
  238. package/lib/rules/sync-onwrite-name-func.js +5 -1
  239. package/lib/rules/test-file-location-enforcement.d.ts +1 -0
  240. package/lib/rules/test-file-location-enforcement.js +57 -0
  241. package/lib/rules/use-custom-link.js +6 -1
  242. package/lib/rules/use-custom-router.js +6 -1
  243. package/lib/rules/use-latest-callback.d.ts +3 -0
  244. package/lib/rules/use-latest-callback.js +271 -0
  245. package/lib/rules/vertically-group-related-functions.d.ts +16 -0
  246. package/lib/rules/vertically-group-related-functions.js +480 -0
  247. package/lib/utils/ASTHelpers.d.ts +13 -1
  248. package/lib/utils/ASTHelpers.js +34 -0
  249. package/lib/utils/createRule.js +1 -1
  250. package/lib/utils/getMethodName.d.ts +27 -0
  251. package/lib/utils/getMethodName.js +35 -0
  252. package/lib/utils/graph/ClassGraphSorterReadability.js +1 -1
  253. package/lib/utils/ruleTester.d.ts +1 -0
  254. package/lib/utils/ruleTester.js +4 -1
  255. package/lib/utils/tsTypeClassifier.d.ts +30 -0
  256. package/lib/utils/tsTypeClassifier.js +149 -0
  257. package/package.json +23 -14
  258. package/lib/rules/enforce-assertSafe-object-key.d.ts +0 -2
@@ -0,0 +1,402 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.noRedundantAnnotationAssertion = void 0;
27
+ const utils_1 = require("@typescript-eslint/utils");
28
+ const visitor_keys_1 = require("@typescript-eslint/visitor-keys");
29
+ const ts = __importStar(require("typescript"));
30
+ const ASTHelpers_1 = require("../utils/ASTHelpers");
31
+ const createRule_1 = require("../utils/createRule");
32
+ /**
33
+ * Type string formatting flags chosen to keep comparisons stable and predictable.
34
+ * - NoTruncation avoids `...` elisions that can hide important differences.
35
+ * - WriteArrayAsGenericType normalizes arrays to `Array<T>` for consistent output.
36
+ * - UseFullyQualifiedType reduces ambiguity from locally-imported type names.
37
+ * - UseStructuralFallback keeps output meaningful when a nominal name is unavailable.
38
+ */
39
+ const TYPE_FORMAT_FLAGS = ts.TypeFormatFlags.NoTruncation |
40
+ ts.TypeFormatFlags.WriteArrayAsGenericType |
41
+ ts.TypeFormatFlags.UseFullyQualifiedType |
42
+ ts.TypeFormatFlags.UseStructuralFallback;
43
+ function extractAssertionTypeNode(expression) {
44
+ if (!expression)
45
+ return null;
46
+ if (expression.type === utils_1.AST_NODE_TYPES.TSAsExpression) {
47
+ return expression.typeAnnotation;
48
+ }
49
+ if (expression.type === utils_1.AST_NODE_TYPES.TSTypeAssertion) {
50
+ return expression.typeAnnotation;
51
+ }
52
+ return null;
53
+ }
54
+ function isTraversalBoundary(node) {
55
+ /**
56
+ * Nested functions/classes have their own return semantics; inner returns should not
57
+ * influence the outer function's return-type check.
58
+ */
59
+ return (node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
60
+ node.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
61
+ node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
62
+ node.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
63
+ node.type === utils_1.AST_NODE_TYPES.ClassDeclaration ||
64
+ node.type === utils_1.AST_NODE_TYPES.ClassExpression);
65
+ }
66
+ function recordReturnStatement(node, assertions) {
67
+ if (!node.argument)
68
+ return;
69
+ const assertion = extractAssertionTypeNode(node.argument);
70
+ if (assertion)
71
+ assertions.push(assertion);
72
+ }
73
+ function addChildNodesToStack(node, stack) {
74
+ const keys = visitor_keys_1.visitorKeys[node.type];
75
+ if (!keys)
76
+ return;
77
+ for (const key of keys) {
78
+ const value = node[key];
79
+ if (Array.isArray(value)) {
80
+ for (const element of value) {
81
+ if (ASTHelpers_1.ASTHelpers.isNode(element)) {
82
+ stack.push(element);
83
+ }
84
+ }
85
+ continue;
86
+ }
87
+ if (ASTHelpers_1.ASTHelpers.isNode(value)) {
88
+ stack.push(value);
89
+ }
90
+ }
91
+ }
92
+ function collectReturnInfo(body) {
93
+ const assertions = [];
94
+ let returnCount = 0;
95
+ const stack = [...body.body];
96
+ while (stack.length) {
97
+ const current = stack.pop();
98
+ if (current.type === utils_1.AST_NODE_TYPES.ReturnStatement) {
99
+ returnCount += 1;
100
+ recordReturnStatement(current, assertions);
101
+ continue;
102
+ }
103
+ if (isTraversalBoundary(current))
104
+ continue;
105
+ addChildNodesToStack(current, stack);
106
+ }
107
+ return { assertions, returnCount };
108
+ }
109
+ function findTypeAnnotationStart(typeAnnotation, sourceCode) {
110
+ const start = typeAnnotation.range[0];
111
+ const text = sourceCode.getText();
112
+ let removalStart = start;
113
+ /**
114
+ * Scan backward to remove any whitespace before `: Type`, but avoid consuming tokens
115
+ * that belong to the declared name (e.g. `!` definite assignment assertions or `?`
116
+ * optional markers).
117
+ */
118
+ for (let i = start - 1; i >= 0; i -= 1) {
119
+ const char = text.charAt(i);
120
+ if (char === '\n' || char === '\r')
121
+ break;
122
+ if (char === '?' || char === '!') {
123
+ removalStart = i + 1;
124
+ break;
125
+ }
126
+ if (!/\s/.test(char)) {
127
+ removalStart = i + 1;
128
+ break;
129
+ }
130
+ removalStart = i;
131
+ }
132
+ return removalStart;
133
+ }
134
+ function removeTypeAnnotation(fixer, typeAnnotation, sourceCode) {
135
+ const end = typeAnnotation.range[1];
136
+ const removalStart = findTypeAnnotationStart(typeAnnotation, sourceCode);
137
+ return fixer.removeRange([removalStart, end]);
138
+ }
139
+ function typeText(type, checker) {
140
+ return checker.typeToString(type, undefined, TYPE_FORMAT_FLAGS);
141
+ }
142
+ function unwrapAlias(type, checker) {
143
+ const aliasSymbol = type
144
+ .aliasSymbol;
145
+ if (!aliasSymbol)
146
+ return type;
147
+ if ((aliasSymbol.flags & ts.SymbolFlags.Alias) !== 0) {
148
+ const target = checker.getAliasedSymbol(aliasSymbol);
149
+ return checker.getDeclaredTypeOfSymbol(target);
150
+ }
151
+ if ((aliasSymbol.flags & ts.SymbolFlags.TypeAlias) !== 0) {
152
+ const aliasTypeArguments = type.aliasTypeArguments;
153
+ if (aliasTypeArguments?.length) {
154
+ return checker.getApparentType(type);
155
+ }
156
+ return checker.getDeclaredTypeOfSymbol(aliasSymbol);
157
+ }
158
+ return type;
159
+ }
160
+ function formatPropertySignature(prop, parentType, checker) {
161
+ const declaration = prop.valueDeclaration ??
162
+ prop.declarations?.[0] ??
163
+ parentType.symbol?.valueDeclaration ??
164
+ parentType.symbol?.declarations?.[0];
165
+ if (!declaration)
166
+ return null;
167
+ const propType = checker.getTypeOfSymbolAtLocation(prop, declaration);
168
+ const text = typeText(unwrapAlias(propType, checker), checker);
169
+ const isOptional = (prop.getFlags() & ts.SymbolFlags.Optional) !== 0;
170
+ return `${prop.getName()}${isOptional ? '?' : ''}:${text}`;
171
+ }
172
+ function getFormattedTypeProperties(type, checker) {
173
+ return checker
174
+ .getPropertiesOfType(type)
175
+ .map((prop) => formatPropertySignature(prop, type, checker))
176
+ .filter((entry) => Boolean(entry))
177
+ .sort();
178
+ }
179
+ function getFormattedCallSignatures(type, checker) {
180
+ return checker
181
+ .getSignaturesOfType(type, ts.SignatureKind.Call)
182
+ .map((sig) => checker.signatureToString(sig, undefined, TYPE_FORMAT_FLAGS))
183
+ .sort();
184
+ }
185
+ function structuralKey(type, checker) {
186
+ const apparent = checker.getApparentType(type);
187
+ const properties = getFormattedTypeProperties(apparent, checker);
188
+ const signatures = getFormattedCallSignatures(apparent, checker);
189
+ return `${properties.join('|')}::${signatures.join('|')}`;
190
+ }
191
+ function getComparableType(typeNode, checker, services) {
192
+ const tsNode = services.esTreeNodeToTSNodeMap.get(typeNode);
193
+ if (!ts.isTypeNode(tsNode))
194
+ return null;
195
+ const type = checker.getTypeFromTypeNode(tsNode);
196
+ const unwrapped = unwrapAlias(type, checker);
197
+ return unwrapped;
198
+ }
199
+ /**
200
+ * Generate multiple string representations of both types for comparison.
201
+ * Multiple strategies are needed because TypeScript types can be semantically
202
+ * identical yet have different string representations depending on:
203
+ * - Type aliases (MyType vs the underlying type) via canonical/NoTypeReduction
204
+ * - Type formatting options (fully qualified vs relative) via default text
205
+ * - Structural equivalence (different names, same shape) via structural key
206
+ */
207
+ function getTypeRepresentations(annotationType, assertionType, checker) {
208
+ return {
209
+ annotationText: typeText(annotationType, checker),
210
+ assertionText: typeText(assertionType, checker),
211
+ annotationCanonical: checker.typeToString(annotationType, undefined, TYPE_FORMAT_FLAGS | ts.TypeFormatFlags.NoTypeReduction),
212
+ assertionCanonical: checker.typeToString(assertionType, undefined, TYPE_FORMAT_FLAGS | ts.TypeFormatFlags.NoTypeReduction),
213
+ annotationStructural: structuralKey(annotationType, checker),
214
+ assertionStructural: structuralKey(assertionType, checker),
215
+ };
216
+ }
217
+ function areTypesIdentical(annotationType, assertionType, checker) {
218
+ if (annotationType === assertionType)
219
+ return true;
220
+ const isTypeIdenticalTo = checker.isTypeIdenticalTo;
221
+ /** Guard the internal TypeScript helper; newer compiler versions may drop or change it. */
222
+ if (typeof isTypeIdenticalTo !== 'function') {
223
+ return false;
224
+ }
225
+ return isTypeIdenticalTo(annotationType, assertionType) === true;
226
+ }
227
+ function areTypesAssignableBothWays(annotationType, assertionType, checker) {
228
+ const isTypeAssignableTo = checker.isTypeAssignableTo;
229
+ /** Guard for checker.isTypeAssignableTo which may be absent from some d.ts versions. */
230
+ if (typeof isTypeAssignableTo !== 'function') {
231
+ return false;
232
+ }
233
+ return (isTypeAssignableTo(annotationType, assertionType) &&
234
+ isTypeAssignableTo(assertionType, annotationType));
235
+ }
236
+ function doTypeTextsMatch(representations) {
237
+ const { annotationText, assertionText, annotationCanonical, assertionCanonical, annotationStructural, assertionStructural, } = representations;
238
+ return (annotationText === assertionText ||
239
+ annotationCanonical === assertionCanonical ||
240
+ annotationStructural === assertionStructural);
241
+ }
242
+ function selectMatchingTypeRepresentation(representations) {
243
+ return representations.annotationText;
244
+ }
245
+ /**
246
+ * Checks if two types are effectively equal for the purpose of identifying redundant assertions.
247
+ * Types are effectively equal if they are:
248
+ * 1. Identical according to TypeScript's internal identity check.
249
+ * 2. Or, they are assignable both ways AND share at least one string representation
250
+ * (canonical, structural, or default formatting).
251
+ */
252
+ function areTypesEffectivelyEqual(annotationType, assertionType, representations, checker) {
253
+ const identical = areTypesIdentical(annotationType, assertionType, checker);
254
+ if (identical) {
255
+ return true;
256
+ }
257
+ const assignableBothWays = areTypesAssignableBothWays(annotationType, assertionType, checker);
258
+ const textMatches = doTypeTextsMatch(representations);
259
+ return assignableBothWays && textMatches;
260
+ }
261
+ /**
262
+ * Compare annotation and assertion types across identity, assignability, and
263
+ * multiple textual forms so equivalent aliases still count as redundant.
264
+ * @param annotation The type annotation node to compare.
265
+ * @param assertion The type assertion node to compare.
266
+ * @param checker The TypeScript type checker.
267
+ * @param services The parser services.
268
+ * @returns The matching type string if the types are effectively equal, null otherwise.
269
+ */
270
+ function haveMatchingTypes(annotation, assertion, checker, services) {
271
+ const annotationType = getComparableType(annotation, checker, services);
272
+ const assertionType = getComparableType(assertion, checker, services);
273
+ if (!annotationType || !assertionType)
274
+ return null;
275
+ const representations = getTypeRepresentations(annotationType, assertionType, checker);
276
+ if (!areTypesEffectivelyEqual(annotationType, assertionType, representations, checker)) {
277
+ return null;
278
+ }
279
+ return selectMatchingTypeRepresentation(representations);
280
+ }
281
+ function getReturnAssertion(node) {
282
+ const value = node.type === utils_1.AST_NODE_TYPES.MethodDefinition ? node.value : node;
283
+ const body = value.body;
284
+ if (body?.type === utils_1.AST_NODE_TYPES.BlockStatement) {
285
+ const { assertions, returnCount } = collectReturnInfo(body);
286
+ // Skip functions with multiple returns because different branches can assert different types.
287
+ if (returnCount !== 1)
288
+ return null;
289
+ // Ensure the single return is the last statement in the function body
290
+ // to avoid cases where an implicit undefined return exists.
291
+ const lastStatement = body.body[body.body.length - 1];
292
+ if (lastStatement?.type !== utils_1.AST_NODE_TYPES.ReturnStatement) {
293
+ return null;
294
+ }
295
+ return assertions[0] ?? null;
296
+ }
297
+ if (!body)
298
+ return null;
299
+ return extractAssertionTypeNode(body);
300
+ }
301
+ exports.noRedundantAnnotationAssertion = (0, createRule_1.createRule)({
302
+ name: 'no-redundant-annotation-assertion',
303
+ meta: {
304
+ type: 'suggestion',
305
+ docs: {
306
+ description: 'Disallow combining a type annotation with an identical type assertion on the same value. Keep a single source of truth to avoid redundant type declarations that can drift apart.',
307
+ recommended: 'error',
308
+ requiresTypeChecking: true,
309
+ },
310
+ fixable: 'code',
311
+ schema: [],
312
+ messages: {
313
+ redundantAnnotationAndAssertion: 'What\'s wrong: Type "{{type}}" is declared twice: once as an annotation and again as an assertion. \u2192 Why it matters: If you later update the assertion but forget the annotation (or vice-versa), they can drift apart and cause TypeScript to silently bypass type checks or lead to incorrect runtime assumptions. \u2192 How to fix: Remove the annotation and keep the assertion to maintain a single source of truth.',
314
+ },
315
+ },
316
+ defaultOptions: [],
317
+ create(context) {
318
+ const sourceCode = context
319
+ .sourceCode ?? context.getSourceCode?.();
320
+ const parserServices = sourceCode?.parserServices ?? context.parserServices;
321
+ if (!sourceCode ||
322
+ !parserServices?.program ||
323
+ !parserServices.esTreeNodeToTSNodeMap ||
324
+ !parserServices.tsNodeToESTreeNodeMap) {
325
+ /* istanbul ignore next -- without type information the rule cannot run */
326
+ return {};
327
+ }
328
+ const checker = parserServices.program.getTypeChecker();
329
+ function reportIfRedundant(annotation, assertion, reportNode, fixerTarget) {
330
+ const matchingType = haveMatchingTypes(annotation.typeAnnotation, assertion, checker, parserServices);
331
+ if (!matchingType)
332
+ return;
333
+ context.report({
334
+ node: reportNode,
335
+ messageId: 'redundantAnnotationAndAssertion',
336
+ data: { type: matchingType },
337
+ fix: (fixer) => removeTypeAnnotation(fixer, fixerTarget, sourceCode),
338
+ });
339
+ }
340
+ return {
341
+ VariableDeclarator(node) {
342
+ if (node.id.type !== utils_1.AST_NODE_TYPES.Identifier ||
343
+ !node.id.typeAnnotation ||
344
+ node.id.optional ||
345
+ node.definite) {
346
+ return;
347
+ }
348
+ const assertionType = extractAssertionTypeNode(node.init);
349
+ if (!assertionType)
350
+ return;
351
+ reportIfRedundant(node.id.typeAnnotation, assertionType, node.id, node.id.typeAnnotation);
352
+ },
353
+ PropertyDefinition(node) {
354
+ if (!node.typeAnnotation ||
355
+ !node.value ||
356
+ node.optional ||
357
+ node.definite)
358
+ return;
359
+ const assertionType = extractAssertionTypeNode(node.value);
360
+ if (!assertionType)
361
+ return;
362
+ reportIfRedundant(node.typeAnnotation, assertionType, node.key, node.typeAnnotation);
363
+ },
364
+ FunctionDeclaration(node) {
365
+ if (!node.returnType)
366
+ return;
367
+ const assertionType = getReturnAssertion(node);
368
+ if (!assertionType)
369
+ return;
370
+ reportIfRedundant(node.returnType, assertionType, node.id ?? node, node.returnType);
371
+ },
372
+ FunctionExpression(node) {
373
+ if (node.parent?.type === utils_1.AST_NODE_TYPES.MethodDefinition) {
374
+ return;
375
+ }
376
+ if (!node.returnType)
377
+ return;
378
+ const assertionType = getReturnAssertion(node);
379
+ if (!assertionType)
380
+ return;
381
+ reportIfRedundant(node.returnType, assertionType, node, node.returnType);
382
+ },
383
+ ArrowFunctionExpression(node) {
384
+ if (!node.returnType)
385
+ return;
386
+ const assertionType = getReturnAssertion(node);
387
+ if (!assertionType)
388
+ return;
389
+ reportIfRedundant(node.returnType, assertionType, node, node.returnType);
390
+ },
391
+ MethodDefinition(node) {
392
+ if (!node.value.returnType)
393
+ return;
394
+ const assertionType = getReturnAssertion(node);
395
+ if (!assertionType)
396
+ return;
397
+ reportIfRedundant(node.value.returnType, assertionType, node.key, node.value.returnType);
398
+ },
399
+ };
400
+ },
401
+ });
402
+ //# sourceMappingURL=no-redundant-annotation-assertion.js.map
@@ -64,7 +64,7 @@ exports.noRedundantParamTypes = (0, createRule_1.createRule)({
64
64
  fixable: 'code',
65
65
  schema: [],
66
66
  messages: {
67
- redundantParamType: 'Parameter type annotation is redundant',
67
+ redundantParamType: 'Parameter "{{paramText}}" repeats a type that the contextual function type already provides. Duplicate annotations drift out of sync and obscure the single source of truth for the signature. Remove the inline parameter annotation and rely on the variable or property type so the function stays aligned.',
68
68
  },
69
69
  },
70
70
  defaultOptions: [],
@@ -74,13 +74,19 @@ exports.noRedundantParamTypes = (0, createRule_1.createRule)({
74
74
  if (!hasRedundantTypeAnnotation(node))
75
75
  return;
76
76
  const params = node.params;
77
+ const sourceCode = context.getSourceCode();
77
78
  params.forEach((param) => {
79
+ const paramText = sourceCode
80
+ .getText(param)
81
+ .replace(/\s+/g, ' ')
82
+ .trim();
78
83
  if (isIdentifierWithTypeAnnotation(param)) {
79
84
  context.report({
80
85
  node: param,
81
86
  messageId: 'redundantParamType',
87
+ data: { paramText },
82
88
  fix(fixer) {
83
- return removeTypeAnnotation(fixer, param.typeAnnotation, context.getSourceCode());
89
+ return removeTypeAnnotation(fixer, param.typeAnnotation, sourceCode);
84
90
  },
85
91
  });
86
92
  }
@@ -88,8 +94,9 @@ exports.noRedundantParamTypes = (0, createRule_1.createRule)({
88
94
  context.report({
89
95
  node: param,
90
96
  messageId: 'redundantParamType',
97
+ data: { paramText },
91
98
  fix(fixer) {
92
- return removeTypeAnnotation(fixer, param.typeAnnotation, context.getSourceCode());
99
+ return removeTypeAnnotation(fixer, param.typeAnnotation, sourceCode);
93
100
  },
94
101
  });
95
102
  }
@@ -97,8 +104,9 @@ exports.noRedundantParamTypes = (0, createRule_1.createRule)({
97
104
  context.report({
98
105
  node: param,
99
106
  messageId: 'redundantParamType',
107
+ data: { paramText },
100
108
  fix(fixer) {
101
- return removeTypeAnnotation(fixer, param.typeAnnotation, context.getSourceCode());
109
+ return removeTypeAnnotation(fixer, param.typeAnnotation, sourceCode);
102
110
  },
103
111
  });
104
112
  }
@@ -106,8 +114,9 @@ exports.noRedundantParamTypes = (0, createRule_1.createRule)({
106
114
  context.report({
107
115
  node: param,
108
116
  messageId: 'redundantParamType',
117
+ data: { paramText },
109
118
  fix(fixer) {
110
- return removeTypeAnnotation(fixer, param.typeAnnotation, context.getSourceCode());
119
+ return removeTypeAnnotation(fixer, param.typeAnnotation, sourceCode);
111
120
  },
112
121
  });
113
122
  }
@@ -116,8 +125,9 @@ exports.noRedundantParamTypes = (0, createRule_1.createRule)({
116
125
  context.report({
117
126
  node: param,
118
127
  messageId: 'redundantParamType',
128
+ data: { paramText },
119
129
  fix(fixer) {
120
- return removeTypeAnnotation(fixer, left.typeAnnotation, context.getSourceCode());
130
+ return removeTypeAnnotation(fixer, left.typeAnnotation, sourceCode);
121
131
  },
122
132
  });
123
133
  }
@@ -0,0 +1,3 @@
1
+ type MessageIds = 'redundantInstanceArg' | 'redundantInstanceValueInObject';
2
+ export declare const noRedundantThisParams: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<MessageIds, [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
3
+ export {};