Skip to content

Commit b23ec50

Browse files
committed
fix: Add cache for matchers by digets of options, not cwd path
1 parent 33121aa commit b23ec50

File tree

4 files changed

+62
-46
lines changed

4 files changed

+62
-46
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
dist
44
node_modules
55
*.log
6+
.vscode

src/index.ts

+24-15
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ import { CachedInputFileSystem, ResolverFactory } from 'enhanced-resolve'
44

55
import { defaultConditionNames, defaultExtensionAlias, defaultExtensions, defaultMainFields } from './default'
66
import { digestHashObject } from './helpers'
7+
import { init } from './init'
78
import { logger } from './logger'
89
import { resolveImport } from './resolveImport'
910

10-
import type { InternalResolverOptions, ResolvedResult, ResolverOptions } from './types'
11+
import type { InternalResolverOptions, Matcher, ResolvedResult, ResolverOptions } from './types'
1112
import type { Resolver } from 'enhanced-resolve'
1213

1314
const times = []
1415

1516
let cachedOptions: InternalResolverOptions
16-
let previousOptionsHash: ReturnType<typeof digestHashObject>
17-
let optionsHash: ReturnType<typeof digestHashObject>
17+
let previousOptionsHash: ReturnType<typeof digestHashObject> | undefined
18+
let optionsHash: ReturnType<typeof digestHashObject> | undefined
1819
let resolverCachedOptions: InternalResolverOptions
1920
let resolver: Resolver | undefined
2021

