@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
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extractGlobalConstants = void 0;
4
4
  const ASTHelpers_1 = require("../utils/ASTHelpers");
5
5
  const createRule_1 = require("../utils/createRule");
6
+ const utils_1 = require("@typescript-eslint/utils");
6
7
  function isInsideFunction(node) {
7
8
  let current = node;
8
9
  while (current) {
@@ -19,53 +20,61 @@ function isFunctionDefinition(node) {
19
20
  return (node?.type === 'FunctionExpression' ||
20
21
  node?.type === 'ArrowFunctionExpression');
21
22
  }
22
- function isImmutableValue(node) {
23
+ const unwrapOnce = (node) => {
23
24
  if (!node)
24
- return false;
25
+ return null;
26
+ const maybeParen = node;
27
+ if (maybeParen.type === 'ParenthesizedExpression') {
28
+ return maybeParen.expression ?? null;
29
+ }
25
30
  switch (node.type) {
26
- case 'Literal':
27
- return true;
28
- case 'TemplateLiteral':
29
- return node.expressions.length === 0;
30
- case 'UnaryExpression':
31
- return isImmutableValue(node.argument);
32
- case 'BinaryExpression':
33
- if (node.left.type === 'PrivateIdentifier')
34
- return false;
35
- return isImmutableValue(node.left) && isImmutableValue(node.right);
31
+ case utils_1.AST_NODE_TYPES.TSAsExpression:
32
+ case utils_1.AST_NODE_TYPES.TSSatisfiesExpression:
33
+ case utils_1.AST_NODE_TYPES.TSNonNullExpression:
34
+ case utils_1.AST_NODE_TYPES.ChainExpression:
35
+ case utils_1.AST_NODE_TYPES.TSTypeAssertion:
36
+ return node.expression;
36
37
  default:
37
- return false;
38
+ return null;
39
+ }
40
+ };
41
+ function unwrapExpression(node) {
42
+ let current = node;
43
+ while (current) {
44
+ const inner = unwrapOnce(current);
45
+ if (!inner)
46
+ break;
47
+ current = inner;
38
48
  }
49
+ return current;
39
50
  }
40
51
  function isMutableValue(node) {
41
- if (!node)
52
+ const unwrapped = unwrapExpression(node);
53
+ if (!unwrapped)
54
+ return false;
55
+ // If explicitly marked readonly with `as const`, treat as immutable
56
+ if (node && isAsConstExpression(node)) {
42
57
  return false;
58
+ }
43
59
  // Check for JSX elements (always mutable due to props/context)
44
- if (node.type === 'JSXElement' || node.type === 'JSXFragment') {
60
+ if (unwrapped.type === 'JSXElement' || unwrapped.type === 'JSXFragment') {
45
61
  return true;
46
62
  }
47
63
  // Check for object expressions (always mutable)
48
- if (node.type === 'ObjectExpression') {
64
+ if (unwrapped.type === 'ObjectExpression') {
49
65
  return true;
50
66
  }
51
- // Check array literals - mutable if empty or if they contain mutable values
52
- if (node.type === 'ArrayExpression') {
53
- // Empty arrays are mutable since they can be modified later
54
- if (node.elements.length === 0)
55
- return true;
56
- // Arrays with spread elements are mutable
57
- if (node.elements.some((element) => !element || element.type === 'SpreadElement'))
58
- return true;
59
- // Arrays with non-immutable values are mutable
60
- return node.elements.some((element) => !isImmutableValue(element));
67
+ // Arrays are mutable objects unless explicitly narrowed with `as const`.
68
+ if (unwrapped.type === 'ArrayExpression') {
69
+ return true;
61
70
  }
62
71
  // Check for new expressions (e.g., new Map(), new Set())
63
- if (node.type === 'NewExpression') {
72
+ if (unwrapped.type === 'NewExpression') {
64
73
  return true;
65
74
  }
66
75
  // Check for array/object methods that return mutable values
67
- if (node.type === 'CallExpression') {
68
- const callee = node.callee;
76
+ if (unwrapped.type === 'CallExpression') {
77
+ const callee = unwrapped.callee;
69
78
  if (callee.type === 'MemberExpression') {
70
79
  // Handle both Identifier and non-Identifier property nodes
71
80
  if (callee.property.type !== 'Identifier') {
@@ -103,17 +112,31 @@ function isZeroOrOne(node) {
103
112
  return value === 0 || value === 1;
104
113
  }
105
114
  function isAsConstExpression(node) {
106
- if (!node)
107
- return false;
108
- if (node.type === 'TSAsExpression') {
109
- if (node.typeAnnotation.type === 'TSTypeReference' &&
110
- node.typeAnnotation.typeName.type === 'Identifier' &&
111
- node.typeAnnotation.typeName.name === 'const') {
115
+ let current = node;
116
+ while (current) {
117
+ if (current.type === 'TSAsExpression' &&
118
+ current.typeAnnotation.type === 'TSTypeReference' &&
119
+ current.typeAnnotation.typeName.type === 'Identifier' &&
120
+ current.typeAnnotation.typeName.name === 'const') {
112
121
  return true;
113
122
  }
123
+ current = unwrapOnce(current);
114
124
  }
115
125
  return false;
116
126
  }
127
+ function analyzeDeclarator(declaration) {
128
+ const init = declaration.init ?? null;
129
+ const isFunctionOrMutable = isFunctionDefinition(init) || isMutableValue(init);
130
+ return {
131
+ isFunctionOrMutable,
132
+ hasDependencies: !isFunctionOrMutable && init
133
+ ? ASTHelpers_1.ASTHelpers.declarationIncludesIdentifier(init)
134
+ : false,
135
+ hasAsConstAssertion: !isFunctionOrMutable && init ? isAsConstExpression(init) : false,
136
+ hasReportableIdentifier: declaration.id?.type === utils_1.AST_NODE_TYPES.Identifier &&
137
+ !isFunctionOrMutable,
138
+ };
139
+ }
117
140
  exports.extractGlobalConstants = (0, createRule_1.createRule)({
118
141
  create(context) {
119
142
  return {
@@ -121,29 +144,45 @@ exports.extractGlobalConstants = (0, createRule_1.createRule)({
121
144
  if (node.kind !== 'const') {
122
145
  return;
123
146
  }
124
- // Skip if any of the declarations are function definitions or mutable values
125
- if (node.declarations.some((d) => isFunctionDefinition(d.init) || isMutableValue(d.init))) {
147
+ const declarations = node.declarations.filter((declaration) => declaration !== null && declaration !== undefined);
148
+ if (declarations.length === 0) {
149
+ return;
150
+ }
151
+ let hasFunctionOrMutableValue = false;
152
+ let hasDependencies = false;
153
+ let hasAsConstAssertion = false;
154
+ let hasReportableIdentifierDeclaration = false;
155
+ for (const declaration of declarations) {
156
+ const analysis = analyzeDeclarator(declaration);
157
+ if (analysis.isFunctionOrMutable) {
158
+ hasFunctionOrMutableValue = true;
159
+ break;
160
+ }
161
+ hasDependencies ||= analysis.hasDependencies;
162
+ hasAsConstAssertion ||= analysis.hasAsConstAssertion;
163
+ hasReportableIdentifierDeclaration ||=
164
+ analysis.hasReportableIdentifier;
165
+ }
166
+ if (hasFunctionOrMutableValue) {
126
167
  return;
127
168
  }
128
169
  const scope = context.getScope();
129
- const hasDependencies = node.declarations.some((declaration) => declaration.init &&
130
- ASTHelpers_1.ASTHelpers.declarationIncludesIdentifier(declaration.init));
131
- // Skip constants with 'as const' type assertions used in loops
132
- const hasAsConstAssertion = node.declarations.some((declaration) => declaration.init && isAsConstExpression(declaration.init));
133
170
  // Only check function/block scoped constants without dependencies
134
171
  if (!hasDependencies &&
135
172
  !hasAsConstAssertion &&
136
173
  (scope.type === 'function' || scope.type === 'block') &&
137
- isInsideFunction(node)) {
138
- const constName = node.declarations[0].id
139
- .name;
140
- context.report({
141
- node,
142
- messageId: 'extractGlobalConstants',
143
- data: {
144
- declarationName: constName,
145
- },
146
- });
174
+ isInsideFunction(node) &&
175
+ hasReportableIdentifierDeclaration) {
176
+ for (const declaration of declarations) {
177
+ if (declaration.id?.type !== utils_1.AST_NODE_TYPES.Identifier)
178
+ continue;
179
+ const constName = declaration.id.name;
180
+ context.report({
181
+ node: declaration,
182
+ messageId: 'extractGlobalConstants',
183
+ data: { declarationName: constName },
184
+ });
185
+ }
147
186
  }
148
187
  },
149
188
  FunctionDeclaration(node) {
@@ -271,8 +310,8 @@ exports.extractGlobalConstants = (0, createRule_1.createRule)({
271
310
  },
272
311
  schema: [],
273
312
  messages: {
274
- extractGlobalConstants: 'Move this declaration {{ declarationName }} to the global scope and rename it to UPPER_SNAKE_CASE if necessary.',
275
- requireAsConst: 'Numeric literal {{ value }} in loop expression should be extracted to a constant with "as const" type assertion.',
313
+ extractGlobalConstants: 'What\'s wrong: Declaration "{{declarationName}}" does not reference values from this scope.\nWhy it matters: Keeping it nested recreates the same constant/helper on every call, which adds avoidable allocations and obscures that the value can be shared.\nHow to fix: Hoist it to module scope (use UPPER_SNAKE_CASE for immutable constants) so it is created once and can be imported.',
314
+ requireAsConst: 'What\'s wrong: Numeric literal {{value}} is used directly as a loop boundary.\nWhy it matters: Without "as const", TypeScript widens it to number, so if you later extract or reuse the value you lose the literal-type boundary and it is easier for related loops to drift out of sync.\nHow to fix: Extract it to a named constant with "as const" (or add "as const" inline) to keep the boundary explicit and reusable.',
276
315
  },
277
316
  },
278
317
  defaultOptions: [],
@@ -1,3 +1,4 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
1
2
  type MessageIds = 'useFastDeepEqual' | 'addFastDeepEqualImport';
2
- export declare const fastDeepEqualOverMicrodiff: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<MessageIds, [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
3
+ export declare const fastDeepEqualOverMicrodiff: TSESLint.RuleModule<MessageIds, [], TSESLint.RuleListener>;
3
4
  export {};