Files
ci_cd_email_templates/dist/lib/jsx.js
T
2026-03-26 14:55:12 -05:00

97 lines
2.6 KiB
JavaScript

export const Fragment = Symbol.for("email-template.fragment");
const VOID_ELEMENTS = new Set([
"area",
"base",
"br",
"col",
"embed",
"hr",
"img",
"input",
"link",
"meta",
"param",
"source",
"track",
"wbr"
]);
export function h(type, props, ...children) {
const normalizedProps = props ?? {};
if (type === Fragment) {
return children;
}
if (typeof type === "function") {
return type({
...normalizedProps,
children
});
}
return {
type,
props: normalizedProps,
children
};
}
export function renderEmail(node) {
return minifyHtml(`<!DOCTYPE html>${renderNode(node)}`);
}
function renderNode(node) {
if (node === null || node === undefined || typeof node === "boolean") {
return "";
}
if (Array.isArray(node)) {
return node.map((child) => renderNode(child)).join("");
}
if (typeof node === "string" || typeof node === "number") {
return escapeHtml(String(node));
}
const attributes = renderAttributes(node.props);
if (VOID_ELEMENTS.has(node.type)) {
return `<${node.type}${attributes}>`;
}
const content = node.children.map((child) => renderNode(child)).join("");
return `<${node.type}${attributes}>${content}</${node.type}>`;
}
function renderAttributes(props) {
return Object.entries(props)
.filter(([key, value]) => key !== "children" && value !== null && value !== undefined && value !== false)
.map(([key, value]) => {
const attrName = key === "className" ? "class" : key;
if (value === true) {
return ` ${attrName}`;
}
if (attrName === "style") {
return ` style="${escapeAttribute(serializeStyle(value))}"`;
}
return ` ${attrName}="${escapeAttribute(String(value))}"`;
})
.join("");
}
function serializeStyle(style) {
if (typeof style === "string") {
return style.trim();
}
return Object.entries(style)
.filter(([, value]) => value !== null && value !== undefined)
.map(([key, value]) => `${toKebabCase(key)}:${String(value)}`)
.join(";");
}
function toKebabCase(value) {
return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
}
function escapeHtml(value) {
return value
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;");
}
function escapeAttribute(value) {
return escapeHtml(value).replaceAll("\"", "&quot;");
}
function minifyHtml(html) {
return html
.replace(/>\s+</g, "><")
.replace(/\s{2,}/g, " ")
.trim();
}