very-small-parser
Version:
A very small Markdown, HTML, and CSS parser.
69 lines (68 loc) • 2.73 kB
JavaScript
const escapeText = (str) => str.replace(/[\u00A0-\u9999<>\&]/gim, (i) => '&#' + i.charCodeAt(0) + ';');
const escapeAttr = (str) => str.replace(/&/g, '&').replace(/'/g, ''').replace(/</g, '<');
const PROPS = {};
/**
* Pretty-prints an HTML node to text.
*
* @param node HTML node to convert to text
* @param tab Tabulation for children
* @param ident Current indentation
* @returns Text representation of the HTML node
*/
export const toText = (node, tab = '', ident = '') => {
if (Array.isArray(node)) {
const root = { type: 'root', len: 0, children: node };
return toText(root, tab, ident);
}
const { type } = node;
switch (type) {
case 'text':
return ident + escapeText(node.value || '');
case 'comment': {
const { value } = node;
return value ? ident + '<!--' + escapeText(value) + '-->' : '';
}
// case 'doctype': return '';
case 'root':
case 'element': {
const children = node.children;
let tagName = '';
let properties = PROPS;
if (type === 'element') {
tagName = node.tagName;
properties = node.properties;
}
const isFragment = !tagName;
const childrenIdent = ident + (isFragment ? '' : tab);
const doIdent = !!tab;
let childrenStr = '';
let textOnlyChildren = true;
if (children) {
const childrenLength = children.length;
for (let i = 0; i < childrenLength; i++)
if (children[i].type !== 'text') {
textOnlyChildren = false;
break;
}
if (textOnlyChildren)
for (let i = 0; i < childrenLength; i++)
childrenStr += escapeText(children[i].value || '');
else
for (let i = 0; i < childrenLength; i++)
childrenStr += (doIdent ? (!isFragment || i ? '\n' : '') : '') + toText(children[i], tab, childrenIdent);
}
if (isFragment)
return childrenStr;
let attrStr = '';
if (properties)
for (const key in properties)
attrStr += ' ' + key + "='" + escapeAttr(properties[key] + '') + "'";
const htmlHead = '<' + tagName + attrStr;
return (ident +
(childrenStr
? htmlHead + '>' + childrenStr + (doIdent && !textOnlyChildren ? '\n' + ident : '') + '</' + tagName + '>'
: htmlHead + ' />'));
}
}
return '';
};