Skip to content

Commit 8b82290

Browse files
authored
Fix resolution of an index.d.ts inside a directory, Closes #99
1 parent 59a1307 commit 8b82290

8 files changed

Lines changed: 93 additions & 14 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ output/
1313
**/test/**/*.js
1414
**/test/**/*.js.map
1515
**/test/**/*.d.ts
16-
!/test/data/**/*.d.ts
1716
**/bin/**/*.js
1817
**/bin/**/*.js.map
1918
**/bin/**/*.d.ts
2019
**/index.js
2120
**/index.js.map
2221
**/index.d.ts
22+
!/test/data/**/*.d.ts

lib/parse/ClassFinder.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export class ClassFinder {
4242
Promise<{ named: ClassIndex<ClassReference>; unnamed: { packageName: string; fileName: string }[] }> {
4343
// Load the elements of the class
4444
const {
45+
resolvedPath,
4546
exportedClasses,
4647
exportedInterfaces,
4748
exportedImportedElements,
@@ -63,17 +64,17 @@ export class ClassFinder {
6364
packageName,
6465
localName,
6566
qualifiedPath: undefined,
66-
fileName,
67-
fileNameReferenced: fileName,
67+
fileName: resolvedPath,
68+
fileNameReferenced: resolvedPath,
6869
};
6970
}
7071
for (const localName in exportedInterfaces) {
7172
exportDefinitions.named[localName] = {
7273
packageName,
7374
localName,
7475
qualifiedPath: undefined,
75-
fileName,
76-
fileNameReferenced: fileName,
76+
fileName: resolvedPath,
77+
fileNameReferenced: resolvedPath,
7778
};
7879
}
7980

@@ -84,7 +85,7 @@ export class ClassFinder {
8485
localName,
8586
qualifiedPath: undefined,
8687
fileName: importedFileName,
87-
fileNameReferenced: fileName,
88+
fileNameReferenced: resolvedPath,
8889
};
8990
}
9091

@@ -98,8 +99,8 @@ export class ClassFinder {
9899
packageName,
99100
localName,
100101
qualifiedPath: undefined,
101-
fileName,
102-
fileNameReferenced: fileName,
102+
fileName: resolvedPath,
103+
fileNameReferenced: resolvedPath,
103104
};
104105
break;
105106
}
@@ -110,8 +111,8 @@ export class ClassFinder {
110111
packageName,
111112
localName,
112113
qualifiedPath: undefined,
113-
fileName,
114-
fileNameReferenced: fileName,
114+
fileName: resolvedPath,
115+
fileNameReferenced: resolvedPath,
115116
};
116117
break;
117118
}

