Skip to content

Commit e577bfc

Browse files
committed
Improve support for none sections
Resolves #2922
1 parent a4b022e commit e577bfc

31 files changed

+1818
-107
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ title: Changelog
44

55
## Unreleased
66

7+
### Features
8+
9+
- `@group none` and `@category none` will now render their children without a section
10+
heading in the default theme, #2922.
11+
- Added `@disableGroups` tag to completely disable the grouping mechanism for a
12+
given reflection, #2922.
13+
714
### Bug Fixes
815

916
- Variables using `@class` now correctly handle `@category`, #2914.

scripts/capture_screenshots.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import puppeteer from "puppeteer";
77

88
const viewport = { width: 1024, height: 768 };
99

10-
class PQueue {
10+
export class PQueue {
1111
/** @private @type {Array<() => Promise<void>>} */
1212
_queued = [];
1313
/** @param {number} concurrency */

scripts/clone_api_users.js

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#!/usr/bin/env node
2+
// @ts-check
3+
// Purpose: Download repos known to use TypeDoc's APIs for custom plugins/themes
4+
// which are NOT published to NPM. This is used to check potentially-breaking
5+
// changes which are likely not actually breaking anyone, so could be included
6+
// in a patch release with little risk.
7+
8+
import cp from "node:child_process";
9+
import fs from "node:fs/promises";
10+
import { PQueue } from "./capture_screenshots.mjs";
11+
import { ALL_API_USERS, API_USERS, OLD_API_USERS } from "./data/api_users.js";
12+
import { parseArgs } from "node:util";
13+
import { existsSync, readFileSync } from "node:fs";
14+
import semver from "semver";
15+
16+
if (import.meta.url.endsWith(process.argv[1])) {
17+
const args = parseArgs({
18+
options: {
19+
jobs: {
20+
short: "j",
21+
type: "string",
22+
default: "6",
23+
},
24+
rebuild: {
25+
type: "boolean",
26+
default: false,
27+
},
28+
all: {
29+
type: "boolean",
30+
default: false,
31+
},
32+
output: {
33+
short: "o",
34+
type: "string",
35+
default: "../typedoc_api_users",
36+
},
37+
},
38+
});
39+
40+
const rebuild = args.values.rebuild;
41+
const outDir = args.values.output;
42+
const jobs = parseInt(args.values.jobs) || 1;
43+
44+
/**
45+
* @param {string[]} args
46+
* @returns {Promise<void>}
47+
*/
48+
const git = (...args) =>
49+
new Promise((resolve, reject) => {
50+
const child = cp.spawn("git", args, { cwd: outDir, stdio: "inherit" });
51+
child.on("close", () => {
52+
if (child.exitCode) reject(new Error(`When executing git ${args.join(" ")}`));
53+
resolve();
54+
});
55+
});
56+
57+
const start = Date.now();
58+
59+
if (rebuild) {
60+
await fs.rm(outDir, { recursive: true, force: true });
61+
}
62+
await fs.mkdir(outDir, { recursive: true });
63+
64+
const q = new PQueue(jobs);
65+
66+
for (const { repo, branch, pkg = "package.json", filter } of args.values.all ? ALL_API_USERS : API_USERS) {
67+
q.add(async () => {
68+
const repoDir = `${repo.replace("/", "_")}`;
69+
if (!existsSync(`${outDir}/${repoDir}`)) {
70+
await git(
71+
"clone",
72+
"--quiet",
73+
"--filter=blob:none",
74+
"--no-checkout",
75+
"--depth=1",
76+
`git@github.com:${repo}.git`,
77+
repoDir,
78+
);
79+
}
80+
81+
await git("-C", repoDir, "fetch", "--quiet", "--depth=1", "origin", branch);
82+
83+
const filterArg = Array.isArray(filter) ? filter : [filter];
84+
await git("-C", repoDir, "checkout", "--quiet", branch, "--", pkg, ...filterArg);
85+
});
86+
}
87+
88+
try {
89+
await q.run();
90+
} catch (error) {
91+
console.error(error);
92+
process.exit(1);
93+
}
94+
95+
console.log(`Cloning/updating took ${(Date.now() - start) / 1000} seconds`);
96+
97+
// Check for repos listed in the wrong list
98+
const currentMinor = semver.parse(JSON.parse(readFileSync("package.json", "utf-8")).version)?.minor;
99+
console.log("Current minor is", currentMinor);
100+
101+
for (const { repo, pkg = "package.json" } of API_USERS) {
102+
const repoDir = `${repo.replace("/", "_")}`;
103+
const manifest = JSON.parse(readFileSync(`${outDir}/${repoDir}/${pkg}`, "utf-8"));
104+
const depVersion = manifest.devDependencies?.typedoc || manifest.dependencies?.typedoc ||
105+
"(missing dependency)";
106+
const depMinor = semver.parse(depVersion.replace(/^[\^<=~]+/, ""))?.minor;
107+
108+
if (depMinor !== currentMinor) {
109+
console.log(`API->OLD ${repo} ${depVersion}`);
110+
}
111+
}
112+
113+
if (args.values.all) {
114+
for (const { repo, pkg = "package.json" } of OLD_API_USERS) {
115+
const repoDir = `${repo.replace("/", "_")}`;
116+
const manifest = JSON.parse(readFileSync(`${outDir}/${repoDir}/${pkg}`, "utf-8"));
117+
const depVersion = manifest.devDependencies?.typedoc || manifest.dependencies?.typedoc;
118+
if (!depVersion) {
119+
console.log(`OLD->DEL ${repo} (missing dependency)`);
120+
continue;
121+
}
122+
123+
const depMinor = semver.parse(depVersion.replace(/^[\^<=~]+/, ""))?.minor;
124+
125+
if (depMinor === currentMinor) {
126+
console.log(`OLD->API ${repo} ${depVersion}`);
127+
} else if (depMinor !== (currentMinor || 0) - 1) {
128+
console.log(`OLD->DEL ${repo} ${depVersion}`);
129+
}
130+
}
131+
}
132+
}

scripts/data/api_users.js

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// @ts-check
2+
3+
// A list of projects on GitHub which are not published TypeDoc plugins which are
4+
// known to use TypeDoc's JS API. Feel free to add your repo here! This list is
5+
// occasionally used to review known users for potentially breaking changes to
6+
// better gauge impact.
7+
8+
/**
9+
* @typedef {object} ApiUser
10+
* @property {string} repo the GitHub repository to check out
11+
* @property {string} branch the branch to check out
12+
* @property {string[] | string} filter files/directories containing TypeDoc API usage
13+
* @property {string} [pkg] location of package.json containing TypeDoc dependency if not at the repo root
14+
*/
15+
16+
// cspell:disable
17+
18+
/** @type {ApiUser[]} */
19+
export const API_USERS = [
20+
{
21+
repo: "playcanvas/engine",
22+
branch: "main",
23+
filter: "utils/typedoc/typedoc-plugin.mjs",
24+
},
25+
{
26+
repo: "clerk/javascript",
27+
branch: "main",
28+
filter: ".typedoc",
29+
},
30+
];
31+
32+
// Users are moved to this list periodically when they are a minor version behind
33+
// and might be dropped off the list of repos checked for breaking changes eventually
34+
/** @type {ApiUser[]} */
35+
export const OLD_API_USERS = [
36+
{
37+
repo: "Fevol/obsidian-typings",
38+
branch: "main",
39+
pkg: "docs/package.json",
40+
filter: "docs/typedoc-plugins/alter-frontmatter-plugin.js",
41+
},
42+
{
43+
repo: "akaday/probot",
44+
branch: "fb37787c230d4599ff11644e5a3ee7a2120ea5e8",
45+
filter: ".typedoc/typedoc_ga.mjs",
46+
},
47+
{
48+
repo: "cbunt/react-distortion",
49+
branch: "main",
50+
filter: ".config/typedoc-minimal-theme.js",
51+
},
52+
{
53+
repo: "gohypergiant/standard-toolkit",
54+
branch: "main",
55+
pkg: "apps/docs/package.json",
56+
filter: "apps/docs/lib/",
57+
},
58+
{
59+
repo: "vltpkg/vltpkg",
60+
branch: "main",
61+
pkg: "www/docs/package.json",
62+
filter: "www/docs/typedoc",
63+
},
64+
{
65+
repo: "pixiv/three-vrm",
66+
branch: "dev",
67+
filter: "typedoc-redirect-legacy-docs-plugin.mjs",
68+
},
69+
];
70+
71+
export const ALL_API_USERS = [...API_USERS, ...OLD_API_USERS];

scripts/download_plugins.cjs

100644100755
+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#!/usr/bin/env node
12
// @ts-check
23
// Helper script to download recently updated plugins
34
// Used to review code changes for breaking changes.
@@ -95,7 +96,7 @@ async function main(args) {
9596
);
9697
console.log(`Inflating...`);
9798
await Promise.all(tarballFiles.map(inflate));
98-
console.log(`Done.`);
99+
console.log(`Done, plugins are in ../typedoc_plugins`);
99100
}
100101

101102
main(process.argv.slice(2)).catch(console.error);

site/options/organization.md

+16-4
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,15 @@ Defaults to 'Other'
4242
}
4343
```
4444

45-
Array option which allows overriding the order categories display in. A string of `*` indicates where categories that are not in the list should appear.
45+
Array option which allows overriding the order categories display in. A string
46+
of `*` indicates where categories that are not in the list should appear.
4647

47-
Categories whose order is not specified will be sorted alphabetically. If `*` is not specified and unknown categories are found, they will be listed at the end by default.
48+
Categories whose order is not specified will be sorted alphabetically. If `*` is
49+
not specified and unknown categories are found, they will be listed at the end
50+
by default.
51+
52+
A category called `none` (case-insensitive) is reserved and treated specially by
53+
the default theme to be displayed without a category before other categories.
4854

4955
## groupOrder
5056

@@ -55,9 +61,15 @@ Categories whose order is not specified will be sorted alphabetically. If `*` is
5561
}
5662
```
5763

