Skip to content

Commit 2efdf79

Browse files
committed
[eslint] avoid hoisting
1 parent 70ca58f commit 2efdf79

File tree

10 files changed

+216
-211
lines changed

10 files changed

+216
-211
lines changed

.eslintrc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"no-multiple-empty-lines": [2, { "max": 1, "maxEOF": 1, "maxBOF": 0 }],
9797
"no-return-assign": [2, "always"],
9898
"no-trailing-spaces": 2,
99+
"no-use-before-define": [2, { "functions": true, "classes": true, "variables": true }],
99100
"no-var": 2,
100101
"object-curly-spacing": [2, "always"],
101102
"object-shorthand": ["error", "always", {
@@ -225,6 +226,15 @@
225226
"no-console": 1,
226227
},
227228
},
229+
{
230+
"files": [
231+
"utils/**", // TODO
232+
"src/ExportMap.js", // TODO
233+
],
234+
"rules": {
235+
"no-use-before-define": "off",
236+
},
237+
},
228238
{
229239
"files": [
230240
"resolvers/*/test/**/*",

src/core/importType.js

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import isCoreModule from 'is-core-module';
44
import resolve from 'eslint-module-utils/resolve';
55
import { getContextPackagePath } from './packagePath';
66

7+
const scopedRegExp = /^@[^/]+\/?[^/]+/;
8+
export function isScoped(name) {
9+
return name && scopedRegExp.test(name);
10+
}
11+
712
function baseModule(name) {
813
if (isScoped(name)) {
914
const [scope, pkg] = name.split('/');
@@ -30,20 +35,6 @@ export function isBuiltIn(name, settings, path) {
3035
return isCoreModule(base) || extras.indexOf(base) > -1;
3136
}
3237

33-
export function isExternalModule(name, path, context) {
34-
if (arguments.length < 3) {
35-
throw new TypeError('isExternalModule: name, path, and context are all required');
36-
}
37-
return (isModule(name) || isScoped(name)) && typeTest(name, context, path) === 'external';
38-
}
39-
40-
export function isExternalModuleMain(name, path, context) {
41-
if (arguments.length < 3) {
42-
throw new TypeError('isExternalModule: name, path, and context are all required');
43-
}
44-
return isModuleMain(name) && typeTest(name, context, path) === 'external';
45-
}
46-
4738
const moduleRegExp = /^\w/;
4839
function isModule(name) {
4940
return name && moduleRegExp.test(name);
@@ -54,20 +45,9 @@ function isModuleMain(name) {
5445
return name && moduleMainRegExp.test(name);
5546
}
5647

57-
const scopedRegExp = /^@[^/]+\/?[^/]+/;
58-
export function isScoped(name) {
59-
return name && scopedRegExp.test(name);
60-
}
61-
62-
const scopedMainRegExp = /^@[^/]+\/?[^/]+$/;
63-
export function isScopedMain(name) {
64-
return name && scopedMainRegExp.test(name);
65-
}
66-
6748
function isRelativeToParent(name) {
6849
return (/^\.\.$|^\.\.[\\/]/).test(name);
6950
}
70-
7151
const indexFiles = ['.', './', './index', './index.js'];
7252
function isIndex(name) {
7353
return indexFiles.indexOf(name) !== -1;
@@ -123,6 +103,25 @@ function typeTest(name, context, path) {
123103
return 'unknown';
124104
}
125105

106+
export function isExternalModule(name, path, context) {
107+
if (arguments.length < 3) {
108+
throw new TypeError('isExternalModule: name, path, and context are all required');
109+
}
110+
return (isModule(name) || isScoped(name)) && typeTest(name, context, path) === 'external';
111+
}
112+
113+
export function isExternalModuleMain(name, path, context) {
114+
if (arguments.length < 3) {
115+
throw new TypeError('isExternalModule: name, path, and context are all required');
116+
}
117+
return isModuleMain(name) && typeTest(name, context, path) === 'external';
118+
}
119+
120+
const scopedMainRegExp = /^@[^/]+\/?[^/]+$/;
121+
export function isScopedMain(name) {
122+
return name && scopedMainRegExp.test(name);
123+
}
124+
126125
export default function resolveImportType(name, context) {
127126
return typeTest(name, context, resolve(name, context));
128127
}

src/core/packagePath.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import { dirname } from 'path';
22
import pkgUp from 'eslint-module-utils/pkgUp';
33
import readPkgUp from 'eslint-module-utils/readPkgUp';
44

5-
export function getContextPackagePath(context) {
6-
return getFilePackagePath(context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename());
7-
}
8-
95
export function getFilePackagePath(filePath) {
106
const fp = pkgUp({ cwd: filePath });
117
return dirname(fp);
128
}
139

10+
export function getContextPackagePath(context) {
11+
return getFilePackagePath(context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename());
12+
}
13+
1414
export function getFilePackageName(filePath) {
1515
const { pkg, path } = readPkgUp({ cwd: filePath, normalize: false });
1616
if (pkg) {

src/rules/no-cycle.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import docsUrl from '../docsUrl';
1111

1212
const traversed = new Set();
1313

14+
function routeString(route) {
15+
return route.map((s) => `${s.value}:${s.loc.start.line}`).join('=>');
16+
}
17+
1418
module.exports = {
1519
meta: {
1620
type: 'suggestion',
@@ -151,7 +155,3 @@ module.exports = {
151155
});
152156
},
153157
};
154-
155-
function routeString(route) {
156-
return route.map((s) => `${s.value}:${s.loc.start.line}`).join('=>');
157-
}

src/rules/no-duplicates.js

Lines changed: 80 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,68 @@ try {
99
typescriptPkg = require('typescript/package.json'); // eslint-disable-line import/no-extraneous-dependencies
1010
} catch (e) { /**/ }
1111

12-
function checkImports(imported, context) {
13-
for (const [module, nodes] of imported.entries()) {
14-
if (nodes.length > 1) {
15-
const message = `'${module}' imported multiple times.`;
16-
const [first, ...rest] = nodes;
17-
const sourceCode = context.getSourceCode();
18-
const fix = getFix(first, rest, sourceCode, context);
12+
function isPunctuator(node, value) {
13+
return node.type === 'Punctuator' && node.value === value;
14+
}
1915

20-
context.report({
21-
node: first.source,
22-
message,
23-
fix, // Attach the autofix (if any) to the first import.
24-
});
16+
// Get the name of the default import of `node`, if any.
17+
function getDefaultImportName(node) {
18+
const defaultSpecifier = node.specifiers
19+
.find((specifier) => specifier.type === 'ImportDefaultSpecifier');
20+
return defaultSpecifier != null ? defaultSpecifier.local.name : undefined;
21+
}
2522

26-
for (const node of rest) {
27-
context.report({
28-
node: node.source,
29-
message,
30-
});
31-
}
32-
}
33-
}
23+
// Checks whether `node` has a namespace import.
24+
function hasNamespace(node) {
25+
const specifiers = node.specifiers
26+
.filter((specifier) => specifier.type === 'ImportNamespaceSpecifier');
27+
return specifiers.length > 0;
28+
}
29+
30+
// Checks whether `node` has any non-default specifiers.
31+
function hasSpecifiers(node) {
32+
const specifiers = node.specifiers
33+
.filter((specifier) => specifier.type === 'ImportSpecifier');
34+
return specifiers.length > 0;
35+
}
36+
37+
// Checks whether `node` has a comment (that ends) on the previous line or on
38+
// the same line as `node` (starts).
39+
function hasCommentBefore(node, sourceCode) {
40+
return sourceCode.getCommentsBefore(node)
41+
.some((comment) => comment.loc.end.line >= node.loc.start.line - 1);
42+
}
43+
44+
// Checks whether `node` has a comment (that starts) on the same line as `node`
45+
// (ends).
46+
function hasCommentAfter(node, sourceCode) {
47+
return sourceCode.getCommentsAfter(node)
48+
.some((comment) => comment.loc.start.line === node.loc.end.line);
49+
}
50+
51+
// Checks whether `node` has any comments _inside,_ except inside the `{...}`
52+
// part (if any).
53+
function hasCommentInsideNonSpecifiers(node, sourceCode) {
54+
const tokens = sourceCode.getTokens(node);
55+
const openBraceIndex = tokens.findIndex((token) => isPunctuator(token, '{'));
56+
const closeBraceIndex = tokens.findIndex((token) => isPunctuator(token, '}'));
57+
// Slice away the first token, since we're no looking for comments _before_
58+
// `node` (only inside). If there's a `{...}` part, look for comments before
59+
// the `{`, but not before the `}` (hence the `+1`s).
60+
const someTokens = openBraceIndex >= 0 && closeBraceIndex >= 0
61+
? tokens.slice(1, openBraceIndex + 1).concat(tokens.slice(closeBraceIndex + 1))
62+
: tokens.slice(1);
63+
return someTokens.some((token) => sourceCode.getCommentsBefore(token).length > 0);
64+
}
65+
66+
// It's not obvious what the user wants to do with comments associated with
67+
// duplicate imports, so skip imports with comments when autofixing.
68+
function hasProblematicComments(node, sourceCode) {
69+
return (
70+
hasCommentBefore(node, sourceCode)
71+
|| hasCommentAfter(node, sourceCode)
72+
|| hasCommentInsideNonSpecifiers(node, sourceCode)
73+
);
3474
}
3575

3676
function getFix(first, rest, sourceCode, context) {
@@ -203,68 +243,28 @@ function getFix(first, rest, sourceCode, context) {
203243
};
204244
}
205245

206-
function isPunctuator(node, value) {
207-
return node.type === 'Punctuator' && node.value === value;
208-
}
209-
210-
// Get the name of the default import of `node`, if any.
211-
function getDefaultImportName(node) {
212-
const defaultSpecifier = node.specifiers
213-
.find((specifier) => specifier.type === 'ImportDefaultSpecifier');
214-
return defaultSpecifier != null ? defaultSpecifier.local.name : undefined;
215-
}
216-
217-
// Checks whether `node` has a namespace import.
218-
function hasNamespace(node) {
219-
const specifiers = node.specifiers
220-
.filter((specifier) => specifier.type === 'ImportNamespaceSpecifier');
221-
return specifiers.length > 0;
222-
}
223-
224-
// Checks whether `node` has any non-default specifiers.
225-
function hasSpecifiers(node) {
226-
const specifiers = node.specifiers
227-
.filter((specifier) => specifier.type === 'ImportSpecifier');
228-
return specifiers.length > 0;
229-
}
230-
231-
// It's not obvious what the user wants to do with comments associated with
232-
// duplicate imports, so skip imports with comments when autofixing.
233-
function hasProblematicComments(node, sourceCode) {
234-
return (
235-
hasCommentBefore(node, sourceCode)
236-
|| hasCommentAfter(node, sourceCode)
237-
|| hasCommentInsideNonSpecifiers(node, sourceCode)
238-
);
239-
}
240-
241-
// Checks whether `node` has a comment (that ends) on the previous line or on
242-
// the same line as `node` (starts).
243-
function hasCommentBefore(node, sourceCode) {
244-
return sourceCode.getCommentsBefore(node)
245-
.some((comment) => comment.loc.end.line >= node.loc.start.line - 1);
246-
}
246+
function checkImports(imported, context) {
247+
for (const [module, nodes] of imported.entries()) {
248+
if (nodes.length > 1) {
249+
const message = `'${module}' imported multiple times.`;
250+
const [first, ...rest] = nodes;
251+
const sourceCode = context.getSourceCode();
252+
const fix = getFix(first, rest, sourceCode, context);
247253

248-
// Checks whether `node` has a comment (that starts) on the same line as `node`
249-
// (ends).
250-
function hasCommentAfter(node, sourceCode) {
251-
return sourceCode.getCommentsAfter(node)
252-
.some((comment) => comment.loc.start.line === node.loc.end.line);
253-
}
254+
context.report({
255+
node: first.source,
256+
message,
257+
fix, // Attach the autofix (if any) to the first import.
258+
});
254259

255-
// Checks whether `node` has any comments _inside,_ except inside the `{...}`
256-
// part (if any).
257-
function hasCommentInsideNonSpecifiers(node, sourceCode) {
258-
const tokens = sourceCode.getTokens(node);
259-
const openBraceIndex = tokens.findIndex((token) => isPunctuator(token, '{'));
260-
const closeBraceIndex = tokens.findIndex((token) => isPunctuator(token, '}'));
261-
// Slice away the first token, since we're no looking for comments _before_
262-
// `node` (only inside). If there's a `{...}` part, look for comments before
263-
// the `{`, but not before the `}` (hence the `+1`s).
264-
const someTokens = openBraceIndex >= 0 && closeBraceIndex >= 0
265-
? tokens.slice(1, openBraceIndex + 1).concat(tokens.slice(closeBraceIndex + 1))
266-
: tokens.slice(1);
267-
return someTokens.some((token) => sourceCode.getCommentsBefore(token).length > 0);
260+
for (const node of rest) {
261+
context.report({
262+
node: node.source,
263+
message,
264+
});
265+
}
266+
}
267+
}
268268
}
269269

270270
module.exports = {

0 commit comments

Comments
 (0)