@@ -25,7 +26,7 @@ export const interfaceVersion = 2
2526
* @param file the importing file's full path; i.e. '/usr/local/bin/file.js'
2627
* @param options
2728
*/
28-
export function resolve(specifier: string, file: string, options?: ResolverOptions | undefined | null): ResolvedResult {
29+
export function resolve(specifier: string, file: string, options?: ResolverOptions): ResolvedResult {
2930
let t0: DOMHighResTimeStamp = 0
3031

3132
if (options?.performanceToLog) t0 = performance.now()
@@ -43,12 +44,14 @@ export function resolve(specifier: string, file: string, options?: ResolverOptio
4344
}
4445
}
4546

47+
const matchers: Matcher[] = init(options ?? {}, optionsHash ?? digestHashObject(options))
48+
4649
if (!resolver || resolverCachedOptions !== cachedOptions) {
4750
resolver = ResolverFactory.createResolver(cachedOptions)
4851
resolverCachedOptions = cachedOptions
4952
}
5053

51-
const result = resolveImport(specifier, file, cachedOptions, resolver)
54+
const result = resolveImport(matchers, specifier, file, cachedOptions, resolver)
5255

5356
if (options?.performanceToLog) {
5457
const t1 = performance.now()
@@ -60,15 +63,21 @@ export function resolve(specifier: string, file: string, options?: ResolverOptio
6063
}
6164

6265
export function createImportResolver(options: ResolverOptions) {
63-
const resolver = ResolverFactory.createResolver({
64-
...options,
65-
conditionNames: options?.conditionNames ?? defaultConditionNames,
66-
extensions: options?.extensions ?? defaultExtensions,
67-
extensionAlias: options?.extensionAlias ?? defaultExtensionAlias,
68-
mainFields: options?.mainFields ?? defaultMainFields,
69-
fileSystem: new CachedInputFileSystem(fs, 5 * 1000),
70-
useSyncFileSystemCalls: true,
71-
})
66+
if (!cachedOptions || previousOptionsHash !== (optionsHash = digestHashObject(options))) {
67+
previousOptionsHash = optionsHash
68+
cachedOptions = {
69+
...options,
70+
conditionNames: options?.conditionNames ?? defaultConditionNames,
71+
extensions: options?.extensions ?? defaultExtensions,
72+
extensionAlias: options?.extensionAlias ?? defaultExtensionAlias,
73+
mainFields: options?.mainFields ?? defaultMainFields,
74+
fileSystem: new CachedInputFileSystem(fs, 5 * 1000),
75+
useSyncFileSystemCalls: true,
76+
}
77+
}
78+
79+
const matchers: Matcher[] = init(options, optionsHash ?? digestHashObject(options))
80+
const resolver = ResolverFactory.createResolver(cachedOptions)
7281

7382
return {
7483
name: 'eslint-import-resolver-x',
@@ -78,7 +87,7 @@ export function createImportResolver(options: ResolverOptions) {
7887

7988
if (options?.performanceToLog) t0 = performance.now()
8089

81-
const result = resolveImport(modulePath, source, cachedOptions, resolver)
90+
const result = resolveImport(matchers, modulePath, source, cachedOptions, resolver)
8291

8392
if (options?.performanceToLog) {
8493
const t1 = performance.now()

src/init.ts

+15-15
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,26 @@ import isGlob from 'is-glob'
77
import { isFile } from './helpers'
88
import { logger } from './logger'
99

10-
import type { InternalResolverOptions, Matcher } from './types'
10+
import type { ResolverOptions, Matcher } from './types'
1111

12-
// Vscode change cwd
13-
const cwdMappersMap: Map<string, Matcher[]> = new Map()
12+
const matchersMap: Map<string, Matcher[]> = new Map()
1413

1514
/**
1615
* Initialize the resolver with the given options
1716
* @param options internal resolver options
18-
* @returns matchers for current cwd
17+
* @returns matchers for options
1918
*/
20-
export function init(options: InternalResolverOptions): Matcher[] {
21-
let matchers: Matcher[] | undefined = cwdMappersMap.get(process.cwd())
19+
export function init(options: ResolverOptions, digestOfOptions: string): Matcher[] {
20+
const matchersByDigets: Matcher[] | undefined = matchersMap.get(digestOfOptions)
2221

23-
if (matchers) {
24-
return matchers
22+
logger('[INIT] Digest of options: ', digestOfOptions)
23+
24+
if (matchersByDigets) {
25+
logger('[INIT] Use matchers from cache by digest')
26+
return matchersByDigets
2527
}
2628

27-
logger('[MAPPER] Init mapper for current cwd', process.cwd())
29+
logger('[INIT] Create matchers for current options: ', options)
2830

2931
const configPaths =
3032
typeof options.project === 'string'
@@ -35,8 +37,6 @@ export function init(options: InternalResolverOptions): Matcher[] {
3537

3638
const ignore = ['!**/node_modules/**']
3739

38-
logger('[MAPPER] options.project:', configPaths)
39-
4040
// turn glob patterns into paths
4141
const projectPaths = [
4242
...new Set([
@@ -47,9 +47,9 @@ export function init(options: InternalResolverOptions): Matcher[] {
4747
]),
4848
]
4949

50-
logger('[MAPPER] config paths of projects:', projectPaths)
50+
const matchers: Matcher[] = []
5151

52-
matchers = []
52+
logger('[INIT] config paths of projects:', projectPaths)
5353

5454
for (let i = 0; i < projectPaths.length; i++) {
5555
let tsconfigResult = null
@@ -71,9 +71,9 @@ export function init(options: InternalResolverOptions): Matcher[] {
7171
}
7272
}
7373

74-
logger('[MAPPER] created matchers:', matchers)
74+
logger('[INIT] created matchers:', matchers)
7575

76-
cwdMappersMap.set(process.cwd(), matchers)
76+
matchersMap.set(digestOfOptions, matchers)
7777

7878
return matchers
7979
}

src/resolveImport.ts

+22-16
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { isBunModule } from 'is-bun-module'
88
import { JS_EXT_PATTERN, RELATIVE_PATH_PATTERN } from './constants'
99
import { defaultExtensions } from './default'
1010
import { isFile, isModule, removeQuerystring } from './helpers'
11-
import { init } from './init'
1211
import { logger } from './logger'
1312

1413
import type { InternalResolverOptions, Matcher, ResolvedResult } from './types'
@@ -21,13 +20,15 @@ const possiblePathsBySpecifier: Map<string, { paths: string[]; path: TsConfigRes
2120

2221
/**
2322
* Resolve an import specifier to a path
23+
* @param {Matcher[]} matchers matchers by digest of options
2424
* @param {string} specifier specifier of import to resolve
2525
* @param {string} file path of the file importing the specifier
2626
* @param {InternalResolverOptions} options options for the resolver
2727
* @param {Resolver} resolver resolver to use for resolving
2828
* @returns {ResolvedResult} whether the import was found and the resolved path
2929
*/
3030
export function resolveImport(
31+
matchers: Matcher[],
3132
specifier: string,
3233
file: string,
3334
options: InternalResolverOptions,
@@ -46,9 +47,7 @@ export function resolveImport(
4647
}
4748
}
4849

49-
const currentMatchersOfCwd = init(options)
50-
51-
const mappedPath = getMappedPath(currentMatchersOfCwd, specifier, file, options.extensions)
50+
const mappedPath = getMappedPath(matchers, specifier, file, options.extensions)
5251

5352
if (mappedPath) {
5453
logger('matched ts path:', mappedPath)
@@ -70,7 +69,13 @@ export function resolveImport(
7069
!path.isAbsolute(specifier) &&
7170
!specifier.startsWith('.')
7271
) {
73-
const definitelyTyped = resolveImport('@types' + path.sep + mangleScopedPackage(specifier), file, options, resolver)
72+
const definitelyTyped = resolveImport(
73+
matchers,
74+
'@types' + path.sep + mangleScopedPackage(specifier),
75+
file,
76+
options,
77+
resolver
78+
)
7479
if (definitelyTyped.found) {
7580
return definitelyTyped
7681
}
@@ -109,13 +114,14 @@ function mangleScopedPackage(moduleName: string): string {
109114

110115
/**
111116
* Get the mapped path for a given import specifier
117+
* @param {Matcher[]} matchers matchers by digest of options
112118
* @param {string} specifier specifier of import to resolve
113119
* @param {string} file path of the file importing the specifier
114120
* @param {string[]} extensions extensions to try
115121
* @returns mapped path if found, undefined otherwise
116122
*/
117123
function getMappedPath(
118-
currentMatchersOfCwd: Matcher[],
124+
matchers: Matcher[],
119125
specifier: string,
120126
file: string,
121127
extensions = defaultExtensions
@@ -146,17 +152,17 @@ function getMappedPath(
146152
logger('project config by file path:', projectConfig?.path)
147153
}
148154

149-
const closestMapper = currentMatchersOfCwd?.find((mapper) => {
150-
return mapper.path === projectConfig?.path
155+
const closestMatcher = matchers?.find((matcher) => {
156+
return matcher.path === projectConfig?.path
151157
})
152158

153-
if (closestMapper) {
154-
logger('found closest mapper by config path:', closestMapper.path)
159+
if (closestMatcher) {
160+
logger('found closest matcher by config path:', closestMatcher.path)
155161
}
156162

157-
const matcherResult = closestMapper
158-
? closestMapper.matcher(specifier)
159-
: currentMatchersOfCwd.map((mapper) => mapper?.matcher(specifier)).flat()
163+
const matcherResult = closestMatcher
164+
? closestMatcher.matcher(specifier)
165+
: matchers.map((mapper) => mapper?.matcher(specifier)).flat()
160166

161167
const matcherPaths = matcherResult
162168
.map((item) => [
@@ -169,7 +175,7 @@ function getMappedPath(
169175

170176
const possiblePaths = possiblePathsBySpecifier.get(specifier)
171177

172-
if (possiblePaths && possiblePaths.path === closestMapper?.path) {
178+
if (possiblePaths && possiblePaths.path === closestMatcher?.path) {
173179
logger(
174180
`found matching paths from cache by specifier ${specifier} and config ${possiblePaths.path} path:`,
175181
possiblePaths.paths
@@ -192,8 +198,8 @@ function getMappedPath(
192198
return false
193199
})
194200

195-
if (closestMapper) {
196-
possiblePathsBySpecifier.set(specifier, { paths, path: closestMapper.path })
201+
if (closestMatcher) {
202+
possiblePathsBySpecifier.set(specifier, { paths, path: closestMatcher.path })
197203
}
198204

199205
if (paths.length > 1) {

0 commit comments

Comments
 (0)