Skip to content

Commit

Permalink
Finish implementation of expandable class heirarchy
Browse files Browse the repository at this point in the history
Resolves #2749
Resolves #2744
  • Loading branch information
Gerrit0 committed Nov 23, 2024
1 parent 5a6c9bf commit 7472d0b
Show file tree
Hide file tree
Showing 14 changed files with 378 additions and 624 deletions.
6 changes: 4 additions & 2 deletions src/lib/internationalization/locales/en.cts
Original file line number Diff line number Diff line change
Expand Up @@ -484,8 +484,6 @@ export = {
theme_hierarchy: "Hierarchy",
theme_hierarchy_summary: "Hierarchy Summary",
theme_hierarchy_view_summary: "View Summary",
theme_hierarchy_expand: "Expand",
theme_hierarchy_collapse: "Collapse",
theme_implemented_by: "Implemented by",
theme_defined_in: "Defined in",
theme_implementation_of: "Implementation of",
Expand Down Expand Up @@ -513,8 +511,12 @@ export = {
theme_permalink: "Permalink",

// Used by the frontend JS
// For the English translations only, these should also be added to
// src/lib/output/themes/default/assets/typedoc/Application.ts
theme_copy: "Copy",
theme_copied: "Copied!",
theme_normally_hidden:
"This member is normally hidden due to your filter settings.",
theme_hierarchy_expand: "Expand",
theme_hierarchy_collapse: "Collapse",
} as const;
3 changes: 3 additions & 0 deletions src/lib/output/plugins/AssetsPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export class AssetsPlugin extends RendererComponent {
copy: this.application.i18n.theme_copy(),
copied: this.application.i18n.theme_copied(),
normally_hidden: this.application.i18n.theme_normally_hidden(),
hierarchy_expand: this.application.i18n.theme_hierarchy_expand(),
hierarchy_collapse:
this.application.i18n.theme_hierarchy_collapse(),
};
}

Expand Down
136 changes: 69 additions & 67 deletions src/lib/output/plugins/HierarchyPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
import * as Path from "path";
import { RendererComponent } from "../components.js";
import { PageEvent, RendererEvent } from "../events.js";
import { JSX, writeFile } from "../../utils/index.js";
import { RendererEvent } from "../events.js";
import { writeFile } from "../../utils/index.js";
import { DefaultTheme } from "../themes/default/DefaultTheme.js";
import { gzip } from "zlib";
import { promisify } from "util";
import {
DeclarationReflection,
ReferenceType,
ReflectionKind,
} from "../../models/index.js";

import type { Renderer } from "../index.js";
import {
getHierarchyRoots,
getKindClass,
getUniquePath,
} from "../themes/lib.js";
import type { DeclarationReflection } from "../../models/index.js";

const gzipP = promisify(gzip);

export interface HierarchyElement {
html: string;
text: string;
path: string;
parents?: ({ path: string } | { html: string; text: string })[];
children?: ({ path: string } | { html: string; text: string })[];
interface JsonHierarchyElement {
name: string;
kind: number;
url: string;
children?: number[];
uniqueNameParents?: number[];
class: string;
}

interface JsonHierarchy {
// ids of root instances
roots: number[];
reflections: Record<number, JsonHierarchyElement>;
}

export class HierarchyPlugin extends RendererComponent {
Expand All @@ -39,60 +48,53 @@ export class HierarchyPlugin extends RendererComponent {
}

private async buildHierarchy(event: RendererEvent) {
const theme = this.owner.theme as DefaultTheme;

const context = theme.getRenderContext(new PageEvent(event.project));

const hierarchy = (
event.project.getReflectionsByKind(
ReflectionKind.ClassOrInterface,
) as DeclarationReflection[]
)
.filter(
(reflection) =>
reflection.extendedTypes?.length ||
reflection.extendedBy?.length,
)
.map((reflection) => ({
html: JSX.renderElement(
context.type(
ReferenceType.createResolvedReference(
reflection.name,
reflection,
reflection.project,
),
),
),
// Full name should be safe here, since this list only includes classes/interfaces.
text: reflection.getFullName(),
path: reflection.url!,
parents: reflection.extendedTypes?.map((type) =>
!(type instanceof ReferenceType) ||
!(type.reflection instanceof DeclarationReflection)
? {
html: JSX.renderElement(context.type(type)),
text: type.toString(),
}
: { path: type.reflection.url! },
),
children: reflection.extendedBy?.map((type) =>
!(type instanceof ReferenceType) ||
!(type.reflection instanceof DeclarationReflection)
? {
html: JSX.renderElement(context.type(type)),
text: type.toString(),
}
: { path: type.reflection.url! },
),
}));

if (!hierarchy.length) return;

hierarchy.forEach((element) => {
if (!element.parents?.length) delete element.parents;

if (!element.children?.length) delete element.children;
});
const project = event.project;

const hierarchy: JsonHierarchy = {
roots: getHierarchyRoots(project).map((refl) => refl.id),
reflections: {},
};

const queue = [...hierarchy.roots];

while (queue.length) {
const id = queue.pop()!;
const refl = project.getReflectionById(id) as DeclarationReflection;
if (id in hierarchy.reflections) continue;
if (!refl.url) continue;

const jsonRecord: JsonHierarchyElement = {
name: refl.name,
kind: refl.kind,
url: refl.url,
class: getKindClass(refl),
};

const path = getUniquePath(refl);
if (path.length > 1) {
jsonRecord.uniqueNameParents = path
.slice(0, -1)
.map((r) => r.id);
queue.push(...jsonRecord.uniqueNameParents);
}

const children = [
...(refl.implementedBy || []),
...(refl.extendedBy || []),
];

for (const child of children) {
if (child.reflection) {
jsonRecord.children ||= [];
jsonRecord.children.push(child.reflection.id);
}
}
if (jsonRecord.children) {
queue.push(...jsonRecord.children);
}

hierarchy.reflections[id] = jsonRecord;
}

const hierarchyJs = Path.join(
event.outputDirectory,
Expand Down
12 changes: 12 additions & 0 deletions src/lib/output/themes/default/assets/typedoc/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,22 @@ declare global {
copy: string;
copied: string;
normally_hidden: string;
hierarchy_expand: string;
hierarchy_collapse: string;
};
}
}

// For debugging with a watch build
window.translations ||= {
copy: "Copy",
copied: "Copied!",
normally_hidden:
"This member is normally hidden due to your filter settings.",
hierarchy_expand: "Expand",
hierarchy_collapse: "Collapse",
};

/**
* Component definition.
*/
Expand Down
Loading

0 comments on commit 7472d0b

Please sign in to comment.