mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 05:28:59 +01:00 
			
		
		
		
	feat(markdown): use different approach for reference links
This commit is contained in:
		
							parent
							
								
									4f22850ea9
								
							
						
					
					
						commit
						6a69e9b208
					
				@ -238,9 +238,15 @@ describe("Markdown export", () => {
 | 
			
		||||
        expect(markdownExportService.toMarkdown(html)).toBe(expected);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("exports reference links as normal links", () => {
 | 
			
		||||
    it("exports normal links verbatim", () => {
 | 
			
		||||
        const html = /*html*/`<p><a href="https://www.google.com">Google</a></p>`;
 | 
			
		||||
        const expected = `[Google](https://www.google.com)`;
 | 
			
		||||
        expect(markdownExportService.toMarkdown(html)).toBe(expected);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("exports reference links verbatim", () => {
 | 
			
		||||
        const html = /*html*/`<p><a class="reference-link" href="../../Canvas.html">Canvas</a></p>`;
 | 
			
		||||
        const expected = `[Canvas](../../Canvas.html)`;
 | 
			
		||||
        const expected = `<a class="reference-link" href="../../Canvas.html">Canvas</a>`;
 | 
			
		||||
        expect(markdownExportService.toMarkdown(html)).toBe(expected);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
import TurndownService from "turndown";
 | 
			
		||||
import TurndownService, { type Rule } from "turndown";
 | 
			
		||||
import { gfm } from "../../../packages/turndown-plugin-gfm/src/gfm.js";
 | 
			
		||||
import type { DOMElement } from "react";
 | 
			
		||||
 | 
			
		||||
let instance: TurndownService | null = null;
 | 
			
		||||
 | 
			
		||||
@ -43,6 +44,7 @@ function toMarkdown(content: string) {
 | 
			
		||||
        instance.addRule("fencedCodeBlock", fencedCodeBlockFilter);
 | 
			
		||||
        instance.addRule("img", buildImageFilter());
 | 
			
		||||
        instance.addRule("admonition", buildAdmonitionFilter());
 | 
			
		||||
        instance.addRule("inlineLink", buildInlineLinkFilter());
 | 
			
		||||
        instance.use(gfm);
 | 
			
		||||
        instance.keep([ "kbd" ]);
 | 
			
		||||
    }
 | 
			
		||||
@ -93,10 +95,6 @@ function buildImageFilter() {
 | 
			
		||||
        return title.replace(/"/g, '\\"')
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function cleanAttribute (attribute: string) {
 | 
			
		||||
        return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const imageFilter: TurndownService.Rule = {
 | 
			
		||||
        filter: "img",
 | 
			
		||||
        replacement(content, node) {
 | 
			
		||||
@ -153,6 +151,48 @@ function buildAdmonitionFilter() {
 | 
			
		||||
    return admonitionFilter;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Variation of the original ruleset: https://github.com/mixmark-io/turndown/blob/master/src/commonmark-rules.js.
 | 
			
		||||
 *
 | 
			
		||||
 * Detects if the URL is a Trilium reference link and returns it verbatim if that's the case.
 | 
			
		||||
 *
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
function buildInlineLinkFilter(): Rule {
 | 
			
		||||
    return {
 | 
			
		||||
        filter: function (node, options) {
 | 
			
		||||
            return (
 | 
			
		||||
            options.linkStyle === 'inlined' &&
 | 
			
		||||
            node.nodeName === 'A' &&
 | 
			
		||||
            !!node.getAttribute('href')
 | 
			
		||||
            )
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        replacement: function (content, _node) {
 | 
			
		||||
            const node = _node as HTMLElement;
 | 
			
		||||
 | 
			
		||||
            // Return reference links verbatim.
 | 
			
		||||
            if (node.classList.contains("reference-link")) {
 | 
			
		||||
                return node.outerHTML;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Otherwise treat as normal.
 | 
			
		||||
            // TODO: Call super() somehow instead of duplicating the implementation.
 | 
			
		||||
            var href = node.getAttribute('href')
 | 
			
		||||
            if (href) href = href.replace(/([()])/g, '\\$1')
 | 
			
		||||
            var title = cleanAttribute(node.getAttribute('title'))
 | 
			
		||||
            if (title) title = ' "' + title.replace(/"/g, '\\"') + '"'
 | 
			
		||||
            return '[' + content + '](' + href + title + ')'
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Taken from upstream since it's not exposed.
 | 
			
		||||
// https://github.com/mixmark-io/turndown/blob/master/src/commonmark-rules.js
 | 
			
		||||
function cleanAttribute(attribute: string | null | undefined) {
 | 
			
		||||
    return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    toMarkdown
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -151,8 +151,14 @@ second line 2</code></pre><ul><li>Hello</li><li>world</li></ul><ol><li>Hello</li
 | 
			
		||||
        expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("imports back to reference links", () => {
 | 
			
		||||
    it("does not touch relative links", () => {
 | 
			
		||||
        const input = `[Canvas](../../Canvas.html)`;
 | 
			
		||||
        const expected = /*html*/`<p><a href="../../Canvas.html">Canvas</a></p>`;
 | 
			
		||||
        expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("imports back to reference links", () => {
 | 
			
		||||
        const input = `<a class="reference-link" href="../../Canvas.html">Canvas</a>`;
 | 
			
		||||
        const expected = /*html*/`<p><a class="reference-link" href="../../Canvas.html">Canvas</a></p>`;
 | 
			
		||||
        expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -64,17 +64,6 @@ class CustomMarkdownRenderer extends Renderer {
 | 
			
		||||
        return `<blockquote>${body}</blockquote>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    link(data: Tokens.Link): string {
 | 
			
		||||
        let html = super.link(data);
 | 
			
		||||
 | 
			
		||||
        // Rewrite local/relative links back to reference links.
 | 
			
		||||
        if (data.href.indexOf("://") === -1) {
 | 
			
		||||
            html = html.replace(/^<a /, `<a class="reference-link" `);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return html;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const renderer = new CustomMarkdownRenderer({ async: false });
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user