From 07a8772b17db4cbf44137d3d13de32f4b9f28d02 Mon Sep 17 00:00:00 2001 From: Christian Scott Date: Thu, 26 May 2022 17:47:24 +1000 Subject: [PATCH 1/6] files depend on .d.ts files referenced via `include` --- src/processors/typescript.ts | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/processors/typescript.ts b/src/processors/typescript.ts index b5c7296..0e35907 100644 --- a/src/processors/typescript.ts +++ b/src/processors/typescript.ts @@ -163,6 +163,11 @@ export class TypeScriptFileProcessor implements FileProcessor { } } + const includes = await this.includesFromNearestTsconfigFile(file); + for (const include of includes) { + importedFiles.add(include); + } + return Promise.resolve(importedFiles); } @@ -189,6 +194,33 @@ export class TypeScriptFileProcessor implements FileProcessor { }, ); + private async includesFromNearestTsconfigFile(file: Path): Promise { + const tsconfigPath = ts.findConfigFile( + path.dirname(file), + ts.sys.fileExists, + ); + if (!tsconfigPath || !tsconfigPath.startsWith(this.rootDir)) { + return []; + } + + const json = ts.parseJsonText( + tsconfigPath, + await fs.promises.readFile(tsconfigPath, 'utf-8'), + ); + const parsed = ts.parseJsonSourceFileConfigFileContent( + json, + ts.sys, + path.dirname(tsconfigPath), + ); + 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: // // export const entryPoint: DynamicEntryPoint = { From 864135678f0f96e79ab12ce8ccbd1e391eb4ef09 Mon Sep 17 00:00:00 2001 From: Christian Scott Date: Thu, 26 May 2022 17:47:31 +1000 Subject: [PATCH 2/6] add tests --- __tests__/fixtures/tsconfigs/decls/one.d.ts | 0 .../fixtures/tsconfigs/decls/tsconfig.json | 3 ++ __tests__/fixtures/tsconfigs/decls/two.d.ts | 0 .../fixtures/tsconfigs/extends/extends.ts | 0 .../fixtures/tsconfigs/extends/tsconfig.json | 4 +++ __tests__/fixtures/tsconfigs/glob/glob.ts | 0 .../fixtures/tsconfigs/glob/tsconfig.json | 3 ++ .../tsconfigs/project/nested/nested.ts | 0 .../fixtures/tsconfigs/project/project.ts | 0 .../fixtures/tsconfigs/project/tsconfig.json | 3 ++ __tests__/index.test.ts | 29 +++++++++++++++++++ 11 files changed, 42 insertions(+) create mode 100644 __tests__/fixtures/tsconfigs/decls/one.d.ts create mode 100644 __tests__/fixtures/tsconfigs/decls/tsconfig.json create mode 100644 __tests__/fixtures/tsconfigs/decls/two.d.ts create mode 100644 __tests__/fixtures/tsconfigs/extends/extends.ts create mode 100644 __tests__/fixtures/tsconfigs/extends/tsconfig.json create mode 100644 __tests__/fixtures/tsconfigs/glob/glob.ts create mode 100644 __tests__/fixtures/tsconfigs/glob/tsconfig.json create mode 100644 __tests__/fixtures/tsconfigs/project/nested/nested.ts create mode 100644 __tests__/fixtures/tsconfigs/project/project.ts create mode 100644 __tests__/fixtures/tsconfigs/project/tsconfig.json 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..1ab6580 --- /dev/null +++ b/__tests__/fixtures/tsconfigs/decls/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} 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..3b5fde2 --- /dev/null +++ b/__tests__/fixtures/tsconfigs/extends/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../project/tsconfig.json", + "include": ["./**/*.*"] +} 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..10ec1eb --- /dev/null +++ b/__tests__/fixtures/tsconfigs/glob/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["../decls/*.d.ts", "./**/*.*"] +} 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 new file mode 100644 index 0000000..4aee49e --- /dev/null +++ b/__tests__/fixtures/tsconfigs/project/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["../decls/one.d.ts", "./**/*.*"] +} diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index d1b3e63..2b824ed 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -499,4 +499,33 @@ describe('dependencyTree', () => { ).rejects.toThrowErrorMatchingSnapshot(); }); }); + + describe('tsconfig', () => { + beforeEach(() => { + dependencyTree = new DependencyTree([fixture('tsconfigs')]); + }); + + 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', 'nested', 'nested.ts'), + new Set([decl1]), + ], + [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])], + ]), + }); + }); + }); }); From 9f8339de2f5700bda46850f8c1f6c19fb63522fb Mon Sep 17 00:00:00 2001 From: Christian Scott Date: Thu, 26 May 2022 17:58:25 +1000 Subject: [PATCH 3/6] debug info when rejecting invalid tsconfig --- src/processors/typescript.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/processors/typescript.ts b/src/processors/typescript.ts index 0e35907..2681d70 100644 --- a/src/processors/typescript.ts +++ b/src/processors/typescript.ts @@ -199,7 +199,20 @@ export class TypeScriptFileProcessor implements FileProcessor { path.dirname(file), ts.sys.fileExists, ); - if (!tsconfigPath || !tsconfigPath.startsWith(this.rootDir)) { + if (!tsconfigPath) { + debug( + `could not find a tsconfig file for '%s'`, + path.relative(this.rootDir, file), + ); + return []; + } + if (!tsconfigPath.startsWith(this.rootDir)) { + debug( + `invalid tsconfig file '%s' found for '%s'. expected a tsconfig file inside the project root '%s'`, + path.relative(this.rootDir, tsconfigPath), + path.relative(this.rootDir, file), + this.rootDir, + ); return []; } From 1eb792c1d114c7659c8a6f3dc4cb9bbd0f4164a2 Mon Sep 17 00:00:00 2001 From: Christian Scott Date: Thu, 26 May 2022 17:58:45 +1000 Subject: [PATCH 4/6] add comment --- src/processors/typescript.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/processors/typescript.ts b/src/processors/typescript.ts index 2681d70..58d5b92 100644 --- a/src/processors/typescript.ts +++ b/src/processors/typescript.ts @@ -104,6 +104,16 @@ export class TypeScriptFileProcessor implements FileProcessor { dependencyTree: DependencyTree, ): Promise> { const importedFiles = new Set(); + + // TypeScript files can *implicitly* depend on .d.ts files. We discover + // these files by extracting them from the nearest tsconfig.json file. + // These do not need to be processed further since they have already been fully + // resolved by the typescript compiler. + const includes = await this.includesFromNearestTsconfigFile(file); + for (const include of includes) { + importedFiles.add(include); + } + const filesList = ts .preProcessFile(contents, true, true) .importedFiles.map(({ fileName }) => fileName); @@ -163,11 +173,6 @@ export class TypeScriptFileProcessor implements FileProcessor { } } - const includes = await this.includesFromNearestTsconfigFile(file); - for (const include of includes) { - importedFiles.add(include); - } - return Promise.resolve(importedFiles); } From 302539c7ec90cd28a83c9157b800014fb86a7c61 Mon Sep 17 00:00:00 2001 From: Christian Scott Date: Thu, 26 May 2022 18:04:08 +1000 Subject: [PATCH 5/6] fail on missing tsconfig.json --- __tests__/fixtures/a/tsconfig.json | 3 +++ __tests__/fixtures/built-ins/tsconfig.json | 3 +++ __tests__/fixtures/directive/tsconfig.json | 3 +++ __tests__/fixtures/entry/tsconfig.json | 3 +++ .../feature-storybook-ref/tsconfig.json | 3 +++ __tests__/fixtures/framework/tsconfig.json | 3 +++ __tests__/fixtures/modules/tsconfig.json | 3 +++ __tests__/fixtures/snapshots/tsconfig.json | 3 +++ src/processors/typescript.ts | 25 +++++++++++-------- 9 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 __tests__/fixtures/a/tsconfig.json create mode 100644 __tests__/fixtures/built-ins/tsconfig.json create mode 100644 __tests__/fixtures/directive/tsconfig.json create mode 100644 __tests__/fixtures/entry/tsconfig.json create mode 100644 __tests__/fixtures/feature-storybook-ref/tsconfig.json create mode 100644 __tests__/fixtures/framework/tsconfig.json create mode 100644 __tests__/fixtures/modules/tsconfig.json create mode 100644 __tests__/fixtures/snapshots/tsconfig.json diff --git a/__tests__/fixtures/a/tsconfig.json b/__tests__/fixtures/a/tsconfig.json new file mode 100644 index 0000000..1ab6580 --- /dev/null +++ b/__tests__/fixtures/a/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} diff --git a/__tests__/fixtures/built-ins/tsconfig.json b/__tests__/fixtures/built-ins/tsconfig.json new file mode 100644 index 0000000..1ab6580 --- /dev/null +++ b/__tests__/fixtures/built-ins/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} diff --git a/__tests__/fixtures/directive/tsconfig.json b/__tests__/fixtures/directive/tsconfig.json new file mode 100644 index 0000000..1ab6580 --- /dev/null +++ b/__tests__/fixtures/directive/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} diff --git a/__tests__/fixtures/entry/tsconfig.json b/__tests__/fixtures/entry/tsconfig.json new file mode 100644 index 0000000..1ab6580 --- /dev/null +++ b/__tests__/fixtures/entry/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} diff --git a/__tests__/fixtures/feature-storybook-ref/tsconfig.json b/__tests__/fixtures/feature-storybook-ref/tsconfig.json new file mode 100644 index 0000000..1ab6580 --- /dev/null +++ b/__tests__/fixtures/feature-storybook-ref/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} diff --git a/__tests__/fixtures/framework/tsconfig.json b/__tests__/fixtures/framework/tsconfig.json new file mode 100644 index 0000000..1ab6580 --- /dev/null +++ b/__tests__/fixtures/framework/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} diff --git a/__tests__/fixtures/modules/tsconfig.json b/__tests__/fixtures/modules/tsconfig.json new file mode 100644 index 0000000..1ab6580 --- /dev/null +++ b/__tests__/fixtures/modules/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} diff --git a/__tests__/fixtures/snapshots/tsconfig.json b/__tests__/fixtures/snapshots/tsconfig.json new file mode 100644 index 0000000..1ab6580 --- /dev/null +++ b/__tests__/fixtures/snapshots/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} diff --git a/src/processors/typescript.ts b/src/processors/typescript.ts index 58d5b92..f45d3d8 100644 --- a/src/processors/typescript.ts +++ b/src/processors/typescript.ts @@ -205,20 +205,25 @@ export class TypeScriptFileProcessor implements FileProcessor { ts.sys.fileExists, ); if (!tsconfigPath) { - debug( - `could not find a tsconfig file for '%s'`, - path.relative(this.rootDir, file), + throw new Error( + `could not find a tsconfig file for '${path.relative( + this.rootDir, + file, + )}'`, ); - return []; } if (!tsconfigPath.startsWith(this.rootDir)) { - debug( - `invalid tsconfig file '%s' found for '%s'. expected a tsconfig file inside the project root '%s'`, - path.relative(this.rootDir, tsconfigPath), - path.relative(this.rootDir, file), - this.rootDir, + throw new Error( + `invalid tsconfig file '${path.relative( + this.rootDir, + tsconfigPath, + )}' found for '${path.relative( + this.rootDir, + file, + )}'. expected a tsconfig file inside the project root '${ + this.rootDir + }'`, ); - return []; } const json = ts.parseJsonText( From c160a94a1ea6ccc0c22ca083d59c42ada4319db0 Mon Sep 17 00:00:00 2001 From: Christian Scott Date: Thu, 26 May 2022 18:21:30 +1000 Subject: [PATCH 6/6] mixed decl and source test --- __tests__/fixtures/tsconfigs/mixed/decl.d.ts | 0 __tests__/fixtures/tsconfigs/mixed/source.ts | 0 __tests__/fixtures/tsconfigs/mixed/tsconfig.json | 3 +++ __tests__/index.test.ts | 6 ++++++ 4 files changed, 9 insertions(+) create mode 100644 __tests__/fixtures/tsconfigs/mixed/decl.d.ts create mode 100644 __tests__/fixtures/tsconfigs/mixed/source.ts create mode 100644 __tests__/fixtures/tsconfigs/mixed/tsconfig.json diff --git a/__tests__/fixtures/tsconfigs/mixed/decl.d.ts b/__tests__/fixtures/tsconfigs/mixed/decl.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/tsconfigs/mixed/source.ts b/__tests__/fixtures/tsconfigs/mixed/source.ts new file mode 100644 index 0000000..e69de29 diff --git a/__tests__/fixtures/tsconfigs/mixed/tsconfig.json b/__tests__/fixtures/tsconfigs/mixed/tsconfig.json new file mode 100644 index 0000000..1ab6580 --- /dev/null +++ b/__tests__/fixtures/tsconfigs/mixed/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["./**/*.*"] +} diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 2b824ed..eb2388d 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -524,6 +524,12 @@ describe('dependencyTree', () => { // 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])], + // files can depend on decls in the same dir + [ + fixture('tsconfigs', 'mixed', 'source.ts'), + new Set([fixture('tsconfigs', 'mixed', 'decl.d.ts')]), + ], + [fixture('tsconfigs', 'mixed', 'decl.d.ts'), new Set([])], ]), }); });