lib/parse/ClassLoader.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -457,11 +457,17 @@ export class ClassLoader {
457457
/**
458458
* Load a class, and get all class elements from it.
459459
* @param packageName Package name we are importing from.
460-
* @param fileName A file path.
460+
* @param filePath A file path.
461+
* @returns {Promise<ClassElements & { resolvedPath: string }>} Promise of the class elements along with
462+
* the resolved file path that was used to load these class elements.
461463
*/
462-
public async loadClassElements(packageName: string, fileName: string): Promise<ClassElements> {
463-
const ast = await this.resolutionContext.parseTypescriptFile(fileName);
464-
return this.getClassElements(packageName, fileName, ast);
464+
public async loadClassElements(packageName: string, filePath: string): Promise<
465+
ClassElements & { resolvedPath: string }
466+
> {
467+
const resolvedPath = await this.resolutionContext.resolveTypesPath(filePath);
468+
const ast = await this.resolutionContext.parseTypescriptFile(resolvedPath);
469+
const classElements = this.getClassElements(packageName, resolvedPath, ast);
470+
return { ...classElements, resolvedPath };
465471
}
466472

467473
/**

lib/resolution/ResolutionContext.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@ export class ResolutionContext {
3131
});
3232
}
3333

34+
/**
35+
* Resolve the correct type declarations path for a specific path used
36+
* in the exports.
37+
*
38+
* @param {string} filePath File path without .d.ts
39+
* @returns {Promise<string>} Promise of the file path without .d.ts that is
40+
* either equal to the parameter or the index of the directory.
41+
*/
42+
public resolveTypesPath(filePath: string): Promise<string> {
43+
return new Promise(resolve => {
44+
fs.access(`${filePath}.d.ts`, error => {
45+
if (error) {
46+
// No file found, treat as directory with an index
47+
filePath = Path.normalize(`${filePath}/index`);
48+
}
49+
resolve(filePath);
50+
});
51+
});
52+
}
53+
3454
/**
3555
* Write the content of a file.
3656
* If any of the underlying directories do not exist, they will be created.

test/ResolutionContextMocked.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* istanbul ignore file */
2+
import * as Path from 'path';
23
import type { AST, TSESTreeOptions } from '@typescript-eslint/typescript-estree';
34
import { ResolutionContext } from '../lib/resolution/ResolutionContext';
45

@@ -15,6 +16,15 @@ export class ResolutionContextMocked extends ResolutionContext {
1516
this.packageNameIndexOverrides = packageNameIndexOverrides;
1617
}
1718

19+
public resolveTypesPath(filePath: string): Promise<string> {
20+
return new Promise(resolve => {
21+
if (!(`${filePath}.d.ts` in this.contentsOverrides)) {
22+
return resolve(Path.normalize(`${filePath}/index`));
23+
}
24+
resolve(filePath);
25+
});
26+
}
27+
1828
public async getFileContent(filePath: string): Promise<string> {
1929
if (!(filePath in this.contentsOverrides)) {
2030
throw new Error(`Could not find mocked path for ${filePath}`);

test/data/directory/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export class MyClass {}

test/parse/ClassFinder.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,35 @@ export {A};
359359
});
360360
});
361361

362+
it('for a directory export', async() => {
363+
resolutionContext.contentsOverrides = {
364+
[Path.normalize('directory-export/index.d.ts')]: `
365+
export * from './lib';
366+
`,
367+
[Path.normalize('directory-export/lib/index.d.ts')]: `
368+
export * from './A';
369+
export * from './C';
370+
`,
371+
[Path.normalize('directory-export/lib/A.d.ts')]: 'export class A {}',
372+
[Path.normalize('directory-export/lib/C.d.ts')]: 'export class C {}',
373+
};
374+
expect(await parser.getPackageExports('package', Path.normalize('directory-export/index')))
375+
.toEqual({
376+
A: {
377+
packageName: 'package',
378+
fileName: Path.normalize('directory-export/lib/A'),
379+
fileNameReferenced: Path.normalize('directory-export/lib/A'),
380+
localName: 'A',
381+
},
382+
C: {
383+
packageName: 'package',
384+
fileName: Path.normalize('directory-export/lib/C'),
385+
fileNameReferenced: Path.normalize('directory-export/lib/C'),
386+
localName: 'C',
387+
},
388+
});
389+
});
390+
362391
it('for a multiple exports', async() => {
363392
resolutionContext.contentsOverrides = {
364393
[Path.normalize('package-multiple/index.d.ts')]: `

test/resolution/ResolutionContext.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,16 @@ describe('ResolutionContext', () => {
168168
.toEqual(Path.normalize('/root/abc.d.ts'));
169169
});
170170
});
171+
172+
describe('resolveTypesPath', () => {
173+
it('Should resolve a types path of a directory', async() => {
174+
expect(await resolutionContext.resolveTypesPath(`${__dirname}/../data/directory`))
175+
.toEqual(Path.normalize(`${__dirname}/../data/directory/index`));
176+
});
177+
178+
it('Should resolve a types path of a file', async() => {
179+
expect(await resolutionContext.resolveTypesPath(`${__dirname}/../data/file`))
180+
.toEqual(`${__dirname}/../data/file`);
181+
});
182+
});
171183
});

0 commit comments

Comments
 (0)