// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. require('./highlight.jsx'); const TextFormatting = require('./text_formatting.jsx'); const Utils = require('./utils.jsx'); const highlightJs = require('highlight.js/lib/highlight.js'); const marked = require('marked'); const HighlightedLanguages = require('../utils/constants.jsx').HighlightedLanguages; function markdownImageLoaded(image) { image.style.height = 'auto'; } window.markdownImageLoaded = markdownImageLoaded; class MattermostInlineLexer extends marked.InlineLexer { constructor(links, options) { super(links, options); this.rules = Object.assign({}, this.rules); // modified version of the regex that doesn't break up words in snake_case, // allows for links starting with www, and allows links succounded by parentheses // the original is /^[\s\S]+?(?=[\\ starting with www. // the original is /^<([^ >]+(@|:\/)[^ >]+)>/ this.rules.autolink = /^<((?:[^ >]+(@|:\/)|www\.)[^ >]+)>/; } } class MattermostParser extends marked.Parser { parse(src) { this.inline = new MattermostInlineLexer(src.links, this.options, this.renderer); this.tokens = src.reverse(); var out = ''; while (this.next()) { out += this.tok(); } return out; } } class MattermostMarkdownRenderer extends marked.Renderer { constructor(options, formattingOptions = {}) { super(options); this.heading = this.heading.bind(this); this.paragraph = this.paragraph.bind(this); this.text = this.text.bind(this); this.formattingOptions = formattingOptions; } code(code, language) { let usedLanguage = language; if (String(usedLanguage).toLocaleLowerCase() === 'html') { usedLanguage = 'xml'; } if (!usedLanguage || highlightJs.listLanguages().indexOf(usedLanguage) < 0) { let parsed = super.code(code, usedLanguage); return '
' + TextFormatting.sanitizeHtml($(parsed).text()) + '
'; } let parsed = highlightJs.highlight(usedLanguage, code); return '
' + '' + HighlightedLanguages[usedLanguage] + '' + '' + parsed.value + '' + '
'; } br() { if (this.formattingOptions.singleline) { return ' '; } return super.br(); } image(href, title, text) { let out = '' + text + '' : '>'; return out; } heading(text, level, raw) { const id = `${this.options.headerPrefix}${raw.toLowerCase().replace(/[^\w]+/g, '-')}`; return `${text}`; } link(href, title, text) { let outHref = href; let outText = text; let prefix = ''; let suffix = ''; // some links like https://en.wikipedia.org/wiki/Rendering_(computer_graphics) contain brackets // and we try our best to differentiate those from ones just wrapped in brackets when autolinking if (outHref.startsWith('(') && outHref.endsWith(')') && text === outHref) { prefix = '('; suffix = ')'; outText = text.substring(1, text.length - 1); outHref = outHref.substring(1, outHref.length - 1); } if (!(/[a-z+.-]+:/i).test(outHref)) { outHref = `http://${outHref}`; } let output = ''; return prefix + output + suffix; } paragraph(text) { if (this.formattingOptions.singleline) { return `

${text}

`; } return super.paragraph(text); } table(header, body) { return `${header}${body}
`; } text(txt) { return TextFormatting.doFormatText(txt, this.formattingOptions); } } export function format(text, options) { const markdownOptions = { renderer: new MattermostMarkdownRenderer(null, options), sanitize: true, gfm: true, tables: true }; const tokens = marked.lexer(text, markdownOptions); return new MattermostParser(markdownOptions).parse(tokens); }