58-
Array option which allows overriding the order groups display in. A string of `*` indicates where groups that are not in the list should appear.
64+
Array option which allows overriding the order groups display in. A string of
65+
`*` indicates where groups that are not in the list should appear.
66+
67+
Groups whose order is not specified will be sorted alphabetically. If `*` is not
68+
specified and unknown groups are found, they will be listed at the end by
69+
default.
5970

60-
Groups whose order is not specified will be sorted alphabetically. If `*` is not specified and unknown groups are found, they will be listed at the end by default.
71+
A group called `none` (case-insensitive) is reserved and treated specially by
72+
the default theme to be displayed without a group heading before list of groups.
6173

6274
## sort
6375

site/tags.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ examples for how to use the export ([`@example`](./tags/example.md)).
115115
- [`@document`](./tags/document.md)
116116
- [`@example`](./tags/example.md)
117117
- [`@expandType`](./tags/expand.md#expandtype)
118-
- [`@group`, `@groupDescription`, `@showGroups`, `@hideGroups`](./tags/group.md)
118+
- [`@group`, `@groupDescription`, `@showGroups`, `@hideGroups`, `@disableGroups`](./tags/group.md)
119119
- [`@import`](./tags/import.md)
120120
- [`@inlineType`](./tags/inline.md#inlinetype)
121121
- [`@license`](./tags/license.md)

site/tags/group.md

+33-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
title: "@group"
33
---
44

5-
# @group
5+
# Group Tags
6+
7+
The `@group`, `@groupDescription`, `@showGroups`, `@hideGroups`, and
8+
`@disableGroups` tags can be used to control how TypeDoc organizes children of a
9+
documentation item.
10+
11+
## @group
612

713
**Tag Kind:** [Block](../tags.md#block-tags)
814

@@ -14,7 +20,7 @@ Unlike the [`@category`](category.md) tag, reflections will be automatically
1420
placed under a header according to their kind if the `@group` tag is not
1521
specified. This tag can be used to simulate custom member types.
1622

17-
## Example
23+
### Example
1824

1925
```ts
2026
/**
@@ -42,7 +48,7 @@ export class App extends EventEmitter {
4248
}
4349
```
4450

45-
## Group Descriptions
51+
## @groupDescription
4652

4753
The `@groupDescription` block tag can be used to provide additional context
4854
about a group of reflections. TypeDoc automatically groups reflections according
@@ -60,7 +66,30 @@ following lines will be used for the description.
6066
Groups can be added to the navigation tree with the `navigation.includeGroups`
6167
option. This can be selectively enabled or disabled by specifying the
6268
`@showGroups` and `@hideGroups` modifier tags within the comment on the parent
63-
reflection.
69+
reflection. These tags have no effect within the page contents.
70+
71+
## @disableGroups
72+
73+
The `@disableGroups` tag can be used to selectively disable TypeDoc's grouping
74+
mechanism on a per-parent basis. This is recommended only for documentation
75+
sites which contain a small number of members.
76+
77+
Note: A corresponding `@disableCategories` tag does not exist as categories are
78+
only created if explicitly requested by including `@category` on at least one
79+
child of the parent.
80+
81+
```ts
82+
/**
83+
* This is a very small module where separating members into groups by type
84+
* doesn't make sense.
85+
* @module
86+
* @disableGroups
87+
*/
88+
89+
export const variable = 123;
90+
91+
export function fn() {}
92+
```
6493

6594
## See Also
6695

src/lib/application.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export interface ApplicationEvents {
9999
* Access to an Application instance can be retrieved with {@link Application.bootstrap} or
100100
* {@link Application.bootstrapWithPlugins}. It can not be constructed manually.
101101
*
102-
* @group Common
102+
* @group None
103103
* @summary Root level class which contains most useful behavior.
104104
*/
105105
export class Application extends AbstractComponent<
@@ -243,7 +243,7 @@ export class Application extends AbstractComponent<
243243
* @example
244244
* Initialize the application with pretty-printing output disabled.
245245
* ```ts
246-
* const app = Application.bootstrap({ pretty: false });
246+
* const app = await Application.bootstrap({ pretty: false });
247247
* ```
248248
*
249249
* @param options Options to set during initialization

src/lib/converter/converter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export interface ConverterEvents {
9292
/**
9393
* Compiles source files using TypeScript and converts compiler symbols to reflections.
9494
*
95-
* @group Common
95+
* @group None
9696
* @summary Responsible for converting TypeScript symbols into {@link Reflection}s and {@link Type}s.
9797
*/
9898
export class Converter extends AbstractComponent<Application, ConverterEvents> {

src/lib/converter/plugins/CategoryPlugin.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export class CategoryPlugin extends ConverterComponent {
100100
}
101101

102102
private categorize(obj: ContainerReflection) {
103-
if (this.categorizeByGroup) {
103+
if (this.categorizeByGroup && obj.groups) {
104104
this.groupCategorize(obj);
105105
} else {
106106
this.lumpCategorize(obj);

src/lib/converter/plugins/GroupPlugin.ts

+3
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ export class GroupPlugin extends ConverterComponent {
130130
this.sortFunction(reflection.childrenIncludingDocuments);
131131
}
132132

133+
if (reflection.comment?.hasModifier("@disableGroups")) {
134+
return;
135+
}
133136
reflection.groups = this.getReflectionGroups(
134137
reflection,
135138
reflection.childrenIncludingDocuments,

0 commit comments

Comments
 (0)