@zenithcore/core
Version:
Core functionality for ZenithKernel framework
58 lines (55 loc) • 1.99 kB
text/typescript
// SSR JSX runtime for ZenithKernel
import { VirtualNode, Fragment } from './jsx-ssr-virtual-runtime';
const VOID_ELEMENTS = new Set([
"area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"
]);
function escapeHtml(str: string): string {
return String(str).replace(/[&<>"']/g, (c) => ({
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
}[c] || ''));
}
export function renderToString(element: any, context: any = {}): string {
if (element == null || typeof element === "boolean") return "";
if (typeof element === "string" || typeof element === "number") {
return escapeHtml(String(element));
}
if (Array.isArray(element)) {
return element.map(child => renderToString(child, context)).join("");
}
if (typeof element === "object" && element !== null && 'type' in element && 'props' in element) {
const { type, props } = element as VirtualNode;
if (type === Fragment) {
return renderToString(props.children, context);
}
if (typeof type === "function") {
return renderToString(type({ ...props, context }), context);
}
let html = `<${type}`;
for (const [key, value] of Object.entries(props)) {
if (key === "children" || value == null) continue;
if (key === "className") {
html += ` class="${escapeHtml(String(value))}"`;
} else if (key.startsWith("on")) {
continue;
} else if (typeof value === "boolean") {
if (value) html += ` ${key}`;
// skip if false
} else {
html += ` ${key}="${escapeHtml(String(value))}"`;
}
}
if (VOID_ELEMENTS.has(type)) {
html += " />";
return html;
}
html += ">";
if (props.dangerouslySetInnerHTML && props.dangerouslySetInnerHTML.__html) {
html += props.dangerouslySetInnerHTML.__html;
} else {
html += renderToString(props.children, context);
}
html += `</${type}>`;
return html;
}
return "";
}