"use strict"; import TurndownService from "turndown"; import turndownPluginGfm from "@joplin/turndown-plugin-gfm"; let instance: TurndownService | null = null; const fencedCodeBlockFilter: TurndownService.Rule = { 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; } const className = node.firstChild.getAttribute("class") || ""; const language = rewriteLanguageTag((className.match(/language-(\S+)/) || [null, ""])[1]); return "\n\n" + options.fence + language + "\n" + node.firstChild.textContent + "\n" + options.fence + "\n\n"; } }; function toMarkdown(content: string) { if (instance === null) { instance = new TurndownService({ codeBlockStyle: "fenced" }); // Filter is heavily based on: https://github.com/mixmark-io/turndown/issues/274#issuecomment-458730974 instance.addRule("fencedCodeBlock", fencedCodeBlockFilter); instance.use(turndownPluginGfm.gfm); } return instance.turndown(content); } function rewriteLanguageTag(source: string) { if (!source) { return source; } switch (source) { case "text-x-trilium-auto": return ""; case "application-javascript-env-frontend": case "application-javascript-env-backend": return "javascript"; default: return source.split("-").at(-1); } } export default { toMarkdown };