UNPKG

bixi

Version:

企业级中后台前端解决方案

143 lines (131 loc) 4.93 kB
import { highlight } from '../converters/highlight'; import { escapeHTML, genAttr, generateSluggedId, isHeading, isStandalone } from './utils'; const JsonML = require('jsonml.js/lib/utils'); let headingList: any[] = []; const converters = [highlight()].concat([ [ (node: any) => typeof node === 'string', (node: any) => { if (node === '(deprecated)') { return `<i class="deprecated" title="已过期(Deprecated)"></i>`; } return node; }, ], [ (node: any) => JsonML.isElement(node) && isHeading(node), (node: any, index: number) => { const tagName = JsonML.getTagName(node); const children = JsonML.getChildren(node); const sluggedId = generateSluggedId(children).id; // <a href="#${sluggedId}" class="anchor">#</a> return `<${tagName} id="${sluggedId}">${children.map(toHtml).join('')}</${tagName}>`; }, ], [ (node: any) => JsonML.isElement(node) && JsonML.getTagName(node) === 'img', (node: any, index: number) => { const attrs = JsonML.getAttributes(node); const ret: any[] = []; if (attrs) { for (const key in attrs) { let value = attrs[key]; if (key === 'src' && ~value.indexOf(' | ')) { const imgWH = value.split(' | ')[1].trim().split('='); for (let i = 0; i < imgWH.length; i += 2) { ret.push(`${imgWH[i]}=${imgWH[i + 1]}`); } value = value.split(' | ')[0]; } if (value) ret.push(`${key}="${value}"`); } } return `<img ${ret.join(' ')} />`; }, ], [ (node: any) => JsonML.isElement(node) && JsonML.getTagName(node) === 'a', (node: any, index: number) => { const attrs = { ...JsonML.getAttributes(node) }; let target = attrs.href.startsWith('//') || attrs.href.startsWith('http') ? ' target="_blank"' : ''; if (~attrs.href.indexOf('bixi.com')) target = ''; return `<a${target} href="${attrs.href}" data-url="${attrs.href}">${JsonML.getChildren(node).map(toHtml).join('')}</a>`; }, ], [ (node: any) => !Array.isArray(node), (node: any, index: number) => { if (!node.url) return ''; return `<!--${node.url}-->`; }, ], [ () => true, (node: any) => { const tagName = JsonML.getTagName(node); const attrs = genAttr({ ...JsonML.getAttributes(node) }); return `${tagName ? `<${tagName}${attrs ? ' ' + attrs : ''}>` : ''}${ isStandalone(tagName) ? '' : JsonML.getChildren(node).map(toHtml).join('') + (tagName ? `</${tagName}>` : '') }`; }, ], ]); export function toHtml(markdownData: any, codeEscape: boolean = true) { const pair: any = converters.filter((converter: any) => { return converter[0](markdownData); })[0]; const ret: string = pair[1](markdownData); if (codeEscape) { return ret.replace( /<pre class="hljs language-([a-zA-Z0-9]+)"><code>([\s\S]+)<\/code><\/pre>/g, (_fullWord: string, lang: string, code: string) => { if (lang === 'html') { code = code.includes(`&lt;`) && code.includes(`&gt;`) ? code : escapeHTML(code); } else if ((lang === 'ts' || lang === 'typescript') && code.includes(`template: `)) { code = code.replace(/template: `([^`]+)`/g, (_tFullword: string, tHtml: string) => { return 'template: `' + escapeHTML(tHtml) + '`'; }); } return `<pre class="hljs language-${lang}"><code>${code}</code></pre>`; }, ); } else { // && ~headingList.indexOf(ret) if (/^<code>/g.test(ret)) { return ret.replace(/([a-zA-Z]+)/g, (word: string) => { if (headingList.indexOf(word) !== -1) { return `<a data-toc="${word}">${word}</a>`; } return word; }); } } return ret; } function fixAngular(html: string): string { return html.replace(/<code>(.*?)<\/code>/gim, (fullWord: string, content: string) => { return ~content.indexOf(`</a>`) ? fullWord : `<code>${content.replace(`<`, `&lt;`)}</code>`; }); } export function generateMd(markdownData: any) { const contentChildren = JsonML.getChildren(markdownData.content); headingList = contentChildren .filter(node => JsonML.isElement(node) && isHeading(node)) .filter(arr => arr.length === 2) .map(arr => arr[1]); const apiStartIndex = contentChildren.findIndex( (node: any) => JsonML.getTagName(node) === 'h2' && /^API/.test(JsonML.getChildren(node)[0]), ); const ret: any = {}; if (apiStartIndex > -1) { const content = contentChildren.slice(0, apiStartIndex); ret.content = [''].concat(content); const api = contentChildren.slice(apiStartIndex); ret.api = [''].concat(api); } else { ret.content = markdownData.content; } if (ret.content) ret.content = fixAngular(toHtml(ret.content)); if (ret.api) ret.api = fixAngular(toHtml(ret.api)); return ret; }