feat(email-renderer): compile safe semantic styles
Quality / quality (ubuntu-latest) (push) Failing after 10m18s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
Clintchiz committed 2026-09-05 11:11:02 +05:30
1 parent 353cadda60
commit 2428df6e78
3 files changed
+49 -2

No files matched your search

+31 -1
View File
@@ -30,8 +30,38 @@ const html = (value: unknown) =>
.replaceAll('"', """)
.replaceAll("'", "'");
const attrs = (node: BlockNode) => node.props as Record<string, unknown>;
const styleBase = (node: BlockNode, key: string) => {
const value = (node.styles as Record<string, unknown>)[key];
return value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>).base
: undefined;
};
const safeCssValue = (value: unknown, pattern: RegExp) => {
const candidate = String(value ?? "").trim();
return candidate.length <= 80 && pattern.test(candidate) ? candidate : "";
};
const semanticStyle = (node: BlockNode) => {
const declarations: string[] = [];
const color = safeCssValue(styleBase(node, "color"), /^(#[0-9a-f]{3,8}|rgba?\([0-9., %]+\))$/i);
const background = safeCssValue(styleBase(node, "backgroundColor"), /^(#[0-9a-f]{3,8}|rgba?\([0-9., %]+\))$/i);
const padding = safeCssValue(styleBase(node, "padding"), /^\d+(?:\.\d+)?(?:px|rem|em|%)?(?:\s+\d+(?:\.\d+)?(?:px|rem|em|%)?){0,3}$/);
const margin = safeCssValue(styleBase(node, "margin"), /^\d+(?:\.\d+)?(?:px|rem|em|%)?(?:\s+\d+(?:\.\d+)?(?:px|rem|em|%)?){0,3}$/);
const fontSize = safeCssValue(styleBase(node, "fontSize"), /^\d+(?:\.\d+)?(?:px|rem|em|%)$/);
const radius = safeCssValue(styleBase(node, "borderRadius"), /^\d+(?:\.\d+)?(?:px|rem|em|%)$/);
const align = safeCssValue(styleBase(node, "textAlign"), /^(left|center|right|start|end)$/);
const weight = safeCssValue(styleBase(node, "fontWeight"), /^(normal|bold|[1-9]00)$/);
if (color) declarations.push(`color:${color}`);
if (background) declarations.push(`background-color:${background}`);
if (padding) declarations.push(`padding:${padding}`);
if (margin) declarations.push(`margin:${margin}`);
if (fontSize) declarations.push(`font-size:${fontSize}`);
if (radius) declarations.push(`border-radius:${radius}`);
if (align) declarations.push(`text-align:${align}`);
if (weight) declarations.push(`font-weight:${weight}`);
return declarations.join(";");
};
const emailCell = (body: string, node: BlockNode) =>
`<tr><td data-block-id="${html(node.id)}" style="padding:0;">${body}</td></tr>`;
`<tr><td data-block-id="${html(node.id)}" style="padding:0;${semanticStyle(node)}">${body}</td></tr>`;
export const emailDocumentBlock = defineBlock({
manifest: {