Skip to content

Commit 5c9757c

Browse files
committed
[Refactor] add some more type info; switch for-ofs to forEaches
1 parent a9815da commit 5c9757c

File tree

4 files changed

+72
-44
lines changed

4 files changed

+72
-44
lines changed

src/rules/consistent-type-specifier-style.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ function isComma(token) {
66
return token.type === 'Punctuator' && token.value === ',';
77
}
88

9+
/**
10+
* @param {import('eslint').Rule.Fix[]} fixes
11+
* @param {import('eslint').Rule.RuleFixer} fixer
12+
* @param {import('eslint').SourceCode.SourceCode} sourceCode
13+
* @param {(ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier)[]} specifiers
14+
* */
915
function removeSpecifiers(fixes, fixer, sourceCode, specifiers) {
1016
for (const specifier of specifiers) {
1117
// remove the trailing comma
@@ -17,6 +23,7 @@ function removeSpecifiers(fixes, fixer, sourceCode, specifiers) {
1723
}
1824
}
1925

26+
/** @type {(node: import('estree').Node, sourceCode: import('eslint').SourceCode.SourceCode, specifiers: (ImportSpecifier | ImportNamespaceSpecifier)[], kind: 'type' | 'typeof') => string} */
2027
function getImportText(
2128
node,
2229
sourceCode,
@@ -38,6 +45,7 @@ function getImportText(
3845
return `import ${kind} {${names.join(', ')}} from ${sourceString};`;
3946
}
4047

48+
/** @type {import('eslint').Rule.RuleModule} */
4149
module.exports = {
4250
meta: {
4351
type: 'suggestion',
@@ -102,6 +110,7 @@ module.exports = {
102110

103111
// prefer-top-level
104112
return {
113+
/** @param {import('estree').ImportDeclaration} node */
105114
ImportDeclaration(node) {
106115
if (
107116
// already top-level is valid
@@ -120,9 +129,13 @@ module.exports = {
120129
return;
121130
}
122131

132+
/** @type {typeof node.specifiers} */
123133
const typeSpecifiers = [];
134+
/** @type {typeof node.specifiers} */
124135
const typeofSpecifiers = [];
136+
/** @type {typeof node.specifiers} */
125137
const valueSpecifiers = [];
138+
/** @type {typeof node.specifiers[number]} */
126139
let defaultSpecifier = null;
127140
for (const specifier of node.specifiers) {
128141
if (specifier.type === 'ImportDefaultSpecifier') {
@@ -144,6 +157,7 @@ module.exports = {
144157
const newImports = `${typeImport}\n${typeofImport}`.trim();
145158

146159
if (typeSpecifiers.length + typeofSpecifiers.length === node.specifiers.length) {
160+
/** @type {('type' | 'typeof')[]} */
147161
// all specifiers have inline specifiers - so we replace the entire import
148162
const kind = [].concat(
149163
typeSpecifiers.length > 0 ? 'type' : [],
@@ -162,14 +176,15 @@ module.exports = {
162176
});
163177
} else {
164178
// remove specific specifiers and insert new imports for them
165-
for (const specifier of typeSpecifiers.concat(typeofSpecifiers)) {
179+
typeSpecifiers.concat(typeofSpecifiers).forEach((specifier) => {
166180
context.report({
167181
node: specifier,
168182
message: 'Prefer using a top-level {{kind}}-only import instead of inline {{kind}} specifiers.',
169183
data: {
170184
kind: specifier.importKind,
171185
},
172186
fix(fixer) {
187+
/** @type {import('eslint').Rule.Fix[]} */
173188
const fixes = [];
174189

175190
// if there are no value specifiers, then the other report fixer will be called, not this one
@@ -215,7 +230,7 @@ module.exports = {
215230
);
216231
},
217232
});
218-
}
233+
});
219234
}
220235
},
221236
};

src/rules/no-cycle.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,9 @@ module.exports = {
152152
*/
153153
if (path === myPath && toTraverse.length > 0) { return true; }
154154
if (route.length + 1 < maxDepth) {
155-
for (const { source } of toTraverse) {
155+
toTraverse.forEach(({ source }) => {
156156
untraversed.push({ mget: getter, route: route.concat(source) });
157-
}
157+
});
158158
}
159159
}
160160
}

src/rules/no-duplicates.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ function hasProblematicComments(node, sourceCode) {
7474
);
7575
}
7676

77+
/** @type {(first: import('estree').ImportDeclaration, rest: import('estree').ImportDeclaration[], sourceCode: import('eslint').SourceCode.SourceCode, context: import('eslint').Rule.RuleContext) => import('eslint').Rule.ReportFixer | undefined} */
7778
function getFix(first, rest, sourceCode, context) {
7879
// Sorry ESLint <= 3 users, no autofix for you. Autofixing duplicate imports
7980
// requires multiple `fixer.whatever()` calls in the `fix`: We both need to
@@ -123,7 +124,7 @@ function getFix(first, rest, sourceCode, context) {
123124
isEmpty: !hasSpecifiers(node),
124125
};
125126
})
126-
.filter(Boolean);
127+
.filter((x) => !!x);
127128

128129
const unnecessaryImports = restWithoutComments.filter((node) => !hasSpecifiers(node)
129130
&& !hasNamespace(node)
@@ -139,6 +140,7 @@ function getFix(first, rest, sourceCode, context) {
139140
return undefined;
140141
}
141142

143+
/** @type {import('eslint').Rule.ReportFixer} */
142144
return (fixer) => {
143145
const tokens = sourceCode.getTokens(first);
144146
const openBrace = tokens.find((token) => isPunctuator(token, '{'));
@@ -185,6 +187,7 @@ function getFix(first, rest, sourceCode, context) {
185187
['', !firstHasTrailingComma && !firstIsEmpty, firstExistingIdentifiers],
186188
);
187189

190+
/** @type {import('eslint').Rule.Fix[]} */
188191
const fixes = [];
189192

190193
if (shouldAddSpecifiers && preferInline && first.importKind === 'type') {
@@ -228,7 +231,7 @@ function getFix(first, rest, sourceCode, context) {
228231
}
229232

230233
// Remove imports whose specifiers have been moved into the first import.
231-
for (const specifier of specifiers) {
234+
specifiers.forEach((specifier) => {
232235
const importNode = specifier.importNode;
233236
fixes.push(fixer.remove(importNode));
234237

@@ -237,25 +240,26 @@ function getFix(first, rest, sourceCode, context) {
237240
if (charAfterImport === '\n') {
238241
fixes.push(fixer.removeRange(charAfterImportRange));
239242
}
240-
}
243+
});
241244

242245
// Remove imports whose default import has been moved to the first import,
243246
// and side-effect-only imports that are unnecessary due to the first
244247
// import.
245-
for (const node of unnecessaryImports) {
248+
unnecessaryImports.forEach((node) => {
246249
fixes.push(fixer.remove(node));
247250

248251
const charAfterImportRange = [node.range[1], node.range[1] + 1];
249252
const charAfterImport = sourceCode.text.substring(charAfterImportRange[0], charAfterImportRange[1]);
250253
if (charAfterImport === '\n') {
251254
fixes.push(fixer.removeRange(charAfterImportRange));
252255
}
253-
}
256+
});
254257

255258
return fixes;
256259
};
257260
}
258261

262+
/** @type {(imported: Map<string, import('estree').ImportDeclaration[]>, context: import('eslint').Rule.RuleContext) => void} */
259263
function checkImports(imported, context) {
260264
for (const [module, nodes] of imported.entries()) {
261265
if (nodes.length > 1) {
@@ -270,16 +274,17 @@ function checkImports(imported, context) {
270274
fix, // Attach the autofix (if any) to the first import.
271275
});
272276

273-
for (const node of rest) {
277+
rest.forEach((node) => {
274278
context.report({
275279
node: node.source,
276280
message,
277281
});
278-
}
282+
});
279283
}
280284
}
281285
}
282286

287+
/** @type {import('eslint').Rule.RuleModule} */
283288
module.exports = {
284289
meta: {
285290
type: 'problem',
@@ -305,10 +310,13 @@ module.exports = {
305310
],
306311
},
307312

313+
/** @param {import('eslint').Rule.RuleContext} context */
308314
create(context) {
315+
/** @type {boolean} */
309316
// Prepare the resolver from options.
310-
const considerQueryStringOption = context.options[0]
311-
&& context.options[0].considerQueryString;
317+
const considerQueryStringOption = context.options[0] && context.options[0].considerQueryString;
318+
/** @type {boolean} */
319+
const preferInline = context.options[0] && context.options[0]['prefer-inline'];
312320
const defaultResolver = (sourcePath) => resolve(sourcePath, context) || sourcePath;
313321
const resolver = considerQueryStringOption ? (sourcePath) => {
314322
const parts = sourcePath.match(/^([^?]*)\?(.*)$/);
@@ -318,19 +326,21 @@ module.exports = {
318326
return `${defaultResolver(parts[1])}?${parts[2]}`;
319327
} : defaultResolver;
320328

329+
/** @type {Map<unknown, { imported: Map<string, import('estree').ImportDeclaration[]>, nsImported: Map<string, import('estree').ImportDeclaration[]>, defaultTypesImported: Map<string, import('estree').ImportDeclaration[]>, namedTypesImported: Map<string, import('estree').ImportDeclaration[]>}>} */
321330
const moduleMaps = new Map();
322331

332+
/** @param {import('estree').ImportDeclaration} n */
333+
/** @returns {typeof moduleMaps[keyof typeof moduleMaps]} */
323334
function getImportMap(n) {
324335
if (!moduleMaps.has(n.parent)) {
325-
moduleMaps.set(n.parent, {
336+
moduleMaps.set(n.parent, /** @type {typeof moduleMaps} */ {
326337
imported: new Map(),
327338
nsImported: new Map(),
328339
defaultTypesImported: new Map(),
329340
namedTypesImported: new Map(),
330341
});
331342
}
332343
const map = moduleMaps.get(n.parent);
333-
const preferInline = context.options[0] && context.options[0]['prefer-inline'];
334344
if (!preferInline && n.importKind === 'type') {
335345
return n.specifiers.length > 0 && n.specifiers[0].type === 'ImportDefaultSpecifier' ? map.defaultTypesImported : map.namedTypesImported;
336346
}
@@ -342,7 +352,9 @@ module.exports = {
342352
}
343353

344354
return {
355+
/** @param {import('estree').ImportDeclaration} n */
345356
ImportDeclaration(n) {
357+
/** @type {string} */
346358
// resolved path will cover aliased duplicates
347359
const resolvedPath = resolver(n.source.value);
348360
const importMap = getImportMap(n);

src/rules/no-mutable-exports.js

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { getScope } from 'eslint-module-utils/contextCompat';
22

33
import docsUrl from '../docsUrl';
44

5+
/** @type {import('eslint').Rule.RuleModule} */
56
module.exports = {
67
meta: {
78
type: 'suggestion',
@@ -21,41 +22,41 @@ module.exports = {
2122
}
2223
}
2324

25+
/** @type {(scope: import('eslint').Scope.Scope, name: string) => void} */
2426
function checkDeclarationsInScope({ variables }, name) {
25-
for (const variable of variables) {
26-
if (variable.name === name) {
27-
for (const def of variable.defs) {
28-
if (def.type === 'Variable' && def.parent) {
27+
variables
28+
.filter((variable) => variable.name === name)
29+
.forEach((variable) => {
30+
variable.defs
31+
.filter((def) => def.type === 'Variable' && def.parent)
32+
.forEach((def) => {
2933
checkDeclaration(def.parent);
30-
}
31-
}
32-
}
33-
}
34-
}
35-
36-
function handleExportDefault(node) {
37-
const scope = getScope(context, node);
38-
39-
if (node.declaration.name) {
40-
checkDeclarationsInScope(scope, node.declaration.name);
41-
}
34+
});
35+
});
4236
}
4337

44-
function handleExportNamed(node) {
45-
const scope = getScope(context, node);
38+
return {
39+
/** @param {import('estree').ExportDefaultDeclaration} node */
40+
ExportDefaultDeclaration(node) {
41+
const scope = getScope(context, node);
4642

47-
if (node.declaration) {
48-
checkDeclaration(node.declaration);
49-
} else if (!node.source) {
50-
for (const specifier of node.specifiers) {
51-
checkDeclarationsInScope(scope, specifier.local.name);
43+
if ('name' in node.declaration && node.declaration.name) {
44+
checkDeclarationsInScope(scope, node.declaration.name);
5245
}
53-
}
54-
}
55-
56-
return {
57-
ExportDefaultDeclaration: handleExportDefault,
58-
ExportNamedDeclaration: handleExportNamed,
46+
},
47+
48+
/** @param {import('estree').ExportNamedDeclaration} node */
49+
ExportNamedDeclaration(node) {
50+
const scope = getScope(context, node);
51+
52+
if ('declaration' in node && node.declaration) {
53+
checkDeclaration(node.declaration);
54+
} else if (!('source' in node) || !node.source) {
55+
node.specifiers.forEach((specifier) => {
56+
checkDeclarationsInScope(scope, specifier.local.name);
57+
});
58+
}
59+
},
5960
};
6061
},
6162
};

0 commit comments

Comments
 (0)