@blumintinc/eslint-plugin-blumint 1.12.6 → 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.
- package/README.md +140 -99
- package/lib/index.js +111 -17
- package/lib/rules/array-methods-this-context.js +20 -2
- package/lib/rules/avoid-utils-directory.js +11 -2
- package/lib/rules/dynamic-https-errors.d.ts +3 -1
- package/lib/rules/dynamic-https-errors.js +48 -10
- package/lib/rules/enforce-assert-safe-object-key.d.ts +8 -0
- package/lib/rules/{enforce-assertSafe-object-key.js → enforce-assert-safe-object-key.js} +51 -95
- package/lib/rules/enforce-assert-throws.d.ts +3 -1
- package/lib/rules/enforce-assert-throws.js +493 -51
- package/lib/rules/enforce-boolean-naming-prefixes.d.ts +3 -1
- package/lib/rules/enforce-boolean-naming-prefixes.js +832 -39
- package/lib/rules/enforce-callable-types.js +4 -4
- package/lib/rules/enforce-callback-memo.js +143 -18
- package/lib/rules/enforce-centralized-mock-firestore.js +4 -1
- package/lib/rules/enforce-console-error.d.ts +3 -0
- package/lib/rules/enforce-console-error.js +250 -0
- package/lib/rules/enforce-css-media-queries.js +24 -46
- package/lib/rules/enforce-dynamic-firebase-imports.js +100 -19
- package/lib/rules/enforce-dynamic-imports.js +1 -1
- package/lib/rules/enforce-exported-function-types.js +3 -3
- package/lib/rules/enforce-fieldpath-syntax-in-docsetter.d.ts +2 -0
- package/lib/rules/enforce-fieldpath-syntax-in-docsetter.js +212 -0
- package/lib/rules/enforce-firestore-doc-ref-generic.js +335 -0
- package/lib/rules/enforce-firestore-facade.js +347 -157
- package/lib/rules/enforce-firestore-rules-get-access.d.ts +3 -0
- package/lib/rules/enforce-firestore-rules-get-access.js +109 -0
- package/lib/rules/enforce-global-constants.d.ts +4 -1
- package/lib/rules/enforce-global-constants.js +240 -12
- package/lib/rules/enforce-memoize-async.d.ts +2 -1
- package/lib/rules/enforce-memoize-async.js +96 -27
- package/lib/rules/enforce-memoize-getters.d.ts +3 -0
- package/lib/rules/enforce-memoize-getters.js +123 -0
- package/lib/rules/enforce-microdiff.js +2 -1
- package/lib/rules/enforce-positive-naming.js +5 -7
- package/lib/rules/enforce-props-argument-name.d.ts +2 -7
- package/lib/rules/enforce-props-argument-name.js +165 -151
- package/lib/rules/enforce-props-naming-consistency.d.ts +2 -0
- package/lib/rules/enforce-props-naming-consistency.js +145 -0
- package/lib/rules/enforce-querykey-ts.d.ts +9 -0
- package/lib/rules/enforce-querykey-ts.js +274 -0
- package/lib/rules/enforce-singular-type-names.js +9 -5
- package/lib/rules/enforce-typescript-markdown-code-blocks.d.ts +1 -0
- package/lib/rules/enforce-typescript-markdown-code-blocks.js +96 -0
- package/lib/rules/enforce-verb-noun-naming.js +85 -10
- package/lib/rules/extract-global-constants.js +57 -45
- package/lib/rules/fast-deep-equal-over-microdiff.d.ts +2 -1
- package/lib/rules/fast-deep-equal-over-microdiff.js +356 -78
- package/lib/rules/firestore-transaction-reads-before-writes.d.ts +1 -0
- package/lib/rules/firestore-transaction-reads-before-writes.js +231 -0
- package/lib/rules/generic-starts-with-t.js +8 -2
- package/lib/rules/memoize-root-level-hocs.d.ts +7 -0
- package/lib/rules/memoize-root-level-hocs.js +242 -0
- package/lib/rules/no-array-length-in-deps.d.ts +12 -0
- package/lib/rules/no-array-length-in-deps.js +308 -0
- package/lib/rules/no-async-array-filter.js +5 -2
- package/lib/rules/no-complex-cloud-params.js +15 -2
- package/lib/rules/no-compositing-layer-props.js +4 -2
- package/lib/rules/no-entire-object-hook-deps.d.ts +3 -1
- package/lib/rules/no-entire-object-hook-deps.js +317 -63
- package/lib/rules/no-excessive-parent-chain.d.ts +5 -0
- package/lib/rules/no-excessive-parent-chain.js +273 -0
- package/lib/rules/no-firestore-object-arrays.js +345 -30
- package/lib/rules/no-hungarian.js +13 -13
- package/lib/rules/no-margin-properties.d.ts +7 -1
- package/lib/rules/no-margin-properties.js +16 -3
- package/lib/rules/no-misleading-boolean-prefixes.d.ts +7 -0
- package/lib/rules/no-misleading-boolean-prefixes.js +327 -0
- package/lib/rules/no-overridable-method-calls-in-constructor.d.ts +1 -0
- package/lib/rules/no-overridable-method-calls-in-constructor.js +260 -0
- package/lib/rules/no-passthrough-getters.d.ts +4 -0
- package/lib/rules/no-passthrough-getters.js +170 -0
- package/lib/rules/no-redundant-usecallback-wrapper.d.ts +8 -0
- package/lib/rules/no-redundant-usecallback-wrapper.js +315 -0
- package/lib/rules/no-restricted-properties-fix.d.ts +12 -0
- package/lib/rules/no-restricted-properties-fix.js +172 -0
- package/lib/rules/no-separate-loading-state.d.ts +8 -0
- package/lib/rules/no-separate-loading-state.js +142 -0
- package/lib/rules/no-stale-state-across-await.d.ts +1 -0
- package/lib/rules/no-stale-state-across-await.js +185 -0
- package/lib/rules/no-static-constants-in-dynamic-files.d.ts +3 -0
- package/lib/rules/no-static-constants-in-dynamic-files.js +149 -0
- package/lib/rules/no-try-catch-already-exists-in-transaction.d.ts +1 -0
- package/lib/rules/no-try-catch-already-exists-in-transaction.js +342 -0
- package/lib/rules/no-type-assertion-returns.js +6 -0
- package/lib/rules/no-undefined-null-passthrough.js +166 -19
- package/lib/rules/no-unnecessary-verb-suffix.js +0 -2
- package/lib/rules/no-unsafe-firestore-spread.js +8 -5
- package/lib/rules/no-unused-props.d.ts +3 -0
- package/lib/rules/no-unused-props.js +213 -78
- package/lib/rules/optimize-object-boolean-conditions.d.ts +1 -0
- package/lib/rules/optimize-object-boolean-conditions.js +234 -0
- package/lib/rules/parallelize-async-operations.d.ts +8 -0
- package/lib/rules/parallelize-async-operations.js +375 -0
- package/lib/rules/prefer-batch-operations.js +199 -33
- package/lib/rules/prefer-block-comments-for-declarations.js +13 -3
- package/lib/rules/prefer-document-flattening.d.ts +4 -0
- package/lib/rules/prefer-document-flattening.js +239 -0
- package/lib/rules/prefer-field-paths-in-transforms.d.ts +7 -0
- package/lib/rules/prefer-field-paths-in-transforms.js +250 -0
- package/lib/rules/prefer-fragment-component.js +3 -3
- package/lib/rules/prefer-global-router-state-key.d.ts +7 -3
- package/lib/rules/prefer-global-router-state-key.js +230 -31
- package/lib/rules/prefer-next-dynamic.d.ts +9 -0
- package/lib/rules/prefer-next-dynamic.js +366 -0
- package/lib/rules/prefer-nullish-coalescing-boolean-props.d.ts +1 -0
- package/lib/rules/prefer-nullish-coalescing-boolean-props.js +430 -0
- package/lib/rules/prefer-nullish-coalescing-override.d.ts +6 -0
- package/lib/rules/prefer-nullish-coalescing-override.js +182 -0
- package/lib/rules/prefer-params-over-parent-id.d.ts +5 -0
- package/lib/rules/prefer-params-over-parent-id.js +228 -0
- package/lib/rules/prefer-settings-object.js +23 -15
- package/lib/rules/prefer-type-alias-over-typeof-constant.d.ts +3 -0
- package/lib/rules/prefer-type-alias-over-typeof-constant.js +259 -0
- package/lib/rules/prefer-url-tostring-over-tojson.d.ts +2 -0
- package/lib/rules/prefer-url-tostring-over-tojson.js +166 -0
- package/lib/rules/prefer-use-deep-compare-memo.d.ts +4 -0
- package/lib/rules/prefer-use-deep-compare-memo.js +428 -0
- package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +24 -1
- package/lib/rules/prefer-usememo-over-useeffect-usestate.js +24 -5
- package/lib/rules/react-usememo-should-be-component.d.ts +2 -1
- package/lib/rules/react-usememo-should-be-component.js +144 -78
- package/lib/rules/require-dynamic-firebase-imports.js +2 -1
- package/lib/rules/require-image-optimized.js +1 -1
- package/lib/rules/require-memo.js +11 -1
- package/lib/rules/require-usememo-object-literals.js +7 -1
- package/lib/rules/semantic-function-prefixes.js +38 -18
- package/lib/rules/sync-onwrite-name-func.js +5 -1
- package/lib/rules/test-file-location-enforcement.d.ts +1 -0
- package/lib/rules/test-file-location-enforcement.js +57 -0
- package/lib/rules/use-custom-link.js +6 -1
- package/lib/rules/use-custom-router.js +6 -1
- package/lib/rules/use-latest-callback.d.ts +3 -0
- package/lib/rules/use-latest-callback.js +270 -0
- package/lib/utils/ASTHelpers.js +10 -0
- package/lib/utils/createRule.js +1 -1
- package/lib/utils/graph/ClassGraphSorterReadability.js +1 -1
- package/lib/utils/ruleTester.d.ts +1 -0
- package/lib/utils/ruleTester.js +4 -1
- package/package.json +21 -14
- package/lib/rules/enforce-assertSafe-object-key.d.ts +0 -2
|
@@ -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>;
|