diff --git a/CHANGELOG.md b/CHANGELOG.md
index 454023f25..6b3334ad1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
- Added `Application.EVENT_VALIDATE_PROJECT` event for plugins which implement custom validation, #2183.
- Plugins may now return an object from external symbol resolvers, #2066.
+- Expose `Comment.displayPartsToMarkdown` on for themes overwriting the `comment` helper, #2115.
### Bug Fixes
diff --git a/src/lib/models/comments/comment.ts b/src/lib/models/comments/comment.ts
index 37079324c..c39e2f8e4 100644
--- a/src/lib/models/comments/comment.ts
+++ b/src/lib/models/comments/comment.ts
@@ -121,6 +121,65 @@ export class Comment {
return result;
}
+ /**
+ * Helper function to convert an array of comment display parts into markdown suitable for
+ * passing into Marked. `urlTo` will be used to resolve urls to any reflections linked to with
+ * `@link` tags.
+ */
+ static displayPartsToMarkdown(
+ parts: readonly CommentDisplayPart[],
+ urlTo: (ref: Reflection) => string
+ ) {
+ const result: string[] = [];
+
+ for (const part of parts) {
+ switch (part.kind) {
+ case "text":
+ case "code":
+ result.push(part.text);
+ break;
+ case "inline-tag":
+ switch (part.tag) {
+ case "@label":
+ case "@inheritdoc": // Shouldn't happen
+ break; // Not rendered.
+ case "@link":
+ case "@linkcode":
+ case "@linkplain": {
+ if (part.target) {
+ const url =
+ typeof part.target === "string"
+ ? part.target
+ : urlTo(part.target);
+ const text =
+ part.tag === "@linkcode"
+ ? `${part.text}
`
+ : part.text;
+ result.push(
+ url
+ ? `${text}`
+ : part.text
+ );
+ } else {
+ result.push(part.text);
+ }
+ break;
+ }
+ default:
+ // Hmm... probably want to be able to render these somehow, so custom inline tags can be given
+ // special rendering rules. Future capability. For now, just render their text.
+ result.push(`{${part.tag} ${part.text}}`);
+ break;
+ }
+ break;
+ default:
+ assertNever(part);
+ }
+ }
+
+ return result.join("");
+ }
+
/**
* Helper utility to clone {@link Comment.summary} or {@link CommentTag.content}
*/
diff --git a/src/lib/output/themes/default/DefaultThemeRenderContext.ts b/src/lib/output/themes/default/DefaultThemeRenderContext.ts
index 6c72ccee5..208255a92 100644
--- a/src/lib/output/themes/default/DefaultThemeRenderContext.ts
+++ b/src/lib/output/themes/default/DefaultThemeRenderContext.ts
@@ -1,11 +1,11 @@
import type { RendererHooks } from "../..";
-import type {
+import {
+ Comment,
CommentDisplayPart,
ReferenceType,
Reflection,
} from "../../../models";
import type { NeverIfInternal, Options } from "../../../utils";
-import { displayPartsToMarkdown } from "../lib";
import type { DefaultTheme } from "./DefaultTheme";
import { defaultLayout } from "./layouts/default";
import { index } from "./partials";
@@ -62,14 +62,14 @@ export class DefaultThemeRenderContext {
return url ? this.theme.markedPlugin.getRelativeUrl(url) : url;
};
- urlTo = (reflection: Reflection) => this.relativeURL(reflection.url);
+ urlTo = (reflection: Reflection) => this.relativeURL(reflection.url)!;
markdown = (
md: readonly CommentDisplayPart[] | NeverIfInternal
) => {
if (md instanceof Array) {
return this.theme.markedPlugin.parseMarkdown(
- displayPartsToMarkdown(md, this.urlTo)
+ Comment.displayPartsToMarkdown(md, this.urlTo)
);
}
return md ? this.theme.markedPlugin.parseMarkdown(md) : "";
diff --git a/src/lib/output/themes/lib.tsx b/src/lib/output/themes/lib.tsx
index 3b01121fb..e38397be9 100644
--- a/src/lib/output/themes/lib.tsx
+++ b/src/lib/output/themes/lib.tsx
@@ -1,14 +1,12 @@
import {
Comment,
- CommentDisplayPart,
DeclarationReflection,
Reflection,
ReflectionFlags,
SignatureReflection,
TypeParameterReflection,
} from "../../models";
-import { assertNever, JSX } from "../../utils";
-import type { DefaultThemeRenderContext } from "./default/DefaultThemeRenderContext";
+import { JSX } from "../../utils";
export function stringify(data: unknown) {
if (typeof data === "bigint") {
@@ -117,50 +115,6 @@ export function camelToTitleCase(text: string) {
return text.substring(0, 1).toUpperCase() + text.substring(1).replace(/[a-z][A-Z]/g, (x) => `${x[0]} ${x[1]}`);
}
-export function displayPartsToMarkdown(
- parts: readonly CommentDisplayPart[],
- urlTo: DefaultThemeRenderContext["urlTo"]
-) {
- const result: string[] = [];
-
- for (const part of parts) {
- switch (part.kind) {
- case "text":
- case "code":
- result.push(part.text);
- break;
- case "inline-tag":
- switch (part.tag) {
- case "@label":
- case "@inheritdoc": // Shouldn't happen
- break; // Not rendered.
- case "@link":
- case "@linkcode":
- case "@linkplain": {
- if (part.target) {
- const url = typeof part.target === "string" ? part.target : urlTo(part.target);
- const text = part.tag === "@linkcode" ? `${part.text}
` : part.text;
- result.push(url ? `${text}` : part.text);
- } else {
- result.push(part.text);
- }
- break;
- }
- default:
- // Hmm... probably want to be able to render these somehow, so custom inline tags can be given
- // special rendering rules. Future capability. For now, just render their text.
- result.push(`{${part.tag} ${part.text}}`);
- break;
- }
- break;
- default:
- assertNever(part);
- }
- }
-
- return result.join("");
-}
-
/**
* Renders the reflection name with an additional `?` if optional.
*/