aubade
Version:
filesystem-based content processor
62 lines (61 loc) • 3.36 kB
JavaScript
import { escape as sanitize } from '../utils.js';
import { compose } from './engine.js';
export function forge({ renderer = {} } = {}) {
const resolver = {
'parent:html': ({ token, render }) => `<div>${token.children.map(render).join('')}</div>`,
'parent:heading': ({ token, render }) => {
const tag = `h${token.meta.level}`;
const attributes = Object.entries(token.attr).flatMap(([k, v]) => v.length ? `${k}="${sanitize(v)}"` : []);
const children = token.children.map(render).join('');
return `<${tag} ${attributes.join(' ')}>${children}</${tag}>`;
},
'parent:quote': ({ token, render }) => {
return `<blockquote>${token.children.map(render).join('')}</blockquote>`;
},
'block:code': ({ token, render, sanitize }) => {
const attributes = Object.entries(token.attr)
.flatMap(([k, v]) => (v.length ? `${k}="${sanitize(v)}"` : []))
.join(' ');
const children = token.children.map(render).join('\n');
return `<pre${attributes ? ' ' + attributes : ''}>${children}</pre>`;
},
'block:list': ({ token, render }) => `<ul>${token.children.map(render).join('')}</ul>`,
// 'parent:item': ({ token, render }) => `<li>${token.children.map(render).join('')}</li>`,
'parent:paragraph': ({ token, render }) => {
const children = token.children.map(render).join('');
return `<p>${children || sanitize(token.text || '')}</p>`;
},
'block:break': () => `<hr />`,
'inline:autolink': ({ token, sanitize }) => {
const attributes = Object.entries(token.attr).flatMap(([k, v]) => v.length ? `${k}="${sanitize(v)}"` : []);
return `<a ${attributes.join(' ')}>${sanitize(token.text || '')}</a>`;
},
'inline:code': ({ token, sanitize }) => `<code>${sanitize(token.text || '')}</code>`,
'inline:image': ({ token, sanitize }) => {
const attributes = Object.entries(token.attr).flatMap(([k, v]) => v.length ? `${k}="${sanitize(v)}"` : []);
return `<img ${attributes.join(' ')} />`;
},
'inline:link': ({ token, sanitize }) => {
const attributes = Object.entries(token.attr).flatMap(([k, v]) => v.length ? `${k}="${sanitize(v)}"` : []);
const children = token.children.map(render).join('');
return `<a ${attributes.join(' ')}>${children}</a>`;
},
'modifier:strong': ({ token, render }) => `<strong>${token.children.map(render).join('')}</strong>`,
'modifier:emphasis': ({ token, render }) => `<em>${token.children.map(render).join('')}</em>`,
'modifier:strike': ({ token, render }) => `<s>${token.children.map(render).join('')}</s>`,
'inline:text': ({ token, sanitize }) => sanitize(token.text || ''),
...renderer,
};
function render(token) {
const resolve = resolver[token.type];
if (!resolve)
throw new Error(`Unknown token type: ${token.type}`);
return resolve({ render, sanitize, token });
}
return (input) => {
const { children: tokens } = compose(input);
return { tokens, html: () => tokens.map(render).join('\n') };
};
}
export const engrave = forge();
export { forge as markdown };