Skip to content

Commit 2ce3796

Browse files
committed
Add hierarchy.html page to docs
Resolves #182
1 parent 0117c99 commit 2ce3796

File tree

6 files changed

+124
-9
lines changed

6 files changed

+124
-9
lines changed

CHANGELOG.md

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

33
## Features
44

5+
- Added a new hierarchy.html page to HTML output which displays the full inheritance hierarchy for classes included in the documentation, #182.
56
- Added a `--navigation.includeFolders` (default: `true`) option to create nested navigation for projects which include many entry points, #2388.
67
- Type parameters on functions/classes can will now link to the "Type Parameters" section, #2322.
78
Type parameters have also been changed to have a distinct color from type aliases when rendering, which can be changed with custom CSS.

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ export class DefaultTheme extends Theme {
6666
indexTemplate = (pageEvent: PageEvent<ProjectReflection>) => {
6767
return this.getRenderContext(pageEvent).indexTemplate(pageEvent);
6868
};
69+
hierarchyTemplate = (pageEvent: PageEvent<ProjectReflection>) => {
70+
return this.getRenderContext(pageEvent).hierarchyTemplate(pageEvent);
71+
};
6972
defaultLayoutTemplate = (pageEvent: PageEvent<Reflection>, template: RenderTemplate<PageEvent<Reflection>>) => {
7073
return this.getRenderContext(pageEvent).defaultLayout(template, pageEvent);
7174
};
@@ -148,10 +151,14 @@ export class DefaultTheme extends Theme {
148151
urls.push(new UrlMapping("index.html", project, this.indexTemplate));
149152
} else {
150153
project.url = "modules.html";
151-
urls.push(new UrlMapping<ContainerReflection>("modules.html", project, this.reflectionTemplate));
154+
urls.push(new UrlMapping("modules.html", project, this.reflectionTemplate));
152155
urls.push(new UrlMapping("index.html", project, this.indexTemplate));
153156
}
154157

158+
if (includeHierarchyPage(project)) {
159+
urls.push(new UrlMapping("hierarchy.html", project, this.hierarchyTemplate));
160+
}
161+
155162
project.children?.forEach((child: Reflection) => {
156163
if (child instanceof DeclarationReflection) {
157164
this.buildUrls(child, urls);
@@ -458,3 +465,17 @@ function shouldShowGroups(reflection: Reflection, opts: { includeCategories: boo
458465
}
459466
return reflection.comment?.hasModifier("@showGroups") === true;
460467
}
468+
469+
function includeHierarchyPage(project: ProjectReflection) {
470+
for (const id in project.reflections) {
471+
const refl = project.reflections[id] as DeclarationReflection;
472+
473+
if (refl.kindOf(ReflectionKind.ClassOrInterface)) {
474+
// Keep this condition in sync with the one in hierarchy.tsx for determining roots
475+
if (!(refl.implementedTypes || refl.extendedTypes) && (refl.implementedBy || refl.extendedBy)) {
476+
return true;
477+
}
478+
}
479+
}
480+
return false;
481+
}

src/lib/output/themes/default/DefaultThemeRenderContext.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import { type } from "./partials/type";
4545
import { typeAndParent } from "./partials/typeAndParent";
4646
import { typeParameters } from "./partials/typeParameters";
4747
import { indexTemplate } from "./templates";
48+
import { hierarchyTemplate } from "./templates/hierarchy";
4849
import { reflectionTemplate } from "./templates/reflection";
4950

5051
function bind<F, L extends any[], R>(fn: (f: F, ...a: L) => R, first: F) {
@@ -116,6 +117,7 @@ export class DefaultThemeRenderContext {
116117

117118
reflectionTemplate = bind(reflectionTemplate, this);
118119
indexTemplate = bind(indexTemplate, this);
120+
hierarchyTemplate = bind(hierarchyTemplate, this);
119121
defaultLayout = bind(defaultLayout, this);
120122

121123
/**

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

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,39 @@
11
import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext";
22
import { JSX } from "../../../../utils";
3-
import type { DeclarationHierarchy } from "../../../../models";
3+
import type { DeclarationHierarchy, Type } from "../../../../models";
4+
5+
const isLinkedReferenceType = (type: Type) =>
6+
type.visit({
7+
reference: (ref) => ref.reflection !== undefined,
8+
}) ?? false;
9+
10+
function hasAnyLinkedReferenceType(h: DeclarationHierarchy | undefined): boolean {
11+
if (!h) return false;
12+
13+
if (!h.isTarget && h.types.some(isLinkedReferenceType)) return true;
14+
15+
return hasAnyLinkedReferenceType(h.next);
16+
}
417

518
export function hierarchy(context: DefaultThemeRenderContext, props: DeclarationHierarchy | undefined) {
619
if (!props) return;
720

21+
const fullLink = hasAnyLinkedReferenceType(props) ? (
22+
<>
23+
{" "}
24+
(
25+
<a class="link" href={context.relativeURL("hierarchy.html") + "#" + context.page.model.getFullName()}>
26+
view full
27+
</a>
28+
)
29+
</>
30+
) : (
31+
<></>
32+
);
33+
834
return (
935
<section class="tsd-panel tsd-hierarchy">
10-
<h4>Hierarchy</h4>
36+
<h4>Hierarchy{fullLink}</h4>
1137
{hierarchyList(context, props)}
1238
</section>
1339
);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext";
2+
import type { PageEvent } from "../../../events";
3+
import { JSX } from "../../../../utils";
4+
import { ReflectionKind, type ProjectReflection, DeclarationReflection } from "../../../../models";
5+
6+
function fullHierarchy(context: DefaultThemeRenderContext, root: DeclarationReflection) {
7+
// Note: We don't use root.anchor for the anchor, because those are built on a per page basis.
8+
// And classes/interfaces get their own page, so all the anchors will be empty anyways.
9+
// Full name should be safe here, since this list only includes classes/interfaces.
10+
return (
11+
<li>
12+
<a id={root.getFullName()} class="tsd-anchor"></a>
13+
<a href={context.urlTo(root)}>
14+
{context.icons[root.kind]()}
15+
{root.name}
16+
</a>
17+
<ul>
18+
{root.implementedBy?.map((child) => {
19+
return child.reflection && fullHierarchy(context, child.reflection as DeclarationReflection);
20+
})}
21+
{root.extendedBy?.map((child) => {
22+
return child.reflection && fullHierarchy(context, child.reflection as DeclarationReflection);
23+
})}
24+
</ul>
25+
</li>
26+
);
27+
}
28+
29+
export function hierarchyTemplate(context: DefaultThemeRenderContext, props: PageEvent<ProjectReflection>) {
30+
// Keep this condition in sync with the one in DefaultTheme.tsx
31+
const roots = (props.project.getReflectionsByKind(ReflectionKind.ClassOrInterface) as DeclarationReflection[])
32+
.filter((refl) => !(refl.implementedTypes || refl.extendedTypes) && (refl.implementedBy || refl.extendedBy))
33+
.sort((a, b) => a.name.localeCompare(b.name));
34+
35+
return (
36+
<>
37+
<h2>Class Hierarchy</h2>
38+
{roots.map((root) => (
39+
<ul class="tsd-full-hierarchy">{fullHierarchy(context, root)}</ul>
40+
))}
41+
</>
42+
);
43+
}

static/style.css

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -266,12 +266,12 @@ h6 {
266266
line-height: 1.2;
267267
}
268268

269-
h1 > a,
270-
h2 > a,
271-
h3 > a,
272-
h4 > a,
273-
h5 > a,
274-
h6 > a {
269+
h1 > a:not(.link),
270+
h2 > a:not(.link),
271+
h3 > a:not(.link),
272+
h4 > a:not(.link),
273+
h5 > a:not(.link),
274+
h6 > a:not(.link) {
275275
text-decoration: none;
276276
color: var(--color-text);
277277
}
@@ -649,6 +649,28 @@ input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark {
649649
font-weight: bold;
650650
}
651651

652+
.tsd-full-hierarchy:not(:last-child) {
653+
margin-bottom: 1em;
654+
padding-bottom: 1em;
655+
border-bottom: 1px solid var(--color-accent);
656+
}
657+
.tsd-full-hierarchy,
658+
.tsd-full-hierarchy ul {
659+
list-style: none;
660+
margin: 0;
661+
padding: 0;
662+
}
663+
.tsd-full-hierarchy ul {
664+
padding-left: 1.5rem;
665+
}
666+
.tsd-full-hierarchy a {
667+
padding: 0.25rem 0 !important;
668+
font-size: 1rem;
669+
display: inline-flex;
670+
align-items: center;
671+
color: var(--color-text);
672+
}
673+
652674
.tsd-panel-group.tsd-index-group {
653675
margin-bottom: 0;
654676
}

0 commit comments

Comments
 (0)