Skip to content

Commit 0117c99

Browse files
committed
Add --navigation.includeFolders
Closes #2388
1 parent 65c83a9 commit 0117c99

File tree

5 files changed

+85
-18
lines changed

5 files changed

+85
-18
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Features
44

5+
- Added a `--navigation.includeFolders` (default: `true`) option to create nested navigation for projects which include many entry points, #2388.
56
- Type parameters on functions/classes can will now link to the "Type Parameters" section, #2322.
67
Type parameters have also been changed to have a distinct color from type aliases when rendering, which can be changed with custom CSS.
78
- TypeDoc now provides warnings if a signature comment is directly specified on a signature and contains `@param` tags which do not apply, #2368.
@@ -29,6 +30,8 @@
2930
- `@group` and `@category` organization is now applied later to allow inherited comments to create groups/categories, #2459.
3031
- Conversion order should no longer affect link resolution for classes with properties whose type does not rely on `this`, #2466.
3132
- Keyword syntax highlighting introduced in 0.25.4 was not always applied to keywords.
33+
- Module reflections now have a custom `M` icon rather than sharing with the namespace icon.
34+
Note: The default CSS still colors both modules and namespaces the same, as it is generally uncommon to have both in a generated site.
3235
- If all members in a group are hidden from the page, the group will be hidden in the page index on page load.
3336

3437
## v0.25.4 (2023-11-26)

src/lib/output/themes/default/DefaultTheme.tsx

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -305,27 +305,70 @@ export class DefaultTheme extends Theme {
305305
return parent.groups.map(toNavigation);
306306
}
307307

308+
if (
309+
opts.includeFolders &&
310+
parent.children?.every((child) => child.kindOf(ReflectionKind.Module)) &&
311+
parent.children.some((child) => child.name.includes("/"))
312+
) {
313+
return deriveModuleFolders(parent.children);
314+
}
315+
308316
return parent.children?.map(toNavigation);
309317
}
310318

311-
function shouldShowCategories(
312-
reflection: Reflection,
313-
opts: { includeCategories: boolean; includeGroups: boolean },
314-
) {
315-
if (opts.includeCategories) {
316-
return !reflection.comment?.hasModifier("@hideCategories");
319+
function deriveModuleFolders(children: DeclarationReflection[]) {
320+
const result: NavigationElement[] = [];
321+
322+
const resolveOrCreateParents = (
323+
path: string[],
324+
root: NavigationElement[] = result,
325+
): NavigationElement[] => {
326+
if (path.length > 1) {
327+
const inner = root.find((el) => el.text === path[0]);
328+
if (inner) {
329+
inner.children ||= [];
330+
return resolveOrCreateParents(path.slice(1), inner.children);
331+
} else {
332+
root.push({
333+
text: path[0],
334+
children: [],
335+
});
336+
return resolveOrCreateParents(path.slice(1), root[root.length - 1].children);
337+
}
338+
}
339+
340+
return root;
341+
};
342+
343+
// Note: This might end up putting a module within another module if we document
344+
// both foo/index.ts and foo/bar.ts.
345+
for (const child of children) {
346+
const parts = child.name.split("/");
347+
const collection = resolveOrCreateParents(parts);
348+
const nav = toNavigation(child);
349+
nav.text = parts[parts.length - 1];
350+
collection.push(nav);
317351
}
318-
return reflection.comment?.hasModifier("@showCategories") === true;
319-
}
320352

321-
function shouldShowGroups(
322-
reflection: Reflection,
323-
opts: { includeCategories: boolean; includeGroups: boolean },
324-
) {
325-
if (opts.includeGroups) {
326-
return !reflection.comment?.hasModifier("@hideGroups");
353+
// Now merge single-possible-paths together so we don't have folders in our navigation
354+
// which contain only another single folder.
355+
const queue = [...result];
356+
while (queue.length) {
357+
const review = queue.shift()!;
358+
queue.push(...(review.children || []));
359+
if (review.kind || review.path) continue;
360+
361+
if (review.children?.length === 1) {
362+
const copyFrom = review.children[0];
363+
const fullName = `${review.text}/${copyFrom.text}`;
364+
delete review.children;
365+
Object.assign(review, copyFrom);
366+
review.text = fullName;
367+
queue.push(review);
368+
}
327369
}
328-
return reflection.comment?.hasModifier("@showGroups") === true;
370+
371+
return result;
329372
}
330373
}
331374

@@ -401,3 +444,17 @@ function getReflectionClasses(reflection: DeclarationReflection, filters: Record
401444

402445
return classes.join(" ");
403446
}
447+
448+
function shouldShowCategories(reflection: Reflection, opts: { includeCategories: boolean; includeGroups: boolean }) {
449+
if (opts.includeCategories) {
450+
return !reflection.comment?.hasModifier("@hideCategories");
451+
}
452+
return reflection.comment?.hasModifier("@showCategories") === true;
453+
}
454+
455+
function shouldShowGroups(reflection: Reflection, opts: { includeCategories: boolean; includeGroups: boolean }) {
456+
if (opts.includeGroups) {
457+
return !reflection.comment?.hasModifier("@hideGroups");
458+
}
459+
return reflection.comment?.hasModifier("@showGroups") === true;
460+
}

src/lib/output/themes/default/partials/icon.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,14 @@ export const icons: Record<
123123
true,
124124
),
125125
[ReflectionKind.Module]() {
126-
return this[ReflectionKind.Namespace]();
126+
return kindIcon(
127+
<path
128+
d="M9.162 16V7.24H10.578L11.514 10.072C11.602 10.328 11.674 10.584 11.73 10.84C11.794 11.088 11.842 11.28 11.874 11.416C11.906 11.28 11.954 11.088 12.018 10.84C12.082 10.584 12.154 10.324 12.234 10.06L13.122 7.24H14.538V16H13.482V12.82C13.482 12.468 13.49 12.068 13.506 11.62C13.53 11.172 13.558 10.716 13.59 10.252C13.622 9.78 13.654 9.332 13.686 8.908C13.726 8.476 13.762 8.1 13.794 7.78L12.366 12.16H11.334L9.894 7.78C9.934 8.092 9.97 8.456 10.002 8.872C10.042 9.28 10.078 9.716 10.11 10.18C10.142 10.636 10.166 11.092 10.182 11.548C10.206 12.004 10.218 12.428 10.218 12.82V16H9.162Z"
129+
fill="var(--color-text)"
130+
/>,
131+
"var(--color-ts-module)",
132+
);
127133
},
128-
129134
[ReflectionKind.Namespace]: () =>
130135
kindIcon(
131136
<path
@@ -138,7 +143,7 @@ export const icons: Record<
138143
return this[ReflectionKind.Property]();
139144
},
140145
[ReflectionKind.Project]() {
141-
return this[ReflectionKind.Namespace]();
146+
return this[ReflectionKind.Module]();
142147
},
143148
[ReflectionKind.Property]: () =>
144149
kindIcon(

src/lib/utils/options/declaration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export interface TypeDocOptionMap {
144144
navigation: {
145145
includeCategories: boolean;
146146
includeGroups: boolean;
147+
includeFolders: boolean;
147148
fullTree: boolean;
148149
};
149150
visibilityFilters: ManuallyValidatedOption<{

src/lib/utils/options/sources/typedoc.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,7 @@ export function addTypeDocOptions(options: Pick<Options, "addDeclaration">) {
464464
defaults: {
465465
includeCategories: false,
466466
includeGroups: false,
467+
includeFolders: true,
467468
fullTree: false,
468469
},
469470
});

0 commit comments

Comments
 (0)