@blumintinc/eslint-plugin-blumint 1.12.6 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/README.md +171 -99
  2. package/lib/index.js +300 -17
  3. package/lib/rules/array-methods-this-context.js +20 -2
  4. package/lib/rules/avoid-utils-directory.js +11 -2
  5. package/lib/rules/class-methods-read-top-to-bottom.js +24 -5
  6. package/lib/rules/consistent-callback-naming.js +1 -1
  7. package/lib/rules/dynamic-https-errors.d.ts +3 -1
  8. package/lib/rules/dynamic-https-errors.js +48 -11
  9. package/lib/rules/enforce-assert-safe-object-key.d.ts +8 -0
  10. package/lib/rules/{enforce-assertSafe-object-key.js → enforce-assert-safe-object-key.js} +52 -96
  11. package/lib/rules/enforce-assert-throws.d.ts +3 -1
  12. package/lib/rules/enforce-assert-throws.js +493 -51
  13. package/lib/rules/enforce-boolean-naming-prefixes.d.ts +3 -1
  14. package/lib/rules/enforce-boolean-naming-prefixes.js +820 -39
  15. package/lib/rules/enforce-callable-types.js +4 -4
  16. package/lib/rules/enforce-callback-memo.js +143 -18
  17. package/lib/rules/enforce-centralized-mock-firestore.js +5 -2
  18. package/lib/rules/enforce-console-error.d.ts +3 -0
  19. package/lib/rules/enforce-console-error.js +278 -0
  20. package/lib/rules/enforce-css-media-queries.js +24 -46
  21. package/lib/rules/enforce-dynamic-file-naming.d.ts +2 -0
  22. package/lib/rules/enforce-dynamic-file-naming.js +53 -28
  23. package/lib/rules/enforce-dynamic-firebase-imports.js +100 -19
  24. package/lib/rules/enforce-dynamic-imports.js +1 -1
  25. package/lib/rules/enforce-early-destructuring.d.ts +2 -0
  26. package/lib/rules/enforce-early-destructuring.js +980 -0
  27. package/lib/rules/enforce-empty-object-check.d.ts +11 -0
  28. package/lib/rules/enforce-empty-object-check.js +502 -0
  29. package/lib/rules/enforce-exported-function-types.js +4 -4
  30. package/lib/rules/enforce-fieldpath-syntax-in-docsetter.d.ts +2 -0
  31. package/lib/rules/enforce-fieldpath-syntax-in-docsetter.js +262 -0
  32. package/lib/rules/enforce-firestore-doc-ref-generic.js +350 -3
  33. package/lib/rules/enforce-firestore-facade.js +349 -157
  34. package/lib/rules/enforce-firestore-rules-get-access.d.ts +3 -0
  35. package/lib/rules/enforce-firestore-rules-get-access.js +109 -0
  36. package/lib/rules/enforce-firestore-set-merge.js +3 -4
  37. package/lib/rules/enforce-global-constants.d.ts +4 -1
  38. package/lib/rules/enforce-global-constants.js +240 -12
  39. package/lib/rules/enforce-identifiable-firestore-type.js +108 -58
  40. package/lib/rules/enforce-memoize-async.d.ts +2 -1
  41. package/lib/rules/enforce-memoize-async.js +92 -27
  42. package/lib/rules/enforce-memoize-getters.d.ts +3 -0
  43. package/lib/rules/enforce-memoize-getters.js +147 -0
  44. package/lib/rules/enforce-microdiff.js +3 -2
  45. package/lib/rules/enforce-object-literal-as-const.js +4 -4
  46. package/lib/rules/enforce-positive-naming.js +9 -7
  47. package/lib/rules/enforce-props-argument-name.d.ts +2 -7
  48. package/lib/rules/enforce-props-argument-name.js +165 -151
  49. package/lib/rules/enforce-props-naming-consistency.d.ts +2 -0
  50. package/lib/rules/enforce-props-naming-consistency.js +145 -0
  51. package/lib/rules/enforce-querykey-ts.d.ts +9 -0
  52. package/lib/rules/enforce-querykey-ts.js +274 -0
  53. package/lib/rules/enforce-safe-stringify.js +1 -1
  54. package/lib/rules/enforce-serializable-params.js +3 -3
  55. package/lib/rules/enforce-singular-type-names.js +10 -6
  56. package/lib/rules/enforce-stable-hash-spread-props.d.ts +13 -0
  57. package/lib/rules/enforce-stable-hash-spread-props.js +342 -0
  58. package/lib/rules/enforce-storage-context.d.ts +9 -0
  59. package/lib/rules/enforce-storage-context.js +646 -0
  60. package/lib/rules/enforce-timestamp-now.js +23 -7
  61. package/lib/rules/enforce-transform-memoization.d.ts +4 -0
  62. package/lib/rules/enforce-transform-memoization.js +416 -0
  63. package/lib/rules/enforce-typescript-markdown-code-blocks.d.ts +1 -0
  64. package/lib/rules/enforce-typescript-markdown-code-blocks.js +100 -0
  65. package/lib/rules/enforce-unique-cursor-headers.d.ts +16 -0
  66. package/lib/rules/enforce-unique-cursor-headers.js +365 -0
  67. package/lib/rules/enforce-verb-noun-naming.js +90 -14
  68. package/lib/rules/ensure-pointer-events-none.js +28 -2
  69. package/lib/rules/export-if-in-doubt.js +27 -4
  70. package/lib/rules/extract-global-constants.js +92 -53
  71. package/lib/rules/fast-deep-equal-over-microdiff.d.ts +2 -1
  72. package/lib/rules/fast-deep-equal-over-microdiff.js +351 -83
  73. package/lib/rules/firestore-transaction-reads-before-writes.d.ts +1 -0
  74. package/lib/rules/firestore-transaction-reads-before-writes.js +277 -0
  75. package/lib/rules/flatten-push-calls.d.ts +2 -0
  76. package/lib/rules/flatten-push-calls.js +428 -0
  77. package/lib/rules/generic-starts-with-t.js +8 -2
  78. package/lib/rules/global-const-style.js +50 -19
  79. package/lib/rules/jsdoc-above-field.d.ts +11 -0
  80. package/lib/rules/jsdoc-above-field.js +208 -0
  81. package/lib/rules/key-only-outermost-element.js +21 -3
  82. package/lib/rules/logical-top-to-bottom-grouping.d.ts +5 -0
  83. package/lib/rules/logical-top-to-bottom-grouping.js +1258 -0
  84. package/lib/rules/memo-compare-deeply-complex-props.d.ts +3 -0
  85. package/lib/rules/memo-compare-deeply-complex-props.js +788 -0
  86. package/lib/rules/memo-nested-react-components.d.ts +8 -0
  87. package/lib/rules/memo-nested-react-components.js +410 -0
  88. package/lib/rules/memoize-root-level-hocs.d.ts +7 -0
  89. package/lib/rules/memoize-root-level-hocs.js +242 -0
  90. package/lib/rules/no-always-true-false-conditions.d.ts +2 -1
  91. package/lib/rules/no-always-true-false-conditions.js +68 -8
  92. package/lib/rules/no-array-length-in-deps.d.ts +12 -0
  93. package/lib/rules/no-array-length-in-deps.js +314 -0
  94. package/lib/rules/no-async-array-filter.js +5 -2
  95. package/lib/rules/no-async-foreach.js +210 -12
  96. package/lib/rules/no-circular-references.js +18 -17
  97. package/lib/rules/no-class-instance-destructuring.js +55 -12
  98. package/lib/rules/no-complex-cloud-params.js +22 -5
  99. package/lib/rules/no-compositing-layer-props.js +6 -4
  100. package/lib/rules/no-conditional-literals-in-jsx.js +37 -12
  101. package/lib/rules/no-console-error.d.ts +9 -0
  102. package/lib/rules/no-console-error.js +525 -0
  103. package/lib/rules/no-curly-brackets-around-commented-properties.d.ts +2 -0
  104. package/lib/rules/no-curly-brackets-around-commented-properties.js +258 -0
  105. package/lib/rules/no-empty-dependency-use-callbacks.d.ts +11 -0
  106. package/lib/rules/no-empty-dependency-use-callbacks.js +576 -0
  107. package/lib/rules/no-entire-object-hook-deps.d.ts +3 -1
  108. package/lib/rules/no-entire-object-hook-deps.js +320 -68
  109. package/lib/rules/no-excessive-parent-chain.d.ts +5 -0
  110. package/lib/rules/no-excessive-parent-chain.js +273 -0
  111. package/lib/rules/no-explicit-return-type.d.ts +2 -1
  112. package/lib/rules/no-explicit-return-type.js +215 -26
  113. package/lib/rules/no-filter-without-return.js +5 -1
  114. package/lib/rules/no-firestore-jest-mock.d.ts +2 -1
  115. package/lib/rules/no-firestore-jest-mock.js +126 -8
  116. package/lib/rules/no-firestore-object-arrays.js +398 -28
  117. package/lib/rules/no-handler-suffix.d.ts +12 -0
  118. package/lib/rules/no-handler-suffix.js +305 -0
  119. package/lib/rules/no-hungarian.js +14 -14
  120. package/lib/rules/no-inline-component-prop.d.ts +10 -0
  121. package/lib/rules/no-inline-component-prop.js +456 -0
  122. package/lib/rules/no-jsx-in-hooks.js +6 -1
  123. package/lib/rules/no-jsx-whitespace-literal.js +8 -2
  124. package/lib/rules/no-margin-properties.d.ts +7 -1
  125. package/lib/rules/no-margin-properties.js +22 -9
  126. package/lib/rules/no-memoize-on-static.js +9 -1
  127. package/lib/rules/no-misleading-boolean-prefixes.d.ts +7 -0
  128. package/lib/rules/no-misleading-boolean-prefixes.js +331 -0
  129. package/lib/rules/no-misused-switch-case.js +22 -1
  130. package/lib/rules/no-mixed-firestore-transactions.d.ts +3 -1
  131. package/lib/rules/no-mixed-firestore-transactions.js +296 -34
  132. package/lib/rules/no-mock-firebase-admin.js +5 -2
  133. package/lib/rules/no-object-values-on-strings.js +10 -2
  134. package/lib/rules/no-overridable-method-calls-in-constructor.d.ts +1 -0
  135. package/lib/rules/no-overridable-method-calls-in-constructor.js +272 -0
  136. package/lib/rules/no-passthrough-getters.d.ts +4 -0
  137. package/lib/rules/no-passthrough-getters.js +206 -0
  138. package/lib/rules/no-redundant-annotation-assertion.d.ts +2 -0
  139. package/lib/rules/no-redundant-annotation-assertion.js +402 -0
  140. package/lib/rules/no-redundant-param-types.js +16 -6
  141. package/lib/rules/no-redundant-this-params.d.ts +3 -0
  142. package/lib/rules/no-redundant-this-params.js +459 -0
  143. package/lib/rules/no-redundant-usecallback-wrapper.d.ts +8 -0
  144. package/lib/rules/no-redundant-usecallback-wrapper.js +328 -0
  145. package/lib/rules/no-res-error-status-in-onrequest.d.ts +4 -0
  146. package/lib/rules/no-res-error-status-in-onrequest.js +521 -0
  147. package/lib/rules/no-restricted-properties-fix.d.ts +12 -0
  148. package/lib/rules/no-restricted-properties-fix.js +173 -0
  149. package/lib/rules/no-separate-loading-state.d.ts +8 -0
  150. package/lib/rules/no-separate-loading-state.js +133 -0
  151. package/lib/rules/no-stale-state-across-await.d.ts +1 -0
  152. package/lib/rules/no-stale-state-across-await.js +185 -0
  153. package/lib/rules/no-static-constants-in-dynamic-files.d.ts +3 -0
  154. package/lib/rules/no-static-constants-in-dynamic-files.js +149 -0
  155. package/lib/rules/no-try-catch-already-exists-in-transaction.d.ts +1 -0
  156. package/lib/rules/no-try-catch-already-exists-in-transaction.js +342 -0
  157. package/lib/rules/no-type-assertion-returns.js +49 -49
  158. package/lib/rules/no-undefined-null-passthrough.js +217 -40
  159. package/lib/rules/no-unmemoized-memo-without-props.d.ts +8 -0
  160. package/lib/rules/no-unmemoized-memo-without-props.js +426 -0
  161. package/lib/rules/no-unnecessary-destructuring-rename.d.ts +2 -0
  162. package/lib/rules/no-unnecessary-destructuring-rename.js +347 -0
  163. package/lib/rules/no-unnecessary-destructuring.js +14 -4
  164. package/lib/rules/no-unnecessary-verb-suffix.js +2 -3
  165. package/lib/rules/no-unpinned-dependencies.js +36 -5
  166. package/lib/rules/no-unsafe-firestore-spread.js +8 -5
  167. package/lib/rules/no-unused-props.d.ts +5 -2
  168. package/lib/rules/no-unused-props.js +451 -112
  169. package/lib/rules/no-unused-usestate.js +6 -2
  170. package/lib/rules/no-useless-fragment.js +28 -2
  171. package/lib/rules/no-useless-usememo-primitives.d.ts +9 -0
  172. package/lib/rules/no-useless-usememo-primitives.js +393 -0
  173. package/lib/rules/no-usememo-for-pass-by-value.d.ts +13 -0
  174. package/lib/rules/no-usememo-for-pass-by-value.js +757 -0
  175. package/lib/rules/no-uuidv4-base62-as-key.js +18 -13
  176. package/lib/rules/omit-index-html.d.ts +2 -1
  177. package/lib/rules/omit-index-html.js +62 -7
  178. package/lib/rules/optimize-object-boolean-conditions.d.ts +1 -0
  179. package/lib/rules/optimize-object-boolean-conditions.js +236 -0
  180. package/lib/rules/parallelize-async-operations.d.ts +8 -0
  181. package/lib/rules/parallelize-async-operations.js +394 -0
  182. package/lib/rules/prefer-batch-operations.d.ts +1 -3
  183. package/lib/rules/prefer-batch-operations.js +228 -35
  184. package/lib/rules/prefer-block-comments-for-declarations.js +22 -7
  185. package/lib/rules/prefer-clone-deep.js +3 -3
  186. package/lib/rules/prefer-destructuring-no-class.d.ts +2 -1
  187. package/lib/rules/prefer-destructuring-no-class.js +244 -59
  188. package/lib/rules/prefer-docsetter-setall.d.ts +2 -0
  189. package/lib/rules/prefer-docsetter-setall.js +243 -0
  190. package/lib/rules/prefer-document-flattening.d.ts +4 -0
  191. package/lib/rules/prefer-document-flattening.js +239 -0
  192. package/lib/rules/prefer-field-paths-in-transforms.d.ts +7 -0
  193. package/lib/rules/prefer-field-paths-in-transforms.js +251 -0
  194. package/lib/rules/prefer-fragment-component.js +4 -4
  195. package/lib/rules/prefer-fragment-shorthand.js +2 -1
  196. package/lib/rules/prefer-getter-over-parameterless-method.d.ts +13 -0
  197. package/lib/rules/prefer-getter-over-parameterless-method.js +648 -0
  198. package/lib/rules/prefer-global-router-state-key.d.ts +7 -3
  199. package/lib/rules/prefer-global-router-state-key.js +305 -31
  200. package/lib/rules/prefer-memoized-props.d.ts +3 -0
  201. package/lib/rules/prefer-memoized-props.js +445 -0
  202. package/lib/rules/prefer-next-dynamic.d.ts +9 -0
  203. package/lib/rules/prefer-next-dynamic.js +357 -0
  204. package/lib/rules/prefer-nullish-coalescing-boolean-props.d.ts +1 -0
  205. package/lib/rules/prefer-nullish-coalescing-boolean-props.js +435 -0
  206. package/lib/rules/prefer-nullish-coalescing-override.d.ts +7 -0
  207. package/lib/rules/prefer-nullish-coalescing-override.js +188 -0
  208. package/lib/rules/prefer-params-over-parent-id.d.ts +5 -0
  209. package/lib/rules/prefer-params-over-parent-id.js +277 -0
  210. package/lib/rules/prefer-settings-object.js +23 -15
  211. package/lib/rules/prefer-type-alias-over-typeof-constant.d.ts +3 -0
  212. package/lib/rules/prefer-type-alias-over-typeof-constant.js +259 -0
  213. package/lib/rules/prefer-type-over-interface.js +7 -2
  214. package/lib/rules/prefer-url-tostring-over-tojson.d.ts +2 -0
  215. package/lib/rules/prefer-url-tostring-over-tojson.js +169 -0
  216. package/lib/rules/prefer-use-deep-compare-memo.d.ts +4 -0
  217. package/lib/rules/prefer-use-deep-compare-memo.js +431 -0
  218. package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +25 -2
  219. package/lib/rules/prefer-usememo-over-useeffect-usestate.js +24 -5
  220. package/lib/rules/prefer-utility-function-over-private-static.js +34 -2
  221. package/lib/rules/prevent-children-clobber.d.ts +2 -0
  222. package/lib/rules/prevent-children-clobber.js +536 -0
  223. package/lib/rules/react-memoize-literals.d.ts +4 -0
  224. package/lib/rules/react-memoize-literals.js +495 -0
  225. package/lib/rules/react-usememo-should-be-component.d.ts +2 -1
  226. package/lib/rules/react-usememo-should-be-component.js +144 -78
  227. package/lib/rules/require-dynamic-firebase-imports.js +2 -1
  228. package/lib/rules/require-hooks-default-params.js +17 -16
  229. package/lib/rules/require-https-error-cause.d.ts +4 -0
  230. package/lib/rules/require-https-error-cause.js +136 -0
  231. package/lib/rules/require-https-error.js +43 -21
  232. package/lib/rules/require-image-optimized.js +2 -2
  233. package/lib/rules/require-memo.js +12 -2
  234. package/lib/rules/require-memoize-jsx-returners.d.ts +3 -0
  235. package/lib/rules/require-memoize-jsx-returners.js +485 -0
  236. package/lib/rules/require-usememo-object-literals.js +9 -4
  237. package/lib/rules/semantic-function-prefixes.js +38 -18
  238. package/lib/rules/sync-onwrite-name-func.js +5 -1
  239. package/lib/rules/test-file-location-enforcement.d.ts +1 -0
  240. package/lib/rules/test-file-location-enforcement.js +57 -0
  241. package/lib/rules/use-custom-link.js +6 -1
  242. package/lib/rules/use-custom-router.js +6 -1
  243. package/lib/rules/use-latest-callback.d.ts +3 -0
  244. package/lib/rules/use-latest-callback.js +271 -0
  245. package/lib/rules/vertically-group-related-functions.d.ts +16 -0
  246. package/lib/rules/vertically-group-related-functions.js +480 -0
  247. package/lib/utils/ASTHelpers.d.ts +13 -1
  248. package/lib/utils/ASTHelpers.js +34 -0
  249. package/lib/utils/createRule.js +1 -1
  250. package/lib/utils/getMethodName.d.ts +27 -0
  251. package/lib/utils/getMethodName.js +35 -0
  252. package/lib/utils/graph/ClassGraphSorterReadability.js +1 -1
  253. package/lib/utils/ruleTester.d.ts +1 -0
  254. package/lib/utils/ruleTester.js +4 -1
  255. package/lib/utils/tsTypeClassifier.d.ts +30 -0
  256. package/lib/utils/tsTypeClassifier.js +149 -0
  257. package/package.json +23 -14
  258. package/lib/rules/enforce-assertSafe-object-key.d.ts +0 -2
