| import { |
| loadTsconfig, |
| tsConfigLoader, |
| walkForTsConfig, |
| } from "../tsconfig-loader"; |
| import { join } from "path"; |
| |
| describe("tsconfig-loader", () => { |
| it("should find tsconfig in cwd", () => { |
| const result = tsConfigLoader({ |
| cwd: "/foo/bar", |
| getEnv: (_: string) => undefined, |
| loadSync: (cwd: string) => { |
| return { |
| tsConfigPath: `${cwd}/tsconfig.json`, |
| baseUrl: "./", |
| paths: {}, |
| }; |
| }, |
| }); |
| |
| // assert.equal(result.tsConfigPath, "/foo/bar/tsconfig.json"); |
| expect(result.tsConfigPath).toBe("/foo/bar/tsconfig.json"); |
| }); |
| |
| it("should return loaderResult.tsConfigPath as undefined when not found", () => { |
| const result = tsConfigLoader({ |
| cwd: "/foo/bar", |
| getEnv: (_: string) => undefined, |
| loadSync: (_: string) => { |
| return { |
| tsConfigPath: undefined, |
| baseUrl: "./", |
| paths: {}, |
| }; |
| }, |
| }); |
| |
| // assert.isUndefined(result.tsConfigPath); |
| expect(result.tsConfigPath).toBeUndefined(); |
| }); |
| |
| it("should use TS_NODE_PROJECT env if exists", () => { |
| const result = tsConfigLoader({ |
| cwd: "/foo/bar", |
| getEnv: (key: string) => |
| key === "TS_NODE_PROJECT" ? "/foo/baz" : undefined, |
| loadSync: (cwd: string, fileName: string) => { |
| if (cwd === "/foo/bar" && fileName === "/foo/baz") { |
| return { |
| tsConfigPath: "/foo/baz/tsconfig.json", |
| baseUrl: "./", |
| paths: {}, |
| }; |
| } |
| |
| return { |
| tsConfigPath: undefined, |
| baseUrl: "./", |
| paths: {}, |
| }; |
| }, |
| }); |
| |
| // assert.equal(result.tsConfigPath, "/foo/baz/tsconfig.json"); |
| expect(result.tsConfigPath).toBe("/foo/baz/tsconfig.json"); |
| }); |
| |
| it("should use TS_NODE_BASEURL env if exists", () => { |
| const result = tsConfigLoader({ |
| cwd: "/foo/bar", |
| getEnv: (key: string) => |
| key === "TS_NODE_BASEURL" ? "SOME_BASEURL" : undefined, |
| loadSync: (_0: string, _1: string, baseUrl: string) => { |
| return { |
| tsConfigPath: undefined, |
| baseUrl, |
| paths: {}, |
| }; |
| }, |
| }); |
| |
| // assert.equal(result.baseUrl, "SOME_BASEURL"); |
| expect(result.baseUrl).toBe("SOME_BASEURL"); |
| }); |
| |
| it("should not use TS_NODE_BASEURL env if it does not exist", () => { |
| const result = tsConfigLoader({ |
| cwd: "/foo/bar", |
| getEnv: (_: string) => { |
| return undefined; |
| }, |
| loadSync: (_0: string, _1: string, baseUrl: string) => { |
| return { |
| tsConfigPath: undefined, |
| baseUrl, |
| paths: {}, |
| }; |
| }, |
| }); |
| |
| // assert.equal(result.baseUrl, undefined); |
| expect(result.baseUrl).toBeUndefined(); |
| }); |
| }); |
| |
| 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); |
| 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); |
| expect(res).toBe(pathToTsconfig); |
| }); |
| |
| it("should return undefined when reaching the top", () => { |
| const res = walkForTsConfig(join("/root", "dir1", "kalle"), () => false); |
| // assert.equal(res, undefined); |
| expect(res).toBeUndefined(); |
| }); |
| }); |
| |
| describe("loadConfig", () => { |
| it("should load a config", () => { |
| const config = { compilerOptions: { baseUrl: "hej" } }; |
| const res = loadTsconfig( |
| "/root/dir1/tsconfig.json", |
| (path) => path === "/root/dir1/tsconfig.json", |
| (_) => JSON.stringify(config) |
| ); |
| // assert.deepEqual(res, config); |
| expect(res).toStrictEqual(config); |
| }); |
| |
| it("should load a config with comments", () => { |
| const config = { compilerOptions: { baseUrl: "hej" } }; |
| const res = loadTsconfig( |
| "/root/dir1/tsconfig.json", |
| (path) => path === "/root/dir1/tsconfig.json", |
| (_) => `{ |
| // my comment |
| "compilerOptions": { |
| "baseUrl": "hej" |
| } |
| }` |
| ); |
| // assert.deepEqual(res, config); |
| expect(res).toStrictEqual(config); |
| }); |
| |
| it("should load a config with trailing commas", () => { |
| const config = { compilerOptions: { baseUrl: "hej" } }; |
| const res = loadTsconfig( |
| "/root/dir1/tsconfig.json", |
| (path) => path === "/root/dir1/tsconfig.json", |
| (_) => `{ |
| "compilerOptions": { |
| "baseUrl": "hej", |
| }, |
| }` |
| ); |
| // assert.deepEqual(res, config); |
| expect(res).toStrictEqual(config); |
| }); |
| |
| it("should throw an error including the file path when encountering invalid JSON5", () => { |
| expect(() => |
| loadTsconfig( |
| "/root/dir1/tsconfig.json", |
| (path) => path === "/root/dir1/tsconfig.json", |
| (_) => `{ |
| "compilerOptions": { |
| }` |
| ) |
| ).toThrowError( |
| "/root/dir1/tsconfig.json is malformed JSON5: invalid end of input at 3:12" |
| ); |
| }); |
| |
| it("should load a config with string extends and overwrite all options", () => { |
| const firstConfig = { |
| extends: "../base-config.json", |
| compilerOptions: { baseUrl: "kalle", paths: { foo: ["bar2"] } }, |
| }; |
| const firstConfigPath = join("/root", "dir1", "tsconfig.json"); |
| const baseConfig = { |
| compilerOptions: { |
| baseUrl: "olle", |
| paths: { foo: ["bar1"] }, |
| strict: true, |
| }, |
| }; |
| const baseConfigPath = join("/root", "base-config.json"); |
| const res = loadTsconfig( |
| join("/root", "dir1", "tsconfig.json"), |
| (path) => path === firstConfigPath || path === baseConfigPath, |
| (path) => { |
| if (path === firstConfigPath) { |
| return JSON.stringify(firstConfig); |
| } |
| if (path === baseConfigPath) { |
| return JSON.stringify(baseConfig); |
| } |
| return ""; |
| } |
| ); |
| |
| // assert.deepEqual(res, { |
| // extends: "../base-config.json", |
| // compilerOptions: { |
| // baseUrl: "kalle", |
| // paths: { foo: ["bar2"] }, |
| // strict: true, |
| // }, |
| // }); |
| expect(res).toEqual({ |
| extends: "../base-config.json", |
| compilerOptions: { |
| baseUrl: "kalle", |
| paths: { foo: ["bar2"] }, |
| strict: true, |
| }, |
| }); |
| }); |
| |
| it("should load a config with string extends from node_modules and overwrite all options", () => { |
| const firstConfig = { |
| extends: "my-package/base-config.json", |
| compilerOptions: { baseUrl: "kalle", paths: { foo: ["bar2"] } }, |
| }; |
| const firstConfigPath = join("/root", "dir1", "tsconfig.json"); |
| const baseConfig = { |
| compilerOptions: { |
| baseUrl: "olle", |
| paths: { foo: ["bar1"] }, |
| strict: true, |
| }, |
| }; |
| const baseConfigPath = join( |
| "/root", |
| "dir1", |
| "node_modules", |
| "my-package", |
| "base-config.json" |
| ); |
| const res = loadTsconfig( |
| join("/root", "dir1", "tsconfig.json"), |
| (path) => path === firstConfigPath || path === baseConfigPath, |
| (path) => { |
| if (path === firstConfigPath) { |
| return JSON.stringify(firstConfig); |
| } |
| if (path === baseConfigPath) { |
| return JSON.stringify(baseConfig); |
| } |
| return ""; |
| } |
| ); |
| |
| // assert.deepEqual(res, { |
| // extends: "my-package/base-config.json", |
| // compilerOptions: { |
| // baseUrl: "kalle", |
| // paths: { foo: ["bar2"] }, |
| // strict: true, |
| // }, |
| // }); |
| expect(res).toEqual({ |
| extends: "my-package/base-config.json", |
| compilerOptions: { |
| baseUrl: "kalle", |
| paths: { foo: ["bar2"] }, |
| strict: true, |
| }, |
| }); |
| }); |
| |
| it("should use baseUrl relative to location of extended tsconfig", () => { |
| const firstConfig = { compilerOptions: { baseUrl: "." } }; |
| const firstConfigPath = join("/root", "first-config.json"); |
| const secondConfig = { extends: "../first-config.json" }; |
| const secondConfigPath = join("/root", "dir1", "second-config.json"); |
| const thirdConfig = { extends: "../second-config.json" }; |
| const thirdConfigPath = join("/root", "dir1", "dir2", "third-config.json"); |
| const res = loadTsconfig( |
| join("/root", "dir1", "dir2", "third-config.json"), |
| (path) => |
| path === firstConfigPath || |
| path === secondConfigPath || |
| path === thirdConfigPath, |
| (path) => { |
| if (path === firstConfigPath) { |
| return JSON.stringify(firstConfig); |
| } |
| if (path === secondConfigPath) { |
| return JSON.stringify(secondConfig); |
| } |
| if (path === thirdConfigPath) { |
| return JSON.stringify(thirdConfig); |
| } |
| return ""; |
| } |
| ); |
| |
| // assert.deepEqual(res, { |
| // extends: "../second-config.json", |
| // compilerOptions: { baseUrl: join("..", "..") }, |
| // }); |
| expect(res).toEqual({ |
| extends: "../second-config.json", |
| compilerOptions: { baseUrl: join("..", "..") }, |
| }); |
| }); |
| |
| it("should load a config with array extends and overwrite all options", () => { |
| const baseConfig1 = { |
| compilerOptions: { baseUrl: ".", paths: { foo: ["bar"] } }, |
| }; |
| const baseConfig1Path = join("/root", "base-config-1.json"); |
| const baseConfig2 = { compilerOptions: { baseUrl: "." } }; |
| const baseConfig2Path = join("/root", "dir1", "base-config-2.json"); |
| const baseConfig3 = { |
| compilerOptions: { baseUrl: ".", paths: { foo: ["bar2"] } }, |
| }; |
| const baseConfig3Path = join("/root", "dir1", "dir2", "base-config-3.json"); |
| const actualConfig = { |
| extends: [ |
| "./base-config-1.json", |
| "./dir1/base-config-2.json", |
| "./dir1/dir2/base-config-3.json", |
| ], |
| }; |
| const actualConfigPath = join("/root", "tsconfig.json"); |
| |
| const res = loadTsconfig( |
| join("/root", "tsconfig.json"), |
| (path) => |
| [ |
| baseConfig1Path, |
| baseConfig2Path, |
| baseConfig3Path, |
| actualConfigPath, |
| ].indexOf(path) >= 0, |
| (path) => { |
| if (path === baseConfig1Path) { |
| return JSON.stringify(baseConfig1); |
| } |
| if (path === baseConfig2Path) { |
| return JSON.stringify(baseConfig2); |
| } |
| if (path === baseConfig3Path) { |
| return JSON.stringify(baseConfig3); |
| } |
| if (path === actualConfigPath) { |
| return JSON.stringify(actualConfig); |
| } |
| return ""; |
| } |
| ); |
| |
| expect(res).toEqual({ |
| extends: [ |
| "./base-config-1.json", |
| "./dir1/base-config-2.json", |
| "./dir1/dir2/base-config-3.json", |
| ], |
| compilerOptions: { |
| baseUrl: join("dir1", "dir2"), |
| paths: { foo: ["bar2"] }, |
| }, |
| }); |
| }); |
| |
| it("should load a config with array extends without .json extension", () => { |
| const baseConfig = { |
| compilerOptions: { baseUrl: ".", paths: { foo: ["bar"] } }, |
| }; |
| const baseConfigPath = join("/root", "base-config-1.json"); |
| const actualConfig = { extends: ["./base-config-1"] }; |
| const actualConfigPath = join("/root", "tsconfig.json"); |
| |
| const res = loadTsconfig( |
| join("/root", "tsconfig.json"), |
| (path) => [baseConfigPath, actualConfigPath].indexOf(path) >= 0, |
| (path) => { |
| if (path === baseConfigPath) { |
| return JSON.stringify(baseConfig); |
| } |
| if (path === actualConfigPath) { |
| return JSON.stringify(actualConfig); |
| } |
| return ""; |
| } |
| ); |
| |
| expect(res).toEqual({ |
| extends: ["./base-config-1"], |
| compilerOptions: { |
| baseUrl: ".", |
| paths: { foo: ["bar"] }, |
| }, |
| }); |
| }); |
| }); |