@blumintinc/eslint-plugin-blumint 1.12.5 → 1.13.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 (142) hide show
  1. package/README.md +140 -99
  2. package/lib/index.js +111 -20
  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/dynamic-https-errors.d.ts +3 -1
  6. package/lib/rules/dynamic-https-errors.js +48 -10
  7. package/lib/rules/enforce-assert-safe-object-key.d.ts +8 -0
  8. package/lib/rules/{enforce-assertSafe-object-key.js → enforce-assert-safe-object-key.js} +51 -95
  9. package/lib/rules/enforce-assert-throws.d.ts +3 -1
  10. package/lib/rules/enforce-assert-throws.js +493 -51
  11. package/lib/rules/enforce-boolean-naming-prefixes.d.ts +3 -1
  12. package/lib/rules/enforce-boolean-naming-prefixes.js +832 -39
  13. package/lib/rules/enforce-callable-types.js +4 -4
  14. package/lib/rules/enforce-callback-memo.js +143 -18
  15. package/lib/rules/enforce-centralized-mock-firestore.js +4 -1
  16. package/lib/rules/enforce-console-error.d.ts +3 -0
  17. package/lib/rules/enforce-console-error.js +250 -0
  18. package/lib/rules/enforce-css-media-queries.js +24 -46
  19. package/lib/rules/enforce-dynamic-firebase-imports.js +100 -19
  20. package/lib/rules/enforce-dynamic-imports.js +1 -1
  21. package/lib/rules/enforce-exported-function-types.js +3 -3
  22. package/lib/rules/enforce-fieldpath-syntax-in-docsetter.d.ts +2 -0
  23. package/lib/rules/enforce-fieldpath-syntax-in-docsetter.js +212 -0
  24. package/lib/rules/enforce-firestore-doc-ref-generic.js +335 -0
  25. package/lib/rules/enforce-firestore-facade.js +347 -157
  26. package/lib/rules/enforce-firestore-rules-get-access.d.ts +3 -0
  27. package/lib/rules/enforce-firestore-rules-get-access.js +109 -0
  28. package/lib/rules/enforce-global-constants.d.ts +4 -1
  29. package/lib/rules/enforce-global-constants.js +240 -12
  30. package/lib/rules/enforce-memoize-async.d.ts +2 -1
  31. package/lib/rules/enforce-memoize-async.js +96 -27
  32. package/lib/rules/enforce-memoize-getters.d.ts +3 -0
  33. package/lib/rules/enforce-memoize-getters.js +123 -0
  34. package/lib/rules/enforce-microdiff.js +2 -1
  35. package/lib/rules/enforce-positive-naming.js +5 -7
  36. package/lib/rules/enforce-props-argument-name.d.ts +2 -7
  37. package/lib/rules/enforce-props-argument-name.js +165 -151
  38. package/lib/rules/enforce-props-naming-consistency.d.ts +2 -0
  39. package/lib/rules/enforce-props-naming-consistency.js +145 -0
  40. package/lib/rules/enforce-querykey-ts.d.ts +9 -0
  41. package/lib/rules/enforce-querykey-ts.js +274 -0
  42. package/lib/rules/enforce-singular-type-names.js +9 -5
  43. package/lib/rules/enforce-typescript-markdown-code-blocks.d.ts +1 -0
  44. package/lib/rules/enforce-typescript-markdown-code-blocks.js +96 -0
  45. package/lib/rules/enforce-verb-noun-naming.js +85 -10
  46. package/lib/rules/extract-global-constants.js +57 -45
  47. package/lib/rules/fast-deep-equal-over-microdiff.d.ts +2 -1
  48. package/lib/rules/fast-deep-equal-over-microdiff.js +356 -78
  49. package/lib/rules/firestore-transaction-reads-before-writes.d.ts +1 -0
  50. package/lib/rules/firestore-transaction-reads-before-writes.js +231 -0
  51. package/lib/rules/generic-starts-with-t.js +8 -2
  52. package/lib/rules/memoize-root-level-hocs.d.ts +7 -0
  53. package/lib/rules/memoize-root-level-hocs.js +242 -0
  54. package/lib/rules/no-array-length-in-deps.d.ts +12 -0
  55. package/lib/rules/no-array-length-in-deps.js +308 -0
  56. package/lib/rules/no-async-array-filter.js +5 -2
  57. package/lib/rules/no-complex-cloud-params.js +15 -2
  58. package/lib/rules/no-compositing-layer-props.js +4 -2
  59. package/lib/rules/no-entire-object-hook-deps.d.ts +3 -1
  60. package/lib/rules/no-entire-object-hook-deps.js +317 -63
  61. package/lib/rules/no-excessive-parent-chain.d.ts +5 -0
  62. package/lib/rules/no-excessive-parent-chain.js +273 -0
  63. package/lib/rules/no-firestore-object-arrays.js +345 -30
  64. package/lib/rules/no-hungarian.js +13 -13
  65. package/lib/rules/no-margin-properties.d.ts +7 -1
  66. package/lib/rules/no-margin-properties.js +16 -3
  67. package/lib/rules/no-misleading-boolean-prefixes.d.ts +7 -0
  68. package/lib/rules/no-misleading-boolean-prefixes.js +327 -0
  69. package/lib/rules/no-overridable-method-calls-in-constructor.d.ts +1 -0
  70. package/lib/rules/no-overridable-method-calls-in-constructor.js +260 -0
  71. package/lib/rules/no-passthrough-getters.d.ts +4 -0
  72. package/lib/rules/no-passthrough-getters.js +170 -0
  73. package/lib/rules/no-redundant-usecallback-wrapper.d.ts +8 -0
  74. package/lib/rules/no-redundant-usecallback-wrapper.js +315 -0
  75. package/lib/rules/no-restricted-properties-fix.d.ts +12 -0
  76. package/lib/rules/no-restricted-properties-fix.js +172 -0
  77. package/lib/rules/no-separate-loading-state.d.ts +8 -0
  78. package/lib/rules/no-separate-loading-state.js +142 -0
  79. package/lib/rules/no-stale-state-across-await.d.ts +1 -0
  80. package/lib/rules/no-stale-state-across-await.js +185 -0
  81. package/lib/rules/no-static-constants-in-dynamic-files.d.ts +3 -0
  82. package/lib/rules/no-static-constants-in-dynamic-files.js +149 -0
  83. package/lib/rules/no-try-catch-already-exists-in-transaction.d.ts +1 -0
  84. package/lib/rules/no-try-catch-already-exists-in-transaction.js +342 -0
  85. package/lib/rules/no-undefined-null-passthrough.js +166 -19
  86. package/lib/rules/no-unnecessary-verb-suffix.js +0 -2
  87. package/lib/rules/no-unsafe-firestore-spread.js +8 -5
  88. package/lib/rules/no-unused-props.d.ts +3 -0
  89. package/lib/rules/no-unused-props.js +213 -78
  90. package/lib/rules/optimize-object-boolean-conditions.d.ts +1 -0
  91. package/lib/rules/optimize-object-boolean-conditions.js +234 -0
  92. package/lib/rules/parallelize-async-operations.d.ts +8 -0
  93. package/lib/rules/parallelize-async-operations.js +375 -0
  94. package/lib/rules/prefer-batch-operations.js +199 -33
  95. package/lib/rules/prefer-block-comments-for-declarations.js +13 -3
  96. package/lib/rules/prefer-document-flattening.d.ts +4 -0
  97. package/lib/rules/prefer-document-flattening.js +239 -0
  98. package/lib/rules/prefer-field-paths-in-transforms.d.ts +7 -0
  99. package/lib/rules/prefer-field-paths-in-transforms.js +250 -0
  100. package/lib/rules/prefer-fragment-component.js +3 -3
  101. package/lib/rules/prefer-global-router-state-key.d.ts +7 -3
  102. package/lib/rules/prefer-global-router-state-key.js +230 -31
  103. package/lib/rules/prefer-next-dynamic.d.ts +9 -0
  104. package/lib/rules/prefer-next-dynamic.js +366 -0
  105. package/lib/rules/prefer-nullish-coalescing-boolean-props.d.ts +1 -0
  106. package/lib/rules/prefer-nullish-coalescing-boolean-props.js +430 -0
  107. package/lib/rules/prefer-nullish-coalescing-override.d.ts +6 -0
  108. package/lib/rules/prefer-nullish-coalescing-override.js +182 -0
  109. package/lib/rules/prefer-params-over-parent-id.d.ts +5 -0
  110. package/lib/rules/prefer-params-over-parent-id.js +228 -0
  111. package/lib/rules/prefer-settings-object.js +23 -15
  112. package/lib/rules/prefer-type-alias-over-typeof-constant.d.ts +3 -0
  113. package/lib/rules/prefer-type-alias-over-typeof-constant.js +259 -0
  114. package/lib/rules/prefer-url-tostring-over-tojson.d.ts +2 -0
  115. package/lib/rules/prefer-url-tostring-over-tojson.js +166 -0
  116. package/lib/rules/prefer-use-deep-compare-memo.d.ts +4 -0
  117. package/lib/rules/prefer-use-deep-compare-memo.js +428 -0
  118. package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +24 -1
  119. package/lib/rules/prefer-usememo-over-useeffect-usestate.js +24 -5
  120. package/lib/rules/react-usememo-should-be-component.d.ts +2 -1
  121. package/lib/rules/react-usememo-should-be-component.js +144 -78
  122. package/lib/rules/require-dynamic-firebase-imports.js +2 -1
  123. package/lib/rules/require-image-optimized.js +1 -1
  124. package/lib/rules/require-memo.js +11 -1
  125. package/lib/rules/require-usememo-object-literals.js +7 -1
  126. package/lib/rules/semantic-function-prefixes.js +38 -18
  127. package/lib/rules/sync-onwrite-name-func.js +5 -1
  128. package/lib/rules/test-file-location-enforcement.d.ts +1 -0
  129. package/lib/rules/test-file-location-enforcement.js +57 -0
  130. package/lib/rules/use-custom-link.js +6 -1
  131. package/lib/rules/use-custom-router.js +6 -1
  132. package/lib/rules/use-latest-callback.d.ts +3 -0
  133. package/lib/rules/use-latest-callback.js +270 -0
  134. package/lib/utils/ASTHelpers.js +10 -0
  135. package/lib/utils/createRule.js +1 -1
  136. package/lib/utils/graph/ClassGraphSorterReadability.js +1 -1
  137. package/lib/utils/ruleTester.d.ts +1 -0
  138. package/lib/utils/ruleTester.js +4 -1
  139. package/package.json +21 -14
  140. package/lib/rules/enforce-assertSafe-object-key.d.ts +0 -2
  141. package/lib/rules/no-restricted-imports-dynamic.d.ts +0 -25
  142. package/lib/rules/no-restricted-imports-dynamic.js +0 -213