@@ -0,0 +1,331 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noMisleadingBooleanPrefixes = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const createRule_1 = require("../utils/createRule");
6
+ const DEFAULT_PREFIXES = ['is', 'has', 'should'];
7
+ function unwrapTypeNode(node) {
8
+ let current = node;
9
+ while (current.type === 'TSParenthesizedType' &&
10
+ current.typeAnnotation) {
11
+ current = current.typeAnnotation;
12
+ }
13
+ return current;
14
+ }
15
+ function isUppercaseLetter(char) {
16
+ return char >= 'A' && char <= 'Z';
17
+ }
18
+ function isDigit(char) {
19
+ return char >= '0' && char <= '9';
20
+ }
21
+ function startsWithBooleanPrefix(name, prefixes) {
22
+ if (!name)
23
+ return false;
24
+ const lower = name.toLowerCase();
25
+ for (const prefix of prefixes) {
26
+ const p = prefix.toLowerCase();
27
+ if (lower.startsWith(p)) {
28
+ if (name.length === p.length)
29
+ return true; // edge: exact match like "is"
30
+ const next = name[p.length];
31
+ if (isUppercaseLetter(next) || next === '_' || isDigit(next)) {
32
+ return true;
33
+ }
34
+ }
35
+ }
36
+ return false;
37
+ }
38
+ function isTsBooleanLike(typeNode) {
39
+ if (!typeNode)
40
+ return false;
41
+ typeNode = unwrapTypeNode(typeNode);
42
+ if (typeNode.type === utils_1.AST_NODE_TYPES.TSBooleanKeyword)
43
+ return true;
44
+ if (typeNode.type === utils_1.AST_NODE_TYPES.TSLiteralType &&
45
+ typeof typeNode.literal.value === 'boolean') {
46
+ return true;
47
+ }
48
+ const isBooleanishUnionMember = (t) => {
49
+ const unwrapped = unwrapTypeNode(t);
50
+ return (unwrapped.type === utils_1.AST_NODE_TYPES.TSBooleanKeyword ||
51
+ (unwrapped.type === utils_1.AST_NODE_TYPES.TSLiteralType &&
52
+ typeof unwrapped.literal.value ===
53
+ 'boolean') ||
54
+ unwrapped.type === utils_1.AST_NODE_TYPES.TSUndefinedKeyword ||
55
+ unwrapped.type === utils_1.AST_NODE_TYPES.TSNullKeyword ||
56
+ unwrapped.type === utils_1.AST_NODE_TYPES.TSVoidKeyword);
57
+ };
58
+ // Allow unions like boolean | undefined | null | void
59
+ if (typeNode.type === utils_1.AST_NODE_TYPES.TSUnionType) {
60
+ return typeNode.types.every((t) => isBooleanishUnionMember(t));
61
+ }
62
+ // Promise<boolean> (or Promise<boolean | undefined | null>)
63
+ if (typeNode.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
64
+ typeNode.typeName.type === utils_1.AST_NODE_TYPES.Identifier &&
65
+ typeNode.typeName.name === 'Promise' &&
66
+ typeNode.typeParameters?.params?.length) {
67
+ const inner = typeNode.typeParameters.params[0];
68
+ if (!inner)
69
+ return false;
70
+ const resolvedInner = unwrapTypeNode(inner);
71
+ if (isBooleanishUnionMember(resolvedInner))
72
+ return true;
73
+ const innerType = resolvedInner;
74
+ if (innerType.type === utils_1.AST_NODE_TYPES.TSUnionType &&
75
+ Array.isArray(innerType.types) &&
76
+ innerType.types.every((t) => isBooleanishUnionMember(t))) {
77
+ return true;
78
+ }
79
+ }
80
+ return false;
81
+ }
82
+ function isExpressionBooleanLike(expr) {
83
+ switch (expr.type) {
84
+ case utils_1.AST_NODE_TYPES.Literal:
85
+ return typeof expr.value === 'boolean' ? true : 'non';
86
+ case utils_1.AST_NODE_TYPES.TemplateLiteral:
87
+ return 'non';
88
+ case utils_1.AST_NODE_TYPES.ObjectExpression:
89
+ case utils_1.AST_NODE_TYPES.ArrayExpression:
90
+ case utils_1.AST_NODE_TYPES.NewExpression:
91
+ case utils_1.AST_NODE_TYPES.ClassExpression:
92
+ case utils_1.AST_NODE_TYPES.FunctionExpression:
93
+ case utils_1.AST_NODE_TYPES.ArrowFunctionExpression:
94
+ return 'non';
95
+ case utils_1.AST_NODE_TYPES.UnaryExpression:
96
+ if (expr.operator === '!')
97
+ return true; // !x or !!x
98
+ if (expr.operator === 'void')
99
+ return 'non';
100
+ return 'unknown';
101
+ case utils_1.AST_NODE_TYPES.BinaryExpression: {
102
+ const cmp = ['===', '!==', '==', '!=', '>', '<', '>=', '<='];
103
+ return cmp.includes(expr.operator) ? true : 'unknown';
104
+ }
105
+ case utils_1.AST_NODE_TYPES.LogicalExpression:
106
+ // && and || often return non-boolean operands; don't infer true
107
+ return 'unknown';
108
+ case utils_1.AST_NODE_TYPES.MemberExpression: {
109
+ if (expr.property.type === utils_1.AST_NODE_TYPES.Identifier &&
110
+ expr.property.name === 'length') {
111
+ return 'non';
112
+ }
113
+ return 'unknown';
114
+ }
115
+ case utils_1.AST_NODE_TYPES.ConditionalExpression: {
116
+ const cons = isExpressionBooleanLike(expr.consequent);
117
+ const alt = isExpressionBooleanLike(expr.alternate);
118
+ if (cons === true && alt === true)
119
+ return true;
120
+ if (cons === 'non' || alt === 'non')
121
+ return 'non';
122
+ return 'unknown';
123
+ }
124
+ case utils_1.AST_NODE_TYPES.CallExpression: {
125
+ if (expr.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
126
+ expr.callee.name === 'Boolean') {
127
+ return true;
128
+ }
129
+ return 'unknown';
130
+ }
131
+ case utils_1.AST_NODE_TYPES.Identifier:
132
+ if (expr.name === 'undefined')
133
+ return 'non';
134
+ return 'unknown';
135
+ case utils_1.AST_NODE_TYPES.AwaitExpression:
136
+ return 'unknown';
137
+ default:
138
+ return 'unknown';
139
+ }
140
+ }
141
+ function getReturnTypeNode(node) {
142
+ if (node.returnType?.typeAnnotation)
143
+ return node.returnType.typeAnnotation;
144
+ return undefined;
145
+ }
146
+ function hasTypePredicate(node) {
147
+ return (node.returnType?.typeAnnotation?.type === utils_1.AST_NODE_TYPES.TSTypePredicate);
148
+ }
149
+ function collectReturnExpressions(fn) {
150
+ const results = [];
151
+ const visited = new Set();
152
+ function visit(n) {
153
+ if (!n || visited.has(n))
154
+ return;
155
+ visited.add(n);
156
+ // Do not traverse into nested functions/classes
157
+ if (n.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
158
+ n.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
159
+ n.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
160
+ n.type === utils_1.AST_NODE_TYPES.ClassDeclaration ||
161
+ n.type === utils_1.AST_NODE_TYPES.ClassExpression) {
162
+ if (n === fn) {
163
+ // traverse this function's body
164
+ // continue
165
+ }
166
+ else {
167
+ return;
168
+ }
169
+ }
170
+ if (n.type === utils_1.AST_NODE_TYPES.ReturnStatement) {
171
+ if (n.argument && n.argument.type) {
172
+ results.push(n.argument);
173
+ }
174
+ else {
175
+ // return; without value
176
+ // Represent as Identifier 'undefined' to treat as non-boolean
177
+ // We won't push undefined, but handle later by a flag
178
+ results.noValueReturn = true;
179
+ }
180
+ }
181
+ for (const key of Object.keys(n)) {
182
+ if (key === 'parent' || key === 'range' || key === 'loc')
183
+ continue;
184
+ const value = n[key];
185
+ if (!value)
186
+ continue;
187
+ if (Array.isArray(value)) {
188
+ for (const child of value) {
189
+ if (child && typeof child === 'object' && 'type' in child)
190
+ visit(child);
191
+ }
192
+ }
193
+ else if (value && typeof value === 'object' && 'type' in value) {
194
+ visit(value);
195
+ }
196
+ }
197
+ }
198
+ if (fn.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression && fn.expression) {
199
+ // expression-bodied arrow function: synthesize a return
200
+ const bodyExpr = fn.body;
201
+ results.push(bodyExpr);
202
+ return results;
203
+ }
204
+ if (fn.body && fn.body.type === utils_1.AST_NODE_TYPES.BlockStatement)
205
+ visit(fn.body);
206
+ return results;
207
+ }
208
+ exports.noMisleadingBooleanPrefixes = (0, createRule_1.createRule)({
209
+ name: 'no-misleading-boolean-prefixes',
210
+ meta: {
211
+ type: 'problem',
212
+ docs: {
213
+ description: 'Reserve boolean-style prefixes (is/has/should) for functions that actually return boolean values to avoid misleading call sites.',
214
+ recommended: 'error',
215
+ },
216
+ schema: [
217
+ {
218
+ type: 'object',
219
+ properties: {
220
+ prefixes: {
221
+ type: 'array',
222
+ items: { type: 'string' },
223
+ },
224
+ },
225
+ additionalProperties: false,
226
+ },
227
+ ],
228
+ messages: {
229
+ nonBooleanReturn: 'Function "{{name}}" uses a boolean-style prefix but its return value is not guaranteed to be boolean. Boolean prefixes promise a yes/no answer; returning strings, objects, or void misleads callers and hides incorrect branching. Return a real boolean (e.g., add an explicit comparison or Boolean(...)) or rename the function to drop the boolean-style prefix (prefixes treated as boolean: {{prefixes}}).',
230
+ },
231
+ },
232
+ defaultOptions: [{ prefixes: DEFAULT_PREFIXES }],
233
+ create(context, [options]) {
234
+ const prefixes = (options && options.prefixes) || DEFAULT_PREFIXES;
235
+ function shouldCheckName(name) {
236
+ return startsWithBooleanPrefix(name, prefixes);
237
+ }
238
+ function report(node, name) {
239
+ context.report({
240
+ node,
241
+ messageId: 'nonBooleanReturn',
242
+ data: { name, prefixes: prefixes.join(', ') },
243
+ });
244
+ }
245
+ function checkFunctionLike(node, name, reportNode) {
246
+ if (!shouldCheckName(name))
247
+ return;
248
+ // Type predicate allows boolean-like
249
+ if (hasTypePredicate(node))
250
+ return;
251
+ const typeNode = getReturnTypeNode(node);
252
+ if (typeNode) {
253
+ if (isTsBooleanLike(typeNode))
254
+ return;
255
+ // Explicit non-boolean annotation
256
+ report(reportNode, name);
257
+ return;
258
+ }
259
+ const returns = collectReturnExpressions(node);
260
+ const noValueReturn = returns.noValueReturn === true;
261
+ if (noValueReturn) {
262
+ report(reportNode, name);
263
+ return;
264
+ }
265
+ if (returns.length === 0) {
266
+ // No returns implies void
267
+ report(reportNode, name);
268
+ return;
269
+ }
270
+ for (const expr of returns) {
271
+ const kind = isExpressionBooleanLike(expr);
272
+ if (kind === 'non') {
273
+ report(reportNode, name);
274
+ return;
275
+ }
276
+ }
277
+ // If we can't determine it's non-boolean, do not report to avoid false positives
278
+ }
279
+ return {
280
+ FunctionDeclaration(node) {
281
+ if (!node.id)
282
+ return;
283
+ checkFunctionLike(node, node.id.name, node.id);
284
+ },
285
+ FunctionExpression(node) {
286
+ // Prefer variable declarator or method/property name
287
+ if (node.parent?.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
288
+ node.parent.id.type === utils_1.AST_NODE_TYPES.Identifier) {
289
+ checkFunctionLike(node, node.parent.id.name, node.parent.id);
290
+ return;
291
+ }
292
+ // If part of a property or method, let dedicated visitors handle it to avoid duplicates
293
+ if (node.parent?.type === utils_1.AST_NODE_TYPES.Property)
294
+ return;
295
+ if (node.parent?.type === utils_1.AST_NODE_TYPES.MethodDefinition)
296
+ return;
297
+ if (node.id) {
298
+ checkFunctionLike(node, node.id.name, node.id);
299
+ }
300
+ },
301
+ ArrowFunctionExpression(node) {
302
+ if (node.parent?.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
303
+ node.parent.id.type === utils_1.AST_NODE_TYPES.Identifier) {
304
+ checkFunctionLike(node, node.parent.id.name, node.parent.id);
305
+ return;
306
+ }
307
+ // If part of a property, let the Property visitor handle it to avoid duplicates
308
+ if (node.parent?.type === utils_1.AST_NODE_TYPES.Property)
309
+ return;
310
+ },
311
+ MethodDefinition(node) {
312
+ if (node.key.type !== utils_1.AST_NODE_TYPES.Identifier)
313
+ return;
314
+ const name = node.key.name;
315
+ const fn = node.value;
316
+ if (fn.type === utils_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression)
317
+ return;
318
+ checkFunctionLike(fn, name, node.key);
319
+ },
320
+ Property(node) {
321
+ if (node.key.type !== utils_1.AST_NODE_TYPES.Identifier)
322
+ return;
323
+ if (node.value.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
324
+ node.value.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
325
+ checkFunctionLike(node.value, node.key.name, node.key);
326
+ }
327
+ },
328
+ };
329
+ },
330
+ });
331
+ //# sourceMappingURL=no-misleading-boolean-prefixes.js.map
@@ -12,19 +12,40 @@ exports.noMisusedSwitchCase = (0, createRule_1.createRule)({
12
12
  },
13
13
  schema: [],
14
14
  messages: {
15
- noMisusedSwitchCase: 'Avoid using logical OR (||) in switch case statements. Instead of `case x || y:`, use cascading cases like `case x: case y:`.',
15
+ noMisusedSwitchCase: 'Case expression uses logical OR "{{expressionText}}", but "||" collapses to a single operand so only one branch is reachable. Move each operand into its own case (e.g., "{{cascadingCases}}") so every value is matched and the switch intent stays clear.',
16
16
  },
17
17
  },
