diff --git a/README.md b/README.md index bb7191de8..267019dc2 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ Note that different platforms (e.g. Windows) may use different path separators s Also note that you need to quote paths with `*` as otherwise the shell will expand the paths and therefore only pass the first path to the generator. +By default, the command-line generator will use the `tsconfig.json` file in the current working directory, or the first parent directory that contains a `tsconfig.json` file up to the root of the filesystem. If you want to use a different `tsconfig.json` file, you can use the `--tsconfig` option. In particular, if you need to use different compilation options for types, you may want to create a separate `tsconfig.json` file for the schema generation only. + ### Options ``` diff --git a/src/Utils/findTsConfig.ts b/src/Utils/findTsConfig.ts new file mode 100644 index 000000000..a241475c5 --- /dev/null +++ b/src/Utils/findTsConfig.ts @@ -0,0 +1,22 @@ +import fs from "fs"; +import path from "path"; + +/** + * Find the tsconfig.json file in the current working directory or any parent directory. + * This is the behavior from tsc: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html + * + * @param directory - The directory to start searching from. Defaults to the current working directory. + * @param filename - The filename of the tsconfig.json file. Defaults to "tsconfig.json". + * @returns The path to the tsconfig.json file or undefined if no such file was found. + */ +export function findTsConfig(directory: string = process.cwd(), filename = "tsconfig.json"): string | undefined { + const tsConfigPath = path.join(directory, filename); + if (fs.existsSync(tsConfigPath)) { + return tsConfigPath; + } + const parentDir = path.dirname(directory); + if (parentDir === directory) { + return undefined; + } + return findTsConfig(parentDir, filename); +} diff --git a/test/unit/findTsConfig.test.ts b/test/unit/findTsConfig.test.ts new file mode 100644 index 000000000..ec137bb77 --- /dev/null +++ b/test/unit/findTsConfig.test.ts @@ -0,0 +1,53 @@ +import path from "path"; +import fs from "fs"; +import { findTsConfig } from "../../src/Utils/findTsConfig.js"; + +jest.mock("fs"); + +describe("findTsConfig", () => { + const mockCwd = "/mock/project"; + const mockTsConfigPath = path.join(mockCwd, "tsconfig.json"); + + beforeEach(() => { + jest.resetAllMocks(); + jest.spyOn(process, "cwd").mockReturnValue(mockCwd); + }); + + afterAll(() => { + jest.restoreAllMocks(); + }); + + it("returns the path to the tsconfig.json file when it exists", () => { + (fs.existsSync as jest.Mock).mockReturnValue(true); + const foundTsConfig = findTsConfig(); + expect(foundTsConfig).toBe(mockTsConfigPath); + }); + + it("returns undefined when tsconfig.json is not found in any parent directory", () => { + (fs.existsSync as jest.Mock).mockReturnValue(false); + const foundTsConfig = findTsConfig(); + expect(foundTsConfig).toBeUndefined(); + }); + + it("searches in parent directories until tsconfig.json is found", () => { + (fs.existsSync as jest.Mock).mockReturnValueOnce(false).mockReturnValueOnce(false).mockReturnValueOnce(true); + + const expectedPath = path.join(path.dirname(path.dirname(mockCwd)), "tsconfig.json"); + const foundTsConfig = findTsConfig(); + expect(foundTsConfig).toBe(expectedPath); + }); + + it("returns undefined when reaching the root directory without finding tsconfig.json", () => { + (fs.existsSync as jest.Mock).mockReturnValue(false); + const foundTsConfig = findTsConfig("/"); + expect(foundTsConfig).toBeUndefined(); + }); + + it("uses the provided filename when searching for the config file", () => { + (fs.existsSync as jest.Mock).mockReturnValue(true); + const customFilename = "custom-tsconfig.json"; + const expectedPath = path.join(mockCwd, customFilename); + const foundTsConfig = findTsConfig(undefined, customFilename); + expect(foundTsConfig).toBe(expectedPath); + }); +}); diff --git a/ts-json-schema-generator.ts b/ts-json-schema-generator.ts index 953929041..7f8fb425e 100644 --- a/ts-json-schema-generator.ts +++ b/ts-json-schema-generator.ts @@ -5,6 +5,7 @@ import stableStringify from "safe-stable-stringify"; import { createGenerator } from "./factory/generator.js"; import type { Config } from "./src/Config.js"; import { BaseError } from "./src/Error/BaseError.js"; +import { findTsConfig } from "./src/Utils/findTsConfig.js"; import pkg from "./package.json"; @@ -56,7 +57,7 @@ const args = new Command() const config: Config = { minify: args.minify, path: args.path, - tsconfig: args.tsconfig, + tsconfig: args.tsconfig ?? findTsConfig(), type: args.type, schemaId: args.id, expose: args.expose,