Skip to content

Commit ef3a42e

Browse files
committed
Convert compiler options before setting overrides
Resolves #3000
1 parent 708e77d commit ef3a42e

File tree

11 files changed

+69
-20
lines changed

11 files changed

+69
-20
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"Msys",
6767
"nodoc",
6868
"shiki",
69+
"srcset",
6970
"tsbuildinfo",
7071
"tsdoc",
7172
"typedoc",

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ title: Changelog
77
### Bug Fixes
88

99
- Fixed link resolution not working correctly in first comment on the file in some cases, #2994.
10+
- The `compilerOptions` option now functions properly with non-boolean options, #3000.
11+
- Configuration errors within the `compilerOptions` option are now handled gracefully, #3000.
1012

1113
## v0.28.10 (2025-08-10)
1214

src/lib/application.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ export class Application extends AbstractComponent<
496496
);
497497
}
498498

499-
if (Object.keys(this.options.getCompilerOptions()).length === 0) {
499+
if (Object.keys(this.options.getCompilerOptions(this.logger)).length === 0) {
500500
this.logger.warn(i18n.no_compiler_options_set());
501501
}
502502

@@ -525,7 +525,7 @@ export class Application extends AbstractComponent<
525525

526526
const host = ts.createWatchCompilerHost(
527527
tsconfigFile,
528-
this.options.fixCompilerOptions({}),
528+
this.options.fixCompilerOptions({}, this.logger),
529529
ts.sys,
530530
ts.createEmitAndSemanticDiagnosticsBuilderProgram,
531531
(d) => diagnostic(this.logger, d),

src/lib/internationalization/locales/en.cts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ export = {
242242

243243
options_file_0_does_not_exist: `The options file {0} does not exist`,
244244
failed_read_options_file_0: `Failed to parse {0}, ensure it exists and exports an object`,
245+
failed_to_apply_compilerOptions_overrides_0: "Failed to apply compilerOptions overrides: {0}",
245246

246247
// plugins
247248
invalid_plugin_0_missing_load_function: `Invalid structure in plugin {0}, no load function found`,

src/lib/utils/entry-point.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ export function getExpandedEntryPointsForPaths(
344344
options: Options,
345345
programs = getEntryPrograms(inputFiles, logger, options),
346346
): DocumentationEntryPoint[] {
347-
const compilerOptions = options.getCompilerOptions();
347+
const compilerOptions = options.getCompilerOptions(logger);
348348
const supportedFileRegex = compilerOptions.allowJs || compilerOptions.checkJs
349349
? /\.([cm][tj]s|[tj]sx?)$/
350350
: /\.([cm]ts|tsx?)$/;
@@ -410,16 +410,16 @@ function getEntryPrograms(
410410
const rootProgram = noTsConfigFound
411411
? ts.createProgram({
412412
rootNames: inputFiles,
413-
options: options.getCompilerOptions(),
413+
options: options.getCompilerOptions(logger),
414414
})
415415
: ts.createProgram({
416416
rootNames: options.getFileNames(),
417-
options: options.getCompilerOptions(),
417+
options: options.getCompilerOptions(logger),
418418
projectReferences: options.getProjectReferences(),
419419
});
420420

421421
addInferredDeclarationMapPaths(
422-
options.getCompilerOptions(),
422+
options.getCompilerOptions(logger),
423423
options.getFileNames(),
424424
);
425425

@@ -438,6 +438,7 @@ function getEntryPrograms(
438438
ts.createProgram({
439439
options: options.fixCompilerOptions(
440440
ref.commandLine.options,
441+
logger,
441442
),
442443
rootNames: ref.commandLine.fileNames,
443444
projectReferences: ref.commandLine.projectReferences,

src/lib/utils/options/options.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type ts from "typescript";
1+
import ts from "typescript";
22
import { resolve } from "path";
33
import { ParameterType } from "./declaration.js";
44
import type { OutputSpecification } from "../index.js";
@@ -361,19 +361,34 @@ export class Options {
361361
/**
362362
* Gets the set compiler options.
363363
*/
364-
getCompilerOptions(): ts.CompilerOptions {
365-
return this.fixCompilerOptions(this._compilerOptions);
364+
getCompilerOptions(logger: Logger): ts.CompilerOptions {
365+
return this.fixCompilerOptions(this._compilerOptions, logger);
366366
}
367367

368368
/** @internal */
369369
fixCompilerOptions(
370370
options: Readonly<ts.CompilerOptions>,
371+
logger: Logger,
371372
): ts.CompilerOptions {
372373
const overrides = this.getValue("compilerOptions");
373374
const result = { ...options };
374375

375376
if (overrides) {
376-
Object.assign(result, overrides);
377+
const tsOptions = ts.convertCompilerOptionsFromJson(overrides, ".", "typedoc-overrides.json");
378+
379+
if (tsOptions.errors.length) {
380+
for (const error of tsOptions.errors) {
381+
logger.error(
382+
i18n.failed_to_apply_compilerOptions_overrides_0(
383+
ts.flattenDiagnosticMessageText(error.messageText, "\n"),
384+
),
385+
);
386+
}
387+
} else {
388+
for (const key in overrides) {
389+
result[key] = tsOptions.options[key];
390+
}
391+
}
377392
}
378393

379394
if (this.getValue("emit") !== "both") {
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
---
2-
title: "Windows Line Endings"
3-
---
4-
5-
This file contains CRLF line endings
1+
---
2+
title: "Windows Line Endings"
3+
---
4+
5+
This file contains CRLF line endings

src/test/programs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export function getConverterProgram() {
9696
const app = getConverterApp();
9797
converterProgram = ts.createProgram(
9898
app.options.getFileNames(),
99-
app.options.getCompilerOptions(),
99+
app.options.getCompilerOptions(app.logger),
100100
);
101101

102102
const errors = ts.getPreEmitDiagnostics(converterProgram);
@@ -134,7 +134,7 @@ export function getConverter2Program() {
134134
const app = getConverter2App();
135135
converter2Program = ts.createProgram(
136136
app.options.getFileNames(),
137-
app.options.getCompilerOptions(),
137+
app.options.getCompilerOptions(app.logger),
138138
);
139139

140140
const errors = ts.getPreEmitDiagnostics(converter2Program);

src/test/slow/internationalization-usage.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ describe("Internationalization", () => {
99
it("Does not include strings in translatable object which are unused", () => {
1010
const options = new Options();
1111
const tsconfigReader = new TSConfigReader();
12-
tsconfigReader.read(options, new Logger(), process.cwd());
12+
const logger = new Logger();
13+
tsconfigReader.read(options, logger, process.cwd());
1314

1415
const defaultLocaleTs = join(
1516
fileURLToPath(import.meta.url),
@@ -26,7 +27,7 @@ describe("Internationalization", () => {
2627
);
2728
},
2829
getCurrentDirectory: () => process.cwd(),
29-
getCompilationSettings: () => options.getCompilerOptions(),
30+
getCompilationSettings: () => options.getCompilerOptions(logger),
3031
getDefaultLibFileName: (opts) => ts.getDefaultLibFilePath(opts),
3132
fileExists: ts.sys.fileExists,
3233
readFile: ts.sys.readFile,

src/test/utils/options/options.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { type MapDeclarationOption, type NumberDeclarationOption, Option } from
33
import { deepStrictEqual as equal, throws } from "assert";
44
import type { DeclarationOption, EmitStrategy } from "../../../lib/utils/options/index.js";
55
import { LogLevel } from "#utils";
6+
import { TestLogger } from "../../TestLogger.js";
7+
import ts from "typescript";
68

79
describe("Options", () => {
810
let options: Options & {
@@ -180,6 +182,32 @@ describe("Options", () => {
180182

181183
throws(() => options.reset("thisOptionDoesNotExist" as never));
182184
});
185+
186+
it("Handles tsconfig overrides which aren't strings, #3000", () => {
187+
const logger = new TestLogger();
188+
const options = new Options();
189+
190+
options.setValue("compilerOptions", {
191+
moduleResolution: "bundler",
192+
});
193+
194+
const compilerOptions = options.getCompilerOptions(logger);
195+
equal(compilerOptions.moduleResolution, ts.ModuleResolutionKind.Bundler);
196+
});
197+
198+
it("Handles tsconfig overrides which are invalid, #3000", () => {
199+
const logger = new TestLogger();
200+
const options = new Options();
201+
202+
options.setValue("compilerOptions", {
203+
moduleResolution: "bad",
204+
});
205+
206+
const compilerOptions = options.getCompilerOptions(logger);
207+
equal(compilerOptions.moduleResolution, undefined);
208+
209+
logger.expectMessage("error: Failed to apply compilerOptions overrides: *");
210+
});
183211
});
184212

185213
describe("Option", () => {

0 commit comments

Comments
 (0)