diff options
author | Chocobozzz <me@florianbigard.com> | 2022-03-07 11:48:53 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-03-07 11:48:53 +0100 |
commit | 2f19481147b12e2ae503ed3d1f28621c94447ac3 (patch) | |
tree | 6a5d1ab08432d0653b2391f67726e5d0c71ace65 /server/helpers | |
parent | 907ba7e270b78507a8d9b6aa20da0f6231c37d25 (diff) | |
download | PeerTube-2f19481147b12e2ae503ed3d1f28621c94447ac3.tar.gz PeerTube-2f19481147b12e2ae503ed3d1f28621c94447ac3.tar.zst PeerTube-2f19481147b12e2ae503ed3d1f28621c94447ac3.zip |
Optimize markdown renderer
Diffstat (limited to 'server/helpers')
-rw-r--r-- | server/helpers/markdown.ts | 54 |
1 files changed, 32 insertions, 22 deletions
diff --git a/server/helpers/markdown.ts b/server/helpers/markdown.ts index 25685ec6d..f9291bdad 100644 --- a/server/helpers/markdown.ts +++ b/server/helpers/markdown.ts | |||
@@ -7,8 +7,13 @@ const sanitizeHtml = require('sanitize-html') | |||
7 | const markdownItEmoji = require('markdown-it-emoji/light') | 7 | const markdownItEmoji = require('markdown-it-emoji/light') |
8 | const MarkdownItClass = require('markdown-it') | 8 | const MarkdownItClass = require('markdown-it') |
9 | 9 | ||
10 | const markdownItWithHTML = new MarkdownItClass('default', { linkify: true, breaks: true, html: true }) | 10 | const markdownItForSafeHtml = new MarkdownItClass('default', { linkify: true, breaks: true, html: true }) |
11 | const markdownItWithoutHTML = new MarkdownItClass('default', { linkify: true, breaks: true, html: false }) | 11 | .enable(TEXT_WITH_HTML_RULES) |
12 | .use(markdownItEmoji) | ||
13 | |||
14 | const markdownItForPlainText = new MarkdownItClass('default', { linkify: false, breaks: true, html: false }) | ||
15 | .use(markdownItEmoji) | ||
16 | .use(plainTextPlugin) | ||
12 | 17 | ||
13 | const toSafeHtml = (text: string) => { | 18 | const toSafeHtml = (text: string) => { |
14 | if (!text) return '' | 19 | if (!text) return '' |
@@ -17,9 +22,7 @@ const toSafeHtml = (text: string) => { | |||
17 | const textWithLineFeed = text.replace(/<br.?\/?>/g, '\r\n') | 22 | const textWithLineFeed = text.replace(/<br.?\/?>/g, '\r\n') |
18 | 23 | ||
19 | // Convert possible markdown (emojis, emphasis and lists) to html | 24 | // Convert possible markdown (emojis, emphasis and lists) to html |
20 | const html = markdownItWithHTML.enable(TEXT_WITH_HTML_RULES) | 25 | const html = markdownItForSafeHtml.render(textWithLineFeed) |
21 | .use(markdownItEmoji) | ||
22 | .render(textWithLineFeed) | ||
23 | 26 | ||
24 | // Convert to safe Html | 27 | // Convert to safe Html |
25 | return sanitizeHtml(html, defaultSanitizeOptions) | 28 | return sanitizeHtml(html, defaultSanitizeOptions) |
@@ -28,12 +31,10 @@ const toSafeHtml = (text: string) => { | |||
28 | const mdToOneLinePlainText = (text: string) => { | 31 | const mdToOneLinePlainText = (text: string) => { |
29 | if (!text) return '' | 32 | if (!text) return '' |
30 | 33 | ||
31 | markdownItWithoutHTML.use(markdownItEmoji) | 34 | markdownItForPlainText.render(text) |
32 | .use(plainTextPlugin) | ||
33 | .render(text) | ||
34 | 35 | ||
35 | // Convert to safe Html | 36 | // Convert to safe Html |
36 | return sanitizeHtml(markdownItWithoutHTML.plainText, textOnlySanitizeOptions) | 37 | return sanitizeHtml(markdownItForPlainText.plainText, textOnlySanitizeOptions) |
37 | } | 38 | } |
38 | 39 | ||
39 | // --------------------------------------------------------------------------- | 40 | // --------------------------------------------------------------------------- |
@@ -47,30 +48,39 @@ export { | |||
47 | 48 | ||
48 | // Thanks: https://github.com/wavesheep/markdown-it-plain-text | 49 | // Thanks: https://github.com/wavesheep/markdown-it-plain-text |
49 | function plainTextPlugin (markdownIt: any) { | 50 | function plainTextPlugin (markdownIt: any) { |
50 | let lastSeparator = '' | ||
51 | |||
52 | function plainTextRule (state: any) { | 51 | function plainTextRule (state: any) { |
53 | const text = scan(state.tokens) | 52 | const text = scan(state.tokens) |
54 | 53 | ||
55 | markdownIt.plainText = text.replace(/\s+/g, ' ') | 54 | // markdownIt.plainText = text.replace(/\s+/g, ' ') |
55 | markdownIt.plainText = text | ||
56 | } | 56 | } |
57 | 57 | ||
58 | function scan (tokens: any[]) { | 58 | function scan (tokens: any[]) { |
59 | let lastSeparator = '' | ||
59 | let text = '' | 60 | let text = '' |
60 | 61 | ||
61 | for (const token of tokens) { | 62 | function buildSeparator (token: any) { |
62 | if (token.children !== null) { | ||
63 | text += scan(token.children) | ||
64 | continue | ||
65 | } | ||
66 | |||
67 | if (token.type === 'list_item_close') { | 63 | if (token.type === 'list_item_close') { |
68 | lastSeparator = ', ' | 64 | lastSeparator = ', ' |
69 | } else if (/[a-zA-Z]+_close/.test(token.type)) { | 65 | } |
66 | |||
67 | if (token.tag === 'br' || token.type === 'paragraph_close') { | ||
70 | lastSeparator = ' ' | 68 | lastSeparator = ' ' |
71 | } else if (token.content) { | 69 | } |
72 | text += lastSeparator | 70 | } |
73 | text += token.content | 71 | |
72 | for (const token of tokens) { | ||
73 | buildSeparator(token) | ||
74 | |||
75 | if (token.type !== 'inline') continue | ||
76 | |||
77 | for (const child of token.children) { | ||
78 | buildSeparator(child) | ||
79 | |||
80 | if (!child.content) continue | ||
81 | |||
82 | text += lastSeparator + child.content | ||
83 | lastSeparator = '' | ||
74 | } | 84 | } |
75 | } | 85 | } |
76 | 86 | ||