Skip to content

Commit 039f536

Browse files
committed
Fix issue with double decoding HTML when outputting Markdown
1 parent 3f6e91a commit 039f536

File tree

3 files changed

+77
-31
lines changed

3 files changed

+77
-31
lines changed

src/Importer.js

+36-21
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,39 @@ class Importer {
255255
}
256256
}
257257

258+
async getTransformedContent(entry, isWritingToMarkdown) {
259+
let content = entry.content;
260+
261+
if(Importer.isHtml(entry)) {
262+
let transformedHtml = content;
263+
if(!isWritingToMarkdown) {
264+
// decoding built-in with Markdown
265+
transformedHtml = entities.decodeHTML(content);
266+
}
267+
268+
if(!this.shouldDownloadAssets()) {
269+
content = transformedHtml;
270+
} else {
271+
content = await this.htmlTransformer.transform(transformedHtml, entry);
272+
}
273+
}
274+
275+
if(isWritingToMarkdown) {
276+
if(Importer.isText(entry)) {
277+
// _only_ decode newlines
278+
content = content.split("
").join("\n");
279+
}
280+
281+
if(Importer.shouldConvertToMarkdown(entry)) {
282+
await this.markdownService.asyncInit();
283+
284+
content = await this.markdownService.toMarkdown(content, entry);
285+
}
286+
}
287+
288+
return content;
289+
}
290+
258291
async getEntries(options = {}) {
259292
let isWritingToMarkdown = options.contentType === "markdown";
260293

@@ -279,28 +312,10 @@ class Importer {
279312
let promises = await Promise.allSettled(entries.map(async entry => {
280313
await this.fetchRelatedMedia(entry);
281314

282-
if(Importer.isHtml(entry)) {
283-
let decodedHtml = entities.decodeHTML(entry.content);
284-
if(!this.shouldDownloadAssets()) {
285-
entry.content = decodedHtml;
286-
} else {
287-
entry.content = await this.htmlTransformer.transform(decodedHtml, entry);
288-
}
289-
}
290-
291-
if(isWritingToMarkdown) {
292-
if(Importer.isText(entry)) {
293-
// _only_ decode newlines
294-
entry.content = entry.content.split("
").join("\n");
295-
}
296-
297-
if(Importer.shouldConvertToMarkdown(entry)) {
298-
await this.markdownService.asyncInit();
315+
entry.content = await this.getTransformedContent(entry, isWritingToMarkdown);
299316

300-
entry.content = await this.markdownService.toMarkdown(entry.content, entry);
301-
302-
entry.contentType = "markdown";
303-
}
317+
if(isWritingToMarkdown && Importer.shouldConvertToMarkdown(entry)) {
318+
entry.contentType = "markdown";
304319
}
305320

306321
return entry;

src/MarkdownToHtml.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -187,24 +187,26 @@ class MarkdownToHtml {
187187
finalLanguage = WORDPRESS_TO_PRISM_LANGUAGE_TRANSLATION[language] || language;
188188

189189
// TODO customizable
190-
// Questionable default: for code blocks bookended with ` (unnecessarily)
190+
// Questionable default: for code blocks unnecessarily bookended with `
191191
let trimmed = content.trim();
192192
if(trimmed.startsWith("`") && trimmed.endsWith("`")) {
193193
content = trimmed.slice(1, -1);
194194
}
195195
}
196196

197197
try {
198-
if(isFromWordPress && language === "markup" && !content.trimStart().startsWith("<") || !this.prettierLanguages[finalLanguage]) {
199-
// Mislabeled as "markup" (hi WordPress) or no-parser found for prettier
200-
content = entities.decodeHTML(striptags(""+node.outerHTML));
201-
} else if (this.prettierLanguages[finalLanguage]) {
198+
if(isFromWordPress && language === "markup" && !content.trimStart().startsWith("<")) {
199+
// This code block was mislabeled as "markup" (hi WordPress), so we do nothing
200+
} else if(this.prettierLanguages[finalLanguage]) {
202201
// Attempt to format the code with Prettier
203202
let parserName = this.prettierLanguages[finalLanguage][0];
204203
content = prettierSync.format(content, { parser: parserName });
204+
} else {
205+
// preserve \n
206+
content = entities.decodeHTML(striptags(""+node.innerHTML));
205207
}
206208
} catch(e) {
207-
console.error(`Error running code formatting on code block from ${filePath}. Returning unformatted code.`, e);
209+
console.error(`Error running code formatting on code block from ${filePath}${language ? ` (${language})` : ""}. Returning unformatted code:\n\n${content}`, e);
208210
}
209211

210212
return MarkdownToHtml.outputMarkdownCodeBlock(content, finalLanguage);

test/test.js

+33-4
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ test("WordPress import", async (t) => {
109109

110110
assert.equal(cleanContent(post.content), `We’re so close to launching version 6, and we figured it was high time to make an official announcement. So, save the date for February. Font Awesome 6 will go beyond pure icon-imagination!
111111
112-
![](assets/image-calendar-exclamation-2-eKNZqhhuChge.png)
112+
![](assets/image-calendar-exclamation-2-fgQFmKKbUClc.png)
113113
114114
Save the date! February 2022 is just around the corner!
115115
@@ -121,23 +121,23 @@ So, what’s new?
121121
122122
Font Awesome 6 contains over 7,000 new icons, so you’re sure to find what you need for your project. Plus, we’ve redesigned most of our icons from scratch, so they’re more consistent and easier to use.
123123
124-
![](assets/image-icons-2-66KjmgCOuZQw.png)
124+
![](assets/image-icons-2-QjKY2bnBAg1T.png)
125125
126126
* * *
127127
128128
## More Styles
129129
130130
Font Awesome 6 includes five icons styles: solid, regular, light, duotone, and the new THIN style — not to mention all of our brand icons. And coming later in 2022 is the entirely new SHARP family of styles.
131131
132-
![](assets/image-styles-2-SNjQOsXaJuRQ.png)
132+
![](assets/image-styles-2-L9iIR9SlzG26.png)
133133
134134
* * *
135135
136136
## More Ways to Use
137137
138138
Font Awesome 6 makes it even easier to use icons where you want to. More plugins and packages to match your stack. Less time wrestling browser rendering.
139139
140-
![](assets/image-awesome-2-1AOLfzrlbkMJ.png)
140+
![](assets/image-awesome-2-O2xta1tL8p5n.png)
141141
142142
* * *
143143
@@ -252,3 +252,32 @@ test("Fetcher asset location tests (absolute)", async (t) => {
252252
url: "/assets/test-NzhbK6MSYu2g.png",
253253
});
254254
});
255+
256+
257+
test("Markdown cleanup code blocks strip tags", async (t) => {
258+
let importer = new Importer();
259+
260+
importer.setVerbose(false);
261+
importer.setDryRun(true);
262+
263+
let content = await importer.getTransformedContent({
264+
content: `<pre id=\"b088\" class=\"graf graf--pre graf-after--p\">$ npm config set “<a class=\"markup--anchor markup--pre-anchor\" title=\"Twitter profile for @fortawesome\" href=\"http://twitter.com/fortawesome\" target=\"_blank\" rel=\"noopener noreferrer\" data-href=\"http://twitter.com/fortawesome\">@fortawesome</a>:registry” <a class=\"markup--anchor markup--pre-anchor\" href=\"https://npm.fontawesome.com/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" data-href=\"https://npm.fontawesome.com/\">https://npm.fontawesome.com/</a></pre>`,
265+
contentType: "html"
266+
}, true);
267+
268+
assert.equal(content.trim(), "```\n$ npm config set “@fortawesome:registry” https://npm.fontawesome.com/\n```");
269+
});
270+
271+
test("Markdown cleanup code blocks with nested <code>", async (t) => {
272+
let importer = new Importer();
273+
274+
importer.setVerbose(false);
275+
importer.setDryRun(true);
276+
277+
let content2 = await importer.getTransformedContent({
278+
content: `<pre id=\"9da4\" class=\"graf graf--pre graf-after--p\">Authorization: Bearer <code>DEAD-BEEF</code></pre>`,
279+
contentType: "html"
280+
}, true);
281+
282+
assert.equal(content2.trim(), "```\nAuthorization: Bearer DEAD-BEEF\n```");
283+
});

0 commit comments

Comments
 (0)