@@ -0,0 +1,366 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.preferNextDynamic = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const createRule_1 = require("../utils/createRule");
6
+ const DEFAULT_USE_DYNAMIC_SOURCES = [
7
+ 'useDynamic',
8
+ './useDynamic',
9
+ '../hooks/useDynamic',
10
+ '../../hooks/useDynamic',
11
+ ];
12
+ function matchesAllowedSource(source, allowedSources) {
13
+ return allowedSources.some((pattern) => source === pattern || source.endsWith(`/${pattern}`));
14
+ }
15
+ function isUseDynamicCall(node) {
16
+ const { callee, arguments: args } = node;
17
+ if (callee.type === utils_1.AST_NODE_TYPES.Identifier &&
18
+ callee.name === 'useDynamic' &&
19
+ args.length === 1 &&
20
+ args[0].type === utils_1.AST_NODE_TYPES.ImportExpression) {
21
+ return true;
22
+ }
23
+ return false;
24
+ }
25
+ function findProgramNode(node) {
26
+ let current = node;
27
+ while (current && current.type !== utils_1.AST_NODE_TYPES.Program) {
28
+ current = current.parent;
29
+ }
30
+ return current || null;
31
+ }
32
+ function getImportDeclarations(program) {
33
+ return program.body.filter((n) => n.type === utils_1.AST_NODE_TYPES.ImportDeclaration);
34
+ }
35
+ function findUseDynamicImport(program, allowedSources) {
36
+ const imports = getImportDeclarations(program);
37
+ for (const imp of imports) {
38
+ if (typeof imp.source.value !== 'string')
39
+ continue;
40
+ const source = imp.source.value;
41
+ if (!matchesAllowedSource(source, allowedSources))
42
+ continue;
43
+ const importedUseDynamic = imp.specifiers.find((s) => (s.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
44
+ s.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
45
+ s.imported.name === 'useDynamic') ||
46
+ s.type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier ||
47
+ (s.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
48
+ s.local.name === 'useDynamic'));
49
+ if (importedUseDynamic && importedUseDynamic.local.name === 'useDynamic') {
50
+ return {
51
+ importNode: imp,
52
+ specifier: importedUseDynamic,
53
+ localName: importedUseDynamic.local.name,
54
+ };
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+ function getNextDynamicLocalName(program) {
60
+ for (const imp of getImportDeclarations(program)) {
61
+ if (imp.source.value === 'next/dynamic') {
62
+ const def = imp.specifiers.find((s) => s.type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier);
63
+ if (def)
64
+ return def.local.name;
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ function buildDynamicReplacement(call, variableKind, variableIdText, namedExportKey, sourceCode, dynamicIdent) {
70
+ const expr = buildDynamicExpression(call, namedExportKey, sourceCode, dynamicIdent);
71
+ return `${variableKind} ${variableIdText} = ${expr};`;
72
+ }
73
+ function buildDynamicExpression(call, namedExportKey, sourceCode, dynamicIdent) {
74
+ // call.arguments[0] is ImportExpression
75
+ const importExpr = call.arguments[0];
76
+ const importArgText = sourceCode.getText(importExpr.source);
77
+ const returnExpr = namedExportKey ? `mod.${namedExportKey}` : 'mod.default';
78
+ const dynamicText = `${dynamicIdent}(
79
+ async () => {
80
+ const mod = await import(${importArgText});
81
+ return ${returnExpr};
82
+ },
83
+ { ssr: false }
84
+ )`;
85
+ return dynamicText;
86
+ }
87
+ function inferVariableInfo(node) {
88
+ // Support: const Foo = useDynamic(import('...'));
89
+ // or: const { Picker } = useDynamic(import('...'));
90
+ const decl = node;
91
+ if (!decl.init || decl.init.type !== utils_1.AST_NODE_TYPES.CallExpression) {
92
+ return null;
93
+ }
94
+ if (!isUseDynamicCall(decl.init))
95
+ return null;
96
+ let kind = 'const';
97
+ const parent = decl.parent;
98
+ if (parent &&
99
+ parent.type === utils_1.AST_NODE_TYPES.VariableDeclaration &&
100
+ (parent.kind === 'const' || parent.kind === 'let' || parent.kind === 'var')) {
101
+ kind = parent.kind;
102
+ }
103
+ if (decl.id.type === utils_1.AST_NODE_TYPES.Identifier) {
104
+ return { kind, idText: decl.id.name, namedExportKey: null };
105
+ }
106
+ if (decl.id.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
107
+ // Only handle a single-property destructure like { Picker }
108
+ if (decl.id.properties.length !== 1) {
109
+ return null;
110
+ }
111
+ const prop = decl.id.properties[0];
112
+ if (prop && prop.type === utils_1.AST_NODE_TYPES.Property) {
113
+ const key = prop.key.type === utils_1.AST_NODE_TYPES.Identifier ? prop.key.name : null;
114
+ const valueName = prop.value.type === utils_1.AST_NODE_TYPES.Identifier ? prop.value.name : null;
115
+ if (key && valueName) {
116
+ return { kind, idText: valueName, namedExportKey: key };
117
+ }
118
+ }
119
+ }
120
+ return null;
121
+ }
122
+ exports.preferNextDynamic = (0, createRule_1.createRule)({
123
+ name: 'prefer-next-dynamic',
124
+ meta: {
125
+ type: 'problem',
126
+ docs: {
127
+ description: 'Prefer Next.js dynamic() over custom useDynamic() for component imports',
128
+ recommended: 'error',
129
+ requiresTypeChecking: true,
130
+ },
131
+ fixable: 'code',
132
+ schema: [
133
+ {
134
+ type: 'object',
135
+ properties: {
136
+ useDynamicSources: {
137
+ type: 'array',
138
+ items: { type: 'string' },
139
+ minItems: 1,
140
+ },
141
+ },
142
+ additionalProperties: false,
143
+ },
144
+ ],
145
+ messages: {
146
+ preferNextDynamic: 'Use Next.js dynamic() instead of useDynamic(import(...)) for component imports',
147
+ addNextDynamicImport: "Add default import: import dynamic from 'next/dynamic'",
148
+ removeUseDynamicImport: 'Remove unused useDynamic import',
149
+ },
150
+ },
151
+ defaultOptions: [{}],
152
+ create(context) {
153
+ const [options = {}] = context.options;
154
+ const allowedUseDynamicSources = options.useDynamicSources && options.useDynamicSources.length > 0
155
+ ? options.useDynamicSources
156
+ : DEFAULT_USE_DYNAMIC_SOURCES;
157
+ const sourceCode = context.getSourceCode();
158
+ return {
159
+ VariableDeclarator(node) {
160
+ const info = inferVariableInfo(node);
161
+ if (!info)
162
+ return;
163
+ // For edge case 1 (Non-Component Imports): we conservatively only transform when the LHS is used in JSX.
164
+ // Heuristic: if identifier appears in any JSXOpeningElement as name, consider a component.
165
+ const program = findProgramNode(node);
166
+ if (!program)
167
+ return;
168
+ const useDynamicImportInfo = findUseDynamicImport(program, allowedUseDynamicSources);
169
+ if (!useDynamicImportInfo)
170
+ return;
171
+ const identifierName = info.idText;
172
+ let usedInJsx = false;
173
+ const scopeBody = program.body;
174
+ // Walk AST to find JSX usage; track visited nodes to avoid cycles
175
+ // Note: We intentionally avoid relying on tokens here.
176
+ // Fallback AST traversal for JSX usage
177
+ const visited = new WeakSet();
178
+ const checkJsxUsage = (n) => {
179
+ if (visited.has(n))
180
+ return;
181
+ visited.add(n);
182
+ if (usedInJsx)
183
+ return;
184
+ if (n.type === utils_1.AST_NODE_TYPES.JSXOpeningElement) {
185
+ const name = n.name;
186
+ if (name.type === utils_1.AST_NODE_TYPES.JSXIdentifier) {
187
+ if (name.name === identifierName)
188
+ usedInJsx = true;
189
+ }
190
+ else if (name.type === utils_1.AST_NODE_TYPES.JSXMemberExpression) {
191
+ // Not matching identifier simple usage
192
+ }
193
+ }
194
+ // recurse
195
+ const anyNode = n;
196
+ for (const key of Object.keys(anyNode)) {
197
+ if (key === 'parent')
198
+ continue;
199
+ const child = anyNode[key];
200
+ if (Array.isArray(child)) {
201
+ for (const c of child) {
202
+ if (c && typeof c.type === 'string') {
203
+ checkJsxUsage(c);
204
+ }
205
+ }
206
+ }
207
+ else if (child && typeof child === 'object') {
208
+ if (child.type &&
209
+ typeof child.type === 'string') {
210
+ checkJsxUsage(child);
211
+ }
212
+ }
213
+ }
214
+ };
215
+ scopeBody.forEach((b) => checkJsxUsage(b));
216
+ if (!usedInJsx) {
217
+ // Skip to avoid flagging non-component dynamic imports
218
+ return;
219
+ }
220
+ // Now we are confident enough to report and fix
221
+ const init = node.init;
222
+ const parentDecl = node.parent;
223
+ context.report({
224
+ node: init,
225
+ messageId: 'preferNextDynamic',
226
+ fix(fixer) {
227
+ const fixes = [];
228
+ // ensure dynamic import is present
229
+ const programNode = findProgramNode(node);
230
+ let dynamicLocal = getNextDynamicLocalName(programNode);
231
+ const hasDynamic = !!dynamicLocal;
232
+ if (!hasDynamic) {
233
+ // Insert after directive prologue (e.g., "use client")
234
+ const insertionIndex = programNode.body.findIndex((stmt) => {
235
+ return !(stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement &&
236
+ stmt.expression.type === utils_1.AST_NODE_TYPES.Literal &&
237
+ typeof stmt.expression.value === 'string');
238
+ });
239
+ const target = insertionIndex === -1
240
+ ? programNode.body[0]
241
+ : programNode.body[insertionIndex];
242
+ const indentation = '';
243
+ fixes.push(fixer.insertTextBefore(target, `${indentation}import dynamic from 'next/dynamic';\n`));
244
+ dynamicLocal = 'dynamic';
245
+ }
246
+ // Replace the variable declarator text with dynamic(...) usage
247
+ if (parentDecl.declarations.length === 1) {
248
+ const variableText = buildDynamicReplacement(init, parentDecl.kind, info.idText, info.namedExportKey, sourceCode, dynamicLocal || 'dynamic');
249
+ fixes.push(fixer.replaceText(parentDecl, variableText));
250
+ }
251
+ else {
252
+ // Multiple declarators:
253
+ if (node.id.type === utils_1.AST_NODE_TYPES.Identifier) {
254
+ // Replace only the initializer expression
255
+ const dynamicExpr = buildDynamicExpression(init, info.namedExportKey, sourceCode, dynamicLocal || 'dynamic');
256
+ fixes.push(fixer.replaceText(init, dynamicExpr));
257
+ }
258
+ else if (node.id.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
259
+ // Replace the whole declarator with "<localName> = dynamic(...)"
260
+ const dynamicExpr = buildDynamicExpression(init, info.namedExportKey, sourceCode, dynamicLocal || 'dynamic');
261
+ const replacement = `${info.idText} = ${dynamicExpr}`;
262
+ fixes.push(fixer.replaceText(node, replacement));
263
+ }
264
+ }
265
+ // Remove unused useDynamic import if present and no longer referenced
266
+ const latestUseDynamicImport = findUseDynamicImport(programNode, allowedUseDynamicSources);
267
+ if (latestUseDynamicImport) {
268
+ // Abort removal if there are other useDynamic(import(...)) calls in the file
269
+ let otherUseDynamicCalls = false;
270
+ const visit = (n) => {
271
+ if (otherUseDynamicCalls)
272
+ return;
273
+ if (n.type === utils_1.AST_NODE_TYPES.CallExpression &&
274
+ isUseDynamicCall(n)) {
275
+ if (n !== init)
276
+ otherUseDynamicCalls = true;
277
+ }
278
+ const anyNode = n;
279
+ for (const key of Object.keys(anyNode)) {
280
+ if (key === 'parent')
281
+ continue;
282
+ const child = anyNode[key];
283
+ if (Array.isArray(child)) {
284
+ for (const c of child)
285
+ if (c && typeof c.type === 'string')
286
+ visit(c);
287
+ }
288
+ else if (child &&
289
+ typeof child === 'object' &&
290
+ child.type) {
291
+ visit(child);
292
+ }
293
+ }
294
+ };
295
+ programNode.body.forEach((b) => visit(b));
296
+ if (otherUseDynamicCalls) {
297
+ return fixes; // keep the import; other occurrences still rely on it
298
+ }
299
+ // If import had only useDynamic, remove entire declaration; else remove just its specifier
300
+ const specifiers = latestUseDynamicImport.importNode.specifiers;
301
+ const useDynamicSpecifier = specifiers.find((s) => (s.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
302
+ s.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
303
+ s.imported.name === 'useDynamic') ||
304
+ (s.type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier &&
305
+ s.local.name === 'useDynamic') ||
306
+ (s.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
307
+ s.local.name === 'useDynamic'));
308
+ if (useDynamicSpecifier) {
309
+ if (specifiers.length === 1) {
310
+ // Remove entire import
311
+ fixes.push(fixer.remove(latestUseDynamicImport.importNode));
312
+ // If dynamic was already present (we didn't insert), collapse the extra newline left by removal
313
+ if (hasDynamic) {
314
+ const after = latestUseDynamicImport.importNode.range[1];
315
+ if (after < sourceCode.text.length) {
316
+ const ch = sourceCode.text[after];
317
+ if (ch === '\n' || ch === '\r') {
318
+ fixes.push(fixer.removeRange([after, after + 1]));
319
+ }
320
+ }
321
+ }
322
+ }
323
+ else {
324
+ // If only named specifiers exist, reconstruct a clean import text
325
+ const onlyNamed = specifiers.every((s) => s.type === utils_1.AST_NODE_TYPES.ImportSpecifier);
326
+ if (onlyNamed) {
327
+ const remaining = specifiers.filter((s) => s !== useDynamicSpecifier);
328
+ const specText = remaining
329
+ .map((s) => s.imported.name === s.local.name
330
+ ? s.local.name
331
+ : `${s.imported.name} as ${s.local.name}`)
332
+ .join(', ');
333
+ const newText = `import { ${specText} } from '${latestUseDynamicImport.importNode.source.value}';`;
334
+ fixes.push(fixer.replaceText(latestUseDynamicImport.importNode, newText));
335
+ }
336
+ else {
337
+ // Otherwise, remove the specifier with proper comma handling
338
+ const tokenAfter = sourceCode.getTokenAfter(useDynamicSpecifier);
339
+ const tokenBefore = sourceCode.getTokenBefore(useDynamicSpecifier);
340
+ if (tokenAfter && tokenAfter.value === ',') {
341
+ fixes.push(fixer.removeRange([
342
+ useDynamicSpecifier.range[0],
343
+ tokenAfter.range[1],
344
+ ]));
345
+ }
346
+ else if (tokenBefore && tokenBefore.value === ',') {
347
+ fixes.push(fixer.removeRange([
348
+ tokenBefore.range[0],
349
+ useDynamicSpecifier.range[1],
350
+ ]));
351
+ }
352
+ else {
353
+ fixes.push(fixer.remove(useDynamicSpecifier));
354
+ }
355
+ }
356
+ }
357
+ }
358
+ }
359
+ return fixes;
360
+ },
361
+ });
362
+ },
363
+ };
364
+ },
365
+ });
366
+ //# sourceMappingURL=prefer-next-dynamic.js.map
@@ -0,0 +1 @@
1
+ export declare const preferNullishCoalescingBooleanProps: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"preferNullishCoalescing", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;