Skip to content

Commit c184e47

Browse files
committed
Cache interface range resolution
1 parent f87ea4c commit c184e47

2 files changed

Lines changed: 43 additions & 0 deletions

File tree

lib/parse/ParameterResolver.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { TSTypeLiteral } from '@typescript-eslint/types/dist/ts-estree';
22
import { AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
3+
import * as LRUCache from 'lru-cache';
34
import type { ClassIndex, ClassReference, ClassReferenceLoaded, InterfaceLoaded } from './ClassIndex';
45
import type { ClassLoader } from './ClassLoader';
56
import type { CommentLoader } from './CommentLoader';
@@ -18,11 +19,13 @@ export class ParameterResolver {
1819
private readonly classLoader: ClassLoader;
1920
private readonly commentLoader: CommentLoader;
2021
private readonly ignoreClasses: Record<string, boolean>;
22+
private readonly cacheInterfaceRange: LRUCache<string, ParameterRangeResolved>;
2123

2224
public constructor(args: ParameterResolverArgs) {
2325
this.classLoader = args.classLoader;
2426
this.commentLoader = args.commentLoader;
2527
this.ignoreClasses = args.ignoreClasses;
28+
this.cacheInterfaceRange = new LRUCache(2_048);
2629
}
2730

2831
/**
@@ -250,6 +253,32 @@ export class ParameterResolver {
250253
rootOwningClass: ClassReferenceLoaded,
251254
genericTypeRemappings: Record<string, ParameterRangeUnresolved>,
252255
getNestedFields: boolean,
256+
): Promise<ParameterRangeResolved> {
257+
const cacheKey = `${interfaceName}::${(qualifiedPath || []).join('.')}::${owningClass.fileName}`;
258+
let resolved = this.cacheInterfaceRange.get(cacheKey);
259+
if (!resolved) {
260+
resolved = await this.resolveRangeInterfaceInner(
261+
interfaceName,
262+
qualifiedPath,
263+
genericTypeParameterInstances,
264+
owningClass,
265+
rootOwningClass,
266+
genericTypeRemappings,
267+
getNestedFields,
268+
);
269+
this.cacheInterfaceRange.set(cacheKey, resolved);
270+
}
271+
return resolved;
272+
}
273+
274+
protected async resolveRangeInterfaceInner(
275+
interfaceName: string,
276+
qualifiedPath: string[] | undefined,
277+
genericTypeParameterInstances: ParameterRangeUnresolved[] | undefined,
278+
owningClass: ClassReferenceLoaded,
279+
rootOwningClass: ClassReferenceLoaded,
280+
genericTypeRemappings: Record<string, ParameterRangeUnresolved>,
281+
getNestedFields: boolean,
253282
): Promise<ParameterRangeResolved> {
254283
const classOrInterface = await this.loadClassOrInterfacesChain({
255284
packageName: owningClass.packageName,

test/parse/ParameterResolver.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,20 @@ class ClassA {}
12051205
});
12061206
});
12071207

1208+
it('should resolve a class multiple times via cache', async() => {
1209+
resolutionContext.contentsOverrides = {
1210+
'A.d.ts': `
1211+
class ClassA {}
1212+
`,
1213+
};
1214+
const first = await loader
1215+
.resolveRangeInterface('ClassA', undefined, undefined, classReference, classReference, {}, true);
1216+
const second = await loader
1217+
.resolveRangeInterface('ClassA', undefined, undefined, classReference, classReference, {}, true);
1218+
expect(first).toBe(second);
1219+
expect((<any> loader).cacheInterfaceRange.keys()).toEqual([ 'ClassA::::A' ]);
1220+
});
1221+
12081222
it('should resolve an implicit class', async() => {
12091223
resolutionContext.contentsOverrides = {
12101224
'A.d.ts': `

0 commit comments

Comments
 (0)