@blumintinc/eslint-plugin-blumint 1.5.5 → 1.7.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 (29) hide show
  1. package/README.md +62 -39
  2. package/lib/index.js +37 -1
  3. package/lib/rules/enforce-assert-throws.d.ts +1 -0
  4. package/lib/rules/enforce-assert-throws.js +132 -0
  5. package/lib/rules/enforce-centralized-mock-firestore.d.ts +1 -0
  6. package/lib/rules/enforce-centralized-mock-firestore.js +55 -0
  7. package/lib/rules/enforce-exported-function-types.js +3 -2
  8. package/lib/rules/enforce-firestore-facade.d.ts +3 -0
  9. package/lib/rules/enforce-firestore-facade.js +126 -0
  10. package/lib/rules/enforce-firestore-set-merge.js +83 -2
  11. package/lib/rules/enforce-verb-noun-naming.js +2 -0
  12. package/lib/rules/no-complex-cloud-params.d.ts +1 -0
  13. package/lib/rules/no-complex-cloud-params.js +363 -0
  14. package/lib/rules/no-explicit-return-type.js +11 -3
  15. package/lib/rules/no-firestore-jest-mock.d.ts +1 -0
  16. package/lib/rules/no-firestore-jest-mock.js +59 -0
  17. package/lib/rules/no-mixed-firestore-transactions.d.ts +1 -0
  18. package/lib/rules/no-mixed-firestore-transactions.js +115 -0
  19. package/lib/rules/no-mock-firebase-admin.d.ts +1 -0
  20. package/lib/rules/no-mock-firebase-admin.js +50 -0
  21. package/lib/rules/prefer-batch-operations.d.ts +3 -0
  22. package/lib/rules/prefer-batch-operations.js +176 -0
  23. package/lib/rules/prefer-clone-deep.d.ts +1 -0
  24. package/lib/rules/prefer-clone-deep.js +72 -0
  25. package/lib/rules/prefer-settings-object.js +164 -6
  26. package/lib/rules/semantic-function-prefixes.js +7 -0
  27. package/lib/rules/sync-onwrite-name-func.d.ts +1 -0
  28. package/lib/rules/sync-onwrite-name-func.js +79 -0
  29. package/package.json +2 -2
@@ -41,8 +41,80 @@ exports.enforceFirestoreSetMerge = (0, createRule_1.createRule)({
41
41
  }
42
42
  }
43
43
  }
