diff --git a/spec/services/export/md.spec.ts b/spec/services/export/md.spec.ts new file mode 100644 index 000000000..612b43513 --- /dev/null +++ b/spec/services/export/md.spec.ts @@ -0,0 +1,24 @@ +import markdownExportService from "../../../src/services/export/md.js"; +import { trimIndentation } from "../../support/utils.js"; + +describe("Markdown export", () => { + it("trims language tag for code blocks", () => { + const html = trimIndentation`\ +
A diff:
+Hello
+ -world
+ +worldy
+
`;
+ const expected = trimIndentation`\
+ A diff:
+
+ \`\`\`diff
+ Hello
+ -world
+ +worldy
+
+ \`\`\``;
+
+ expect(markdownExportService.toMarkdown(html)).toBe(expected);
+ });
+});
\ No newline at end of file
diff --git a/src/services/export/md.ts b/src/services/export/md.ts
index 84af6f56f..8f7213f84 100644
--- a/src/services/export/md.ts
+++ b/src/services/export/md.ts
@@ -8,12 +8,44 @@ let instance: TurndownService | null = null;
function toMarkdown(content: string) {
if (instance === null) {
instance = new TurndownService({ codeBlockStyle: 'fenced' });
+ instance.addRule('fencedCodeBlock', {
+ filter: function (node, options) {
+ return (
+ options.codeBlockStyle === 'fenced' &&
+ node.nodeName === 'PRE' &&
+ node.firstChild !== null &&
+ node.firstChild.nodeName === 'CODE'
+ )
+ },
+
+ replacement: function (content, node, options) {
+ if (!node.firstChild || !("getAttribute" in node.firstChild) || typeof node.firstChild.getAttribute !== "function") {
+ return content;
+ }
+
+ var className = node.firstChild.getAttribute('class') || ''
+ var language = (className.match(/language-(\S+)/) || [null, ''])[1];
+ language = rewriteLanguageTag(language);
+
+ return (
+ '\n\n' + options.fence + language + '\n' +
+ node.firstChild.textContent +
+ '\n' + options.fence + '\n\n'
+ )
+ }
+ })
instance.use(turndownPluginGfm.gfm);
}
return instance.turndown(content);
}
+function rewriteLanguageTag(source: string) {
+ return source
+ .split("-")
+ .at(-1);
+}
+
export default {
toMarkdown
};