@blumintinc/eslint-plugin-blumint 1.5.4 → 1.6.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.
@@ -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
@@ -87,12 +87,31 @@ function isInterfaceOrAbstractMethodSignature(node) {
87
87
  }
88
88
  return false;
89
89
  }
90
+ function isTypeGuardFunction(node) {
91
+ if (!('returnType' in node) || !node.returnType)
92
+ return false;
93
+ const returnType = node.returnType;
94
+ if (returnType.type !== utils_1.AST_NODE_TYPES.TSTypeAnnotation)
95
+ return false;
96
+ const typeAnnotation = returnType.typeAnnotation;
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;
108
+ }
90
109
  exports.noExplicitReturnType = (0, createRule_1.createRule)({
91
110
  name: 'no-explicit-return-type',
92
111
  meta: {
93
112
  type: 'suggestion',
94
113
  docs: {
95
- description: 'Disallow explicit return type annotations on functions when TypeScript can infer them. This reduces code verbosity and maintenance burden while leveraging TypeScript\'s powerful type inference. Exceptions are made for recursive functions, overloaded functions, interface methods, and abstract methods where explicit types improve clarity.',
114
+ description: 'Disallow explicit return type annotations on functions when TypeScript can infer them. This reduces code verbosity and maintenance burden while leveraging TypeScript\'s powerful type inference. Exceptions are made for type guard functions (using the `is` keyword), recursive functions, overloaded functions, interface methods, and abstract methods where explicit types improve clarity.',
96
115
  recommended: 'error',
97
116
  requiresTypeChecking: false,
98
117
  extendsBaseRule: false,
@@ -136,8 +155,8 @@ exports.noExplicitReturnType = (0, createRule_1.createRule)({
136
155
  FunctionDeclaration(node) {
137
156
  if (!node.returnType)
138
157
  return;
139
- if (mergedOptions.allowRecursiveFunctions &&
140
- isRecursiveFunction(node)) {
158
+ if (isTypeGuardFunction(node) ||
159
+ (mergedOptions.allowRecursiveFunctions && isRecursiveFunction(node))) {
141
160
  return;
142
161
  }
143
162
  context.report({
@@ -149,8 +168,8 @@ exports.noExplicitReturnType = (0, createRule_1.createRule)({
149
168
  FunctionExpression(node) {
150
169
  if (!node.returnType)
151
170
  return;
152
- if (mergedOptions.allowRecursiveFunctions &&
153
- isRecursiveFunction(node)) {
171
+ if (isTypeGuardFunction(node) ||
172
+ (mergedOptions.allowRecursiveFunctions && isRecursiveFunction(node))) {
154
173
  return;
155
174
  }
156
175
  context.report({
@@ -162,6 +181,9 @@ exports.noExplicitReturnType = (0, createRule_1.createRule)({
162
181
  ArrowFunctionExpression(node) {
163
182
  if (!node.returnType)
164
183
  return;
184
+ if (isTypeGuardFunction(node)) {
185
+ return;
186
+ }
165
187
  context.report({
166
188
  node: node.returnType,
167
189
  messageId: 'noExplicitReturnType',
@@ -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>;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noMixedFirestoreTransactions = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const createRule_1 = require("../utils/createRule");
6
+ const NON_TRANSACTIONAL_CLASSES = new Set([
7
+ 'DocSetter',
8
+ 'FirestoreDocFetcher',
9
+ 'FirestoreFetcher',
10
+ ]);
11
+ exports.noMixedFirestoreTransactions = (0, createRule_1.createRule)({
12
+ name: 'no-mixed-firestore-transactions',
13
+ meta: {
14
+ type: 'problem',
15
+ docs: {
16
+ description: 'Prevent mixing transactional and non-transactional Firestore operations within a transaction',
17
+ recommended: 'error',
18
+ },
19
+ schema: [],
20
+ messages: {
21
+ noMixedTransactions: 'Do not use non-transactional Firestore operations ({{ className }}) inside a transaction. Use {{ transactionalClass }} instead.',
22
+ },
23
+ },
24
+ defaultOptions: [],
25
+ create(context) {
26
+ const transactionScopes = new Set();
27
+ function getTransactionalClassName(className) {
28
+ if (className === 'DocSetter')
29
+ return 'DocSetterTransaction';
30
+ if (className === 'FirestoreDocFetcher')
31
+ return 'FirestoreDocFetcherTransaction';
32
+ if (className === 'FirestoreFetcher')
33
+ return 'FirestoreFetcherTransaction';
34
+ return className;
35
+ }
36
+ function isFirestoreTransaction(node) {
37
+ const callee = node.callee;
38
+ if (callee.type !== utils_1.AST_NODE_TYPES.MemberExpression)
39
+ return false;
40
+ const property = callee.property;
41
+ return property.type === utils_1.AST_NODE_TYPES.Identifier && property.name === 'runTransaction';
42
+ }
43
+ function isNonTransactionalClass(node) {
44
+ const callee = node.callee;
45
+ if (callee.type !== utils_1.AST_NODE_TYPES.Identifier)
46
+ return false;
47
+ return NON_TRANSACTIONAL_CLASSES.has(callee.name);
48
+ }
49
+ function isTransactionParameter(param) {
50
+ if (param.type !== utils_1.AST_NODE_TYPES.Identifier)
51
+ return false;
52
+ const typeAnnotation = param.typeAnnotation;
53
+ if (!typeAnnotation || typeAnnotation.type !== utils_1.AST_NODE_TYPES.TSTypeAnnotation)
54
+ return false;
55
+ const type = typeAnnotation.typeAnnotation;
56
+ if (type.type !== utils_1.AST_NODE_TYPES.TSTypeReference)
57
+ return false;
58
+ const typeName = type.typeName;
59
+ if (typeName.type !== utils_1.AST_NODE_TYPES.TSQualifiedName)
60
+ return false;
61
+ return typeName.left.type === utils_1.AST_NODE_TYPES.Identifier && typeName.left.name === 'FirebaseFirestore' &&
62
+ typeName.right.type === utils_1.AST_NODE_TYPES.Identifier && typeName.right.name === 'Transaction';
63
+ }
64
+ function isInTransactionScope(node) {
65
+ let current = node;
66
+ while (current) {
67
+ if (transactionScopes.has(current)) {
68
+ return true;
69
+ }
70
+ if (current.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
71
+ current.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
72
+ current.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
73
+ const params = current.params;
74
+ if (params.some(isTransactionParameter)) {
75
+ return true;
76
+ }
77
+ }
78
+ current = current.parent;
79
+ }
80
+ return false;
81
+ }
82
+ return {
83
+ 'CallExpression[callee.property.name="runTransaction"]'(node) {
84
+ if (!isFirestoreTransaction(node))
85
+ return;
86
+ const callback = node.arguments[0];
87
+ if (callback.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
88
+ callback.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
89
+ transactionScopes.add(callback.body);
90
+ }
91
+ },
92
+ 'CallExpression[callee.property.name="runTransaction"]:exit'(node) {
93
+ const callback = node.arguments[0];
94
+ if (callback.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
95
+ callback.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
96
+ transactionScopes.delete(callback.body);
97
+ }
98
+ },
99
+ NewExpression(node) {
100
+ if (!isInTransactionScope(node) || !isNonTransactionalClass(node))
101
+ return;
102
+ const className = node.callee.name;
103
+ context.report({
104
+ node,
105
+ messageId: 'noMixedTransactions',
106
+ data: {
107
+ className,
108
+ transactionalClass: getTransactionalClassName(className),
109
+ },
110
+ });
111
+ },
112
+ };
113
+ },
114
+ });
115
+ //# sourceMappingURL=no-mixed-firestore-transactions.js.map
@@ -39,9 +39,35 @@ exports.noUnusedProps = (0, createRule_1.createRule)({
39
39
  typeNode.types.forEach(extractProps);
40
40
  }
41
41
  else if (typeNode.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
42
- // For referenced types like FormControlLabelProps, we need to track that these props should be forwarded
43
42
  if (typeNode.typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
44
- props[`...${typeNode.typeName.name}`] = typeNode.typeName;
43
+ if (typeNode.typeName.name === 'Pick' && typeNode.typeParameters) {
44
+ // Handle Pick utility type
45
+ const [baseType, pickedProps] = typeNode.typeParameters.params;
46
+ if (baseType.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
47
+ baseType.typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
48
+ // Extract the picked properties from the union type
49
+ if (pickedProps.type === utils_1.AST_NODE_TYPES.TSUnionType) {
50
+ pickedProps.types.forEach((type) => {
51
+ if (type.type === utils_1.AST_NODE_TYPES.TSLiteralType &&
52
+ type.literal.type === utils_1.AST_NODE_TYPES.Literal &&
53
+ typeof type.literal.value === 'string') {
54
+ // Add each picked property as a regular prop
55
+ props[type.literal.value] = type.literal;
56
+ }
57
+ });
58
+ }
59
+ else if (pickedProps.type === utils_1.AST_NODE_TYPES.TSLiteralType &&
60
+ pickedProps.literal.type === utils_1.AST_NODE_TYPES.Literal &&
61
+ typeof pickedProps.literal.value === 'string') {
62
+ // Single property pick
63
+ props[pickedProps.literal.value] = pickedProps.literal;
64
+ }
65
+ }
66
+ }
67
+ else {
68
+ // For referenced types like FormControlLabelProps, we need to track that these props should be forwarded
69
+ props[`...${typeNode.typeName.name}`] = typeNode.typeName;
70
+ }
45
71
  }
46
72
  }
47
73
  }
@@ -0,0 +1,3 @@
1
+ type MessageIds = 'preferSetAll' | 'preferOverwriteAll';
2
+ export declare const preferBatchOperations: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<MessageIds, [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
3
+ export {};