UNPKG

@yozora/core-html-renderer

Version:
236 lines (212 loc) 8.66 kB
'use strict'; var prism = require('prismjs'); var ast = require('@yozora/ast'); var sanitize = require('sanitize-html'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var prism__default = /*#__PURE__*/_interopDefault(prism); var sanitize__default = /*#__PURE__*/_interopDefault(sanitize); const renderBlockquote = (node, context) => { const children = context.renderChildren(node.children); return `<blockquote class="yozora-blockquote">${children}</blockquote>`; }; const renderBreak = () => { return '<br class="yozora-break" />'; }; const renderCode = (node, context) => { const { value, lang } = node; const highlightedCode = lang != null && prism__default.default.languages[lang] != null ? prism__default.default.highlight(value, prism__default.default.languages[lang], lang) : context.sanitize(value); return `<pre class="yozora-code"><code>${highlightedCode}</code></pre>`; }; const renderDelete = (node, context) => { const children = context.renderChildren(node.children); return `<del class="yozora-delete">${children}</del>`; }; const renderEmphasis = (node, context) => { const children = context.renderChildren(node.children); return `<em class="yozora-emphasis">${children}</em>`; }; const renderHeading = (node, context) => { const depth = Number(node.depth); const H = `h${depth}`; const children = context.renderChildren(node.children); return `<${H} class="yozora-heading">${children}</${H}>`; }; const renderImage = (node, context) => { const url = context.sanitize(node.url); const alt = context.sanitize(node.alt); const title = context.sanitize(node.title || alt); return `<img class="yozora-image" alt="${alt}" src="${url}" title="${title}" />`; }; const renderImageReference = (node, context) => { const definition = context.getDefinition(node.identifier); if (definition == null) return ''; const url = context.sanitize(definition.url); const alt = context.sanitize(definition.label); const title = context.sanitize(definition.title || alt); return `<img class="yozora-image" alt="${alt}" src="${url}" title="${title}" />`; }; const renderInlineCode = (node, context) => { const value = context.sanitize(node.value); return `<pre class="yozora-inline-code"><code>${value}</code></pre>`; }; const renderLink = (node, context) => { const url = context.sanitize(node.url); const title = context.sanitize(node.title || url); const children = context.renderChildren(node.children); return `<a class="yozora-link" href="${url}" title="${title}" target="_blank" rel="noopener,noreferrer">${children}</a>`; }; const renderLinkReference = (node, context) => { const definition = context.getDefinition(node.identifier); if (definition == null) return ''; const url = context.sanitize(definition.url); const title = context.sanitize(definition.title || url); const children = context.renderChildren(node.children); return `<a class="yozora-link" href="${url}" title="${title}" target="_blank" rel="noopener,noreferrer">${children}</a>`; }; const renderList = (node, context) => { const children = context.renderChildren(node.children); if (node.ordered) { const { start = 1 } = node; return `<ol class="yozora-list" start="${Number(start)}">${children}</ol>`; } return `<ul class="yozora-list">${children}</ul>`; }; const renderListItem = (node, context) => { const children = context.renderChildren(node.children); let checkbox = ''; if (node.status != null) { switch (node.status) { case 'todo': checkbox = '<input disabled="" type="checkbox" /> '; break; case 'done': checkbox = '<input checked="" disabled="" type="checkbox" /> '; break; } } return `<li class="yozora-list-item">${checkbox}${children}</li>`; }; const renderParagraph = (node, context) => { const children = context.renderChildren(node.children); return `<p class="yozora-paragraph">${children}</p>`; }; const renderStrong = (node, context) => { const children = context.renderChildren(node.children); return `<strong class="yozora-strong">${children}</strong>`; }; const ColumnAlignTypeMap = { left: 'left', right: 'right', center: 'center', }; const renderTable = (node, context) => { const aligns = node.columns.map(col => { if (col.align == null) return null; return ColumnAlignTypeMap[col.align.toLowerCase()] ?? null; }); const [tHeadRow, ...tBodyRows] = node.children; const thead = '<thead class="yozora-table__thead"><tr class="yozora-table-row">' + tHeadRow.children .map((th, i) => { const align = aligns[i] == null ? '' : ` align="${aligns[i]}"`; const ths = context.renderChildren(th.children); return `<th class="yozora-table-cell"${align}>${ths}</th>`; }) .join('') + '</tr></thead>'; const tbody = '<tbody class="yozora-table__tbody">' + tBodyRows .map((row) => { const tds = row.children .map((td, i) => { const align = aligns[i] == null ? '' : ` align="${aligns[i]}"`; const ths = context.renderChildren(td.children); return `<td class="yozora-table-cell"${align}>${ths}</td>`; }) .join(''); return `<tr class="yozora-table-row">${tds}</tr>`; }) .join('') + '</tbody>'; return `<table class="yozora-table">${thead}${tbody}</table>`; }; const renderText = (node, context) => { const value = context.sanitize(node.value); return `<span class="yozora-text">${value}</span>`; }; const renderThematicBreak = () => { return '<hr class="yozora-thematic-break" />'; }; const defaultRendererMap = { [ast.BlockquoteType]: renderBlockquote, [ast.BreakType]: renderBreak, [ast.CodeType]: renderCode, [ast.DefinitionType]: () => '', [ast.DeleteType]: renderDelete, [ast.EmphasisType]: renderEmphasis, [ast.HeadingType]: renderHeading, [ast.HtmlType]: () => '', [ast.ImageType]: renderImage, [ast.ImageReferenceType]: renderImageReference, [ast.InlineCodeType]: renderInlineCode, [ast.LinkType]: renderLink, [ast.LinkReferenceType]: renderLinkReference, [ast.ListType]: renderList, [ast.ListItemType]: renderListItem, [ast.ParagraphType]: renderParagraph, [ast.StrongType]: renderStrong, [ast.TableType]: renderTable, [ast.TextType]: renderText, [ast.ThematicBreakType]: renderThematicBreak, _fallback: node => { console.warn(`Cannot find render for \`${node.type}\` type node:`, node); return ''; }, }; function createNodeRendererContext(definitionMap, footnoteDefinitionMap, rendererMap = defaultRendererMap) { const context = { sanitize: value => sanitize__default.default(value, { allowedTags: [] }), getDefinition: (identifier) => definitionMap[identifier], getFootnoteDefinition: (identifier) => footnoteDefinitionMap[identifier], renderChildren: (nodes) => { if (nodes == null || nodes.length < 1) return ''; return nodes .map(node => { const renderNode = rendererMap[node.type]; if (renderNode === undefined) { console.warn(`Cannot find renderer for node ${node.type}`); return ''; } return renderNode(node, context); }) .join(''); }, }; return context; } exports.createNodeRendererContext = createNodeRendererContext; exports.defaultRendererMap = defaultRendererMap; exports.renderBlockquote = renderBlockquote; exports.renderBreak = renderBreak; exports.renderCode = renderCode; exports.renderDelete = renderDelete; exports.renderEmphasis = renderEmphasis; exports.renderHeading = renderHeading; exports.renderImage = renderImage; exports.renderImageReference = renderImageReference; exports.renderInlineCode = renderInlineCode; exports.renderLink = renderLink; exports.renderLinkReference = renderLinkReference; exports.renderList = renderList; exports.renderListItem = renderListItem; exports.renderParagraph = renderParagraph; exports.renderStrong = renderStrong; exports.renderTable = renderTable; exports.renderText = renderText; exports.renderThematicBreak = renderThematicBreak;