44
- // Only flag update() calls
45
- return property.name === 'update';
44
+ // Only flag update() calls that are Firestore operations
45
+ if (property.name === 'update') {
46
+ const object = node.callee.object;
47
+ // Check for BatchManager update calls
48
+ if (object.type === utils_1.AST_NODE_TYPES.MemberExpression &&
49
+ object.property.type === utils_1.AST_NODE_TYPES.Identifier &&
50
+ object.property.name === 'batchManager') {
51
+ return true;
52
+ }
53
+ if (object.type === utils_1.AST_NODE_TYPES.CallExpression) {
54
+ // Check if it's a createHash().update() call
55
+ if (object.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
56
+ object.callee.name === 'createHash') {
57
+ return false;
58
+ }
59
+ }
60
+ // Check if it's a Firestore document reference or transaction
61
+ let current = node;
62
+ while (current?.parent) {
63
+ current = current.parent;
64
+ if (current.type === utils_1.AST_NODE_TYPES.MemberExpression) {
65
+ const obj = current.object;
66
+ if (obj.type === utils_1.AST_NODE_TYPES.Identifier) {
67
+ // Check for common Firestore variable names
68
+ if (obj.name === 'db' ||
69
+ obj.name === 'firestore' ||
70
+ obj.name === 'transaction' ||
71
+ obj.name === 'docRef' ||
72
+ obj.name === 'userRef' ||
73
+ obj.name.endsWith('Ref')) {
74
+ return true;
75
+ }
76
+ }
77
+ }
78
+ }
79
+ // Check if it's a Firestore document reference method chain
80
+ let currentObj = object;
81
+ while (currentObj.type === utils_1.AST_NODE_TYPES.MemberExpression) {
82
+ if (currentObj.property.type === utils_1.AST_NODE_TYPES.Identifier) {
83
+ const methodName = currentObj.property.name;
84
+ if (methodName === 'collection' || methodName === 'doc') {
85
+ return true;
86
+ }
87
+ }
88
+ currentObj = currentObj.object;
89
+ }
90
+ // Check if it's a transaction.update() call
91
+ if (object.type === utils_1.AST_NODE_TYPES.Identifier &&
92
+ object.name === 'transaction') {
93
+ return true;
94
+ }
95
+ // Check if it's a Firestore document reference by looking at imports
96
+ const program = context
97
+ .getAncestors()
98
+ .find((node) => node.type === utils_1.AST_NODE_TYPES.Program);
99
+ if (program) {
100
+ for (const node of program.body) {
101
+ if (node.type === utils_1.AST_NODE_TYPES.VariableDeclaration) {
102
+ for (const decl of node.declarations) {
103
+ if (decl.init?.type === utils_1.AST_NODE_TYPES.CallExpression &&
104
+ decl.init.callee.type ===
105
+ utils_1.AST_NODE_TYPES.MemberExpression &&
106
+ decl.init.callee.property.type ===
107
+ utils_1.AST_NODE_TYPES.Identifier &&
108
+ decl.init.callee.property.name === 'firestore') {
109
+ return true;
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
115
+ return false;
116
+ }
117
+ return false;
46
118
  }
47
119
  }
48
120
  if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier) {
@@ -75,6 +147,15 @@ exports.enforceFirestoreSetMerge = (0, createRule_1.createRule)({
75
147
  const data = sourceCode.getText(args[1]);
76
148
  return `${object}.set(${docRef}, ${data}, { merge: true })`;
77
149
  }
150
+ if (object.includes('batchManager')) {
151
+ const docRef = sourceCode.getText(args[0]);
152
+ const data = sourceCode.getText(args[1]);
153
+ return `${object}.set({
154
+ ref: ${docRef},
155
+ data: ${data},
156
+ merge: true,
157
+ })`;
158
+ }
78
159
  const data = sourceCode.getText(args[0]);
79
160
  return `${object}.set(${data}, { merge: true })`;
80
161
  }
@@ -69,6 +69,7 @@ const VERBS_SET = new Set([
69
69
  'auto',
70
70
  'avoid',
71
71
  'back',
72
+ 'backfill',
72
73
  'backup',
73
74
  'bake',
74
75
  'balance',
@@ -432,6 +433,7 @@ const VERBS_SET = new Set([
432
433
  'include',
433
434
  'includes',
434
435
  'increase',
436
+ 'increment',
435
437
  'index',
436
438
  'influence',
437
439
  'inform',
@@ -0,0 +1 @@
1
+ export declare const noComplexCloudParams: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"noComplexObjects", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
@@ -0,0 +1,363 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noComplexCloudParams = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const createRule_1 = require("../utils/createRule");
6
+ exports.noComplexCloudParams = (0, createRule_1.createRule)({
7
+ name: 'no-complex-cloud-params',
8
+ meta: {
9
+ type: 'problem',
10
+ docs: {
11
+ description: 'Disallow passing complex objects to cloud functions',
12
+ recommended: 'error',
13
+ },
14
+ schema: [],
15
+ messages: {
16
+ noComplexObjects: 'Do not pass complex objects to cloud functions. Complex objects include class instances, objects with methods, non-serializable values (RegExp, BigInt, TypedArray, etc.), or objects with nested complex properties.',
17
+ },
18
+ },
19
+ defaultOptions: [],
20
+ create(context) {
21
+ // Track imported cloud functions
22
+ const cloudFunctions = new Set();
23
+ // Track objects to detect circular references
24
+ const objectsInPath = new Set();
25
+ // Track nodes that have already been reported
26
+ const reportedNodes = new Set();
27
+ function isFunction(node) {
28
+ return [
29
+ utils_1.AST_NODE_TYPES.FunctionExpression,
30
+ utils_1.AST_NODE_TYPES.ArrowFunctionExpression,
31
+ utils_1.AST_NODE_TYPES.MethodDefinition,
32
+ ].includes(node.type);
33
+ }
34
+ function isMethod(node) {
35
+ if (node.type === utils_1.AST_NODE_TYPES.MethodDefinition) {
36
+ return true;
37
+ }
38
+ if (node.type === utils_1.AST_NODE_TYPES.Property) {
39
+ // Check for methods, getters, setters
40
+ if (node.method || node.kind === 'get' || node.kind === 'set') {
41
+ return true;
42
+ }
43
+ // Check if the value is a function
44
+ if (node.value && isFunction(node.value)) {
45
+ return true;
46
+ }
47
+ // Check for bound functions
48
+ if (node.value &&
49
+ node.value.type === utils_1.AST_NODE_TYPES.CallExpression &&
50
+ node.value.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
51
+ node.value.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
52
+ node.value.callee.property.name === 'bind') {
53
+ return true;
54
+ }
55
+ // Check for generator methods
56
+ if (node.value &&
57
+ node.value.type === utils_1.AST_NODE_TYPES.FunctionExpression &&
58
+ node.value.generator) {
59
+ return true;
60
+ }
61
+ // Check for async methods
62
+ if (node.value &&
63
+ node.value.type === utils_1.AST_NODE_TYPES.FunctionExpression &&
64
+ node.value.async) {
65
+ return true;
66
+ }
67
+ }
68
+ return false;
69
+ }
70
+ function isClassInstance(node) {
71
+ if (node.type === utils_1.AST_NODE_TYPES.NewExpression) {
72
+ // Check for known non-serializable constructors
73
+ if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier) {
74
+ const nonSerializableTypes = new Set([
75
+ 'RegExp',
76
+ 'BigInt',
77
+ 'Int8Array',
78
+ 'Uint8Array',
79
+ 'Uint8ClampedArray',
80
+ 'Int16Array',
81
+ 'Uint16Array',
82
+ 'Int32Array',
83
+ 'Uint32Array',
84
+ 'Float32Array',
85
+ 'Float64Array',
86
+ 'BigInt64Array',
87
+ 'BigUint64Array',
88
+ 'WeakMap',
89
+ 'WeakSet',
90
+ 'Promise',
91
+ 'Error',
92
+ 'Proxy',
93
+ 'Map',
94
+ 'Set',
95
+ 'ArrayBuffer',
96
+ 'SharedArrayBuffer',
97
+ 'DataView',
98
+ ]);
99
+ if (nonSerializableTypes.has(node.callee.name)) {
100
+ return true;
101
+ }
102
+ // Allow Date objects as they are serializable
103
+ if (node.callee.name === 'Date') {
104
+ return false;
105
+ }
106
+ }
107
+ return true;
108
+ }
109
+ if (node.type === utils_1.AST_NODE_TYPES.Identifier) {
110
+ // Try to find the variable declaration
111
+ const scope = context.getScope();
112
+ const variable = scope.variables.find((v) => v.name === node.name);
113
+ if (variable && variable.defs.length > 0) {
114
+ const def = variable.defs[0];
115
+ if (def.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
116
+ def.node.init) {
117
+ return isClassInstance(def.node.init);
118
+ }
119
+ }
120
+ // Check if the identifier starts with a capital letter (potential class instance)
121
+ return node.name[0] === node.name[0].toUpperCase();
122
+ }
123
+ return false;
124
+ }
125
+ function isNonSerializableLiteral(node) {
126
+ if (node.type === utils_1.AST_NODE_TYPES.Literal) {
127
+ // Check for RegExp literal
128
+ if ('regex' in node && node.regex) {
129
+ return true;
130
+ }
131
+ // Check for BigInt literal
132
+ if ('bigint' in node && node.bigint) {
133
+ return true;
134
+ }
135
+ return false;
136
+ }
137
+ // Check for RegExp constructor or literal
138
+ if ((node.type === utils_1.AST_NODE_TYPES.NewExpression ||
139
+ node.type === utils_1.AST_NODE_TYPES.CallExpression) &&
140
+ node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
141
+ node.callee.name === 'RegExp') {
142
+ return true;
143
+ }
144
+ // Check for BigInt constructor or function
145
+ if ((node.type === utils_1.AST_NODE_TYPES.CallExpression ||
146
+ node.type === utils_1.AST_NODE_TYPES.NewExpression) &&
147
+ node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
148
+ node.callee.name === 'BigInt') {
149
+ return true;
150
+ }
151
+ return false;
152
+ }
153
+ function isComplexValue(node) {
154
+ // Prevent infinite recursion with circular references
155
+ if (objectsInPath.has(node)) {
156
+ return true;
157
+ }
158
+ objectsInPath.add(node);
159
+ try {
160
+ // Check for function expressions
161
+ if (isFunction(node)) {
162
+ return true;
163
+ }
164
+ // Check for class instances
165
+ if (isClassInstance(node)) {
166
+ return true;
167
+ }
168
+ // Check for non-serializable literals
169
+ if (isNonSerializableLiteral(node)) {
170
+ return true;
171
+ }
172
+ // Check for method calls that could create complex objects
173
+ if (node.type === utils_1.AST_NODE_TYPES.CallExpression) {
174
+ // Allow JSON.stringify
175
+ if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
176
+ node.callee.object.type === utils_1.AST_NODE_TYPES.Identifier &&
177
+ node.callee.object.name === 'JSON' &&
178
+ node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
179
+ node.callee.property.name === 'stringify') {
180
+ return false;
181
+ }
182
+ // Allow Object.create(null)
183
+ if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
184
+ node.callee.object.type === utils_1.AST_NODE_TYPES.Identifier &&
185
+ node.callee.object.name === 'Object' &&
186
+ node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
187
+ node.callee.property.name === 'create') {
188
+ // Only allow Object.create(null), check if the prototype object is complex
189
+ if (node.arguments.length === 1) {
190
+ if (node.arguments[0].type === utils_1.AST_NODE_TYPES.Literal &&
191
+ node.arguments[0].value === null) {
192
+ return false;
193
+ }
194
+ return isComplexValue(node.arguments[0]);
195
+ }
196
+ return true;
197
+ }
198
+ // Check for function binding
199
+ if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
200
+ node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
201
+ node.callee.property.name === 'bind') {
202
+ return true;
203
+ }
204
+ return isComplexValue(node.callee);
205
+ }
206
+ // Check for arrays
207
+ if (node.type === utils_1.AST_NODE_TYPES.ArrayExpression) {
208
+ return node.elements.some((element) => element !== null && isComplexValue(element));
209
+ }
210
+ // Check for objects
211
+ if (node.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
212
+ return node.properties.some((prop) => {
213
+ if (prop.type === utils_1.AST_NODE_TYPES.Property) {
214
+ // Check for computed properties (including Symbols)
215
+ if (prop.computed) {
216
+ return true;
217
+ }
218
+ // Check for methods, getters, and setters
219
+ if (isMethod(prop)) {
220
+ return true;
221
+ }
222
+ // Check property value
223
+ return isComplexValue(prop.value);
224
+ }
225
+ // SpreadElement or other non-Property types are considered complex
226
+ return true;
227
+ });
228
+ }
229
+ // Check for member expressions that might be complex
230
+ if (node.type === utils_1.AST_NODE_TYPES.MemberExpression) {
231
+ // Check for prototype chain access
232
+ if (node.property.type === utils_1.AST_NODE_TYPES.Identifier &&
233
+ (node.property.name === 'prototype' ||
234
+ node.property.name === '__proto__')) {
235
+ return true;
236
+ }
237
+ // Check for Symbol properties
238
+ if (node.object.type === utils_1.AST_NODE_TYPES.Identifier &&
239
+ node.object.name === 'Symbol') {
240
+ return true;
241
+ }
242
+ // Check for WeakMap, WeakSet, Promise, Error constructors
243
+ if (node.object.type === utils_1.AST_NODE_TYPES.Identifier &&
244
+ ['WeakMap', 'WeakSet', 'Promise', 'Error'].includes(node.object.name)) {
245
+ return true;
246
+ }
247
+ // Check for circular references in member expressions
248
+ return isComplexValue(node.object) || isComplexValue(node.property);
249
+ }
250
+ // Check for Symbols
251
+ if (node.type === utils_1.AST_NODE_TYPES.Identifier && node.name === 'Symbol') {
252
+ return true;
253
+ }
254
+ // Check for object references that might be circular
255
+ if (node.type === utils_1.AST_NODE_TYPES.Identifier) {
256
+ const scope = context.getScope();
257
+ const variable = scope.variables.find((v) => v.name === node.name);
258
+ if (variable && variable.references.length > 0) {
259
+ // Check if this identifier is used in a way that creates a circular reference
260
+ const isCircular = variable.references.some((ref) => {
261
+ const refParent = ref.identifier.parent;
262
+ if (refParent) {
263
+ // Check for direct assignment
264
+ if (refParent.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
265
+ if (refParent.right === ref.identifier) {
266
+ // The identifier is being assigned to a property of itself
267
+ let current = refParent.parent;
268
+ while (current) {
269
+ if (current === node) {
270
+ return true;
271
+ }
272
+ current = current.parent;
273
+ }
274
+ }
275
+ }
276
+ // Check for property assignment
277
+ if (refParent.type === utils_1.AST_NODE_TYPES.Property) {
278
+ let current = refParent.parent;
279
+ while (current) {
280
+ if (current === node) {
281
+ return true;
282
+ }
283
+ current = current.parent;
284
+ }
285
+ }
286
+ }
287
+ return false;
288
+ });
289
+ if (isCircular) {
290
+ return true;
291
+ }
292
+ // Check the value the identifier refers to
293
+ if (variable.defs.length > 0) {
294
+ const def = variable.defs[0];
295
+ if (def.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
296
+ def.node.init) {
297
+ return isComplexValue(def.node.init);
298
+ }
299
+ }
300
+ }
301
+ }
302
+ return false;
303
+ }
304
+ finally {
305
+ objectsInPath.delete(node);
306
+ }
307
+ }
308
+ function hasComplexProperties(node) {
309
+ return isComplexValue(node);
310
+ }
311
+ function checkCloudFunctionCall(node) {
312
+ if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
313
+ cloudFunctions.has(node.callee.name)) {
314
+ // Check each argument for complex objects
315
+ node.arguments.forEach((arg) => {
316
+ if (hasComplexProperties(arg) && !reportedNodes.has(node)) {
317
+ reportedNodes.add(node);
318
+ context.report({
319
+ node,
320
+ messageId: 'noComplexObjects',
321
+ });
322
+ }
323
+ });
324
+ }
325
+ }
326
+ return {
327
+ // Track cloud function imports
328
+ ImportExpression(node) {
329
+ if (node.source.type === utils_1.AST_NODE_TYPES.Literal &&
330
+ typeof node.source.value === 'string' &&
331
+ node.source.value.includes('firebaseCloud')) {
332
+ // Find the variable declarator that contains this import
333
+ let parent = node.parent;
334
+ while (parent && parent.type !== utils_1.AST_NODE_TYPES.VariableDeclarator) {
335
+ parent = parent.parent;
336
+ }
337
+ if (parent && parent.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
338
+ // Handle destructuring pattern
339
+ if (parent.id.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
340
+ parent.id.properties.forEach((prop) => {
341
+ if (prop.type === utils_1.AST_NODE_TYPES.Property &&
342
+ prop.value.type === utils_1.AST_NODE_TYPES.Identifier) {
343
+ cloudFunctions.add(prop.value.name);
344
+ }
345
+ });
346
+ }
347
+ }
348
+ }
349
+ },
350
+ // Check for complex objects in cloud function calls
351
+ CallExpression(node) {
352
+ checkCloudFunctionCall(node);
353
+ },
354
+ // Check for await expressions with cloud function calls
355
+ AwaitExpression(node) {
356
+ if (node.argument.type === utils_1.AST_NODE_TYPES.CallExpression) {
357
+ checkCloudFunctionCall(node.argument);
358
+ }
359
+ },
360
+ };
361
+ },
362
+ });
363
+ //# sourceMappingURL=no-complex-cloud-params.js.map
@@ -94,9 +94,17 @@ function isTypeGuardFunction(node) {
94
94
  if (returnType.type !== utils_1.AST_NODE_TYPES.TSTypeAnnotation)
95
95
  return false;
96
96
  const typeAnnotation = returnType.typeAnnotation;
97
- if (typeAnnotation.type !== utils_1.AST_NODE_TYPES.TSTypePredicate)
98
- return false;
99
- return true;
97
+ // Check for type predicates (is keyword)
98
+ if (typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypePredicate)
99
+ return true;
100
+ // Check for assertion functions (asserts keyword)
101
+ if (typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
102
+ const typeName = typeAnnotation.typeName;
103
+ if (typeName.type === utils_1.AST_NODE_TYPES.Identifier && typeName.name === 'asserts') {
104
+ return true;
105
+ }
106
+ }
107
+ return false;
100
108
  }
101
109
  exports.noExplicitReturnType = (0, createRule_1.createRule)({
102
110
  name: 'no-explicit-return-type',
@@ -0,0 +1 @@
1
+ export declare const noFirestoreJestMock: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"noFirestoreJestMock", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noFirestoreJestMock = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const createRule_1 = require("../utils/createRule");
6
+ exports.noFirestoreJestMock = (0, createRule_1.createRule)({
7
+ name: 'no-firestore-jest-mock',
8
+ meta: {
9
+ type: 'problem',
10
+ docs: {
11
+ description: 'Prevent importing firestore-jest-mock in test files',
12
+ recommended: 'error',
13
+ },
14
+ fixable: 'code',
15
+ schema: [],
16
+ messages: {
17
+ noFirestoreJestMock: 'Do not import from firestore-jest-mock. Use mockFirestore from the centralized mock utility instead.',
18
+ },
19
+ },
20
+ defaultOptions: [],
21
+ create(context) {
22
+ const filename = context.getFilename();
23
+ // Only apply rule to test files
24
+ if (!filename.endsWith('.test.ts')) {
25
+ return {};
26
+ }
27
+ return {
28
+ ImportDeclaration(node) {
29
+ if (node.source.value === 'firestore-jest-mock') {
30
+ context.report({
31
+ node,
32
+ messageId: 'noFirestoreJestMock',
33
+ fix(fixer) {
34
+ // Replace with mockFirestore import
35
+ return fixer.replaceText(node, "import { mockFirestore } from '../../../../../__mocks__/functions/src/config/mockFirestore';");
36
+ },
37
+ });
38
+ }
39
+ },
40
+ CallExpression(node) {
41
+ // Check for jest.mock('firestore-jest-mock')
42
+ if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
43
+ node.callee.object.type === utils_1.AST_NODE_TYPES.Identifier &&
44
+ node.callee.object.name === 'jest' &&
45
+ node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
46
+ node.callee.property.name === 'mock' &&
47
+ node.arguments.length > 0 &&
48
+ node.arguments[0].type === utils_1.AST_NODE_TYPES.Literal &&
49
+ node.arguments[0].value === 'firestore-jest-mock') {
50
+ context.report({
51
+ node,
52
+ messageId: 'noFirestoreJestMock',
53
+ });
54
+ }
55
+ },
56
+ };
57
+ },
58
+ });
59
+ //# sourceMappingURL=no-firestore-jest-mock.js.map
@@ -0,0 +1 @@
1
+ export declare const noMixedFirestoreTransactions: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"noMixedTransactions", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;