import marked from 'marked'; import hljs from 'highlight.js'; import MarkdownFixer from './PreProcessor/MarkdownFixer'; import Linker from './PreProcessor/Linker'; import ImageExpander from './PreProcessor/ImageExpander'; import Emoji from './PreProcessor/Emoji'; import Tsv2Table from './LangProcessor/Tsv2Table'; import Template from './LangProcessor/Template'; export default class CrowiRenderer { constructor(plugins) { this.preProcessors = [ new MarkdownFixer(), new Linker(), new ImageExpander(), new Emoji(), ]; this.langProcessors = { 'tsv': new Tsv2Table(), 'tsv-h': new Tsv2Table({header: true}), 'template': new Template(), }; this.parseMarkdown = this.parseMarkdown.bind(this); this.codeRenderer = this.codeRenderer.bind(this); } preProcess(markdown) { for (let i = 0; i < this.preProcessors.length; i++) { if (!this.preProcessors[i].process) { continue; } markdown = this.preProcessors[i].process(markdown); } return markdown; } codeRenderer(code, lang, escaped) { let result = '', hl; if (lang) { const langPattern = lang.split(':')[0]; if (this.langProcessors[langPattern]) { return this.langProcessors[langPattern].process(code, lang); } try { hl = hljs.highlight(lang, code); result = hl.value; escaped = true; } catch (e) { result = code; } result = (escape ? result : Crowi.escape(result, true)); return `
${result}\n\n`;
}
// no lang specified
return `${Crowi.escape(code, true)}\n`;
}
parseMarkdown(markdown) {
let parsed = '';
const markedRenderer = new marked.Renderer();
markedRenderer.code = this.codeRenderer;
try {
// TODO
marked.setOptions({
gfm: true,
tables: true,
breaks: true,
pedantic: false,
sanitize: false,
smartLists: true,
smartypants: false,
renderer: markedRenderer,
});
parsed = marked(markdown);
} catch (e) { console.log(e, e.stack); }
return parsed;
}
render(markdown) {
let html = '';
markdown = this.preProcess(markdown);
html = this.parseMarkdown(markdown);
return html;
}
}