diff --git a/CHANGELOG.md b/CHANGELOG.md index 6829e8e0c..8fd5799b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ### Bug Fixes - Type parameters will now be resolved for arrow-methods on classes like regular class methods, #2320. +- TypeDoc now inherits `typedocOptions` fields from extended tsconfig files, #2334. - Methods which return function types no longer have duplicated comments, #2336. - Comments on function-like type aliases will now show up under the type alias, rather than nested within the type declaration, #2372. - Fix crash when converting some complicated union/intersection types, #2451. diff --git a/src/lib/utils/options/readers/tsconfig.ts b/src/lib/utils/options/readers/tsconfig.ts index e6df93df8..a3e19a036 100644 --- a/src/lib/utils/options/readers/tsconfig.ts +++ b/src/lib/utils/options/readers/tsconfig.ts @@ -21,7 +21,11 @@ import { tsdocModifierTags, } from "../tsdoc-defaults"; import { unique } from "../../array"; -import { findTsConfigFile, readTsConfig } from "../../tsconfig"; +import { + findTsConfigFile, + getTypeDocOptionsFromTsConfig, + readTsConfig, +} from "../../tsconfig"; function isSupportForTags(obj: unknown): obj is Record<`@${string}`, boolean> { return ( @@ -95,8 +99,11 @@ export class TSConfigReader implements OptionsReader { } logger.diagnostics(parsed.errors); + if (parsed.errors.length) { + return; + } - const typedocOptions = parsed.raw?.typedocOptions ?? {}; + const typedocOptions = getTypeDocOptionsFromTsConfig(fileToRead); if (typedocOptions.options) { logger.error( [ diff --git a/src/lib/utils/tsconfig.ts b/src/lib/utils/tsconfig.ts index 915176e67..f25bd41bf 100644 --- a/src/lib/utils/tsconfig.ts +++ b/src/lib/utils/tsconfig.ts @@ -1,6 +1,7 @@ import ts from "typescript"; -import { isFile, isDir } from "./fs"; +import { isFile, isDir, readFile } from "./fs"; import type { Logger } from "./loggers"; +import { createRequire } from "module"; export function findTsConfigFile(path: string): string | undefined { let fileToRead: string | undefined = path; @@ -15,6 +16,45 @@ export function findTsConfigFile(path: string): string | undefined { return fileToRead; } +// We don't need recursive read checks because that would cause a diagnostic +// when reading the tsconfig for compiler options, which happens first, and we bail before +// doing this in that case. +export function getTypeDocOptionsFromTsConfig(file: string): any { + const readResult = ts.readConfigFile(file, readFile); + + const result = {}; + + if (readResult.error) { + return result; + } + + if ("extends" in readResult.config) { + const resolver = createRequire(file); + const extended = Array.isArray(readResult.config.extends) + ? readResult.config.extends.map(String) + : [String(readResult.config.extends)]; + + for (const extendedFile of extended) { + let resolvedParent: string; + try { + resolvedParent = resolver.resolve(extendedFile); + } catch { + continue; + } + Object.assign( + result, + getTypeDocOptionsFromTsConfig(resolvedParent), + ); + } + } + + if ("typedocOptions" in readResult.config) { + Object.assign(result, readResult.config.typedocOptions); + } + + return result; +} + const tsConfigCache: Record = {}; export function readTsConfig( diff --git a/src/test/converter2/tsconfig.json b/src/test/converter2/tsconfig.json index 61e0d66ca..1ba818c62 100644 --- a/src/test/converter2/tsconfig.json +++ b/src/test/converter2/tsconfig.json @@ -8,7 +8,6 @@ "noImplicitAny": false, - // See #1524. We might force this to false eventually. "skipLibCheck": true }, "typedocOptions": { diff --git a/src/test/utils/options/readers/tsconfig.test.ts b/src/test/utils/options/readers/tsconfig.test.ts index b3747853d..71e0c61bb 100644 --- a/src/test/utils/options/readers/tsconfig.test.ts +++ b/src/test/utils/options/readers/tsconfig.test.ts @@ -91,6 +91,24 @@ describe("Options - TSConfigReader", () => { equal(logger.hasErrors(), false); }); + it("Reads typedocOptions from extended tsconfig files", async () => { + const project = tempdirProject(); + project.addFile("file.ts", "export const abc = 123"); + project.addJsonFile("tsconfig.json", { + extends: ["./base.tsconfig.json"], + files: ["./file.ts"], + typedocOptions: { plugin: ["a"] }, + }); + project.addJsonFile("base.tsconfig.json", { + typedocOptions: { name: "a", plugin: ["b"] }, + }); + + await readWithProject(project); + logger.expectNoOtherMessages(); + equal(options.getValue("name"), "a"); + equal(options.getValue("plugin"), ["a"]); + }); + async function readTsconfig(tsconfig: object) { const project = tempdirProject(); project.addFile("file.ts", "export const abc = 123");