@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
@@ -13,10 +13,10 @@ exports.enforceCallableTypes = (0, createRule_1.createRule)({
13
13
  },
14
14
  schema: [],
15
15
  messages: {
16
- missingPropsType: 'Missing Props type export in callable function file',
17
- missingResponseType: 'Missing Response type export in callable function file',
18
- unusedPropsType: 'Props type is exported but not used in the callable function',
19
- unusedResponseType: 'Response type is exported but not used in the callable function',
16
+ missingPropsType: 'Callable functions must export a Props type to describe the request payload. Without Props the callable accepts any data and loses compile-time validation; export `type Props = { ... }` and use it in `CallableRequest<Props>` so request.data stays typed.',
17
+ missingResponseType: 'Callable functions must export a Response type to document what the function returns. Without Response the callable can return any shape and break clients; export `type Response = ...` and return that shape from the handler.',
18
+ unusedPropsType: 'Props is exported but never used in the onCall handler. An unused Props type lets the request payload drift from the code that reads it; annotate the handler parameter as `CallableRequest<Props>` or remove Props if the callable does not accept data.',
19
+ unusedResponseType: 'Response is exported but never used in the callable return type. Without applying Response, the callable can return any payload and clients lose a stable contract; return Response (or Promise<Response>) from the handler or remove the unused type.',
20
20
  },
21
21
  },
22
22
  defaultOptions: [],
