From 61ee5bf5c54d431f176e3a407f47000227d1440a Mon Sep 17 00:00:00 2001 From: "yufeng.freeman" Date: Fri, 25 Mar 2022 11:55:28 +0800 Subject: [PATCH 1/6] feat: add support for jsconfig.json --- src/__tests__/tsconfig-loader.test.ts | 20 ++++++++++++++++++++ src/tsconfig-loader.ts | 7 ++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/__tests__/tsconfig-loader.test.ts b/src/__tests__/tsconfig-loader.test.ts index 7394482..b69a07d 100644 --- a/src/__tests__/tsconfig-loader.test.ts +++ b/src/__tests__/tsconfig-loader.test.ts @@ -115,6 +115,16 @@ describe("walkForTsConfig", () => { expect(res).toBe(pathToTsconfig); }); + it("should find jsconfig in starting directory", () => { + const pathToJsconfig = join("/root", "dir1", "jsconfig.json"); + const res = walkForTsConfig( + join("/root", "dir1"), + (path) => path === pathToJsconfig + ); + // assert.equal(res, pathToTsconfig); + expect(res).toBe(pathToJsconfig); + }); + it("should find tsconfig in parent directory", () => { const pathToTsconfig = join("/root", "tsconfig.json"); const res = walkForTsConfig( @@ -125,6 +135,16 @@ describe("walkForTsConfig", () => { expect(res).toBe(pathToTsconfig); }); + it("should find jsconfig in parent directory", () => { + const pathToTsconfig = join("/root", "jsconfig.json"); + const res = walkForTsConfig( + join("/root", "dir1"), + (path) => path === pathToTsconfig + ); + // assert.equal(res, pathToTsconfig); + expect(res).toBe(pathToTsconfig); + }); + it("should return undefined when reaching the top", () => { const res = walkForTsConfig(join("/root", "dir1", "kalle"), () => false); // assert.equal(res, undefined); diff --git a/src/tsconfig-loader.ts b/src/tsconfig-loader.ts index 40a0744..9854f34 100644 --- a/src/tsconfig-loader.ts +++ b/src/tsconfig-loader.ts @@ -96,7 +96,12 @@ export function walkForTsConfig( // eslint-disable-next-line no-shadow existsSync: (path: string) => boolean = fs.existsSync ): string | undefined { - const configPath = path.join(directory, "./tsconfig.json"); + let configPath = path.join(directory, "./tsconfig.json"); + if (existsSync(configPath)) { + return configPath; + } + + configPath = path.join(directory, "./jsconfig.json"); if (existsSync(configPath)) { return configPath; } From 4a5c0c0a788594a53094e5089d3a1a44f29bf589 Mon Sep 17 00:00:00 2001 From: Feng Yu Date: Wed, 30 Mar 2022 10:21:56 +0800 Subject: [PATCH 2/6] Update src/tsconfig-loader.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michaƫl De Boey --- src/__tests__/tsconfig-loader.test.ts | 63 +++++++++++++++++---------- src/tsconfig-loader.ts | 22 ++++------ 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/src/__tests__/tsconfig-loader.test.ts b/src/__tests__/tsconfig-loader.test.ts index b69a07d..4836898 100644 --- a/src/__tests__/tsconfig-loader.test.ts +++ b/src/__tests__/tsconfig-loader.test.ts @@ -107,47 +107,66 @@ describe("tsconfig-loader", () => { describe("walkForTsConfig", () => { it("should find tsconfig in starting directory", () => { const pathToTsconfig = join("/root", "dir1", "tsconfig.json"); - const res = walkForTsConfig( - join("/root", "dir1"), - (path) => path === pathToTsconfig - ); - // assert.equal(res, pathToTsconfig); + const res = walkForTsConfig(join("/root", "dir1"), (path) => { + if (path === "/root/dir1") { + return ["tsconfig.json"]; + } else { + return []; + } + }); expect(res).toBe(pathToTsconfig); }); it("should find jsconfig in starting directory", () => { const pathToJsconfig = join("/root", "dir1", "jsconfig.json"); - const res = walkForTsConfig( - join("/root", "dir1"), - (path) => path === pathToJsconfig - ); - // assert.equal(res, pathToTsconfig); + const res = walkForTsConfig(join("/root", "dir1"), (path) => { + if (path === "/root/dir1") { + return ["jsconfig.json"]; + } else { + return []; + } + }); expect(res).toBe(pathToJsconfig); }); + it("tsconfig.json take precedence over jsconfig.json when both exist", () => { + const pathToTsconfig = join("/root/dir1", "tsconfig.json"); + const res = walkForTsConfig(join("/root", "dir1"), (path) => { + if (path === "/root/dir1") { + return ["jsconfig.json", "tsconfig.json"]; + } else { + return []; + } + }); + expect(res).toBe(pathToTsconfig); + }); + it("should find tsconfig in parent directory", () => { const pathToTsconfig = join("/root", "tsconfig.json"); - const res = walkForTsConfig( - join("/root", "dir1"), - (path) => path === pathToTsconfig - ); - // assert.equal(res, pathToTsconfig); + const res = walkForTsConfig(join("/root", "dir1"), (path) => { + if (path === "/root") { + return ["tsconfig.json"]; + } else { + return []; + } + }); expect(res).toBe(pathToTsconfig); }); it("should find jsconfig in parent directory", () => { const pathToTsconfig = join("/root", "jsconfig.json"); - const res = walkForTsConfig( - join("/root", "dir1"), - (path) => path === pathToTsconfig - ); - // assert.equal(res, pathToTsconfig); + const res = walkForTsConfig(join("/root", "dir1"), (path) => { + if (path === "/root") { + return ["jsconfig.json"]; + } else { + return []; + } + }); expect(res).toBe(pathToTsconfig); }); it("should return undefined when reaching the top", () => { - const res = walkForTsConfig(join("/root", "dir1", "kalle"), () => false); - // assert.equal(res, undefined); + const res = walkForTsConfig(join("/root", "dir1", "kalle"), () => []); expect(res).toBeUndefined(); }); }); diff --git a/src/tsconfig-loader.ts b/src/tsconfig-loader.ts index 9854f34..93b6326 100644 --- a/src/tsconfig-loader.ts +++ b/src/tsconfig-loader.ts @@ -90,30 +90,26 @@ function resolveConfigPath(cwd: string, filename?: string): string | undefined { const configAbsolutePath = walkForTsConfig(cwd); return configAbsolutePath ? path.resolve(configAbsolutePath) : undefined; } - export function walkForTsConfig( directory: string, - // eslint-disable-next-line no-shadow - existsSync: (path: string) => boolean = fs.existsSync + readdirSync: (path: string) => string[] = fs.readdirSync ): string | undefined { - let configPath = path.join(directory, "./tsconfig.json"); - if (existsSync(configPath)) { - return configPath; - } - - configPath = path.join(directory, "./jsconfig.json"); - if (existsSync(configPath)) { - return configPath; + const files = readdirSync(directory); + const filesToCheck = ["tsconfig.json", "jsconfig.json"]; + for (const fileToCheck of filesToCheck) { + if (files.indexOf(fileToCheck) !== -1) { + return path.join(directory, fileToCheck); + } } - const parentDirectory = path.join(directory, "../"); + const parentDirectory = path.dirname(directory); // If we reached the top if (directory === parentDirectory) { return undefined; } - return walkForTsConfig(parentDirectory, existsSync); + return walkForTsConfig(parentDirectory, readdirSync); } export function loadTsconfig( From acf4a0c007047e55f8ca2c1583f2a6825061dfed Mon Sep 17 00:00:00 2001 From: Feng Yu Date: Sun, 17 Apr 2022 09:28:39 +0800 Subject: [PATCH 3/6] Update src/__tests__/tsconfig-loader.test.ts Co-authored-by: Alec Larson <1925840+aleclarson@users.noreply.github.com> --- src/__tests__/tsconfig-loader.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/__tests__/tsconfig-loader.test.ts b/src/__tests__/tsconfig-loader.test.ts index 4836898..e0f5ec3 100644 --- a/src/__tests__/tsconfig-loader.test.ts +++ b/src/__tests__/tsconfig-loader.test.ts @@ -129,6 +129,7 @@ describe("walkForTsConfig", () => { expect(res).toBe(pathToJsconfig); }); + // see https://github.com/Microsoft/TypeScript/issues/15869#issuecomment-301845650 it("tsconfig.json take precedence over jsconfig.json when both exist", () => { const pathToTsconfig = join("/root/dir1", "tsconfig.json"); const res = walkForTsConfig(join("/root", "dir1"), (path) => { From 8dd225da1d5ece963f9d9ee1021d9e6c986f52cc Mon Sep 17 00:00:00 2001 From: feng Date: Sun, 17 Apr 2022 10:18:36 +0800 Subject: [PATCH 4/6] optimize readdir mock --- src/__tests__/tsconfig-loader.test.ts | 70 +++++++++++++-------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/__tests__/tsconfig-loader.test.ts b/src/__tests__/tsconfig-loader.test.ts index e0f5ec3..e6d245d 100644 --- a/src/__tests__/tsconfig-loader.test.ts +++ b/src/__tests__/tsconfig-loader.test.ts @@ -107,62 +107,62 @@ describe("tsconfig-loader", () => { describe("walkForTsConfig", () => { it("should find tsconfig in starting directory", () => { const pathToTsconfig = join("/root", "dir1", "tsconfig.json"); - const res = walkForTsConfig(join("/root", "dir1"), (path) => { - if (path === "/root/dir1") { - return ["tsconfig.json"]; - } else { - return []; - } - }); + const mockFiles: Record = { + "/root/dir1": ["tsconfig.json"], + }; + const res = walkForTsConfig( + join("/root", "dir1"), + (path) => mockFiles[path] || [] + ); expect(res).toBe(pathToTsconfig); }); it("should find jsconfig in starting directory", () => { const pathToJsconfig = join("/root", "dir1", "jsconfig.json"); - const res = walkForTsConfig(join("/root", "dir1"), (path) => { - if (path === "/root/dir1") { - return ["jsconfig.json"]; - } else { - return []; - } - }); + const mockFiles: Record = { + "/root/dir1": ["jsconfig.json"], + }; + const res = walkForTsConfig( + join("/root", "dir1"), + (path) => mockFiles[path] || [] + ); expect(res).toBe(pathToJsconfig); }); // see https://github.com/Microsoft/TypeScript/issues/15869#issuecomment-301845650 it("tsconfig.json take precedence over jsconfig.json when both exist", () => { const pathToTsconfig = join("/root/dir1", "tsconfig.json"); - const res = walkForTsConfig(join("/root", "dir1"), (path) => { - if (path === "/root/dir1") { - return ["jsconfig.json", "tsconfig.json"]; - } else { - return []; - } - }); + const mockFiles: Record = { + "/root/dir1": ["jsconfig.json", "tsconfig.json"], + }; + const res = walkForTsConfig( + join("/root", "dir1"), + (path) => mockFiles[path] || [] + ); expect(res).toBe(pathToTsconfig); }); it("should find tsconfig in parent directory", () => { const pathToTsconfig = join("/root", "tsconfig.json"); - const res = walkForTsConfig(join("/root", "dir1"), (path) => { - if (path === "/root") { - return ["tsconfig.json"]; - } else { - return []; - } - }); + const mockFiles: Record = { + "/root": ["tsconfig.json"], + }; + const res = walkForTsConfig( + join("/root", "dir1"), + (path) => mockFiles[path] || [] + ); expect(res).toBe(pathToTsconfig); }); it("should find jsconfig in parent directory", () => { const pathToTsconfig = join("/root", "jsconfig.json"); - const res = walkForTsConfig(join("/root", "dir1"), (path) => { - if (path === "/root") { - return ["jsconfig.json"]; - } else { - return []; - } - }); + const mockFiles: Record = { + "/root": ["jsconfig.json"], + }; + const res = walkForTsConfig( + join("/root", "dir1"), + (path) => mockFiles[path] || [] + ); expect(res).toBe(pathToTsconfig); }); From c591de1c0d8edb96daed4ba026b6050c2dac8a3b Mon Sep 17 00:00:00 2001 From: Feng Yu Date: Mon, 18 Apr 2022 08:57:31 +0000 Subject: [PATCH 5/6] add changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fd484c..9a2a619 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Add support for `jsconfig.json`. See PR [#199](https://github.com/dividab/tsconfig-paths/pull/199). Thanks to [@F3n67u](https://github.com/F3n67u) for this PR! + ## [3.14.1] - 2022-03-22 ### Fixed From b2688f0a02411c325089ae0af88c9a9b75aacc13 Mon Sep 17 00:00:00 2001 From: Feng Yu Date: Mon, 18 Apr 2022 09:05:22 +0000 Subject: [PATCH 6/6] update readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 768119e..4a749af 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ [![MIT license][license-image]][license-url] [![code style: prettier][prettier-image]][prettier-url] -Use this to load modules whose location is specified in the `paths` section of `tsconfig.json`. Both loading at run-time and via API are supported. +Use this to load modules whose location is specified in the `paths` section of `tsconfig.json` or `jsconfig.json`. Both loading at run-time and via API are supported. Typescript by default mimics the Node.js runtime resolution strategy of modules. But it also allows the use of [path mapping](https://www.typescriptlang.org/docs/handbook/module-resolution.html) which allows arbitrary module paths (that doesn't start with "/" or ".") to be specified and mapped to physical paths in the filesystem. The typescript compiler can resolve these paths from `tsconfig` so it will compile OK. But if you then try to execute the compiled files with node (or ts-node), it will only look in the `node_modules` folders all the way up to the root of the filesystem and thus will not find the modules specified by `paths` in `tsconfig`. -If you require this package's `tsconfig-paths/register` module it will read the `paths` from `tsconfig.json` and convert node's module loading calls into to physical file paths that node can load. +If you require this package's `tsconfig-paths/register` module it will read the `paths` from `tsconfig.json` or `jsconfig.json` and convert node's module loading calls into to physical file paths that node can load. ## How to install @@ -156,7 +156,7 @@ export interface ExplicitParams { export function register(explicitParams: ExplicitParams): () => void; ``` -This function will patch the node's module loading so it will look for modules in paths specified by tsconfig.json. +This function will patch the node's module loading so it will look for modules in paths specified by `tsconfig.json` or `jsconfig.json`. A function is returned for you to reinstate Node's original module loading. ### loadConfig @@ -180,7 +180,7 @@ export interface ConfigLoaderFailResult { } ``` -This function loads the tsconfig.json. It will start searching from the specified `cwd` directory. Passing the tsconfig.json file directly instead of a directory also works. +This function loads the `tsconfig.json` or `jsconfig.json`. It will start searching from the specified `cwd` directory. Passing the `tsconfig.json` or `jsconfig.json` file directly instead of a directory also works. ### createMatchPath