]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/helpers/markdown.ts
41c1186ec1c089e1ed933bf60d2268ac2cda0512
[github/Chocobozzz/PeerTube.git] / server / helpers / markdown.ts
1 import { getDefaultSanitizeOptions, getTextOnlySanitizeOptions, TEXT_WITH_HTML_RULES } from '@shared/core-utils'
2
3 const defaultSanitizeOptions = getDefaultSanitizeOptions()
4 const textOnlySanitizeOptions = getTextOnlySanitizeOptions()
5
6 const sanitizeHtml = require('sanitize-html')
7 const markdownItEmoji = require('markdown-it-emoji/light')
8 const MarkdownItClass = require('markdown-it')
9
10 const markdownItWithHTML = new MarkdownItClass('default', { linkify: true, breaks: true, html: true })
11 const markdownItWithoutHTML = new MarkdownItClass('default', { linkify: false, breaks: true, html: false })
12
13 const toSafeHtml = (text: string) => {
14 if (!text) return ''
15
16 // Restore line feed
17 const textWithLineFeed = text.replace(/<br.?\/?>/g, '\r\n')
18
19 // Convert possible markdown (emojis, emphasis and lists) to html
20 const html = markdownItWithHTML.enable(TEXT_WITH_HTML_RULES)
21 .use(markdownItEmoji)
22 .render(textWithLineFeed)
23
24 // Convert to safe Html
25 return sanitizeHtml(html, defaultSanitizeOptions)
26 }
27
28 const mdToOneLinePlainText = (text: string) => {
29 if (!text) return ''
30
31 markdownItWithoutHTML.use(markdownItEmoji)
32 .use(plainTextPlugin)
33 .render(text)
34
35 // Convert to safe Html
36 return sanitizeHtml(markdownItWithoutHTML.plainText, textOnlySanitizeOptions)
37 }
38
39 // ---------------------------------------------------------------------------
40
41 export {
42 toSafeHtml,
43 mdToOneLinePlainText
44 }
45
46 // ---------------------------------------------------------------------------
47
48 // Thanks: https://github.com/wavesheep/markdown-it-plain-text
49 function plainTextPlugin (markdownIt: any) {
50 let lastSeparator = ''
51
52 function plainTextRule (state: any) {
53 const text = scan(state.tokens)
54
55 markdownIt.plainText = text.replace(/\s+/g, ' ')
56 }
57
58 function scan (tokens: any[]) {
59 let text = ''
60
61 for (const token of tokens) {
62 if (token.children !== null) {
63 text += scan(token.children)
64 continue
65 }
66
67 if (token.type === 'list_item_close') {
68 lastSeparator = ', '
69 } else if (token.type.endsWith('_close')) {
70 lastSeparator = ' '
71 } else if (token.content) {
72 text += lastSeparator
73 text += token.content
74 }
75 }
76
77 return text
78 }
79
80 markdownIt.core.ruler.push('plainText', plainTextRule)
81 }