@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,342 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noTryCatchAlreadyExistsInTransaction = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const createRule_1 = require("../utils/createRule");
6
+ const ALREADY_EXISTS_STRINGS = new Set(['already-exists', 'ALREADY_EXISTS']);
7
+ const ALREADY_EXISTS_NUMBERS = new Set([6, '6']);
8
+ function unwrapChainExpression(expression) {
9
+ if (expression.type === utils_1.AST_NODE_TYPES.ChainExpression) {
10
+ return expression.expression;
11
+ }
12
+ return expression;
13
+ }
14
+ function isRunTransactionCall(node) {
15
+ const callee = unwrapChainExpression(node.callee);
16
+ if (callee.type === utils_1.AST_NODE_TYPES.Identifier) {
17
+ return callee.name === 'runTransaction';
18
+ }
19
+ if (callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
20
+ const property = callee.property;
21
+ return (!callee.computed &&
22
+ property.type === utils_1.AST_NODE_TYPES.Identifier &&
23
+ property.name === 'runTransaction');
24
+ }
25
+ return false;
26
+ }
27
+ function getCallbackArgument(args) {
28
+ for (const arg of args) {
29
+ if (arg.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
30
+ arg.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
31
+ return arg;
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+ function isErrorAliasExpression(expression, context) {
37
+ if (expression.type === utils_1.AST_NODE_TYPES.Identifier) {
38
+ return context.errorAliases.has(expression.name);
39
+ }
40
+ if (expression.type === utils_1.AST_NODE_TYPES.TSAsExpression ||
41
+ expression.type === utils_1.AST_NODE_TYPES.TSTypeAssertion) {
42
+ return isErrorAliasExpression(expression.expression, context);
43
+ }
44
+ if (expression.type === utils_1.AST_NODE_TYPES.MemberExpression) {
45
+ return isErrorAliasExpression(expression.object, context);
46
+ }
47
+ if (expression.type === utils_1.AST_NODE_TYPES.ChainExpression) {
48
+ return isErrorAliasExpression(expression.expression, context);
49
+ }
50
+ return false;
51
+ }
52
+ function isCodeProperty(property) {
53
+ if (property.type === utils_1.AST_NODE_TYPES.Identifier) {
54
+ return property.name === 'code';
55
+ }
56
+ if (property.type === utils_1.AST_NODE_TYPES.Literal) {
57
+ return property.value === 'code';
58
+ }
59
+ return false;
60
+ }
61
+ function isErrorCodeExpression(expression, context) {
62
+ if (!expression) {
63
+ return false;
64
+ }
65
+ if (expression.type === utils_1.AST_NODE_TYPES.Identifier) {
66
+ return context.codeAliases.has(expression.name);
67
+ }
68
+ const unwrapped = expression.type === utils_1.AST_NODE_TYPES.ChainExpression
69
+ ? expression.expression
70
+ : expression;
71
+ if (unwrapped.type === utils_1.AST_NODE_TYPES.MemberExpression) {
72
+ return (isCodeProperty(unwrapped.property) &&
73
+ isErrorAliasExpression(unwrapped.object, context));
74
+ }
75
+ return false;
76
+ }
77
+ function isAlreadyExistsLiteral(expression) {
78
+ if (!expression) {
79
+ return null;
80
+ }
81
+ if (expression.type === utils_1.AST_NODE_TYPES.PrivateIdentifier) {
82
+ return null;
83
+ }
84
+ if (expression.type === utils_1.AST_NODE_TYPES.Literal) {
85
+ if (ALREADY_EXISTS_STRINGS.has(`${expression.value}`)) {
86
+ return `${expression.value}`;
87
+ }
88
+ if (ALREADY_EXISTS_NUMBERS.has(expression.value)) {
89
+ return `${expression.value}`;
90
+ }
91
+ }
92
+ if (expression.type === utils_1.AST_NODE_TYPES.TemplateLiteral &&
93
+ expression.expressions.length === 0 &&
94
+ expression.quasis.length === 1) {
95
+ const raw = expression.quasis[0].value.cooked;
96
+ if (raw && ALREADY_EXISTS_STRINGS.has(raw)) {
97
+ return raw;
98
+ }
99
+ }
100
+ return null;
101
+ }
102
+ function isAlreadyExistsComparison(expression, context) {
103
+ if (expression.type !== utils_1.AST_NODE_TYPES.BinaryExpression) {
104
+ return null;
105
+ }
106
+ if (!['==', '==='].includes(expression.operator)) {
107
+ return null;
108
+ }
109
+ const leftLiteral = isAlreadyExistsLiteral(expression.left);
110
+ const rightLiteral = isAlreadyExistsLiteral(expression.right);
111
+ if (leftLiteral && isErrorCodeExpression(expression.right, context)) {
112
+ return leftLiteral;
113
+ }
114
+ if (rightLiteral && isErrorCodeExpression(expression.left, context)) {
115
+ return rightLiteral;
116
+ }
117
+ return null;
118
+ }
119
+ function addAliasesFromDeclarator(declarator, context) {
120
+ const init = declarator.init;
121
+ const id = declarator.id;
122
+ const initIsAliasSource = !!init &&
123
+ (isErrorAliasExpression(init, context) ||
124
+ (init.type === utils_1.AST_NODE_TYPES.AssignmentExpression &&
125
+ isErrorAliasExpression(init.right, context)));
126
+ if (id.type === utils_1.AST_NODE_TYPES.Identifier && initIsAliasSource) {
127
+ context.errorAliases.add(id.name);
128
+ }
129
+ if (id.type === utils_1.AST_NODE_TYPES.ObjectPattern && initIsAliasSource) {
130
+ for (const property of id.properties) {
131
+ if (property.type !== utils_1.AST_NODE_TYPES.Property) {
132
+ continue;
133
+ }
134
+ const value = property.value;
135
+ if (isCodeProperty(property.key) &&
136
+ value.type === utils_1.AST_NODE_TYPES.Identifier) {
137
+ context.codeAliases.add(value.name);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ function containsAlreadyExistsCheck(node, context) {
143
+ if (!node) {
144
+ return null;
145
+ }
146
+ switch (node.type) {
147
+ case utils_1.AST_NODE_TYPES.BlockStatement: {
148
+ for (const statement of node.body) {
149
+ const found = containsAlreadyExistsCheck(statement, context);
150
+ if (found)
151
+ return found;
152
+ }
153
+ return null;
154
+ }
155
+ case utils_1.AST_NODE_TYPES.ExpressionStatement:
156
+ return containsAlreadyExistsCheck(node.expression, context);
157
+ case utils_1.AST_NODE_TYPES.ReturnStatement:
158
+ return containsAlreadyExistsCheck(node.argument, context);
159
+ case utils_1.AST_NODE_TYPES.IfStatement: {
160
+ const testMatch = containsAlreadyExistsCheck(node.test, context);
161
+ if (testMatch)
162
+ return testMatch;
163
+ const consequentMatch = containsAlreadyExistsCheck(node.consequent, context);
164
+ if (consequentMatch)
165
+ return consequentMatch;
166
+ return containsAlreadyExistsCheck(node.alternate, context);
167
+ }
168
+ case utils_1.AST_NODE_TYPES.SwitchStatement: {
169
+ const discriminantIsCode = isErrorCodeExpression(node.discriminant, context);
170
+ for (const switchCase of node.cases) {
171
+ const caseLiteral = isAlreadyExistsLiteral(switchCase.test);
172
+ if (discriminantIsCode && caseLiteral) {
173
+ return caseLiteral;
174
+ }
175
+ const found = switchCase.consequent
176
+ .map((stmt) => containsAlreadyExistsCheck(stmt, context))
177
+ .find(Boolean);
178
+ if (found)
179
+ return found;
180
+ }
181
+ return null;
182
+ }
183
+ case utils_1.AST_NODE_TYPES.VariableDeclaration: {
184
+ for (const declarator of node.declarations) {
185
+ addAliasesFromDeclarator(declarator, context);
186
+ const found = containsAlreadyExistsCheck(declarator.init, context);
187
+ if (found)
188
+ return found;
189
+ }
190
+ return null;
191
+ }
192
+ case utils_1.AST_NODE_TYPES.VariableDeclarator:
193
+ addAliasesFromDeclarator(node, context);
194
+ return containsAlreadyExistsCheck(node.init, context);
195
+ case utils_1.AST_NODE_TYPES.AssignmentExpression:
196
+ if (node.left.type === utils_1.AST_NODE_TYPES.Identifier &&
197
+ isErrorAliasExpression(node.right, context)) {
198
+ context.errorAliases.add(node.left.name);
199
+ }
200
+ return containsAlreadyExistsCheck(node.right, context);
201
+ case utils_1.AST_NODE_TYPES.CallExpression:
202
+ case utils_1.AST_NODE_TYPES.NewExpression: {
203
+ const calleeMatch = containsAlreadyExistsCheck(node.callee, context);
204
+ if (calleeMatch)
205
+ return calleeMatch;
206
+ for (const arg of node.arguments) {
207
+ const found = containsAlreadyExistsCheck(arg, context);
208
+ if (found)
209
+ return found;
210
+ }
211
+ return null;
212
+ }
213
+ case utils_1.AST_NODE_TYPES.LogicalExpression: {
214
+ const leftMatch = containsAlreadyExistsCheck(node.left, context);
215
+ if (leftMatch)
216
+ return leftMatch;
217
+ return containsAlreadyExistsCheck(node.right, context);
218
+ }
219
+ case utils_1.AST_NODE_TYPES.BinaryExpression:
220
+ return (isAlreadyExistsComparison(node, context) ||
221
+ containsAlreadyExistsCheck(node.left, context) ||
222
+ containsAlreadyExistsCheck(node.right, context));
223
+ case utils_1.AST_NODE_TYPES.ConditionalExpression: {
224
+ const testMatch = containsAlreadyExistsCheck(node.test, context);
225
+ if (testMatch)
226
+ return testMatch;
227
+ const consequentMatch = containsAlreadyExistsCheck(node.consequent, context);
228
+ if (consequentMatch)
229
+ return consequentMatch;
230
+ return containsAlreadyExistsCheck(node.alternate, context);
231
+ }
232
+ case utils_1.AST_NODE_TYPES.MemberExpression:
233
+ return containsAlreadyExistsCheck(node.object, context);
234
+ case utils_1.AST_NODE_TYPES.ChainExpression:
235
+ return containsAlreadyExistsCheck(node.expression, context);
236
+ case utils_1.AST_NODE_TYPES.AwaitExpression:
237
+ case utils_1.AST_NODE_TYPES.UnaryExpression:
238
+ case utils_1.AST_NODE_TYPES.UpdateExpression:
239
+ return containsAlreadyExistsCheck(node.argument, context);
240
+ case utils_1.AST_NODE_TYPES.TemplateLiteral:
241
+ return null;
242
+ case utils_1.AST_NODE_TYPES.TryStatement: {
243
+ const blockMatch = containsAlreadyExistsCheck(node.block, context);
244
+ if (blockMatch)
245
+ return blockMatch;
246
+ const handlerMatch = containsAlreadyExistsCheck(node.handler?.body, context);
247
+ if (handlerMatch)
248
+ return handlerMatch;
249
+ return containsAlreadyExistsCheck(node.finalizer, context);
250
+ }
251
+ default:
252
+ return null;
253
+ }
254
+ }
255
+ function createCatchContext(handler) {
256
+ const errorAliases = new Set();
257
+ const codeAliases = new Set();
258
+ const param = handler.param;
259
+ if (param?.type === utils_1.AST_NODE_TYPES.Identifier) {
260
+ errorAliases.add(param.name);
261
+ }
262
+ else if (param?.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
263
+ for (const property of param.properties) {
264
+ if (property.type !== utils_1.AST_NODE_TYPES.Property) {
265
+ continue;
266
+ }
267
+ const value = property.value;
268
+ if (isCodeProperty(property.key) &&
269
+ value.type === utils_1.AST_NODE_TYPES.Identifier) {
270
+ codeAliases.add(value.name);
271
+ }
272
+ }
273
+ }
274
+ return { errorAliases, codeAliases };
275
+ }
276
+ exports.noTryCatchAlreadyExistsInTransaction = (0, createRule_1.createRule)({
277
+ name: 'no-try-catch-already-exists-in-transaction',
278
+ meta: {
279
+ type: 'problem',
280
+ docs: {
281
+ description: 'Disallow catching ALREADY_EXISTS errors inside Firestore transaction callbacks',
282
+ recommended: 'error',
283
+ },
284
+ schema: [],
285
+ messages: {
286
+ noAlreadyExistsCatchInTransaction: 'Do not catch ALREADY_EXISTS ({{codeLiteral}}) inside Firestore transaction callbacks. Firestore retries transaction bodies on contention, so this catch will re-run even though ALREADY_EXISTS is permanent. Move the try/catch outside the transaction or use runCreateForgivenessTransaction so the handler runs once.',
287
+ },
288
+ },
289
+ defaultOptions: [],
290
+ create(context) {
291
+ const transactionBodies = new Set();
292
+ function isInsideTransaction(node) {
293
+ let current = node;
294
+ while (current) {
295
+ if (transactionBodies.has(current)) {
296
+ return true;
297
+ }
298
+ current = current.parent;
299
+ }
300
+ return false;
301
+ }
302
+ return {
303
+ CallExpression(node) {
304
+ if (!isRunTransactionCall(node)) {
305
+ return;
306
+ }
307
+ const callback = getCallbackArgument(node.arguments);
308
+ if (callback && callback.body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
309
+ transactionBodies.add(callback.body);
310
+ }
311
+ },
312
+ 'CallExpression:exit'(node) {
313
+ if (!isRunTransactionCall(node)) {
314
+ return;
315
+ }
316
+ const callback = getCallbackArgument(node.arguments);
317
+ if (callback && callback.body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
318
+ transactionBodies.delete(callback.body);
319
+ }
320
+ },
321
+ TryStatement(node) {
322
+ if (!isInsideTransaction(node)) {
323
+ return;
324
+ }
325
+ const handler = node.handler;
326
+ if (!handler) {
327
+ return;
328
+ }
329
+ const catchContext = createCatchContext(handler);
330
+ const match = containsAlreadyExistsCheck(handler.body, catchContext);
331
+ if (match) {
332
+ context.report({
333
+ node: handler,
334
+ messageId: 'noAlreadyExistsCatchInTransaction',
335
+ data: { codeLiteral: match },
336
+ });
337
+ }
338
+ },
339
+ };
340
+ },
341
+ });
342
+ //# sourceMappingURL=no-try-catch-already-exists-in-transaction.js.map
@@ -28,6 +28,12 @@ function isTypePredicate(node) {
28
28
  function isInsideReturnStatement(node) {
29
29
  let current = node;
30
30
  while (current?.parent) {
31
+ // If we encounter a variable declaration before a return statement,
32
+ // then the node is not directly inside a return statement
33
+ if (current.parent.type === utils_1.AST_NODE_TYPES.VariableDeclarator ||
34
+ current.parent.type === utils_1.AST_NODE_TYPES.VariableDeclaration) {
35
+ return false;
36
+ }
31
37
  if (current.parent.type === utils_1.AST_NODE_TYPES.ReturnStatement) {
32
38
  return true;
33
39
  }
@@ -91,13 +97,40 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
91
97
  },
92
98
  ],
93
99
  messages: {
94
- noTypeAssertionReturns: 'Type assertions in return statements are not allowed. Type the variable explicitly before returning it.',
95
- useExplicitVariable: 'Explicit return type annotations are not allowed. Type the variable explicitly before returning it.',
100
+ noTypeAssertionReturns: `What's wrong: Return value uses a type assertion to "{{assertedType}}", which bypasses TypeScript checks. ` +
101
+ `→ Why it matters: Casts can hide missing or invalid data and let unsafe values reach callers without compile-time errors. ` +
102
+ `→ How to fix: Create a typed variable or add a narrowing step before returning so the value is validated by the type system instead of forced with a cast.`,
103
+ useExplicitVariable: `What's wrong: Return type "{{returnType}}" is declared while returning an unchecked expression, so TypeScript trusts the annotation instead of validating the actual value. ` +
104
+ `→ Why it matters: This hides mismatches between implementation and contract, letting incorrect return values propagate without type errors. ` +
105
+ `→ How to fix: Assign the expression to a typed variable or narrow it first, then return that variable so TypeScript can verify it against the declared return type.`,
96
106
  },
97
107
  },
98
108
  defaultOptions: [defaultOptions],
99
109
  create(context, [options]) {
100
110
  const mergedOptions = { ...defaultOptions, ...options };
111
+ const sourceCode = context.getSourceCode();
112
+ function getTypeText(typeNode, fallback) {
113
+ const text = typeNode ? sourceCode.getText(typeNode).trim() : '';
114
+ return text || fallback;
115
+ }
116
+ function reportTypeAssertion(node) {
117
+ context.report({
118
+ node,
119
+ messageId: 'noTypeAssertionReturns',
120
+ data: {
121
+ assertedType: getTypeText(node.typeAnnotation, 'the asserted type'),
122
+ },
123
+ });
124
+ }
125
+ function reportReturnTypeAnnotation(typeAnnotation) {
126
+ context.report({
127
+ node: typeAnnotation,
128
+ messageId: 'useExplicitVariable',
129
+ data: {
130
+ returnType: getTypeText(typeAnnotation.typeAnnotation, 'the declared return type'),
131
+ },
132
+ });
133
+ }
101
134
  /**
102
135
  * Checks if a node is inside a JSX attribute or object property (which could be JSX props)
103
136
  */
@@ -196,7 +229,7 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
196
229
  /**
197
230
  * Check if the current file is a .f.ts file
198
231
  */
199
- function isFunctionFile(context) {
232
+ function isFunctionFile() {
200
233
  const filename = context.getFilename();
201
234
  return filename.endsWith('.f.ts');
202
235
  }
@@ -207,7 +240,7 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
207
240
  if (!node.returnType)
208
241
  return;
209
242
  // Skip checking return types in .f.ts files
210
- if (isFunctionFile(context)) {
243
+ if (isFunctionFile()) {
211
244
  return;
212
245
  }
213
246
  // Allow type predicates if configured
@@ -218,10 +251,7 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
218
251
  // If type predicates are not allowed, report them
219
252
  if (!mergedOptions.allowTypePredicates &&
220
253
  isTypePredicate(node.returnType)) {
221
- context.report({
222
- node: node.returnType,
223
- messageId: 'useExplicitVariable',
224
- });
254
+ reportReturnTypeAnnotation(node.returnType);
225
255
  return;
226
256
  }
227
257
  // Check if the function has a return statement with a direct value (not a variable)
@@ -238,10 +268,7 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
238
268
  if (statement.argument.type === utils_1.AST_NODE_TYPES.ObjectExpression ||
239
269
  statement.argument.type === utils_1.AST_NODE_TYPES.ArrayExpression ||
240
270
  statement.argument.type === utils_1.AST_NODE_TYPES.CallExpression) {
241
- context.report({
242
- node: node.returnType,
243
- messageId: 'useExplicitVariable',
244
- });
271
+ reportReturnTypeAnnotation(node.returnType);
245
272
  break;
246
273
  }
247
274
  }
@@ -261,23 +288,14 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
261
288
  }
262
289
  // For nested type assertions, only report the outermost one
263
290
  if (node.argument.expression.type === utils_1.AST_NODE_TYPES.TSAsExpression) {
264
- context.report({
265
- node: node.argument,
266
- messageId: 'noTypeAssertionReturns',
267
- });
291
+ reportTypeAssertion(node.argument);
268
292
  return;
269
293
  }
270
- context.report({
271
- node: node.argument,
272
- messageId: 'noTypeAssertionReturns',
273
- });
294
+ reportTypeAssertion(node.argument);
274
295
  }
275
296
  // Check for type assertions using angle bracket syntax
276
297
  if (node.argument.type === utils_1.AST_NODE_TYPES.TSTypeAssertion) {
277
- context.report({
278
- node: node.argument,
279
- messageId: 'noTypeAssertionReturns',
280
- });
298
+ reportTypeAssertion(node.argument);
281
299
  }
282
300
  },
283
301
  // Check functions with explicit return types
@@ -295,7 +313,7 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
295
313
  // Check for explicit return type
296
314
  if (node.returnType) {
297
315
  // Skip checking return types in .f.ts files
298
- if (isFunctionFile(context)) {
316
+ if (isFunctionFile()) {
299
317
  return;
300
318
  }
301
319
  // Allow type predicates if configured
@@ -306,19 +324,13 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
306
324
  // If type predicates are not allowed, report them
307
325
  if (!mergedOptions.allowTypePredicates &&
308
326
  isTypePredicate(node.returnType)) {
309
- context.report({
310
- node: node.returnType,
311
- messageId: 'useExplicitVariable',
312
- });
327
+ reportReturnTypeAnnotation(node.returnType);
313
328
  return;
314
329
  }
315
330
  // If returning an object literal with explicit return type, report it
316
331
  if (node.body.type === utils_1.AST_NODE_TYPES.ObjectExpression ||
317
332
  node.body.type === utils_1.AST_NODE_TYPES.ArrayExpression) {
318
- context.report({
319
- node: node.returnType,
320
- messageId: 'useExplicitVariable',
321
- });
333
+ reportReturnTypeAnnotation(node.returnType);
322
334
  }
323
335
  }
324
336
  // Check for type assertions in the body
@@ -327,16 +339,10 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
327
339
  if (mergedOptions.allowAsConst && isAsConstAssertion(node.body)) {
328
340
  return;
329
341
  }
330
- context.report({
331
- node: node.body,
332
- messageId: 'noTypeAssertionReturns',
333
- });
342
+ reportTypeAssertion(node.body);
334
343
  }
335
344
  else if (node.body.type === utils_1.AST_NODE_TYPES.TSTypeAssertion) {
336
- context.report({
337
- node: node.body,
338
- messageId: 'noTypeAssertionReturns',
339
- });
345
+ reportTypeAssertion(node.body);
340
346
  }
341
347
  }
342
348
  else if (node.returnType) {
@@ -359,10 +365,7 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
359
365
  return;
360
366
  }
361
367
  // For standalone type assertions in expressions
362
- context.report({
363
- node,
364
- messageId: 'noTypeAssertionReturns',
365
- });
368
+ reportTypeAssertion(node);
366
369
  },
367
370
  // Check for type assertions using angle bracket syntax
368
371
  TSTypeAssertion(node) {
@@ -371,10 +374,7 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
371
374
  return;
372
375
  }
373
376
  // For standalone type assertions in expressions
374
- context.report({
375
- node,
376
- messageId: 'noTypeAssertionReturns',
377
- });
377
+ reportTypeAssertion(node);
378
378
  },
379
379
  };
380
380
  },