18
18
  defaultOptions: [],
19
19
  create(context) {
20
+ const sourceCode = context.getSourceCode();
21
+ const flattenLogicalOrOperands = (expression) => {
22
+ const operands = [];
23
+ const visit = (node) => {
24
+ if (node.type === 'LogicalExpression' && node.operator === '||') {
25
+ visit(node.left);
26
+ visit(node.right);
27
+ return;
28
+ }
29
+ operands.push(sourceCode.getText(node));
30
+ };
31
+ visit(expression);
32
+ return operands;
33
+ };
20
34
  return {
21
35
  SwitchStatement(node) {
22
36
  for (const switchCase of node.cases) {
23
37
  if (switchCase.test?.type === 'LogicalExpression' &&
24
38
  switchCase.test.operator === '||') {
39
+ const operands = flattenLogicalOrOperands(switchCase.test);
25
40
  context.report({
26
41
  node: switchCase,
27
42
  messageId: 'noMisusedSwitchCase',
43
+ data: {
44
+ expressionText: sourceCode.getText(switchCase.test),
45
+ cascadingCases: operands
46
+ .map((operand) => `case ${operand}:`)
47
+ .join(' '),
48
+ },
28
49
  });
29
50
  }
30
51
  }
@@ -1 +1,3 @@
1
- export declare const noMixedFirestoreTransactions: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"noMixedTransactions", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
1
+ type MessageIds = 'noMixedTransactions' | 'noMixedTransactionsFetcher';
2
+ export declare const noMixedFirestoreTransactions: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<MessageIds, [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
3
+ export {};