@@ -19,37 +19,144 @@ exports.default = (0, createRule_1.createRule)({
19
19
  defaultOptions: [],
20
20
  create(context) {
21
21
  function isFunction(node) {
22
- return (node.type === utils_1.TSESTree.AST_NODE_TYPES.ArrowFunctionExpression ||
23
- node.type === utils_1.TSESTree.AST_NODE_TYPES.FunctionExpression);
22
+ return (node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
23
+ node.type === utils_1.AST_NODE_TYPES.FunctionExpression);
24
+ }
25
+ function isInsideUseCallback(node) {
26
+ let current = node.parent;
27
+ while (current) {
28
+ if (current.type === utils_1.AST_NODE_TYPES.CallExpression) {
29
+ const { callee } = current;
30
+ const isDirectUseCallback = callee.type === utils_1.AST_NODE_TYPES.Identifier &&
31
+ callee.name === 'useCallback';
32
+ const isMemberUseCallback = callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
33
+ !callee.computed &&
34
+ callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
35
+ callee.property.name === 'useCallback';
36
+ if (isDirectUseCallback || isMemberUseCallback) {
37
+ return true;
38
+ }
39
+ }
40
+ current = current.parent;
41
+ }
42
+ return false;
43
+ }
44
+ function collectBoundNames(param, out) {
45
+ if (param.type === utils_1.AST_NODE_TYPES.Identifier) {
46
+ out.push(param.name);
47
+ return;
48
+ }
49
+ if (param.type === utils_1.AST_NODE_TYPES.AssignmentPattern) {
50
+ collectBoundNames(param.left, out);
51
+ return;
52
+ }
53
+ if (param.type === utils_1.AST_NODE_TYPES.RestElement) {
54
+ if (param.argument.type === utils_1.AST_NODE_TYPES.Identifier) {
55
+ out.push(param.argument.name);
56
+ }
57
+ return;
58
+ }
59
+ if (param.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
60
+ for (const property of param.properties) {
61
+ if (property.type === utils_1.AST_NODE_TYPES.RestElement) {
62
+ collectBoundNames(property, out);
63
+ continue;
64
+ }
65
+ if (property.type !== utils_1.AST_NODE_TYPES.Property)
66
+ continue;
67
+ collectBoundNames(property.value, out);
68
+ }
69
+ return;
70
+ }
71
+ if (param.type === utils_1.AST_NODE_TYPES.ArrayPattern) {
72
+ for (const element of param.elements) {
73
+ if (element)
74
+ collectBoundNames(element, out);
75
+ }
76
+ }
77
+ }
78
+ function getParentFunctionParams(node) {
79
+ let current = node.parent;
80
+ while (current) {
81
+ if (isFunction(current)) {
82
+ const params = [];
83
+ for (const param of current.params) {
84
+ collectBoundNames(param, params);
85
+ }
86
+ return params;
87
+ }
88
+ current = current.parent;
89
+ }
90
+ return [];
91
+ }
92
+ function referencesParentScopeVariables(functionNode, parentParams) {
93
+ const scopeManager = context.sourceCode.scopeManager;
94
+ if (!scopeManager)
95
+ return false;
96
+ const scope = scopeManager.acquire(functionNode);
97
+ if (!scope)
98
+ return false;
99
+ // "through" holds references that are not resolved within the function scope
100
+ for (const ref of scope.through) {
101
+ const { identifier } = ref;
102
+ const parent = identifier.parent;
103
+ const isPropertyKey = parent &&
104
+ ((parent.type === utils_1.AST_NODE_TYPES.MemberExpression &&
105
+ !parent.computed &&
106
+ parent.property === identifier) ||
107
+ (parent.type === utils_1.AST_NODE_TYPES.Property &&
108
+ parent.key === identifier &&
109
+ parent.kind === 'init'));
110
+ if (isPropertyKey) {
111
+ continue;
112
+ }
113
+ if (parentParams.includes(identifier.name)) {
114
+ return true;
115
+ }
116
+ }
117
+ return false;
24
118
  }
25
119
  function containsFunction(node) {
26
120
  if (isFunction(node)) {
27
121
  return true;
28
122
  }
29
- if (node.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression) {
123
+ if (node.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
30
124
  return node.properties.some((prop) => {
31
- if (prop.type === utils_1.TSESTree.AST_NODE_TYPES.Property &&
32
- 'value' in prop) {
125
+ if (prop.type === utils_1.AST_NODE_TYPES.Property && 'value' in prop) {
33
126
  return containsFunction(prop.value);
34
127
  }
128
+ if (prop.type === utils_1.AST_NODE_TYPES.SpreadElement) {
129
+ return containsFunction(prop.argument);
130
+ }
35
131
  return false;
36
132
  });
37
133
  }
38
- if (node.type === utils_1.TSESTree.AST_NODE_TYPES.ArrayExpression) {
134
+ if (node.type === utils_1.AST_NODE_TYPES.ArrayExpression) {
39
135
  return node.elements.some((element) => element && containsFunction(element));
40
136
  }
137
+ // Check ternary expressions (conditional expressions)
138
+ if (node.type === utils_1.AST_NODE_TYPES.ConditionalExpression) {
139
+ return (containsFunction(node.consequent) || containsFunction(node.alternate));
140
+ }
141
+ // Check logical expressions (&&, ||)
142
+ if (node.type === utils_1.AST_NODE_TYPES.LogicalExpression) {
143
+ return containsFunction(node.left) || containsFunction(node.right);
144
+ }
41
145
  return false;
42
146
  }
43
147
  function hasJSXWithFunction(node) {
44
- if (node.type === utils_1.TSESTree.AST_NODE_TYPES.JSXElement) {
148
+ if (node.type === utils_1.AST_NODE_TYPES.JSXElement) {
45
149
  return node.openingElement.attributes.some((attr) => {
46
- if (attr.type === utils_1.TSESTree.AST_NODE_TYPES.JSXAttribute &&
47
- attr.value) {
48
- if (attr.value.type ===
49
- utils_1.TSESTree.AST_NODE_TYPES.JSXExpressionContainer) {
150
+ if (attr.type === utils_1.AST_NODE_TYPES.JSXAttribute && attr.value) {
151
+ if (attr.value.type === utils_1.AST_NODE_TYPES.JSXExpressionContainer) {
50
152
  return containsFunction(attr.value.expression);
51
153
  }
52
154
  }
155
+ else if (attr.type === utils_1.AST_NODE_TYPES.JSXSpreadAttribute &&
156
+ attr.argument.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
157
+ // Only inspect literal objects to avoid heavy/static-unsafe analysis on identifiers.
158
+ return containsFunction(attr.argument);
159
+ }
53
160
  return false;
54
161
  });
55
162
  }
@@ -57,19 +164,37 @@ exports.default = (0, createRule_1.createRule)({
57
164
  }
58
165
  function checkJSXAttribute(node) {
59
166
  if (!node.value ||
60
- node.value.type !== utils_1.TSESTree.AST_NODE_TYPES.JSXExpressionContainer) {
167
+ node.value.type !== utils_1.AST_NODE_TYPES.JSXExpressionContainer) {
61
168
  return;
62
169
  }
63
170
  const { expression } = node.value;
64
171
  // Skip if the prop is already wrapped in useCallback or useMemo
65
- if (expression.type === utils_1.TSESTree.AST_NODE_TYPES.CallExpression &&
66
- expression.callee.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier &&
172
+ if (expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
173
+ expression.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
67
174
  (expression.callee.name === 'useCallback' ||
68
175
  expression.callee.name === 'useMemo')) {
69
176
  return;
70
177
  }
71
178
  // Check for direct inline functions
72
179
  if (isFunction(expression)) {
180
+ // Skip reporting if this callback is inside a useCallback and references parent scope variables
181
+ const isInUseCallback = isInsideUseCallback(expression);
182
+ const parentParams = getParentFunctionParams(expression);
183
+ const referencesParentVars = referencesParentScopeVariables(expression, parentParams);
184
+ if (isInUseCallback && referencesParentVars) {
185
+ // Skip reporting - this is a nested callback that needs access to parent scope
186
+ return;
187
+ }
188
+ context.report({
189
+ node,
190
+ messageId: 'enforceCallback',
191
+ });
192
+ return;
193
+ }
194
+ // Check for ternary expressions and logical expressions containing functions
195
+ if ((expression.type === utils_1.AST_NODE_TYPES.ConditionalExpression ||
196
+ expression.type === utils_1.AST_NODE_TYPES.LogicalExpression) &&
197
+ containsFunction(expression)) {
73
198
  context.report({
74
199
  node,
75
200
  messageId: 'enforceCallback',
@@ -77,12 +202,12 @@ exports.default = (0, createRule_1.createRule)({
77
202
  return;
78
203
  }
79
204
  // Check for objects/arrays/JSX elements containing functions
80
- if ((expression.type === utils_1.TSESTree.AST_NODE_TYPES.ObjectExpression ||
81
- expression.type === utils_1.TSESTree.AST_NODE_TYPES.ArrayExpression ||
82
- expression.type === utils_1.TSESTree.AST_NODE_TYPES.JSXElement) &&
205
+ if ((expression.type === utils_1.AST_NODE_TYPES.ObjectExpression ||
206
+ expression.type === utils_1.AST_NODE_TYPES.ArrayExpression ||
207
+ expression.type === utils_1.AST_NODE_TYPES.JSXElement) &&
83
208
  (containsFunction(expression) || hasJSXWithFunction(expression))) {
84
209
  // Skip reporting if this is a JSX element and we already reported an inline function
85
- if (expression.type === utils_1.TSESTree.AST_NODE_TYPES.JSXElement &&
210
+ if (expression.type === utils_1.AST_NODE_TYPES.JSXElement &&
86
211
  hasJSXWithFunction(expression)) {
87
212
  return;
88
213
  }
@@ -15,7 +15,7 @@ exports.enforceCentralizedMockFirestore = (0, createRule_1.createRule)({
15
15
  fixable: 'code',
16
16
  schema: [],
17
17
  messages: {
18
- useCentralizedMockFirestore: 'Use the centralized mockFirestore from the predefined location instead of creating a new mock',
18
+ useCentralizedMockFirestore: 'This file defines or re-exports a local mockFirestore instead of importing the shared one from "{{requiredPath}}". Local mocks drift from the canonical behavior and hide API changes across suites. To fix this, import mockFirestore from the centralized test util so fixes happen in one place.',
19
19
  },
20
20
  },
21
21
  defaultOptions: [],
@@ -140,11 +140,14 @@ exports.enforceCentralizedMockFirestore = (0, createRule_1.createRule)({
140
140
  },
141
141
  'Program:exit'() {
142
142
  if (mockFirestoreNodes.size > 0) {
143
- const sourceCode = context.getSourceCode();
143
+ const sourceCode = context.sourceCode;
144
144
  // Report only once for the entire file
145
145
  context.report({
146
146
  node: Array.from(mockFirestoreNodes)[0],
147
147
  messageId: 'useCentralizedMockFirestore',
148
+ data: {
149
+ requiredPath: MOCK_FIRESTORE_PATH,
150
+ },
148
151
  fix(fixer) {
149
152
  // Instead of trying to modify the code incrementally, we'll generate the entire fixed code
150
153
  const originalText = sourceCode.getText();
@@ -0,0 +1,3 @@
1
+ type MessageIds = 'missingConsoleError' | 'missingConsoleWarn' | 'missingConsoleBoth';
2
+ export declare const enforceConsoleError: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<MessageIds, [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
3
+ export {};
@@ -0,0 +1,278 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enforceConsoleError = void 0;
4
+ const createRule_1 = require("../utils/createRule");
5
+ const utils_1 = require("@typescript-eslint/utils");
6
+ exports.enforceConsoleError = (0, createRule_1.createRule)({
7
+ name: 'enforce-console-error',
8
+ meta: {
9
+ type: 'problem',
10
+ docs: {
11
+ description: 'Enforce proper logging for useAlertDialog based on severity. When severity is "error", console.error must be included. When severity is "warning", console.warn must be included. This ensures all user-facing errors and warnings are properly logged to observability systems.',
12
+ recommended: 'error',
13
+ },
14
+ messages: {
15
+ missingConsoleError: 'useAlertDialog call with severity "{{severity}}" shows an error dialog but this function never logs with {{consoleMethod}}. Without the log the alert is invisible to observability and post-incident breadcrumbs. Add a {{consoleMethod}} call in this function scope before or after the open() call so the dialog is paired with an observable error trail.',
16
+ missingConsoleWarn: 'useAlertDialog call with severity "{{severity}}" shows a warning dialog but this function never logs with {{consoleMethod}}. Without the log the warning is invisible to observability, making degraded states hard to diagnose. Add a {{consoleMethod}} call in this function scope before or after the open() call so the dialog is paired with an observable warning trail.',
17
+ missingConsoleBoth: 'useAlertDialog call uses dynamic severity, so runtime may render an error or a warning dialog. It is missing {{missingMethods}} in this function scope, leaving one or more runtime severity branches (error or warning) without observability breadcrumbs: {{missingPaths}}. Branch on the severity value and add the matching console method before or after the open() call (console.error for error branches, console.warn for warning branches), as in the conditional pattern shown in the rule docs, so each branch leaves a single appropriate log trail instead of double-logging both methods.',
18
+ },
19
+ schema: [],
20
+ },
21
+ defaultOptions: [],
22
+ create(context) {
23
+ // Track all open calls and console calls in the entire file
24
+ const openCalls = [];
25
+ const consoleCalls = [];
26
+ let hasUseAlertDialog = false;
27
+ const functionScopeStack = [];
28
+ let currentFunctionScope = null;
29
+ // Track renamed open functions from useAlertDialog destructuring
30
+ const openFunctionNames = new Set();
31
+ // Track aliased useAlertDialog function names
32
+ const useAlertDialogNames = new Set(['useAlertDialog']);
33
+ function isUseAlertDialogCall(node) {
34
+ return (node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
35
+ useAlertDialogNames.has(node.callee.name));
36
+ }
37
+ function isConsoleCall(node, method) {
38
+ return (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
39
+ node.callee.object.type === utils_1.AST_NODE_TYPES.Identifier &&
40
+ node.callee.object.name === 'console' &&
41
+ node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
42
+ node.callee.property.name === method);
43
+ }
44
+ function getSeverityFromObjectExpression(node) {
45
+ for (const prop of node.properties) {
46
+ if (prop.type === utils_1.AST_NODE_TYPES.Property) {
47
+ // Handle both computed and non-computed properties
48
+ let isSeverityProperty = false;
49
+ if (!prop.computed &&
50
+ prop.key.type === utils_1.AST_NODE_TYPES.Identifier &&
51
+ prop.key.name === 'severity') {
52
+ isSeverityProperty = true;
53
+ }
54
+ else if (prop.computed &&
55
+ prop.key.type === utils_1.AST_NODE_TYPES.Literal &&
56
+ prop.key.value === 'severity') {
57
+ isSeverityProperty = true;
58
+ }
59
+ if (isSeverityProperty) {
60
+ if (prop.value.type === utils_1.AST_NODE_TYPES.Literal &&
61
+ typeof prop.value.value === 'string') {
62
+ return prop.value.value;
63
+ }
64
+ // If severity is not a literal, treat as dynamic
65
+ return 'dynamic';
66
+ }
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ const enterFunction = (node) => {
72
+ functionScopeStack.push(node);
73
+ currentFunctionScope = functionScopeStack[functionScopeStack.length - 1];
74
+ };
75
+ const exitFunction = () => {
76
+ functionScopeStack.pop();
77
+ currentFunctionScope =
78
+ functionScopeStack[functionScopeStack.length - 1] ?? null;
79
+ };
80
+ return {
81
+ ImportDeclaration(node) {
82
+ // Track aliased imports of useAlertDialog
83
+ const importPath = String(node.source.value);
84
+ const isAlertDialogImport = importPath === '../useAlertDialog' ||
85
+ importPath === './useAlertDialog' ||
86
+ importPath === 'useAlertDialog' ||
87
+ importPath.endsWith('/useAlertDialog') ||
88
+ importPath.endsWith('/useAlertDialog/index') ||
89
+ importPath === '@/hooks/useAlertDialog' ||
90
+ importPath === 'src/hooks/useAlertDialog';
91
+ if (!isAlertDialogImport)
92
+ return;
93
+ for (const specifier of node.specifiers) {
94
+ // Named imports
95
+ if (specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
96
+ specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
97
+ specifier.imported.name === 'useAlertDialog' &&
98
+ specifier.local.type === utils_1.AST_NODE_TYPES.Identifier) {
99
+ useAlertDialogNames.add(specifier.local.name);
100
+ }
101
+ // Default or namespace imports still imply useAlertDialog is available via the local name
102
+ if (specifier.type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier ||
103
+ specifier.type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier) {
104
+ if (specifier.local.type === utils_1.AST_NODE_TYPES.Identifier) {
105
+ useAlertDialogNames.add(specifier.local.name);
106
+ }
107
+ }
108
+ }
109
+ },
110
+ 'Program:exit'() {
111
+ // Only check if we have useAlertDialog in the file
112
+ if (!hasUseAlertDialog)
113
+ return;
114
+ // Group open calls by their containing function
115
+ const functionGroups = new Map();
116
+ // Group open calls by function
117
+ openCalls.forEach(({ node, severity, functionScope }) => {
118
+ if (!functionGroups.has(functionScope)) {
119
+ functionGroups.set(functionScope, {
120
+ openCalls: [],
121
+ consoleCalls: [],
122
+ });
123
+ }
124
+ functionGroups.get(functionScope).openCalls.push({ node, severity });
125
+ });
126
+ // Group console calls by function
127
+ consoleCalls.forEach(({ node, method, functionScope }) => {
128
+ if (!functionGroups.has(functionScope)) {
129
+ functionGroups.set(functionScope, {
130
+ openCalls: [],
131
+ consoleCalls: [],
132
+ });
133
+ }
134
+ functionGroups
135
+ .get(functionScope)
136
+ .consoleCalls.push({ node, method });
137
+ });
138
+ // Check each function for violations
139
+ functionGroups.forEach((group) => {
140
+ const hasError = group.openCalls.some((call) => call.severity === 'error');
141
+ const hasWarning = group.openCalls.some((call) => call.severity === 'warning');
142
+ const hasDynamic = group.openCalls.some((call) => call.severity === 'dynamic');
143
+ const hasConsoleError = group.consoleCalls.some((call) => call.method === 'error');
144
+ const hasConsoleWarn = group.consoleCalls.some((call) => call.method === 'warn');
145
+ const needsConsoleError = hasError || hasDynamic;
146
+ const needsConsoleWarn = hasWarning || hasDynamic;
147
+ if (hasDynamic && (!hasConsoleError || !hasConsoleWarn)) {
148
+ const missingMethods = [];
149
+ const missingSeverities = [];
150
+ if (!hasConsoleError) {
151
+ missingMethods.push('console.error');
152
+ missingSeverities.push('error');
153
+ }
154
+ if (!hasConsoleWarn) {
155
+ missingMethods.push('console.warn');
156
+ missingSeverities.push('warning');
157
+ }
158
+ const missingMethodsLabel = missingMethods.length === 2
159
+ ? 'console.error and console.warn'
160
+ : missingMethods[0];
161
+ const missingPathsLabel = missingSeverities.length === 2
162
+ ? 'the error and warning severity paths'
163
+ : `the ${missingSeverities[0]} severity path`;
164
+ const dynamicCalls = group.openCalls.filter((call) => call.severity === 'dynamic');
165
+ dynamicCalls.forEach((dynamicCall) => {
166
+ context.report({
167
+ node: dynamicCall.node,
168
+ messageId: 'missingConsoleBoth',
169
+ data: {
170
+ missingMethods: missingMethodsLabel,
171
+ missingPaths: missingPathsLabel,
172
+ },
173
+ });
174
+ });
175
+ }
176
+ else {
177
+ if (needsConsoleError && !hasConsoleError) {
178
+ const errorCall = group.openCalls.find((call) => call.severity === 'error');
179
+ if (errorCall) {
180
+ context.report({
181
+ node: errorCall.node,
182
+ messageId: 'missingConsoleError',
183
+ data: {
184
+ severity: 'error',
185
+ consoleMethod: 'console.error',
186
+ },
187
+ });
188
+ }
189
+ }
190
+ if (needsConsoleWarn && !hasConsoleWarn) {
191
+ const warningCall = group.openCalls.find((call) => call.severity === 'warning');
192
+ if (warningCall) {
193
+ context.report({
194
+ node: warningCall.node,
195
+ messageId: 'missingConsoleWarn',
196
+ data: {
197
+ severity: 'warning',
198
+ consoleMethod: 'console.warn',
199
+ },
200
+ });
201
+ }
202
+ }
203
+ }
204
+ });
205
+ },
206
+ FunctionDeclaration: enterFunction,
207
+ FunctionExpression: enterFunction,
208
+ ArrowFunctionExpression: enterFunction,
209
+ 'FunctionDeclaration:exit': exitFunction,
210
+ 'FunctionExpression:exit': exitFunction,
211
+ 'ArrowFunctionExpression:exit': exitFunction,
212
+ VariableDeclarator(node) {
213
+ // Track destructuring of open functions from useAlertDialog
214
+ if (node.init &&
215
+ node.init.type === utils_1.AST_NODE_TYPES.CallExpression &&
216
+ isUseAlertDialogCall(node.init) &&
217
+ node.id.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
218
+ // Look for destructured open properties
219
+ for (const prop of node.id.properties) {
220
+ if (prop.type === utils_1.AST_NODE_TYPES.Property &&
221
+ prop.key.type === utils_1.AST_NODE_TYPES.Identifier &&
222
+ prop.key.name === 'open') {
223
+ if (prop.value.type === utils_1.AST_NODE_TYPES.Identifier) {
224
+ // Track the renamed function name
225
+ openFunctionNames.add(prop.value.name);
226
+ }
227
+ }
228
+ }
229
+ }
230
+ },
231
+ CallExpression(node) {
232
+ // Track useAlertDialog calls
233
+ if (isUseAlertDialogCall(node)) {
234
+ hasUseAlertDialog = true;
235
+ }
236
+ // Track open method calls (both member expressions and direct calls)
237
+ const isOpenCall = ((node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
238
+ node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
239
+ node.callee.property.name === 'open') ||
240
+ (node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
241
+ (node.callee.name === 'open' ||
242
+ openFunctionNames.has(node.callee.name)))) &&
243
+ node.arguments.length > 0;
244
+ if (isOpenCall) {
245
+ const firstArg = node.arguments[0];
246
+ if (firstArg.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
247
+ const severity = getSeverityFromObjectExpression(firstArg);
248
+ if (severity && currentFunctionScope) {
249
+ openCalls.push({
250
+ node,
251
+ severity,
252
+ functionScope: currentFunctionScope,
253
+ });
254
+ }
255
+ }
256
+ }
257
+ // Track console calls
258
+ if (currentFunctionScope) {
259
+ if (isConsoleCall(node, 'error')) {
260
+ consoleCalls.push({
261
+ node,
262
+ method: 'error',
263
+ functionScope: currentFunctionScope,
264
+ });
265
+ }
266
+ if (isConsoleCall(node, 'warn')) {
267
+ consoleCalls.push({
268
+ node,
269
+ method: 'warn',
270
+ functionScope: currentFunctionScope,
271
+ });
272
+ }
273
+ }
274
+ },
275
+ };
276
+ },
277
+ });
278
+ //# sourceMappingURL=enforce-console-error.js.map
@@ -16,58 +16,39 @@ exports.enforceCssMediaQueries = (0, createRule_1.createRule)({
16
16
  recommended: 'error',
17
17
  },
18
18
  messages: {
19
- enforceCssMediaQueries: 'Use CSS media queries instead of JavaScript breakpoints for responsive design. JavaScript breakpoint handling can cause unnecessary re-renders and impact performance.',
19
+ enforceCssMediaQueries: 'Responsive breakpoint "{{source}}" uses JavaScript media detection. JavaScript breakpoints attach resize listeners inside the render path, causing avoidable re-renders and drifting from the single CSS breakpoint source of truth. Move this breakpoint into CSS (@media or container queries) and drive layout changes through class names or CSS-driven props instead of runtime hooks.',
20
20
  },
21
21
  schema: [],
22
22
  },
23
23
  defaultOptions: [],
24
24
  create(context) {
25
+ const reportUsage = (node, source) => context.report({
26
+ node,
27
+ messageId: 'enforceCssMediaQueries',
28
+ data: { source },
29
+ });
25
30
  return {
26
- // Check for Material-UI's useMediaQuery and react-responsive imports
31
+ // Only react-responsive is handled at the declaration level to avoid duplicates.
27
32
  ImportDeclaration(node) {
28
- // Check for @mui/material useMediaQuery
29
- if (node.source.value === '@mui/material' &&
30
- node.specifiers.some((specifier) => specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
31
- specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
32
- specifier.imported.name === 'useMediaQuery')) {
33
- context.report({
34
- node,
35
- messageId: 'enforceCssMediaQueries',
36
- });
37
- }
38
- // Check for react-responsive imports
39
- if (node.source.value === 'react-responsive' ||
40
- node.source.value.includes('react-responsive/')) {
41
- context.report({
42
- node,
43
- messageId: 'enforceCssMediaQueries',
44
- });
45
- }
46
- // Check for useMobile import from hooks/useMobile
47
- if (node.source.value.includes('hooks/useMobile') &&
48
- node.specifiers.some((specifier) => specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
49
- specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
50
- specifier.imported.name === 'useMobile')) {
51
- context.report({
52
- node,
53
- messageId: 'enforceCssMediaQueries',
54
- });
33
+ if (node.source.value !== 'react-responsive' &&
34
+ !node.source.value.includes('react-responsive/')) {
35
+ return;
55
36
  }
37
+ reportUsage(node, `react-responsive import "${String(node.source.value)}"`);
56
38
  },
57
- // Check for specific import specifiers
39
+ // Handle specific specifiers to avoid duplicate diagnostics.
58
40
  ImportSpecifier(node) {
59
- if (node.parent &&
60
- node.parent.type === utils_1.AST_NODE_TYPES.ImportDeclaration &&
61
- node.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
62
- // Check for useMediaQuery from @mui/material
63
- ((node.parent.source.value === '@mui/material' &&
64
- node.imported.name === 'useMediaQuery') ||
65
- // Check for useMobile from any source
66
- node.imported.name === 'useMobile')) {
67
- context.report({
68
- node,
69
- messageId: 'enforceCssMediaQueries',
70
- });
41
+ if (node.parent?.type === utils_1.AST_NODE_TYPES.ImportDeclaration &&
42
+ node.imported.type === utils_1.AST_NODE_TYPES.Identifier) {
43
+ if (node.parent.source.value === '@mui/material' &&
44
+ node.imported.name === 'useMediaQuery') {
45
+ reportUsage(node, 'useMediaQuery import from @mui/material');
46
+ return;
47
+ }
48
+ if (node.imported.name === 'useMobile') {
49
+ reportUsage(node, `useMobile import from ${String(node.parent.source.value)}`);
50
+ return;
51
+ }
71
52
  }
72
53
  },
73
54
  // Check for useMediaQuery and useMobile calls
@@ -75,10 +56,7 @@ exports.enforceCssMediaQueries = (0, createRule_1.createRule)({
75
56
  if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
76
57
  (node.callee.name === 'useMediaQuery' ||
77
58
  node.callee.name === 'useMobile')) {
78
- context.report({
79
- node,
80
- messageId: 'enforceCssMediaQueries',
81
- });
59
+ reportUsage(node, `${node.callee.name} call`);
82
60
  }
83
61
  },
84
62
  };
@@ -1,3 +1,5 @@
1
1
  export declare const RULE_NAME = "enforce-dynamic-file-naming";
2
+ export declare const REQUIRE_DYNAMIC_FIREBASE_IMPORTS_RULE = "@blumintinc/blumint/require-dynamic-firebase-imports";
3
+ export declare const DYNAMIC_RULES_LABEL: string;
2
4
  declare const _default: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"requireDynamicExtension" | "requireDisableDirective", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
3
5
  export default _default;