Skip to content

Commit 3727767

Browse files
committed
test: test against the new version of resolver design
1 parent dd6fa6b commit 3727767

File tree

5 files changed

+328
-177
lines changed

5 files changed

+328
-177
lines changed

src/types.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,29 @@ import type { MinimatchOptions } from 'minimatch'
44
import type { KebabCase } from 'type-fest'
55

66
import type { ImportType as ImportType_, PluginName } from './utils'
7-
import type { LegacyImportResolver, LegacyResolver } from './utils/legacy-resolver-settings'
7+
import type {
8+
LegacyImportResolver,
9+
LegacyResolver,
10+
} from './utils/legacy-resolver-settings'
811

912
export type {
1013
LegacyResolver,
11-
14+
// ResolverName
1215
LegacyResolverName,
1316
LegacyResolverName as ResolverName,
14-
17+
// ImportResolver
1518
LegacyImportResolver,
1619
LegacyImportResolver as ImportResolver,
17-
20+
// ResolverResolve
1821
LegacyResolverResolve,
1922
LegacyResolverResolve as ResolverResolve,
20-
23+
// ResolverResolveImport
2124
LegacyResolverResolveImport,
2225
LegacyResolverResolveImport as ResolverResolveImport,
23-
26+
// ResolverRecord
2427
LegacyResolverRecord,
2528
LegacyResolverRecord as ResolverRecord,
26-
29+
// ResolverObject
2730
LegacyResolverObject,
2831
LegacyResolverObject as ResolverObject,
2932
} from './utils/legacy-resolver-settings'
@@ -57,10 +60,10 @@ export type NewResolverResolve = (
5760

5861
// TODO: remove prefix New in the next major version
5962
export type NewResolver = {
60-
interfaceVersion: 3,
63+
interfaceVersion: 3
6164
/** optional name for the resolver, this is used in logs/debug output */
62-
name?: string,
63-
resolve: NewResolverResolve,
65+
name?: string
66+
resolve: NewResolverResolve
6467
}
6568

6669
export type FileExtension = `.${string}`
@@ -96,6 +99,7 @@ export type ImportSettings = {
9699
parsers?: Record<string, readonly FileExtension[]>
97100
resolve?: NodeResolverOptions
98101
resolver?: LegacyImportResolver
102+
'resolver-legacy'?: LegacyImportResolver
99103
'resolver-next'?: NewResolver[]
100104
}
101105

src/utils/legacy-resolver-settings.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
// Although the new import resolver settings is still `import-x/resolver-next`, but it won't stop us from calling existing ones legacy~
22

3-
import type { LiteralUnion } from "type-fest"
4-
53
import { createRequire } from 'node:module'
6-
import type { NodeResolverOptions, ResolvedResult, TsResolverOptions, WebpackResolverOptions } from "../types"
7-
import path from "path"
8-
import { IMPORT_RESOLVE_ERROR_NAME } from "./resolve"
4+
import path from 'node:path'
5+
6+
import type { LiteralUnion } from 'type-fest'
7+
8+
import type {
9+
NodeResolverOptions,
10+
ResolvedResult,
11+
TsResolverOptions,
12+
WebpackResolverOptions,
13+
} from '../types'
14+
915
import { pkgDir } from './pkg-dir'
16+
import { IMPORT_RESOLVE_ERROR_NAME } from './resolve'
1017

1118
export type LegacyResolverName = LiteralUnion<
1219
'node' | 'typescript' | 'webpack',
@@ -40,10 +47,10 @@ export type LegacyResolverObject = {
4047

4148
// Options passed to the resolver
4249
options?:
43-
| NodeResolverOptions
44-
| TsResolverOptions
45-
| WebpackResolverOptions
46-
| unknown
50+
| NodeResolverOptions
51+
| TsResolverOptions
52+
| WebpackResolverOptions
53+
| unknown
4754

4855
// Any object satisfied Resolver type
4956
resolver: LegacyResolver
@@ -62,9 +69,14 @@ export type LegacyImportResolver =
6269
| LegacyResolverObject
6370
| LegacyResolverName[]
6471
| LegacyResolverRecord[]
65-
| LegacyResolverObject[];
72+
| LegacyResolverObject[]
6673

67-
export function resolveWithLegacyResolver(resolver: LegacyResolver, config: unknown, modulePath: string, sourceFile: string): ResolvedResult {
74+
export function resolveWithLegacyResolver(
75+
resolver: LegacyResolver,
76+
config: unknown,
77+
modulePath: string,
78+
sourceFile: string,
79+
): ResolvedResult {
6880
if (resolver.interfaceVersion === 2) {
6981
return resolver.resolve(modulePath, sourceFile, config)
7082
}
@@ -202,7 +214,6 @@ function tryRequire<T>(
202214
return require(resolved)
203215
}
204216

205-
206217
function getBaseDir(sourceFile: string): string {
207218
return pkgDir(sourceFile) || process.cwd()
208219
}

src/utils/resolve.ts

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ import stableHash from 'stable-hash'
55

66
import type {
77
ImportSettings,
8+
NewResolver,
89
PluginSettings,
910
RuleContext,
10-
Resolver,
11-
LegacyResolver,
12-
ResolvedResult,
1311
} from '../types'
1412

13+
import {
14+
normalizeConfigResolvers,
15+
resolveWithLegacyResolver,
16+
} from './legacy-resolver-settings'
1517
import { ModuleCache } from './module-cache'
16-
import { normalizeConfigResolvers, resolveWithLegacyResolver } from './legacy-resolver-settings'
1718

1819
export const CASE_SENSITIVE_FS = !fs.existsSync(
1920
path.resolve(
@@ -26,7 +27,6 @@ export const IMPORT_RESOLVE_ERROR_NAME = 'EslintPluginImportResolveError'
2627

2728
export const fileExistsCache = new ModuleCache()
2829

29-
3030
// https://stackoverflow.com/a/27382838
3131
export function fileExistsWithCaseSync(
3232
filepath: string | null,
@@ -69,6 +69,38 @@ export function fileExistsWithCaseSync(
6969
let prevSettings: PluginSettings | null = null
7070
let memoizedHash: string
7171

72+
function isNamedResolver(resolver: unknown): resolver is { name: string } {
73+
return !!(
74+
typeof resolver === 'object' &&
75+
resolver &&
76+
'name' in resolver &&
77+
typeof resolver.name === 'string'
78+
)
79+
}
80+
81+
function isValidNewResolver(resolver: unknown): resolver is NewResolver {
82+
if (typeof resolver !== 'object' || resolver == null) {
83+
return false
84+
}
85+
86+
if (!('resolve' in resolver) || !('interfaceVersion' in resolver)) {
87+
return false
88+
}
89+
90+
if (
91+
typeof resolver.interfaceVersion !== 'number' ||
92+
resolver.interfaceVersion !== 3
93+
) {
94+
return false
95+
}
96+
97+
if (typeof resolver.resolve !== 'function') {
98+
return false
99+
}
100+
101+
return true
102+
}
103+
72104
function fullResolve(
73105
modulePath: string,
74106
sourceFile: string,
@@ -99,10 +131,24 @@ function fullResolve(
99131
return { found: true, path: cachedPath }
100132
}
101133

102-
if (Object.prototype.hasOwnProperty.call(settings, 'import-x/resolver-next') && settings['import-x/resolver-next']) {
134+
if (
135+
Object.prototype.hasOwnProperty.call(settings, 'import-x/resolver-next') &&
136+
settings['import-x/resolver-next']
137+
) {
103138
const configResolvers = settings['import-x/resolver-next']
104139

105-
for (const resolver of configResolvers) {
140+
for (let i = 0, len = configResolvers.length; i < len; i++) {
141+
const resolver = configResolvers[i]
142+
const resolverName = isNamedResolver(resolver)
143+
? resolver.name
144+
: `settings['import-x/resolver-next'][${i}]`
145+
146+
if (!isValidNewResolver(resolver)) {
147+
const err = new TypeError(`${resolverName} is not a valid import resolver for eslint-plugin-import-x!`)
148+
err.name = IMPORT_RESOLVE_ERROR_NAME
149+
throw err
150+
}
151+
106152
const resolved = resolver.resolve(modulePath, sourceFile)
107153
if (!resolved.found) {
108154
continue
@@ -113,16 +159,25 @@ function fullResolve(
113159
return resolved
114160
}
115161
} else {
116-
const configResolvers = settings['import-x/resolver'] || {
117-
node: settings['import-x/resolve'],
118-
} // backward compatibility
119-
120-
for (const { enable, options, resolver } of normalizeConfigResolvers(configResolvers, sourceFile)) {
162+
const configResolvers = settings['import-x/resolver-legacy'] ||
163+
settings['import-x/resolver'] || {
164+
node: settings['import-x/resolve'],
165+
} // backward compatibility
166+
167+
for (const { enable, options, resolver } of normalizeConfigResolvers(
168+
configResolvers,
169+
sourceFile,
170+
)) {
121171
if (!enable) {
122172
continue
123173
}
124174

125-
const resolved = resolveWithLegacyResolver(resolver, options, modulePath, sourceFile)
175+
const resolved = resolveWithLegacyResolver(
176+
resolver,
177+
options,
178+
modulePath,
179+
sourceFile,
180+
)
126181
if (!resolved.found) {
127182
continue
128183
}
@@ -178,5 +233,3 @@ export function resolve(p: string, context: RuleContext) {
178233
}
179234
}
180235
}
181-
182-
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
var path = require('path')
2+
3+
exports.foobarResolver = (/** @type {import('eslint-plugin-import-x/types').NewResolver} */ {
4+
name: 'resolver-foo-bar',
5+
interfaceVersion: 3,
6+
resolve: function (modulePath, sourceFile) {
7+
var sourceFileName = path.basename(sourceFile)
8+
if (sourceFileName === 'foo.js') {
9+
return { found: true, path: path.join(__dirname, 'bar.jsx') }
10+
}
11+
if (sourceFileName === 'exception.js') {
12+
throw new Error('foo-bar-resolver-v3 resolve test exception')
13+
}
14+
return { found: false }
15+
}
16+
})

0 commit comments

Comments
 (0)