Skip to content

Commit d26f553

Browse files
committed
Use renderElement for html generation in marked plugin
1 parent b8faaf7 commit d26f553

File tree

1 file changed

+38
-65
lines changed

1 file changed

+38
-65
lines changed

src/lib/output/themes/MarkedPlugin.ts renamed to src/lib/output/themes/MarkedPlugin.tsx

Lines changed: 38 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as Marked from "marked";
44

55
import { Component, ContextAwareRendererComponent } from "../components";
66
import { RendererEvent, MarkdownEvent, PageEvent } from "../events";
7-
import { Option, readFile, copySync, isFile } from "../../utils";
7+
import { Option, readFile, copySync, isFile, JSX, renderElement } from "../../utils";
88
import { highlight, isSupportedLanguage } from "../../utils/highlighter";
99
import type { Theme } from "shiki";
1010
import { escapeHtml, getTextContent } from "../../utils/html";
@@ -95,39 +95,27 @@ output file :
9595
path = Path.join(this.includes!, path.trim());
9696
if (isFile(path)) {
9797
const contents = readFile(path);
98-
const event = new MarkdownEvent(
99-
MarkdownEvent.INCLUDE,
100-
page,
101-
contents,
102-
contents,
103-
);
98+
const event = new MarkdownEvent(MarkdownEvent.INCLUDE, page, contents, contents);
10499
this.owner.trigger(event);
105100
return event.parsedText;
106101
} else {
107-
this.application.logger.warn(
108-
"Could not find file to include: " + path,
109-
);
102+
this.application.logger.warn("Could not find file to include: " + path);
110103
return "";
111104
}
112105
});
113106
}
114107

115108
if (this.mediaDirectory) {
116-
text = text.replace(
117-
this.mediaPattern,
118-
(match: string, path: string) => {
119-
const fileName = Path.join(this.mediaDirectory!, path);
120-
121-
if (isFile(fileName)) {
122-
return this.getRelativeUrl("media") + "/" + path;
123-
} else {
124-
this.application.logger.warn(
125-
"Could not find media file: " + fileName,
126-
);
127-
return match;
128-
}
129-
},
130-
);
109+
text = text.replace(this.mediaPattern, (match: string, path: string) => {
110+
const fileName = Path.join(this.mediaDirectory!, path);
111+
112+
if (isFile(fileName)) {
113+
return this.getRelativeUrl("media") + "/" + path;
114+
} else {
115+
this.application.logger.warn("Could not find media file: " + fileName);
116+
return match;
117+
}
118+
});
131119
}
132120

133121
const event = new MarkdownEvent(MarkdownEvent.PARSE, page, text, text);
@@ -148,32 +136,20 @@ output file :
148136

149137
delete this.includes;
150138
if (this.includeSource) {
151-
if (
152-
fs.existsSync(this.includeSource) &&
153-
fs.statSync(this.includeSource).isDirectory()
154-
) {
139+
if (fs.existsSync(this.includeSource) && fs.statSync(this.includeSource).isDirectory()) {
155140
this.includes = this.includeSource;
156141
} else {
157-
this.application.logger.warn(
158-
"Could not find provided includes directory: " +
159-
this.includeSource,
160-
);
142+
this.application.logger.warn("Could not find provided includes directory: " + this.includeSource);
161143
}
162144
}
163145

164146
if (this.mediaSource) {
165-
if (
166-
fs.existsSync(this.mediaSource) &&
167-
fs.statSync(this.mediaSource).isDirectory()
168-
) {
147+
if (fs.existsSync(this.mediaSource) && fs.statSync(this.mediaSource).isDirectory()) {
169148
this.mediaDirectory = Path.join(event.outputDirectory, "media");
170149
copySync(this.mediaSource, this.mediaDirectory);
171150
} else {
172151
this.mediaDirectory = undefined;
173-
this.application.logger.warn(
174-
"Could not find provided media directory: " +
175-
this.mediaSource,
176-
);
152+
this.application.logger.warn("Could not find provided media directory: " + this.mediaSource);
177153
}
178154
}
179155
}
@@ -184,28 +160,22 @@ output file :
184160
* @returns The options object for the markdown parser.
185161
*/
186162
private createMarkedOptions(): Marked.marked.MarkedOptions {
187-
const markedOptions = (this.application.options.getValue(
188-
"markedOptions",
189-
) ?? {}) as Marked.marked.MarkedOptions;
163+
const markedOptions = (this.application.options.getValue("markedOptions") ?? {}) as Marked.marked.MarkedOptions;
190164

191165
// Set some default values if they are not specified via the TypeDoc option
192-
markedOptions.highlight ??= (text, lang) =>
193-
this.getHighlighted(text, lang);
166+
markedOptions.highlight ??= (text, lang) => this.getHighlighted(text, lang);
194167

195168
if (!markedOptions.renderer) {
196169
markedOptions.renderer = new Marked.Renderer();
197170

198171
markedOptions.renderer.link = (href, title, text) => {
199172
// Prefix the #anchor links `#md:`.
200-
href =
201-
href
202-
?.replace(/^#(?:md:)?(.+)/, "#md:$1")
203-
.replace(/"/g, """) || "";
204-
let html = `<a href="${href}"`;
205-
if (title != null)
206-
html += ` title="${title.replace(/"/g, "&quot;")}"`;
207-
html += `>${text}</a>`;
208-
return html;
173+
const target = href?.replace(/^#(?:md:)?(.+)/, "#md:$1") || undefined;
174+
return renderElement(
175+
<a href={target} title={title || undefined}>
176+
<JSX.Raw html={text} />
177+
</a>,
178+
);
209179
};
210180

211181
markedOptions.renderer.heading = (text, level, _, slugger) => {
@@ -216,7 +186,17 @@ output file :
216186
text: getTextContent(text),
217187
level,
218188
});
219-
return `<a id="md:${slug}" class="tsd-anchor"></a><h${level}><a href="#md:${slug}">${text}</a></h${level}>`;
189+
const H = `h${level}`;
190+
return renderElement(
191+
<>
192+
<a id={`md:${slug}`} class="tsd-anchor" />
193+
<H>
194+
<a href={`#md:${slug}`}>
195+
<JSX.Raw html={text} />
196+
</a>
197+
</H>
198+
</>,
199+
);
220200
};
221201
markedOptions.renderer.code = renderCode;
222202
}
@@ -238,12 +218,7 @@ output file :
238218

239219
// Basically a copy/paste of Marked's code, with the addition of the button
240220
// https://github.com/markedjs/marked/blob/v4.3.0/src/Renderer.js#L15-L39
241-
function renderCode(
242-
this: Marked.marked.Renderer,
243-
code: string,
244-
infostring: string | undefined,
245-
escaped: boolean,
246-
) {
221+
function renderCode(this: Marked.marked.Renderer, code: string, infostring: string | undefined, escaped: boolean) {
247222
const lang = (infostring || "").match(/\S*/)![0];
248223
if (this.options.highlight) {
249224
const out = this.options.highlight(code, lang);
@@ -256,9 +231,7 @@ function renderCode(
256231
code = code.replace(/\n$/, "") + "\n";
257232

258233
if (!lang) {
259-
return `<pre><code>${
260-
escaped ? code : escapeHtml(code)
261-
}</code><button>Copy</button></pre>\n`;
234+
return `<pre><code>${escaped ? code : escapeHtml(code)}</code><button>Copy</button></pre>\n`;
262235
}
263236

264237
return `<pre><code class="${this.options.langPrefix + escapeHtml(lang)}">${

0 commit comments

Comments
 (0)