128 lines
3.1 KiB
JavaScript
128 lines
3.1 KiB
JavaScript
// A function that converts react-test-renderer's toJSON() result
|
|
// to HTML usable for React.hydrate()
|
|
//
|
|
// (c) Vitaliy Filippov 2021+
|
|
// License: Dual-license MPL 1.1+ or GNU LGPL 3.0+
|
|
|
|
const enclosedTags = {
|
|
br: true,
|
|
hr: true,
|
|
input: true,
|
|
img: true,
|
|
link: true,
|
|
source: true,
|
|
col: true,
|
|
area: true,
|
|
base: true,
|
|
meta: true,
|
|
embed: true,
|
|
param: true,
|
|
track: true,
|
|
wbr: true,
|
|
keygen: true,
|
|
};
|
|
|
|
const boolAttrs = {
|
|
checked: true,
|
|
selected: true,
|
|
readonly: true,
|
|
defer: true,
|
|
deferred: true,
|
|
disabled: true,
|
|
hidden: true,
|
|
multiple: true,
|
|
required: true,
|
|
reversed: true,
|
|
};
|
|
|
|
function renderToHtml(tree)
|
|
{
|
|
if (tree instanceof Array)
|
|
{
|
|
return tree.map(renderToHtml).join('');
|
|
}
|
|
else if (tree instanceof Object)
|
|
{
|
|
if (typeof(tree.type) == 'string')
|
|
{
|
|
let tag = tree.type.toLowerCase();
|
|
let children = tree.children;
|
|
let html = '<'+tag;
|
|
let k, v;
|
|
let esc = true;
|
|
for (k in tree.props)
|
|
{
|
|
v = tree.props[k];
|
|
k = k.toLowerCase();
|
|
if (k == 'classname')
|
|
{
|
|
k = 'class';
|
|
}
|
|
else if (k == 'htmlfor')
|
|
{
|
|
k = 'for';
|
|
}
|
|
else if (k == 'xlinkhref')
|
|
{
|
|
k = 'xlink:href';
|
|
}
|
|
else if (boolAttrs[k])
|
|
{
|
|
if (v)
|
|
html += ' '+k;
|
|
continue;
|
|
}
|
|
else if (k == 'style' && v instanceof Object)
|
|
{
|
|
v = Object.keys(v).map(sk => sk.replace(/[A-Z]/g, m => '-'+m.toLowerCase())+':'+v[sk]).join(';');
|
|
}
|
|
else if (k == 'value' && tag == 'textarea')
|
|
{
|
|
children = v;
|
|
continue;
|
|
}
|
|
else if (k == 'dangerouslysetinnerhtml')
|
|
{
|
|
children = v == null ? '' : v;
|
|
esc = false;
|
|
continue;
|
|
}
|
|
if (v == null || typeof v == 'function')
|
|
{
|
|
continue;
|
|
}
|
|
html += ' '+k+'="'+htmlspecialchars(''+v)+'"';
|
|
}
|
|
if (!enclosedTags[tag])
|
|
{
|
|
html += '>'+(esc ? renderToHtml(children) : children)+'</'+tag+'>';
|
|
}
|
|
else
|
|
{
|
|
html += ' />';
|
|
}
|
|
return html;
|
|
}
|
|
else
|
|
{
|
|
return renderToHtml(tree.children);
|
|
}
|
|
}
|
|
else if (tree != null)
|
|
{
|
|
return htmlspecialchars(tree);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
function htmlspecialchars(text)
|
|
{
|
|
return (''+text).replace(/&/g, '&')
|
|
.replace(/'/g, ''') // '
|
|
.replace(/"/g, '"') // "
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>');
|
|
}
|
|
|
|
module.exports = renderToHtml;
|