mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-09-09 15:30:45 +08: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);
|
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 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);
|
expect(markdownExportService.toMarkdown(html)).toBe(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import TurndownService from "turndown";
|
import TurndownService, { type Rule } from "turndown";
|
||||||
import { gfm } from "../../../packages/turndown-plugin-gfm/src/gfm.js";
|
import { gfm } from "../../../packages/turndown-plugin-gfm/src/gfm.js";
|
||||||
|
import type { DOMElement } from "react";
|
||||||
|
|
||||||
let instance: TurndownService | null = null;
|
let instance: TurndownService | null = null;
|
||||||
|
|
||||||
@ -43,6 +44,7 @@ function toMarkdown(content: string) {
|
|||||||
instance.addRule("fencedCodeBlock", fencedCodeBlockFilter);
|
instance.addRule("fencedCodeBlock", fencedCodeBlockFilter);
|
||||||
instance.addRule("img", buildImageFilter());
|
instance.addRule("img", buildImageFilter());
|
||||||
instance.addRule("admonition", buildAdmonitionFilter());
|
instance.addRule("admonition", buildAdmonitionFilter());
|
||||||
|
instance.addRule("inlineLink", buildInlineLinkFilter());
|
||||||
instance.use(gfm);
|
instance.use(gfm);
|
||||||
instance.keep([ "kbd" ]);
|
instance.keep([ "kbd" ]);
|
||||||
}
|
}
|
||||||
@ -93,10 +95,6 @@ function buildImageFilter() {
|
|||||||
return title.replace(/"/g, '\\"')
|
return title.replace(/"/g, '\\"')
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanAttribute (attribute: string) {
|
|
||||||
return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''
|
|
||||||
}
|
|
||||||
|
|
||||||
const imageFilter: TurndownService.Rule = {
|
const imageFilter: TurndownService.Rule = {
|
||||||
filter: "img",
|
filter: "img",
|
||||||
replacement(content, node) {
|
replacement(content, node) {
|
||||||
@ -153,6 +151,48 @@ function buildAdmonitionFilter() {
|
|||||||
return admonitionFilter;
|
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 {
|
export default {
|
||||||
toMarkdown
|
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);
|
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 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>`;
|
const expected = /*html*/`<p><a class="reference-link" href="../../Canvas.html">Canvas</a></p>`;
|
||||||
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||||
});
|
});
|
||||||
|
@ -64,17 +64,6 @@ class CustomMarkdownRenderer extends Renderer {
|
|||||||
return `<blockquote>${body}</blockquote>`;
|
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 });
|
const renderer = new CustomMarkdownRenderer({ async: false });
|
||||||
|
Loading…
x
Reference in New Issue
Block a user