Skip to content

Commit

Permalink
feat: lookup project tsconfig
Browse files Browse the repository at this point in the history
This looks up the default tsconfig.json file for the current project when used from the CLI, to avoid possible compliation errors. Fixes #2062
  • Loading branch information
slhck committed Sep 9, 2024
1 parent 46f638e commit 4a1cbd2
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

```
Expand Down
22 changes: 22 additions & 0 deletions src/Utils/findTsConfig.ts
Original file line number Diff line number Diff line change
@@ -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);
}
53 changes: 53 additions & 0 deletions test/unit/findTsConfig.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
3 changes: 2 additions & 1 deletion ts-json-schema-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 4a1cbd2

Please sign in to comment.