very-small-parser
Version:
A very small Markdown, HTML, and CSS parser.
161 lines (160 loc) • 6.08 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.toHast = void 0;
const toHast_1 = require("../inline/toHast");
const toTextChildrenInline = ({ children }) => {
const res = [];
if (!children)
return res;
const length = children.length;
for (let i = 0; i < length; i++)
res.push((0, toHast_1.toHast)(children[i]));
return res;
};
const toHastChildren = ({ children }) => {
const arr = [];
if (!children)
return arr;
const length = children.length;
for (let i = 0; i < length; i++)
arr.push((0, exports.toHast)(children[i]));
return arr;
};
const toHastChildrenSkipSingleParagraph = (node) => {
const { children } = node;
if (children?.length === 1 && children[0].type === 'paragraph')
return toTextChildrenInline(children[0]);
return toHastChildren(node);
};
const el = (tagName, properties, children) => {
const node = {
type: 'element',
tagName,
};
if (properties)
node.properties = properties;
if (children)
node.children = children;
return node;
};
const element = (tagName, block, properties, children = toHastChildren(block)) => el(tagName, properties, children);
const text = (value) => ({ type: 'text', value });
const toHast = (node) => {
if (Array.isArray(node))
return { type: 'root', children: toHastChildren({ children: node }) };
const block = node;
switch (block.type) {
case 'paragraph':
return element('p', block, void 0, toTextChildrenInline(block));
case 'code': {
const lang = block.lang || 'text';
const attr = {
class: 'language-' + lang,
'data-lang': lang,
'data-meta': block.meta || '',
};
return element('pre', block, attr, [element('code', block, { ...attr }, [text(block.value)])]);
}
case 'heading':
return element('h' + block.depth, block, void 0, toTextChildrenInline(block));
case 'blockquote': {
let attr = void 0;
if (block.spoiler)
attr = { 'data-spoiler': 'true' };
return element('blockquote', block, attr, toHastChildren(block));
}
case 'list': {
const children = block.children;
const length = children.length;
const items = [];
for (let i = 0; i < length; i++) {
const item = children[i];
const itemAttr = {};
const checked = item.checked;
if (typeof checked === 'boolean')
itemAttr['data-checked'] = checked + '';
items.push(element('li', item, itemAttr, toHastChildrenSkipSingleParagraph(item)));
}
const attr = {};
let tag = 'ul';
if (block.ordered) {
tag = 'ol';
attr.start = (block.start ?? 1) + '';
}
const list = element(tag, block, attr, items);
return list;
}
case 'thematicBreak':
return el('hr');
case 'table': {
const { align, children } = block;
const rowLength = children.length;
const columnLength = align.length;
const headerRow = children[0];
const headerRowCells = [];
const header = el('thead', void 0, [el('tr', void 0, headerRowCells)]);
if (headerRow) {
const headerCells = headerRow.children;
for (let j = 0; j < columnLength; j++) {
const alignment = align[j];
const cellAttr = alignment ? { align: alignment } : void 0;
headerRowCells.push(el('th', cellAttr, toTextChildrenInline(headerCells[j])));
}
}
const bodyRows = [];
const body = el('tbody', void 0, bodyRows);
for (let i = 1; i < rowLength; i++) {
const row = children[i];
const rowChildren = row.children;
const tds = [];
for (let j = 0; j < columnLength; j++) {
const cell = rowChildren[j];
const alignment = align[j];
const cellAttr = alignment ? { align: alignment } : void 0;
tds.push(el('td', cellAttr, toTextChildrenInline(cell)));
}
bodyRows.push(el('tr', void 0, tds));
}
const attr = {
'data-align': JSON.stringify(align),
};
return el('table', attr, [header, body]);
}
case 'definition': {
const { label, url, title, identifier: id } = block;
const attr = {
'data-node': 'definition',
'data-label': label,
'data-id': id,
'data-title': title || '',
'data-url': url,
};
return el('div', attr, [
el('a', { name: id, id }, [text(block.label)]),
text(': '),
el('a', { href: url, title: title || url }, [text(title || url)]),
]);
}
case 'footnoteDefinition': {
const id = block.identifier;
const attr = {
'data-node': 'footnoteDefinition',
'data-label': block.label,
'data-id': id,
};
return el('div', attr, [el('a', { name: id, id }, [text(block.label)]), ...toHastChildren(block)]);
}
case 'math': {
const attr = {
'data-math': 'true',
};
return element('pre', block, attr, [element('code', block, { ...attr }, [text(block.value)])]);
}
case 'element':
return block;
case '':
return element('br', block);
}
return { ...node, type: 'root', children: toHastChildren(block) };
};
exports.toHast = toHast;