@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
@@ -2,58 +2,54 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.noUndefinedNullPassthrough = void 0;
4
4
  const createRule_1 = require("../utils/createRule");
5
+ const utils_1 = require("@typescript-eslint/utils");
5
6
  exports.noUndefinedNullPassthrough = (0, createRule_1.createRule)({
6
7
  create(context) {
7
8
  return {
8
9
  FunctionDeclaration(node) {
9
- // Only apply to functions with exactly one parameter
10
- if (node.params.length !== 1) {
10
+ if (shouldSkipFunction(node)) {
11
11
  return;
12
12
  }
13
- // Skip React hooks (functions starting with 'use')
14
- if (node.id &&
15
- node.id.type === 'Identifier' &&
16
- node.id.name.startsWith('use')) {
17
- return;
13
+ // For functions with exactly one parameter, check if it's passing through null/undefined
14
+ if (node.params.length === 1) {
15
+ checkFunctionBody(node.body, node.params[0], context);
16
+ }
17
+ else {
18
+ // For functions with multiple parameters, check for early returns without arguments
19
+ checkFunctionBodyForEarlyReturns(node.body, node.params, context);
18
20
  }
19
- checkFunctionBody(node.body, node.params[0], context);
20
21
  },
21
22
  ArrowFunctionExpression(node) {
22
- // Only apply to arrow functions with exactly one parameter
23
- if (node.params.length !== 1) {
24
- return;
25
- }
26
- // Skip if the function is part of a variable declaration that starts with 'use' (React hook)
27
- const parent = node.parent;
28
- if (parent &&
29
- parent.type === 'VariableDeclarator' &&
30
- parent.id.type === 'Identifier' &&
31
- parent.id.name.startsWith('use')) {
23
+ if (shouldSkipFunction(node)) {
32
24
  return;
33
25
  }
34
26
  // For arrow functions with block body
35
27
  if (node.body.type === 'BlockStatement') {
36
- checkFunctionBody(node.body, node.params[0], context);
28
+ if (node.params.length === 1) {
29
+ checkFunctionBody(node.body, node.params[0], context);
30
+ }
31
+ else {
32
+ // For functions with multiple parameters, check for early returns without arguments
33
+ checkFunctionBodyForEarlyReturns(node.body, node.params, context);
34
+ }
37
35
  }
38
- else {
39
- // For arrow functions with expression body (implicit return)
36
+ else if (node.params.length === 1) {
37
+ // For arrow functions with expression body (implicit return) and one parameter
40
38
  checkImplicitReturn(node, context);
41
39
  }
42
40
  },
43
41
  FunctionExpression(node) {
44
- // Only apply to functions with exactly one parameter
45
- if (node.params.length !== 1) {
42
+ if (shouldSkipFunction(node)) {
46
43
  return;
47
44
  }
48
- // Skip if the function is part of a variable declaration that starts with 'use' (React hook)
49
- const parent = node.parent;
50
- if (parent &&
51
- parent.type === 'VariableDeclarator' &&
52
- parent.id.type === 'Identifier' &&
53
- parent.id.name.startsWith('use')) {
54
- return;
45
+ // For functions with exactly one parameter, check if it's passing through null/undefined
46
+ if (node.params.length === 1) {
47
+ checkFunctionBody(node.body, node.params[0], context);
48
+ }
49
+ else {
50
+ // For functions with multiple parameters, check for early returns without arguments
51
+ checkFunctionBodyForEarlyReturns(node.body, node.params, context);
55
52
  }
56
- checkFunctionBody(node.body, node.params[0], context);
57
53
  },
58
54
  };
59
55
  },
@@ -66,7 +62,7 @@ exports.noUndefinedNullPassthrough = (0, createRule_1.createRule)({
66
62
  },
67
63
  schema: [],
68
64
  messages: {
69
- unexpected: 'Avoid functions that return undefined or null when their single argument is undefined or null. Move the null/undefined check to the caller instead.',
65
+ unexpected: 'Function returns null or undefined when "{{paramName}}" is nullish, which just passes the missing value to callers. This hides where validation belongs, delays failures until runtime as null values propagate unpredictably, and forces every caller to add defensive branching—making bugs and debugging more likely. Validate the argument before calling (throw an error if it is required) or return a concrete fallback (for example, an empty array or default object) so this function always provides a meaningful result.',
70
66
  },
71
67
  },
72
68
  defaultOptions: [],
@@ -106,6 +102,7 @@ function checkFunctionBody(body, param, context) {
106
102
  context.report({
107
103
  node: statement,
108
104
  messageId: 'unexpected',
105
+ data: { paramName },
109
106
  });
110
107
  }
111
108
  return;
@@ -122,6 +119,7 @@ function checkFunctionBody(body, param, context) {
122
119
  context.report({
123
120
  node: statement,
124
121
  messageId: 'unexpected',
122
+ data: { paramName },
125
123
  });
126
124
  }
127
125
  return;
@@ -136,18 +134,81 @@ function checkFunctionBody(body, param, context) {
136
134
  function checkForTransformation(body, paramName) {
137
135
  if (!paramName)
138
136
  return false;
139
- // Look for return statements that call functions with the parameter
137
+ // Look for return statements or other statements that use the parameter in a transformation
140
138
  for (const statement of body.body) {
141
139
  if (statement.type === 'ReturnStatement' && statement.argument) {
142
- // Check for return transformData(data) pattern
143
- if (statement.argument.type === 'CallExpression' &&
144
- statement.argument.arguments.some(arg => arg.type === 'Identifier' && arg.name === paramName)) {
140
+ // Check for various transformation patterns
141
+ if (containsParameterTransformation(statement.argument, paramName)) {
142
+ return true;
143
+ }
144
+ }
145
+ // Check for other statements that might contain transformations (like for loops with yield)
146
+ if (statement.type === 'ForStatement' ||
147
+ statement.type === 'ForInStatement' ||
148
+ statement.type === 'ForOfStatement') {
149
+ if (containsTransformationInStatement(statement, paramName)) {
145
150
  return true;
146
151
  }
147
152
  }
148
153
  }
149
154
  return false;
150
155
  }
156
+ /**
157
+ * Check if a statement contains a transformation of the parameter
158
+ */
159
+ function containsTransformationInStatement(statement,
160
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
161
+ _paramName) {
162
+ // For generator functions, check if there are yield expressions with external function calls
163
+ if (statement.type === 'ForOfStatement' &&
164
+ statement.body.type === 'BlockStatement') {
165
+ for (const stmt of statement.body.body) {
166
+ if (stmt.type === 'ExpressionStatement' &&
167
+ stmt.expression.type === 'YieldExpression' &&
168
+ stmt.expression.argument &&
169
+ stmt.expression.argument.type === 'CallExpression' &&
170
+ stmt.expression.argument.callee.type === 'Identifier') {
171
+ return true;
172
+ }
173
+ }
174
+ }
175
+ return false;
176
+ }
177
+ /**
178
+ * Check if an expression contains a transformation of the parameter
179
+ * A transformation is considered to be calling external functions with the parameter,
180
+ * not just calling methods on the parameter itself.
181
+ */
182
+ function containsParameterTransformation(node, paramName) {
183
+ // Check for direct function calls with the parameter: transformData(data)
184
+ // This is considered a transformation because it's calling an external function
185
+ if (node.type === 'CallExpression' &&
186
+ node.callee.type === 'Identifier' && // External function call
187
+ node.arguments.some((arg) => arg.type === 'Identifier' && arg.name === paramName)) {
188
+ return true;
189
+ }
190
+ // Check for Object.* method calls: Object.keys(data), Object.values(data), Object.entries(data)
191
+ if (node.type === 'CallExpression' &&
192
+ node.callee.type === 'MemberExpression' &&
193
+ node.callee.object.type === 'Identifier' &&
194
+ node.callee.object.name === 'Object' &&
195
+ node.arguments.some((arg) => arg.type === 'Identifier' && arg.name === paramName)) {
196
+ return true;
197
+ }
198
+ // Check for chained operations that start with external functions: Object.entries(rounds).reduce(...).sort(...)
199
+ if (node.type === 'CallExpression' &&
200
+ node.callee.type === 'MemberExpression' &&
201
+ node.callee.object.type === 'CallExpression' &&
202
+ node.callee.object.callee.type === 'MemberExpression' &&
203
+ node.callee.object.callee.object.type === 'Identifier' &&
204
+ node.callee.object.callee.object.name === 'Object' &&
205
+ node.callee.object.arguments.some((arg) => arg.type === 'Identifier' && arg.name === paramName)) {
206
+ return true;
207
+ }
208
+ // Method calls on the parameter itself (like data.process(), items.filter())
209
+ // are NOT considered transformations for the purpose of this rule
210
+ return false;
211
+ }
151
212
  /**
152
213
  * Check arrow functions with expression bodies (implicit returns)
153
214
  */
@@ -171,6 +232,7 @@ function checkImplicitReturn(node, context) {
171
232
  context.report({
172
233
  node,
173
234
  messageId: 'unexpected',
235
+ data: { paramName },
174
236
  });
175
237
  }
176
238
  }
@@ -181,6 +243,7 @@ function checkImplicitReturn(node, context) {
181
243
  context.report({
182
244
  node,
183
245
  messageId: 'unexpected',
246
+ data: { paramName },
184
247
  });
185
248
  }
186
249
  }
@@ -189,6 +252,7 @@ function checkImplicitReturn(node, context) {
189
252
  context.report({
190
253
  node,
191
254
  messageId: 'unexpected',
255
+ data: { paramName },
192
256
  });
193
257
  }
194
258
  }
@@ -205,8 +269,10 @@ function isNullUndefinedCheck(node, paramName) {
205
269
  }
206
270
  // Check for param === null, param === undefined, etc.
207
271
  if (node.type === 'BinaryExpression' &&
208
- (node.operator === '===' || node.operator === '==' ||
209
- node.operator === '!==' || node.operator === '!=')) {
272
+ (node.operator === '===' ||
273
+ node.operator === '==' ||
274
+ node.operator === '!==' ||
275
+ node.operator === '!=')) {
210
276
  const left = node.left;
211
277
  const right = node.right;
212
278
  // param === null/undefined
@@ -224,8 +290,7 @@ function isNullUndefinedCheck(node, paramName) {
224
290
  }
225
291
  }
226
292
  // Check for param === null || param === undefined
227
- if (node.type === 'LogicalExpression' &&
228
- node.operator === '||') {
293
+ if (node.type === 'LogicalExpression' && node.operator === '||') {
229
294
  return (isNullUndefinedCheck(node.left, paramName) ||
230
295
  isNullUndefinedCheck(node.right, paramName));
231
296
  }
@@ -251,4 +316,116 @@ function isParameterReference(node, paramName) {
251
316
  return false;
252
317
  return node.type === 'Identifier' && node.name === paramName;
253
318
  }
319
+ /**
320
+ * Check function body for early returns without arguments (implicit undefined)
321
+ * based on parameter null/undefined checks
322
+ */
323
+ function checkFunctionBodyForEarlyReturns(body, params, context) {
324
+ // Get parameter names
325
+ const paramNames = params
326
+ .map((param) => {
327
+ if (param.type === 'Identifier') {
328
+ return param.name;
329
+ }
330
+ else if (param.type === 'AssignmentPattern' &&
331
+ param.left.type === 'Identifier') {
332
+ return param.left.name;
333
+ }
334
+ return null;
335
+ })
336
+ .filter((name) => name !== null);
337
+ if (paramNames.length === 0)
338
+ return;
339
+ // Look for early returns without arguments based on parameter checks
340
+ for (const statement of body.body) {
341
+ if (statement.type === 'IfStatement') {
342
+ const test = statement.test;
343
+ // Check if the test is checking any parameter for null/undefined
344
+ const matchedParam = paramNames.find((paramName) => isNullUndefinedCheck(test, paramName));
345
+ if (matchedParam) {
346
+ // Check if the consequent is a block statement with a return
347
+ if (statement.consequent.type === 'BlockStatement') {
348
+ for (const consequentStmt of statement.consequent.body) {
349
+ if (consequentStmt.type === 'ReturnStatement' &&
350
+ (!consequentStmt.argument ||
351
+ isNullOrUndefinedLiteral(consequentStmt.argument))) {
352
+ // Check if there's a transformation in the function
353
+ const hasTransformation = paramNames.some((paramName) => checkForTransformation(body, paramName));
354
+ if (!hasTransformation) {
355
+ context.report({
356
+ node: statement,
357
+ messageId: 'unexpected',
358
+ data: { paramName: matchedParam },
359
+ });
360
+ }
361
+ return;
362
+ }
363
+ }
364
+ }
365
+ // Check if the consequent is a direct return statement without an argument
366
+ else if (statement.consequent.type === 'ReturnStatement' &&
367
+ (!statement.consequent.argument ||
368
+ isNullOrUndefinedLiteral(statement.consequent.argument))) {
369
+ // Check if there's a transformation in the function
370
+ const hasTransformation = paramNames.some((paramName) => checkForTransformation(body, paramName));
371
+ if (!hasTransformation) {
372
+ context.report({
373
+ node: statement,
374
+ messageId: 'unexpected',
375
+ data: { paramName: matchedParam },
376
+ });
377
+ }
378
+ return;
379
+ }
380
+ }
381
+ }
382
+ }
383
+ }
384
+ function shouldSkipFunction(node) {
385
+ // Skip functions with no parameters
386
+ if (node.params.length === 0) {
387
+ return true;
388
+ }
389
+ // Skip functions with any parameter typed as 'unknown'
390
+ if (node.params.some(isUnknownParameter)) {
391
+ return true;
392
+ }
393
+ // Skip React hooks (functions starting with 'use')
394
+ let name;
395
+ if (node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration) {
396
+ name = node.id?.name;
397
+ }
398
+ else {
399
+ const parent = node.parent;
400
+ if (parent &&
401
+ parent.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
402
+ parent.id.type === utils_1.AST_NODE_TYPES.Identifier) {
403
+ name = parent.id.name;
404
+ }
405
+ }
406
+ if (name?.startsWith('use')) {
407
+ return true;
408
+ }
409
+ return false;
410
+ }
411
+ /**
412
+ * Exempts type-narrowing functions from the rule by checking for 'unknown' parameters.
413
+ * These functions often narrow from 'unknown' and return null/undefined for invalid types,
414
+ * which is a valid pattern.
415
+ *
416
+ * TODO: Handle edge cases like rest parameters (...args: unknown[]),
417
+ * destructured parameters ({ x }: unknown), and array patterns ([a]: unknown).
418
+ */
419
+ function isUnknownParameter(param) {
420
+ if (param.type === utils_1.AST_NODE_TYPES.Identifier) {
421
+ return (param.typeAnnotation?.typeAnnotation.type ===
422
+ utils_1.AST_NODE_TYPES.TSUnknownKeyword);
423
+ }
424
+ if (param.type === utils_1.AST_NODE_TYPES.AssignmentPattern &&
425
+ param.left.type === utils_1.AST_NODE_TYPES.Identifier) {
426
+ return (param.left.typeAnnotation?.typeAnnotation.type ===
427
+ utils_1.AST_NODE_TYPES.TSUnknownKeyword);
428
+ }
429
+ return false;
430
+ }
254
431
  //# sourceMappingURL=no-undefined-null-passthrough.js.map
@@ -0,0 +1,8 @@
1
+ type Options = [
2
+ {
3
+ ignoreHooks?: string[];
4
+ ignoreHocs?: string[];
5
+ }
6
+ ];
7
+ export declare const noUnmemoizedMemoWithoutProps: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"unnecessaryMemoWithoutProps", Options, import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
8
+ export {};