Skip to content

Commit e8ad7fe

Browse files
committed
Improve validation for packageOptions
Ref: #2878
1 parent 55aaa36 commit e8ad7fe

File tree

6 files changed

+119
-3
lines changed

6 files changed

+119
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ title: Changelog
4141
- Introduced `packagesRequiringDocumentation` option for `validation.notDocumented`, TypeDoc will expect comments to be present for symbols in the specified packages.
4242
- TypeDoc now exports a `typedoc/browser` entrypoint for parsing and using serialized JSON files, #2528.
4343
- Type `packageOptions` as `Partial<TypeDocOptions>`, #2878.
44+
- TypeDoc will now warn if an option which should only be set at the root level is set in `packageOptions`, #2878.
4445

4546
### Bug Fixes
4647

src/lib/application.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
} from "./utils/index.js";
1818

1919
import { Option, Options } from "./utils/index.js";
20-
import type { TypeDocOptions } from "./utils/options/declaration.js";
20+
import { rootPackageOptions, type TypeDocOptions } from "./utils/options/declaration.js";
2121
import { type GlobString, i18n, Logger, LogLevel, type TranslatedString, unique } from "#utils";
2222
import { ok } from "assert";
2323
import {
@@ -776,6 +776,16 @@ export class Application extends AbstractComponent<
776776
const origOptions = this.options;
777777
const projects: JSONOutput.ProjectReflection[] = [];
778778

779+
for (const opt of Object.keys(this.options.getValue("packageOptions"))) {
780+
if (rootPackageOptions.includes(opt as never)) {
781+
this.logger.warn(
782+
i18n.package_option_0_should_be_specified_at_root(
783+
opt,
784+
),
785+
);
786+
}
787+
}
788+
779789
const projectsToConvert: { dir: string; options: Options }[] = [];
780790
// Generate a json file for each package
781791
for (const dir of packageDirs) {

src/lib/internationalization/locales/en.cts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export = {
2626
"Failed to find any packages, ensure you have provided at least one directory as an entry point containing package.json",
2727
nested_packages_unsupported_0:
2828
"Project at {0} has entryPointStrategy set to packages, but nested packages are not supported",
29+
package_option_0_should_be_specified_at_root:
30+
"The packageOptions option sets option {0}, which only has an affect at the root level",
2931
previous_error_occurred_when_reading_options_for_0:
3032
"The previous error occurred when reading options for the package at {0}",
3133
converting_project_at_0: "Converting project at {0}",

src/lib/utils/options/declaration.ts

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,77 @@ export type OutputSpecification = {
4242
options?: Partial<TypeDocOptions>;
4343
};
4444

45+
/**
46+
* List of option names which, with `entryPointStrategy` set to `packages`
47+
* should only be set at the root level.
48+
*/
49+
export const rootPackageOptions = [
50+
// Configuration Options
51+
"plugin",
52+
// Input Options
53+
"packageOptions",
54+
"includeHierarchySummary", // GERRIT: Move to output options
55+
// Output Options
56+
"outputs",
57+
"out",
58+
"html",
59+
"json",
60+
"pretty",
61+
// emit
62+
"theme",
63+
"router",
64+
"lightHighlightTheme",
65+
"darkHighlightTheme",
66+
"highlightLanguages",
67+
"ignoredHighlightLanguages",
68+
"typePrintWidth",
69+
"customCss",
70+
"customJs",
71+
"customFooterHtml",
72+
"customFooterHtmlDisableWrapper",
73+
"markdownItOptions",
74+
"markdownItLoader",
75+
// basePath
76+
"cname",
77+
"favicon",
78+
"sourceLinkExternal",
79+
"markdownLinkExternal",
80+
"lang",
81+
"locales",
82+
"githubPages",
83+
"cacheBust",
84+
"hideGenerator",
85+
"searchInComments",
86+
"searchInDocuments",
87+
"cleanOutputDir",
88+
"titleLink",
89+
"navigationLinks",
90+
"sidebarLinks",
91+
"navigation",
92+
"headings",
93+
"sluggerConfiguration",
94+
"navigationLeaves",
95+
"visibilityFilters",
96+
"searchCategoryBoosts",
97+
"searchGroupBoosts",
98+
"hostedBaseUrl",
99+
"useHostedBaseUrlForAbsoluteLinks",
100+
"useFirstParagraphOfCommentAsSummary",
101+
// Comment Options
102+
"notRenderedTags",
103+
// Organization Options
104+
// Validation Options
105+
"treatWarningsAsErrors",
106+
"treatValidationWarningsAsErrors",
107+
// Other Options
108+
"watch",
109+
"preserveWatchOutput",
110+
"help",
111+
"version",
112+
"showConfig",
113+
"logLevel",
114+
] as const satisfies ReadonlyArray<keyof TypeDocOptionMap>;
115+
45116
/**
46117
* An interface describing all TypeDoc specific options. Generated from a
47118
* map which contains more information about each option for better types when
@@ -86,6 +157,13 @@ export type TypeDocOptionValues = {
86157
TypeDocOptionMap[K][keyof TypeDocOptionMap[K]];
87158
};
88159

160+
/**
161+
* Describes TypeDoc options suitable for setting within the `packageOptions` setting.
162+
*
163+
* This is a subset of all options specified in {@link TypeDocOptions}.
164+
*/
165+
export interface TypeDocPackageOptions extends Omit<TypeDocOptions, typeof rootPackageOptions[number]> {}
166+
89167
/**
90168
* Describes all TypeDoc options. Used internally to provide better types when fetching options.
91169
* External consumers should likely use {@link TypeDocOptions} instead.
@@ -109,7 +187,9 @@ export interface TypeDocOptionMap {
109187
plugin: NormalizedPathOrModule[];
110188
lang: string;
111189
locales: ManuallyValidatedOption<Record<string, Record<string, string>>>;
112-
packageOptions: ManuallyValidatedOption<Partial<TypeDocOptions>>;
190+
packageOptions: ManuallyValidatedOption<
191+
Partial<TypeDocPackageOptions>
192+
>;
113193

114194
// Input
115195
entryPoints: GlobString[];

src/lib/utils/options/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export type {
2424
TypeDocOptionMap,
2525
TypeDocOptions,
2626
TypeDocOptionValues,
27+
TypeDocPackageOptions,
2728
ValidationOptions,
2829
} from "./declaration.js";
2930

src/test/utils/options/default-options.test.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { deepStrictEqual as equal, doesNotThrow, ok, throws } from "assert";
22
import { Options, TYPEDOC_ROOT } from "../../../lib/utils/index.js";
33
import { readFileSync } from "fs";
4+
import { rootPackageOptions } from "../../../lib/utils/options/declaration.js";
45

56
describe("Default Options", () => {
67
const opts = new Options();
@@ -143,7 +144,7 @@ describe("Default Options", () => {
143144
"utf-8",
144145
).split("\n")
145146
) {
146-
const match = line.match(/\[`(.*)`\]\(/);
147+
const match = line.match(/\[`(.*?)`\]\(/);
147148
if (match) {
148149
linkedOptions.push(match[1]);
149150
}
@@ -158,6 +159,27 @@ describe("Default Options", () => {
158159
);
159160
});
160161

162+
it("Root package option documentation matches", () => {
163+
const rootOptions: string[] = [];
164+
for (
165+
const line of readFileSync(
166+
`${TYPEDOC_ROOT}/site/options/package-options.md`,
167+
"utf-8",
168+
).split("\n")
169+
) {
170+
const match = line.match(/\[`(.*?)`\]\(.*?\)\s*\| Root/);
171+
if (match) {
172+
rootOptions.push(match[1]);
173+
}
174+
}
175+
176+
equal(
177+
rootOptions,
178+
rootPackageOptions,
179+
"Documented root options to not match internal list of root options",
180+
);
181+
});
182+
161183
it("Option documentation", () => {
162184
const allOptions = opts
163185
.getDeclarations()

0 commit comments

Comments
 (0)