diff --git a/__tests__/fixtures/tsconfigs/includes/a.d.ts b/__tests__/fixtures/tsconfigs copy/includes/a.d.ts similarity index 100% rename from __tests__/fixtures/tsconfigs/includes/a.d.ts rename to __tests__/fixtures/tsconfigs copy/includes/a.d.ts diff --git a/__tests__/fixtures/tsconfigs/project/a.ts b/__tests__/fixtures/tsconfigs copy/project/a.ts similarity index 100% rename from __tests__/fixtures/tsconfigs/project/a.ts rename to __tests__/fixtures/tsconfigs copy/project/a.ts diff --git a/__tests__/fixtures/tsconfigs/project/nested/b.ts b/__tests__/fixtures/tsconfigs copy/project/extends/d.ts similarity index 100% rename from __tests__/fixtures/tsconfigs/project/nested/b.ts rename to __tests__/fixtures/tsconfigs copy/project/extends/d.ts diff --git a/__tests__/fixtures/tsconfigs copy/project/extends/tsconfig.json b/__tests__/fixtures/tsconfigs copy/project/extends/tsconfig.json new file mode 100644 index 0000000..a8df22f --- /dev/null +++ b/__tests__/fixtures/tsconfigs copy/project/extends/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.json" +} \ No newline at end of file diff --git a/__tests__/fixtures/tsconfigs copy/project/glob/c.ts b/__tests__/fixtures/tsconfigs copy/project/glob/c.ts new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/tsconfigs copy/project/glob/tsconfig.json b/__tests__/fixtures/tsconfigs copy/project/glob/tsconfig.json new file mode 100644 index 0000000..8d8c51c --- /dev/null +++ b/__tests__/fixtures/tsconfigs copy/project/glob/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["../../includes/*.*", "./**/*.*"] +} \ No newline at end of file diff --git a/__tests__/fixtures/tsconfigs copy/project/nested/b.ts b/__tests__/fixtures/tsconfigs copy/project/nested/b.ts new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/tsconfigs copy/project/tsconfig.json b/__tests__/fixtures/tsconfigs copy/project/tsconfig.json new file mode 100644 index 0000000..441ca22 --- /dev/null +++ b/__tests__/fixtures/tsconfigs copy/project/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["../includes/a.d.ts"] +} diff --git a/__tests__/fixtures/tsconfigs/decls/one.d.ts b/__tests__/fixtures/tsconfigs/decls/one.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/tsconfigs/decls/tsconfig.json b/__tests__/fixtures/tsconfigs/decls/tsconfig.json new file mode 100644 index 0000000..f24f40a --- /dev/null +++ b/__tests__/fixtures/tsconfigs/decls/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} \ No newline at end of file diff --git a/__tests__/fixtures/tsconfigs/decls/two.d.ts b/__tests__/fixtures/tsconfigs/decls/two.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/tsconfigs/extends/extends.ts b/__tests__/fixtures/tsconfigs/extends/extends.ts new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/tsconfigs/extends/tsconfig.json b/__tests__/fixtures/tsconfigs/extends/tsconfig.json new file mode 100644 index 0000000..f84b9fd --- /dev/null +++ b/__tests__/fixtures/tsconfigs/extends/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../project/tsconfig.json", + "include": ["./**/*.*"] +} \ No newline at end of file diff --git a/__tests__/fixtures/tsconfigs/glob/glob.ts b/__tests__/fixtures/tsconfigs/glob/glob.ts new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/tsconfigs/glob/tsconfig.json b/__tests__/fixtures/tsconfigs/glob/tsconfig.json new file mode 100644 index 0000000..375f696 --- /dev/null +++ b/__tests__/fixtures/tsconfigs/glob/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["../decls/*.d.ts", "./**/*.*"] +} \ No newline at end of file diff --git a/__tests__/fixtures/tsconfigs/project/nested/nested.ts b/__tests__/fixtures/tsconfigs/project/nested/nested.ts new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/tsconfigs/project/project.ts b/__tests__/fixtures/tsconfigs/project/project.ts new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/tsconfigs/project/tsconfig.json b/__tests__/fixtures/tsconfigs/project/tsconfig.json index 441ca22..4aee49e 100644 --- a/__tests__/fixtures/tsconfigs/project/tsconfig.json +++ b/__tests__/fixtures/tsconfigs/project/tsconfig.json @@ -1,3 +1,3 @@ { - "include": ["../includes/a.d.ts"] + "include": ["../decls/one.d.ts", "./**/*.*"] } diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index f0822c3..2b824ed 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -508,18 +508,22 @@ describe('dependencyTree', () => { it('adds files in `include` from nearest tsconfig.json', async () => { expect.hasAssertions(); const result = await dependencyTree.gather(); + const decl1 = fixture('tsconfigs', 'decls', 'one.d.ts'); + const decl2 = fixture('tsconfigs', 'decls', 'two.d.ts'); expect(result).toStrictEqual({ missing: new Map(), resolved: new Map([ + [fixture('tsconfigs', 'project', 'project.ts'), new Set([decl1])], [ - fixture('tsconfigs', 'project', 'a.ts'), - new Set([fixture('tsconfigs', 'includes', 'a.d.ts')]), + fixture('tsconfigs', 'project', 'nested', 'nested.ts'), + new Set([decl1]), ], - [ - fixture('tsconfigs', 'project', 'nested', 'b.ts'), - new Set([fixture('tsconfigs', 'includes', 'a.d.ts')]), - ], - [fixture('tsconfigs', 'includes', 'a.d.ts'), new Set([])], + [fixture('tsconfigs', 'glob', 'glob.ts'), new Set([decl1, decl2])], + // "includes" is overwritten in the child config + [fixture('tsconfigs', 'extends', 'extends.ts'), new Set([])], + // decls in the same dir that includes './**.*.*' depend on one another + [fixture('tsconfigs', 'decls', 'one.d.ts'), new Set([decl2])], + [fixture('tsconfigs', 'decls', 'two.d.ts'), new Set([decl1])], ]), }); }); diff --git a/src/processors/typescript.ts b/src/processors/typescript.ts index 7ebafbd..8b93f2e 100644 --- a/src/processors/typescript.ts +++ b/src/processors/typescript.ts @@ -190,39 +190,36 @@ export class TypeScriptFileProcessor implements FileProcessor { }, ); - /** - * Finds the tsconfig.json that this file is included by. Does this by searching in the same directory, - * and then searching in each dir all the way to the root directory. - */ - private includesFromNearestTsconfigFile = memoize( - async (file: Path): Promise => { - const maybeTsconfig = await findUp('tsconfig.json', { - cwd: path.dirname(file), - stopAt: this.rootDir, - }); - if (maybeTsconfig == null) { - return []; - } - - const json = JSON.parse( - await fs.promises.readFile(maybeTsconfig, 'utf8'), - ); - if (!('include' in json)) { - return []; - } + private async includesFromNearestTsconfigFile(file: Path): Promise { + const tsconfigPath = ts.findConfigFile( + path.dirname(file), + ts.sys.fileExists, + ); + if (!tsconfigPath || !tsconfigPath.startsWith(this.rootDir)) { + return []; + } - const include = json['include'] as string[]; - const tsconfigDir = path.dirname(maybeTsconfig); - return ( - include - // filter out globbed includes - // TODO: support globbed includes - .filter((maybeGlob) => !maybeGlob.includes('*')) - // make the includes absolute - .map((include) => path.join(tsconfigDir, include)) - ); - }, - ); + debug.enabled = true; + const json = ts.parseJsonText( + tsconfigPath, + await fs.promises.readFile(tsconfigPath, 'utf-8'), + ); + const parsed = ts.parseJsonSourceFileConfigFileContent( + json, + ts.sys, + path.dirname(tsconfigPath), + ); + debug(path.relative(this.rootDir, tsconfigPath)); + debug(parsed); + + return parsed.fileNames.filter( + (fileName) => + // only include .d.ts files. all other references should be made using `import` or `require`. + fileName.endsWith('.d.ts') && + // files do not depend on themselves + fileName !== file, + ); + } // Finds an implicit 'import' in the entry point object literal, like: //