Skip to content

Commit 70ca58f

Browse files
committed
[utils] [refactor] avoid hoisting
1 parent 2d38b33 commit 70ca58f

File tree

3 files changed

+117
-117
lines changed

3 files changed

+117
-117
lines changed

utils/ignore.js

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,6 @@ const log = require('debug')('eslint-plugin-import:utils:ignore');
1010
/** @type {Set<import('./types').Extension>} */ let cachedSet;
1111
/** @type {import('./types').ESLintSettings} */ let lastSettings;
1212

13-
/** @type {(context: import('eslint').Rule.RuleContext) => Set<import('./types').Extension>} */
14-
function validExtensions(context) {
15-
if (cachedSet && context.settings === lastSettings) {
16-
return cachedSet;
17-
}
18-
19-
lastSettings = context.settings;
20-
cachedSet = makeValidExtensionSet(context.settings);
21-
return cachedSet;
22-
}
23-
2413
/** @type {import('./ignore').getFileExtensions} */
2514
function makeValidExtensionSet(settings) {
2615
// start with explicit JS-parsed extensions
@@ -42,6 +31,24 @@ function makeValidExtensionSet(settings) {
4231
}
4332
exports.getFileExtensions = makeValidExtensionSet;
4433

34+
/** @type {(context: import('eslint').Rule.RuleContext) => Set<import('./types').Extension>} */
35+
function validExtensions(context) {
36+
if (cachedSet && context.settings === lastSettings) {
37+
return cachedSet;
38+
}
39+
40+
lastSettings = context.settings;
41+
cachedSet = makeValidExtensionSet(context.settings);
42+
return cachedSet;
43+
}
44+
45+
/** @type {import('./ignore').hasValidExtension} */
46+
function hasValidExtension(path, context) {
47+
// eslint-disable-next-line no-extra-parens
48+
return validExtensions(context).has(/** @type {import('./types').Extension} */ (extname(path)));
49+
}
50+
exports.hasValidExtension = hasValidExtension;
51+
4552
/** @type {import('./ignore').default} */
4653
exports.default = function ignore(path, context) {
4754
// check extension whitelist first (cheap)
@@ -60,10 +67,3 @@ exports.default = function ignore(path, context) {
6067

6168
return false;
6269
};
63-
64-
/** @type {import('./ignore').hasValidExtension} */
65-
function hasValidExtension(path, context) {
66-
// eslint-disable-next-line no-extra-parens
67-
return validExtensions(context).has(/** @type {import('./types').Extension} */ (extname(path)));
68-
}
69-
exports.hasValidExtension = hasValidExtension;

utils/parse.js

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,47 @@ function transformHashbang(text) {
6161
return text.replace(/^#!([^\r\n]+)/u, (_, captured) => `//${captured}`);
6262
}
6363

64+
/** @type {(path: string, context: import('eslint').Rule.RuleContext & { settings?: ESLintSettings }) => import('eslint').Rule.RuleContext['parserPath']} */
65+
function getParserPath(path, context) {
66+
const parsers = context.settings['import/parsers'];
67+
if (parsers != null) {
68+
// eslint-disable-next-line no-extra-parens
69+
const extension = /** @type {Extension} */ (extname(path));
70+
for (const parserPath in parsers) {
71+
if (parsers[parserPath].indexOf(extension) > -1) {
72+
// use this alternate parser
73+
log('using alt parser:', parserPath);
74+
return parserPath;
75+
}
76+
}
77+
}
78+
// default to use ESLint parser
79+
return context.parserPath;
80+
}
81+
82+
/** @type {(path: string, context: import('eslint').Rule.RuleContext) => string | null | (import('eslint').Linter.ParserModule)} */
83+
function getParser(path, context) {
84+
const parserPath = getParserPath(path, context);
85+
if (parserPath) {
86+
return parserPath;
87+
}
88+
if (
89+
!!context.languageOptions
90+
&& !!context.languageOptions.parser
91+
&& typeof context.languageOptions.parser !== 'string'
92+
&& (
93+
// @ts-expect-error TODO: figure out a better type
94+
typeof context.languageOptions.parser.parse === 'function'
95+
// @ts-expect-error TODO: figure out a better type
96+
|| typeof context.languageOptions.parser.parseForESLint === 'function'
97+
)
98+
) {
99+
return context.languageOptions.parser;
100+
}
101+
102+
return null;
103+
}
104+
64105
/** @type {import('./parse').default} */
65106
exports.default = function parse(path, content, context) {
66107
if (context == null) { throw new Error('need context to parse properly'); }
@@ -131,44 +172,3 @@ exports.default = function parse(path, content, context) {
131172
// @ts-expect-error TODO: FIXME
132173
return makeParseReturn(ast, keysFromParser(parserOrPath, parser, undefined));
133174
};
134-
135-
/** @type {(path: string, context: import('eslint').Rule.RuleContext) => string | null | (import('eslint').Linter.ParserModule)} */
136-
function getParser(path, context) {
137-
const parserPath = getParserPath(path, context);
138-
if (parserPath) {
139-
return parserPath;
140-
}
141-
if (
142-
!!context.languageOptions
143-
&& !!context.languageOptions.parser
144-
&& typeof context.languageOptions.parser !== 'string'
145-
&& (
146-
// @ts-expect-error TODO: figure out a better type
147-
typeof context.languageOptions.parser.parse === 'function'
148-
// @ts-expect-error TODO: figure out a better type
149-
|| typeof context.languageOptions.parser.parseForESLint === 'function'
150-
)
151-
) {
152-
return context.languageOptions.parser;
153-
}
154-
155-
return null;
156-
}
157-
158-
/** @type {(path: string, context: import('eslint').Rule.RuleContext & { settings?: ESLintSettings }) => import('eslint').Rule.RuleContext['parserPath']} */
159-
function getParserPath(path, context) {
160-
const parsers = context.settings['import/parsers'];
161-
if (parsers != null) {
162-
// eslint-disable-next-line no-extra-parens
163-
const extension = /** @type {Extension} */ (extname(path));
164-
for (const parserPath in parsers) {
165-
if (parsers[parserPath].indexOf(extension) > -1) {
166-
// use this alternate parser
167-
log('using alt parser:', parserPath);
168-
return parserPath;
169-
}
170-
}
171-
}
172-
// default to use ESLint parser
173-
return context.parserPath;
174-
}

utils/resolve.js

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ const createRequire = Module.createRequire
3434
return mod.exports;
3535
};
3636

37+
/** @type {(resolver: object) => resolver is import('./resolve').Resolver} */
38+
function isResolverValid(resolver) {
39+
if ('interfaceVersion' in resolver && resolver.interfaceVersion === 2) {
40+
return 'resolve' in resolver && !!resolver.resolve && typeof resolver.resolve === 'function';
41+
}
42+
return 'resolveImport' in resolver && !!resolver.resolveImport && typeof resolver.resolveImport === 'function';
43+
}
44+
3745
/** @type {<T extends string>(target: T, sourceFile?: string | null | undefined) => undefined | ReturnType<typeof require>} */
3846
function tryRequire(target, sourceFile) {
3947
let resolved;
@@ -57,6 +65,56 @@ function tryRequire(target, sourceFile) {
5765
return require(resolved);
5866
}
5967

68+
/** @type {<T extends Map<string, unknown>>(resolvers: string[] | string | { [k: string]: string }, map: T) => T} */
69+
function resolverReducer(resolvers, map) {
70+
if (Array.isArray(resolvers)) {
71+
resolvers.forEach((r) => resolverReducer(r, map));
72+
return map;
73+
}
74+
75+
if (typeof resolvers === 'string') {
76+
map.set(resolvers, null);
77+
return map;
78+
}
79+
80+
if (typeof resolvers === 'object') {
81+
for (const key in resolvers) {
82+
map.set(key, resolvers[key]);
83+
}
84+
return map;
85+
}
86+
87+
const err = new Error('invalid resolver config');
88+
err.name = ERROR_NAME;
89+
throw err;
90+
}
91+
92+
/** @type {(sourceFile: string) => string} */
93+
function getBaseDir(sourceFile) {
94+
return pkgDir(sourceFile) || process.cwd();
95+
}
96+
97+
/** @type {(name: string, sourceFile: string) => import('./resolve').Resolver} */
98+
function requireResolver(name, sourceFile) {
99+
// Try to resolve package with conventional name
100+
const resolver = tryRequire(`eslint-import-resolver-${name}`, sourceFile)
101+
|| tryRequire(name, sourceFile)
102+
|| tryRequire(path.resolve(getBaseDir(sourceFile), name));
103+
104+
if (!resolver) {
105+
const err = new Error(`unable to load resolver "${name}".`);
106+
err.name = ERROR_NAME;
107+
throw err;
108+
}
109+
if (!isResolverValid(resolver)) {
110+
const err = new Error(`${name} with invalid interface loaded as resolver`);
111+
err.name = ERROR_NAME;
112+
throw err;
113+
}
114+
115+
return resolver;
116+
}
117+
60118
// https://stackoverflow.com/a/27382838
61119
/** @type {import('./resolve').fileExistsWithCaseSync} */
62120
exports.fileExistsWithCaseSync = function fileExistsWithCaseSync(filepath, cacheSettings, strict) {
@@ -159,64 +217,6 @@ function relative(modulePath, sourceFile, settings) {
159217
}
160218
exports.relative = relative;
161219

162-
/** @type {<T extends Map<string, unknown>>(resolvers: string[] | string | { [k: string]: string }, map: T) => T} */
163-
function resolverReducer(resolvers, map) {
164-
if (Array.isArray(resolvers)) {
165-
resolvers.forEach((r) => resolverReducer(r, map));
166-
return map;
167-
}
168-
169-
if (typeof resolvers === 'string') {
170-
map.set(resolvers, null);
171-
return map;
172-
}
173-
174-
if (typeof resolvers === 'object') {
175-
for (const key in resolvers) {
176-
map.set(key, resolvers[key]);
177-
}
178-
return map;
179-
}
180-
181-
const err = new Error('invalid resolver config');
182-
err.name = ERROR_NAME;
183-
throw err;
184-
}
185-
186-
/** @type {(sourceFile: string) => string} */
187-
function getBaseDir(sourceFile) {
188-
return pkgDir(sourceFile) || process.cwd();
189-
}
190-
191-
/** @type {(name: string, sourceFile: string) => import('./resolve').Resolver} */
192-
function requireResolver(name, sourceFile) {
193-
// Try to resolve package with conventional name
194-
const resolver = tryRequire(`eslint-import-resolver-${name}`, sourceFile)
195-
|| tryRequire(name, sourceFile)
196-
|| tryRequire(path.resolve(getBaseDir(sourceFile), name));
197-
198-
if (!resolver) {
199-
const err = new Error(`unable to load resolver "${name}".`);
200-
err.name = ERROR_NAME;
201-
throw err;
202-
}
203-
if (!isResolverValid(resolver)) {
204-
const err = new Error(`${name} with invalid interface loaded as resolver`);
205-
err.name = ERROR_NAME;
206-
throw err;
207-
}
208-
209-
return resolver;
210-
}
211-
212-
/** @type {(resolver: object) => resolver is import('./resolve').Resolver} */
213-
function isResolverValid(resolver) {
214-
if ('interfaceVersion' in resolver && resolver.interfaceVersion === 2) {
215-
return 'resolve' in resolver && !!resolver.resolve && typeof resolver.resolve === 'function';
216-
}
217-
return 'resolveImport' in resolver && !!resolver.resolveImport && typeof resolver.resolveImport === 'function';
218-
}
219-
220220
/** @type {Set<import('eslint').Rule.RuleContext>} */
221221
const erroredContexts = new Set();
222222

0 commit comments

Comments
 (0)