From 98bbcdc52207758b66b029d3cb694999c80ffaa2 Mon Sep 17 00:00:00 2001 From: Feng Yu Date: Mon, 18 Apr 2022 18:47:20 +0800 Subject: [PATCH] feat: add support for jsconfig.json (#199) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add support for jsconfig.json * Update src/tsconfig-loader.ts Co-authored-by: Michaël De Boey * Update src/__tests__/tsconfig-loader.test.ts Co-authored-by: Alec Larson <1925840+aleclarson@users.noreply.github.com> * optimize readdir mock * add changelog * update readme Co-authored-by: Michaël De Boey Co-authored-by: Alec Larson <1925840+aleclarson@users.noreply.github.com> --- CHANGELOG.md | 2 ++ README.md | 8 ++--- src/__tests__/tsconfig-loader.test.ts | 52 +++++++++++++++++++++++---- src/tsconfig-loader.ts | 17 ++++----- 4 files changed, 61 insertions(+), 18 deletions(-) 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 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 diff --git a/src/__tests__/tsconfig-loader.test.ts b/src/__tests__/tsconfig-loader.test.ts index 7394482..e6d245d 100644 --- a/src/__tests__/tsconfig-loader.test.ts +++ b/src/__tests__/tsconfig-loader.test.ts @@ -107,27 +107,67 @@ describe("tsconfig-loader", () => { describe("walkForTsConfig", () => { it("should find tsconfig in starting directory", () => { const pathToTsconfig = join("/root", "dir1", "tsconfig.json"); + 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 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 mockFiles: Record = { + "/root/dir1": ["jsconfig.json", "tsconfig.json"], + }; const res = walkForTsConfig( join("/root", "dir1"), - (path) => path === pathToTsconfig + (path) => mockFiles[path] || [] ); - // assert.equal(res, pathToTsconfig); expect(res).toBe(pathToTsconfig); }); it("should find tsconfig in parent directory", () => { const pathToTsconfig = join("/root", "tsconfig.json"); + 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 mockFiles: Record = { + "/root": ["jsconfig.json"], + }; const res = walkForTsConfig( join("/root", "dir1"), - (path) => path === pathToTsconfig + (path) => mockFiles[path] || [] ); - // 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); + const res = walkForTsConfig(join("/root", "dir1", "kalle"), () => []); expect(res).toBeUndefined(); }); }); diff --git a/src/tsconfig-loader.ts b/src/tsconfig-loader.ts index 40a0744..93b6326 100644 --- a/src/tsconfig-loader.ts +++ b/src/tsconfig-loader.ts @@ -90,25 +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 { - const configPath = path.join(directory, "./tsconfig.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(