@templatical/import-beefree 0.54.2 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/index.d.ts +10 -0
- package/dist/index.js +2502 -162
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/localization.ts","../src/style-parser.ts","../src/block-mapper.ts","../src/converter.ts"],"sourcesContent":["import { isLocaleTag, sourceHash } from \"@templatical/types\";\nimport type {\n Block,\n BlockLocaleLayer,\n TemplateContent,\n} from \"@templatical/types\";\n\ntype Target = { l10n?: Record<string, BlockLocaleLayer> };\n\nexport function warn(warnings: string[], message: string): void {\n if (!warnings.includes(message)) warnings.push(message);\n}\n\nexport function localeTag(value: string, warnings: string[]): string | null {\n const locale = value.replaceAll(\"_\", \"-\");\n if (isLocaleTag(locale)) return locale;\n warn(warnings, `Dropped language \"${value}\": unsupported language tag.`);\n return null;\n}\n\n/** The `defaultLocale` option as a tag; `null`, with a warning, when it isn't one. */\nexport function defaultLocaleOption(\n value: string | undefined,\n warnings: string[],\n): string | null {\n if (!value) return null;\n const locale = value.replaceAll(\"_\", \"-\");\n if (isLocaleTag(locale)) return locale;\n warn(\n warnings,\n `Ignored defaultLocale \"${value}\": unsupported language tag. Used \"en\".`,\n );\n return null;\n}\n\nexport function text(\n target: Target,\n locale: string,\n path: string,\n base: string | undefined,\n value: string,\n): void {\n if (base === undefined) {\n set(target, locale, path, value);\n return;\n }\n const layer = ((target.l10n ??= {})[locale] ??= {});\n (layer.text ??= {})[path] = { value, sourceHash: sourceHash(base) };\n}\n\nexport function set(\n target: Target,\n locale: string,\n path: string,\n value: unknown,\n): void {\n const layer = ((target.l10n ??= {})[locale] ??= {});\n (layer.set ??= {})[path] = value;\n}\n\n/** Register only non-default versions, leaving single-language imports unchanged. */\nexport function registerLocales(content: TemplateContent): void {\n const locales = new Set<string>();\n const visit = (target: Target) => {\n if (!target.l10n) return;\n delete target.l10n[content.settings.locale];\n for (const locale of Object.keys(target.l10n)) locales.add(locale);\n if (Object.keys(target.l10n).length === 0) delete target.l10n;\n };\n visit(content.settings);\n const walk = (blocks: Block[]) => {\n for (const block of blocks) {\n visit(block);\n if (block.type === \"section\") block.children.forEach(walk);\n }\n };\n walk(content.blocks);\n if (locales.size) content.settings.locales = [...locales];\n}\n","import type {\n BackgroundImage,\n BackgroundPositionX,\n BackgroundPositionY,\n BackgroundSize,\n SpacingValue,\n} from \"@templatical/types\";\n\n/**\n * Parses CSS-like style values from BeeFree descriptors.\n */\n\n/**\n * The CSS-wide keywords. Each one defers to the cascade instead of naming a\n * value, and a block field that carried one would reach the renderer\n * verbatim, so the parsers read them as unset and the caller's fallback\n * applies.\n */\nconst CSS_WIDE_KEYWORDS = new Set([\"inherit\", \"initial\", \"unset\", \"revert\"]);\n\nfunction isCssWideKeyword(value: string): boolean {\n return CSS_WIDE_KEYWORDS.has(value.trim().toLowerCase());\n}\n\nexport function parsePxValue(value: string | undefined): number {\n if (!value) return 0;\n const match = value.match(/^(-?\\d+(?:\\.\\d+)?)\\s*px/);\n return match ? Math.round(parseFloat(match[1])) : 0;\n}\n\n/**\n * An image's corner radius in px, or `undefined` for square corners.\n *\n * Accepts a percentage as well as a px length, because `border-radius: 50%` is\n * the idiomatic way to write a circular avatar and the block stores px only. A\n * percentage resolves against the shorter rendered side, which is what turns a\n * square image into a circle and a wide one into a pill.\n *\n * `width` and `height` must be the dimensions actually read from the source. A\n * percentage with neither known is dropped rather than resolved against the\n * caller's fallback width, which would invent a radius the template never\n * expressed. A non-positive result is dropped for the same reason a px `0` is:\n * both mean square, and only absence keeps it out of the exported JSON.\n */\nexport function parseImageBorderRadius(\n value: string | undefined,\n width: number | undefined,\n height: number | undefined,\n): number | undefined {\n if (!value) return undefined;\n\n // Deliberately no `-?`: a negative percentage falls through to the px parse,\n // which rejects it too.\n const percent = value.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*%$/);\n if (percent) {\n const side = Math.min(width ?? Infinity, height ?? Infinity);\n if (!Number.isFinite(side)) return undefined;\n const radius = Math.round((parseFloat(percent[1]) / 100) * side);\n return radius > 0 ? radius : undefined;\n }\n\n const px = parsePxValue(value);\n return px > 0 ? px : undefined;\n}\n\n/**\n * A color as lowercase 6-digit hex where it is hex, otherwise as written.\n *\n * `\"\"` means unset: returned for transparent, `none` and the CSS-wide\n * keywords, so the caller's fallback applies.\n */\nexport function parseColor(value: string | undefined): string {\n if (!value) return \"\";\n\n const trimmed = value.trim();\n const keyword = trimmed.toLowerCase();\n if (\n keyword === \"transparent\" ||\n keyword === \"none\" ||\n isCssWideKeyword(keyword)\n )\n return \"\";\n\n // Already a valid hex color\n if (/^#[0-9a-fA-F]{6}$/.test(trimmed)) return trimmed.toLowerCase();\n\n // 3-digit hex → 6-digit\n if (/^#[0-9a-fA-F]{3}$/.test(trimmed)) {\n const r = trimmed[1];\n const g = trimmed[2];\n const b = trimmed[3];\n return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();\n }\n\n // Return as-is for rgb(), named colors, etc.\n return trimmed;\n}\n\n/**\n * Whether a CSS colour paints nothing: `transparent`, or an alpha of 0 in a\n * hex (`#rgba`, `#rrggbbaa`) or functional (`rgba()`, `hsl(… / 0%)`) colour.\n */\nexport function isTransparentColor(value: string | undefined): boolean {\n if (!value) return false;\n const color = value.trim().toLowerCase();\n if (color === \"transparent\") return true;\n\n const hex = color.match(\n /^#(?:[0-9a-f]{3}([0-9a-f])|[0-9a-f]{6}([0-9a-f]{2}))$/,\n );\n if (hex) return /^0+$/.test(hex[1] ?? hex[2]);\n\n const fn = color.match(/^(?:rgb|hsl)a?\\((.*)\\)$/);\n if (!fn) return false;\n const alpha = fn[1].includes(\"/\") ? fn[1].split(\"/\")[1] : fn[1].split(\",\")[3];\n if (alpha === undefined) return false;\n const opacity = parseFloat(alpha);\n return Number.isFinite(opacity) && opacity <= 0;\n}\n\nconst BORDER_STYLES = new Set([\n \"none\",\n \"hidden\",\n \"dotted\",\n \"dashed\",\n \"solid\",\n \"double\",\n \"groove\",\n \"ridge\",\n \"inset\",\n \"outset\",\n]);\n\nconst BORDER_WIDTH_KEYWORDS: Record<string, number> = {\n thin: 1,\n medium: 3,\n thick: 5,\n};\n\n/** Split on whitespace outside parentheses, so `rgba(0, 0, 0, 0)` is one part. */\nfunction splitShorthand(value: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let current = \"\";\n for (const ch of value.trim()) {\n if (ch === \"(\") depth++;\n if (ch === \")\") depth = Math.max(0, depth - 1);\n if (depth === 0 && /\\s/.test(ch)) {\n if (current) parts.push(current);\n current = \"\";\n continue;\n }\n current += ch;\n }\n if (current) parts.push(current);\n return parts;\n}\n\n/**\n * A `border-top` shorthand, its parts in any order. `width` is the room the\n * border takes, so a `none` or `hidden` border has none. `drawn` is false when\n * the border paints nothing: a stated 0 width, a `none` or `hidden` style, or a\n * transparent colour. A shorthand without a width reads as 0 wide but drawn.\n */\nexport function parseBorderTop(value: string | undefined): {\n width: number;\n style: string;\n color: string;\n drawn: boolean;\n} {\n if (!value)\n return { width: 0, style: \"solid\", color: \"#000000\", drawn: true };\n\n let width: number | undefined;\n let style: string | undefined;\n let colorPart: string | undefined;\n for (const part of splitShorthand(value)) {\n const lower = part.toLowerCase();\n // Each run of digits has one way to match, so a long one fails in linear\n // time; `\\d*\\.?\\d+` could split it anywhere.\n const length = lower.match(/^(\\d+(?:\\.\\d+)?|\\.\\d+)(px)?$/);\n if (\n width === undefined &&\n length &&\n (length[2] || Number(length[1]) === 0)\n ) {\n width = Number(length[1]);\n } else if (\n width === undefined &&\n Object.hasOwn(BORDER_WIDTH_KEYWORDS, lower)\n ) {\n width = BORDER_WIDTH_KEYWORDS[lower];\n } else if (style === undefined && BORDER_STYLES.has(lower)) {\n style = lower;\n } else {\n colorPart ??= part;\n }\n }\n\n const hidden = style === \"none\" || style === \"hidden\";\n return {\n width: hidden || width === undefined ? 0 : Math.round(width),\n style: style ?? \"solid\",\n color: parseColor(colorPart) || \"#000000\",\n drawn: width !== 0 && !hidden && !isTransparentColor(colorPart),\n };\n}\n\nexport function extractPadding(\n style: Record<string, string> | undefined,\n): SpacingValue {\n if (!style) return { top: 0, right: 0, bottom: 0, left: 0 };\n\n // CSS drops a padding declaration with a negative length: a shorthand with\n // a negative side leaves the longhands, and a negative longhand leaves 0.\n if (style.padding && !hasNegativeLength(style.padding)) {\n return parseShorthandPadding(style.padding);\n }\n\n return {\n top: paddingLonghand(style[\"padding-top\"]),\n right: paddingLonghand(style[\"padding-right\"]),\n bottom: paddingLonghand(style[\"padding-bottom\"]),\n left: paddingLonghand(style[\"padding-left\"]),\n };\n}\n\nfunction paddingLonghand(value: string | undefined): number {\n return Math.max(0, parsePxValue(value));\n}\n\n/**\n * Whether a padding value holds a negative length, read before rounding:\n * `-0.4px` rounds to `-0`, which would pass as valid. A literal `-0` is 0.\n */\nfunction hasNegativeLength(value: string): boolean {\n return value\n .trim()\n .split(/\\s+/)\n .some((part) => parseFloat(part) < 0);\n}\n\nfunction parseShorthandPadding(value: string): SpacingValue {\n const parts = value.trim().split(/\\s+/);\n const values = parts.map((p) => parsePxValue(p));\n\n switch (values.length) {\n case 1:\n return {\n top: values[0],\n right: values[0],\n bottom: values[0],\n left: values[0],\n };\n case 2:\n return {\n top: values[0],\n right: values[1],\n bottom: values[0],\n left: values[1],\n };\n case 3:\n return {\n top: values[0],\n right: values[1],\n bottom: values[2],\n left: values[1],\n };\n default:\n return {\n top: values[0],\n right: values[1],\n bottom: values[2],\n left: values[3],\n };\n }\n}\n\n/**\n * A divider's `width` as a number and its unit, or `undefined` when it is\n * neither a px nor a % length (`auto`, a keyword, anything unreadable).\n */\nexport function parseDividerWidth(\n value: string,\n): { value: number; unit: \"px\" | \"%\" } | undefined {\n const match = value.trim().match(/^(-?\\d+(?:\\.\\d+)?)\\s*(%|px)$/);\n if (!match) return undefined;\n return { value: parseFloat(match[1]), unit: match[2] === \"%\" ? \"%\" : \"px\" };\n}\n\n/** A background image read from the source, with a note for each value that had no exact keyword. */\nexport interface ReadBackgroundImage {\n image: BackgroundImage;\n notes: string[];\n}\n\nconst X_GRID = [\"left\", \"center\", \"right\"] as const;\nconst Y_GRID = [\"top\", \"center\", \"bottom\"] as const;\nconst PERCENT = /^(-?(?:\\d+(?:\\.\\d+)?|\\.\\d+))%$/;\nconst LENGTH = /^-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)[a-z]*$/;\n\n/**\n * `background-size` as a keyword. A size with a side at 100%, or a px width\n * spanning the box, fills it as `cover` does; any other length or percentage\n * draws the image at a size of its own, which `auto` is closest to.\n */\nfunction backgroundSizeKeyword(\n raw: string,\n boxWidth: number | undefined,\n): { size: BackgroundSize; exact: boolean } {\n const parts = raw.toLowerCase().split(/\\s+/);\n const [first] = parts;\n if (parts.length === 1 && (first === \"cover\" || first === \"contain\")) {\n return { size: first, exact: true };\n }\n if (parts.every((part) => part === \"auto\")) {\n return { size: \"auto\", exact: true };\n }\n const px = /^(\\d+(?:\\.\\d+)?|\\.\\d+)px$/.exec(first);\n const fills =\n parts.includes(\"100%\") ||\n (px !== null && boxWidth !== undefined && Number(px[1]) >= boxWidth);\n return { size: fills ? \"cover\" : \"auto\", exact: false };\n}\n\n/**\n * `background-position` split into x and y the way MJML and CSS read it: a\n * lone `top` / `bottom` names y and centres x, any other lone value is x\n * with y centred, and a pair is x then y unless it leads with `top` /\n * `bottom` (or with `center` before `left` / `right`). Three- and four-value\n * edge offsets keep their edge keywords only.\n */\nfunction splitBackgroundPosition(raw: string): {\n x: string;\n y: string;\n exact: boolean;\n} {\n const parts = raw.toLowerCase().split(/\\s+/);\n if (parts.length === 1) {\n const [only] = parts;\n return only === \"top\" || only === \"bottom\"\n ? { x: \"center\", y: only, exact: true }\n : { x: only, y: \"center\", exact: true };\n }\n if (parts.length === 2) {\n const [a, b] = parts;\n const yFirst =\n a === \"top\" ||\n a === \"bottom\" ||\n (a === \"center\" && (b === \"left\" || b === \"right\"));\n return yFirst ? { x: b, y: a, exact: true } : { x: a, y: b, exact: true };\n }\n return {\n x: parts.find((part) => part === \"left\" || part === \"right\") ?? \"center\",\n y: parts.find((part) => part === \"top\" || part === \"bottom\") ?? \"center\",\n exact: false,\n };\n}\n\n/**\n * One axis as a grid point: its keyword; the point nearest a percentage,\n * ties going to the centre; or the start edge for a length, which is an\n * offset from it. `null` when the token is unreadable.\n */\nfunction backgroundAxisPoint<T extends string>(\n token: string,\n grid: readonly [T, T, T],\n): { point: T; exact: boolean } | null {\n const keyword = grid.find((point) => point === token);\n if (keyword) return { point: keyword, exact: true };\n const percent = PERCENT.exec(token);\n if (percent) {\n const n = Number(percent[1]);\n return {\n point: n < 25 ? grid[0] : n > 75 ? grid[2] : grid[1],\n exact: n === 0 || n === 50 || n === 100,\n };\n }\n if (LENGTH.test(token)) {\n return { point: grid[0], exact: parseFloat(token) === 0 };\n }\n return null;\n}\n\n/**\n * `background-repeat`: unrepeated only when every axis is `no-repeat`.\n * Anything but plain `repeat` tiles too, inexactly.\n */\nfunction backgroundRepeatFlag(raw: string): {\n repeat: boolean;\n exact: boolean;\n} {\n const parts = raw.toLowerCase().split(/\\s+/);\n if (parts.every((part) => part === \"no-repeat\")) {\n return { repeat: false, exact: true };\n }\n return { repeat: true, exact: parts.every((part) => part === \"repeat\") };\n}\n\n/** CSS's initial values: what a browser paints for a longhand BeeFree leaves out. */\nconst CSS_BACKGROUND_DEFAULTS = {\n size: \"auto\",\n x: \"left\",\n y: \"top\",\n repeat: true,\n} as const;\n\n/**\n * The URL inside the first CSS `url(…)`, unquoted and trimmed; \"\" when there\n * is none or it is malformed. A forward scan rather than a regex, so a long\n * run of unclosed `url(` can't make it backtrack.\n */\nfunction cssUrl(value: string | undefined): string {\n const text = value ?? \"\";\n const start = text.search(/url\\(/i);\n if (start === -1) return \"\";\n let i = start + 4;\n while (i < text.length && /\\s/.test(text[i])) i++;\n const quote = text[i];\n if (quote === '\"' || quote === \"'\") {\n const close = text.indexOf(quote, i + 1);\n if (close === -1) return \"\";\n let j = close + 1;\n while (j < text.length && /\\s/.test(text[j])) j++;\n return text[j] === \")\" ? text.slice(i + 1, close).trim() : \"\";\n }\n const close = text.indexOf(\")\", i);\n if (close === -1) return \"\";\n const inner = text.slice(i, close);\n return /[\"']/.test(inner) ? \"\" : inner.trim();\n}\n\n/**\n * A row's background image from a BeeFree style map (`content.style` or\n * `container.style`), `null` when `background-image` holds no `url()`.\n * Unset longhands take CSS's initial values; a value with no exact keyword\n * takes the nearest one and adds a note naming it. `label` names the element\n * in each note, and a px `background-size` is measured against `boxWidth`.\n */\nexport function readBeefreeBackgroundImage(\n style: Record<string, string> | undefined,\n label: string,\n boxWidth: number | undefined,\n): ReadBackgroundImage | null {\n const url = cssUrl(style?.[\"background-image\"]);\n if (!url) return null;\n\n const notes: string[] = [];\n const lossy = (name: string, raw: string, shown: string): void => {\n notes.push(\n `${label} ${name} \"${raw}\" has no exact Templatical equivalent; imported as \"${shown}\".`,\n );\n };\n\n let size: BackgroundSize = CSS_BACKGROUND_DEFAULTS.size;\n const rawSize = style?.[\"background-size\"]?.trim();\n if (rawSize) {\n const parsed = backgroundSizeKeyword(rawSize, boxWidth);\n size = parsed.size;\n if (!parsed.exact) lossy(\"background-size\", rawSize, size);\n }\n\n let x: BackgroundPositionX = CSS_BACKGROUND_DEFAULTS.x;\n let y: BackgroundPositionY = CSS_BACKGROUND_DEFAULTS.y;\n const rawPosition = style?.[\"background-position\"]?.trim();\n if (rawPosition) {\n const split = splitBackgroundPosition(rawPosition);\n const readX = backgroundAxisPoint(split.x, X_GRID);\n const readY = backgroundAxisPoint(split.y, Y_GRID);\n x = readX?.point ?? x;\n y = readY?.point ?? y;\n if (!split.exact || !readX?.exact || !readY?.exact) {\n lossy(\"background-position\", rawPosition, `${x} ${y}`);\n }\n }\n\n let repeat: boolean = CSS_BACKGROUND_DEFAULTS.repeat;\n const rawRepeat = style?.[\"background-repeat\"]?.trim();\n if (rawRepeat) {\n const parsed = backgroundRepeatFlag(rawRepeat);\n repeat = parsed.repeat;\n if (!parsed.exact) {\n lossy(\"background-repeat\", rawRepeat, repeat ? \"repeat\" : \"no-repeat\");\n }\n }\n\n return { image: { url, size, position: { x, y }, repeat }, notes };\n}\n","import { localeTag, text, warn } from \"./localization\";\nimport {\n canonicalFontStack,\n isSafeHtmlUrl,\n createTitleBlock,\n createParagraphBlock,\n createImageBlock,\n createButtonBlock,\n createDividerBlock,\n createSpacerBlock,\n createHtmlBlock,\n createSocialIconsBlock,\n createMenuBlock,\n createTableBlock,\n createVideoBlock,\n generateId,\n} from \"@templatical/types\";\nimport type {\n Block,\n DividerBlock,\n HeadingLevel,\n ImageBlock,\n SocialPlatform,\n SocialIcon,\n MenuItemData,\n SpacingValue,\n TableRowData,\n TableCellData,\n} from \"@templatical/types\";\nimport type {\n BeeFreeeIconItem,\n BeeFreeeModule,\n BeeFreeeModuleDescriptor,\n BeeFreeeSocialIcon,\n ImportReportEntry,\n} from \"./types\";\nimport {\n parseImageBorderRadius,\n parsePxValue,\n parseColor,\n parseBorderTop,\n extractPadding,\n parseDividerWidth,\n} from \"./style-parser\";\n\n/**\n * The template text color the import writes when the body sets none.\n */\nexport const FALLBACK_TEXT_COLOR = \"#1a1a1a\";\n\n/**\n * What the caller knows about where a module lands.\n */\nexport interface ModuleContext {\n /**\n * Width in px of the Templatical column the block renders in. Without it a\n * px divider width is kept as pixels.\n */\n columnWidth?: number;\n /**\n * The template's `textColor`, which every text block without a color of\n * its own inherits. Defaults to `FALLBACK_TEXT_COLOR`.\n */\n textColor?: string;\n}\n\n/**\n * Maps BeeFree module type strings to short keys.\n */\nconst MODULE_TYPE_MAP: Record<string, string> = {\n \"mailup-bee-newsletter-modules-text\": \"paragraph\",\n \"mailup-bee-newsletter-modules-paragraph\": \"paragraph\",\n \"mailup-bee-newsletter-modules-heading\": \"title\",\n \"mailup-bee-newsletter-modules-list\": \"list\",\n \"mailup-bee-newsletter-modules-image\": \"image\",\n \"mailup-bee-newsletter-modules-button\": \"button\",\n \"mailup-bee-newsletter-modules-divider\": \"divider\",\n \"mailup-bee-newsletter-modules-spacer\": \"spacer\",\n \"mailup-bee-newsletter-modules-html\": \"html\",\n \"mailup-bee-newsletter-modules-social\": \"social\",\n \"mailup-bee-newsletter-modules-video\": \"video\",\n \"mailup-bee-newsletter-modules-menu\": \"menu\",\n \"mailup-bee-newsletter-modules-table\": \"table\",\n \"mailup-bee-newsletter-modules-icons\": \"icons\",\n};\n\nconst ADDON_MODULE = \"mailup-bee-newsletter-modules-addon\";\nconst EMPTY_MODULE = \"mailup-bee-newsletter-modules-empty\";\n\n/**\n * An addon keeps the payload of the module it stands in for, so the payload it\n * carries names the converter. Checked in this order.\n */\nconst ADDON_PAYLOADS = [\n [\"image\", \"image\"],\n [\"html\", \"html\"],\n [\"heading\", \"title\"],\n [\"paragraph\", \"paragraph\"],\n [\"text\", \"paragraph\"],\n [\"list\", \"list\"],\n [\"button\", \"button\"],\n [\"divider\", \"divider\"],\n [\"menu\", \"menu\"],\n [\"iconsList\", \"icons\"],\n] as const;\n\n/** The converter a module goes to, or `undefined` when there is none. */\nfunction moduleKind(module: BeeFreeeModule): string | undefined {\n if (module.type !== ADDON_MODULE) return MODULE_TYPE_MAP[module.type];\n return ADDON_PAYLOADS.find(\n ([key]) => module.descriptor[key] !== undefined,\n )?.[1];\n}\n\nconst SOCIAL_PLATFORM_MAP: Record<string, SocialPlatform> = {\n facebook: \"facebook\",\n twitter: \"twitter\",\n x: \"twitter\",\n instagram: \"instagram\",\n linkedin: \"linkedin\",\n youtube: \"youtube\",\n tiktok: \"tiktok\",\n pinterest: \"pinterest\",\n email: \"email\",\n whatsapp: \"whatsapp\",\n telegram: \"telegram\",\n discord: \"discord\",\n snapchat: \"snapchat\",\n reddit: \"reddit\",\n github: \"github\",\n dribbble: \"dribbble\",\n behance: \"behance\",\n};\n\ntype Align = \"left\" | \"center\" | \"right\";\ntype LineStyle = \"solid\" | \"dashed\" | \"dotted\";\n\nfunction toAlign(value: string | undefined, fallback: Align = \"left\"): Align {\n if (value === \"left\" || value === \"center\" || value === \"right\") return value;\n return fallback;\n}\n\nfunction toLineStyle(\n value: string | undefined,\n fallback: LineStyle = \"solid\",\n): LineStyle {\n if (value === \"solid\" || value === \"dashed\" || value === \"dotted\")\n return value;\n return fallback;\n}\n\n/**\n * Strip every `<…>` from a button label and reject any stray `<` or `>`\n * left behind (e.g. a truncated `<script`). The original\n * `value.replace(/<[^>]*>/g, \"\")` was both polynomial-ReDoS over\n * `<<<<…` inputs and an incomplete sanitizer — an unterminated `<script`\n * would survive the strip. Downstream HTML-escapes the label at render\n * time, but stripping here keeps the imported JSON clean.\n */\nfunction stripTagsPlain(text: string): string {\n let out = \"\";\n let i = 0;\n while (i < text.length) {\n if (text[i] === \"<\") {\n const close = text.indexOf(\">\", i + 1);\n if (close === -1) {\n // Unterminated tag — discard the rest.\n break;\n }\n i = close + 1;\n continue;\n }\n if (text[i] === \">\") {\n i++;\n continue;\n }\n out += text[i];\n i++;\n }\n return out;\n}\n\nfunction makeStyles(descriptor: BeeFreeeModuleDescriptor): Block[\"styles\"] {\n const padding = extractPadding(descriptor.style);\n const bg = parseColor(descriptor.style?.[\"background-color\"]);\n return {\n padding,\n ...(bg ? { backgroundColor: bg } : {}),\n };\n}\n\n/**\n * Apply BeeFree text styles as TipTap-compatible inline markup.\n * - text-align → added to each <p> tag's style attribute\n * - color, font-size, font-weight, font-family → wrapped in <span style=\"...\"> inside each <p>\n */\nfunction inlineStylesToHtml(\n html: string,\n style: Record<string, string | undefined>,\n textColor: string,\n): string {\n const spanParts: string[] = [];\n const fontSize = parsePxValue(style[\"font-size\"]);\n if (fontSize && fontSize !== 16) spanParts.push(`font-size: ${fontSize}px`);\n const color = parseColor(style.color);\n // A paragraph inherits the template's text color, so only a different\n // color needs a span to survive.\n if (color && color !== textColor) spanParts.push(`color: ${color}`);\n const fontWeight = style[\"font-weight\"];\n // \"400\" is the numeric synonym for \"normal\" — neither needs an explicit\n // span (matches the import-unlayer importer).\n if (fontWeight && fontWeight !== \"normal\" && fontWeight !== \"400\")\n spanParts.push(`font-weight: ${fontWeight}`);\n const fontFamily = canonicalFontStack(style[\"font-family\"]);\n if (fontFamily) spanParts.push(`font-family: ${fontFamily}`);\n\n const textAlign = style[\"text-align\"];\n const pStyle =\n textAlign && textAlign !== \"left\" ? `text-align: ${textAlign}` : \"\";\n\n if (!pStyle && spanParts.length === 0) return html;\n\n const spanStyle = spanParts.join(\"; \");\n\n // Apply styles to each <p> tag in the HTML\n let result = html;\n\n if (pStyle) {\n // Add text-align to existing <p style=\"...\"> or add style to plain <p>\n result = result\n .replace(/<p style=\"([^\"]*)\">/g, `<p style=\"$1; ${pStyle}\">`)\n .replaceAll(\"<p>\", `<p style=\"${pStyle}\">`);\n }\n\n if (spanStyle) {\n // Wrap inner content of each <p> in a styled span.\n result = wrapParagraphInner(result, spanStyle);\n }\n\n return result;\n}\n\n/**\n * Wrap the inner content of every `<p …>…</p>` with `<span style=\"…\">…</span>`.\n *\n * Hand-rolled linear scanner instead of `/<p([^>]*)>([\\s\\S]*?)<\\/p>/g` because\n * the regex is polynomial-ReDoS: the engine retries `[\\s\\S]*?<\\/p>` at every\n * `<p` start, so inputs like `<p>a<p>a<p>a…` (no `</p>` ever) cost O(n²).\n * The scanner advances `i` monotonically via `indexOf`, keeping the work\n * strictly O(n).\n */\nfunction wrapParagraphInner(html: string, spanStyle: string): string {\n let out = \"\";\n let i = 0;\n while (i < html.length) {\n const open = html.indexOf(\"<p\", i);\n if (open === -1) {\n out += html.substring(i);\n break;\n }\n const afterTagName = html[open + 2];\n if (\n afterTagName !== \">\" &&\n afterTagName !== \" \" &&\n afterTagName !== \"\\t\" &&\n afterTagName !== \"\\n\" &&\n afterTagName !== \"\\r\" &&\n afterTagName !== \"/\"\n ) {\n out += html.substring(i, open + 2);\n i = open + 2;\n continue;\n }\n const openEnd = html.indexOf(\">\", open + 2);\n if (openEnd === -1) {\n out += html.substring(i);\n break;\n }\n const closeStart = html.indexOf(\"</p>\", openEnd + 1);\n if (closeStart === -1) {\n out += html.substring(i);\n break;\n }\n const inner = html.substring(openEnd + 1, closeStart);\n out += html.substring(i, openEnd + 1);\n out += `<span style=\"${spanStyle}\">${inner}</span></p>`;\n i = closeStart + 4;\n }\n return out;\n}\n\nfunction convertText(\n descriptor: BeeFreeeModuleDescriptor,\n textColor: string,\n): Block {\n const textContent =\n descriptor.text ?? descriptor.paragraph ?? descriptor.list;\n const html = textContent?.html ?? \"\";\n const style = textContent?.style ?? {};\n\n return createParagraphBlock({\n content: inlineStylesToHtml(html, style, textColor),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction parseHeadingLevel(tag: string): HeadingLevel {\n const match = tag.match(/^h(\\d)$/i);\n if (match) {\n const num = Number(match[1]);\n if (num >= 1 && num <= 4) return num as HeadingLevel;\n }\n return 2;\n}\n\nfunction convertHeading(\n descriptor: BeeFreeeModuleDescriptor,\n textColor: string,\n): Block {\n const heading = descriptor.heading;\n if (!heading) return convertText(descriptor, textColor);\n\n const style = heading.style ?? {};\n const tag = heading.title ?? \"h2\";\n const text = heading.text ?? \"\";\n // Strip heading tags — content goes inside TipTap, heading tag is rendered by the block\n const content = text.startsWith(\"<\")\n ? text.replace(/^<h\\d[^>]*>|<\\/h\\d>$/gi, \"\")\n : text;\n\n return createTitleBlock({\n content: content ? `<p>${content}</p>` : \"<p></p>\",\n level: parseHeadingLevel(tag),\n color: parseColor(style.color) || undefined,\n textAlign: toAlign(style[\"text-align\"]),\n fontFamily: canonicalFontStack(style[\"font-family\"]) || undefined,\n styles: makeStyles(descriptor),\n });\n}\n\n/**\n * The classes BeeFree records in `computedStyle.class` for an image: its\n * alignment, `autowidth` / `fixedwidth`, and in older exports `fullwidth`.\n */\nfunction computedClasses(descriptor: BeeFreeeModuleDescriptor): string[] {\n const value = descriptor.computedStyle?.class;\n return typeof value === \"string\" ? value.trim().split(/\\s+/) : [];\n}\n\n/**\n * A px length BeeFree computed: `\"172.5px\"`, or a bare number in older\n * exports. 0 when it isn't one.\n */\nfunction computedPx(value: unknown): number {\n if (typeof value === \"number\") {\n return Number.isFinite(value) && value > 0 ? Math.round(value) : 0;\n }\n return typeof value === \"string\" ? parsePxValue(value) : 0;\n}\n\n/**\n * The width BeeFree shows an image at, as `ImageBlock.width`. BeeFree records\n * it in `computedStyle.width` for both classes: a `fixedwidth` image at the\n * width the author set, an `autowidth` one at its file's width capped at the\n * column. `image.width` and `image.height` are the file's own size, the\n * fallback for an export without `computedStyle`. No width, or one that\n * reaches `room` (the column less the image's side padding), is `\"full\"`.\n * Older exports class an image that fills its column `fullwidth`, and its\n * computed width leaves out the column padding the import drops, so the class\n * decides. A computed percentage under 100% becomes px of `room`, with a note:\n * px keeps its size on a phone, where the percentage would shrink.\n */\nfunction resolveImageWidth(\n descriptor: BeeFreeeModuleDescriptor,\n room: number | undefined,\n): { width: ImageBlock[\"width\"]; note?: string } {\n if (computedClasses(descriptor).includes(\"fullwidth\")) {\n return { width: \"full\" };\n }\n const percent = computedPercent(descriptor.computedStyle?.width);\n if (percent !== undefined) {\n if (percent >= 100) return { width: \"full\" };\n const width =\n room === undefined\n ? \"full\"\n : shownWidth(Math.round((room * percent) / 100), room);\n const label = width === \"full\" ? \"full width\" : `${width}px`;\n return {\n width,\n note: `Image width ${percent}% was converted to ${label}.`,\n };\n }\n const shown =\n computedPx(descriptor.computedStyle?.width) ||\n parsePxValue(descriptor.image?.width);\n return { width: shownWidth(shown, room) };\n}\n\n/** A percentage BeeFree computed (`\"50%\"`), or `undefined` when it isn't one. */\nfunction computedPercent(value: unknown): number | undefined {\n if (typeof value !== \"string\") return undefined;\n const match = /^(\\d+(?:\\.\\d+)?|\\.\\d+)%$/.exec(value.trim());\n return match ? parseFloat(match[1]) : undefined;\n}\n\n/** A shown px width as `ImageBlock.width`: `\"full\"` when unknown or at `room`. */\nfunction shownWidth(\n shown: number,\n room: number | undefined,\n): ImageBlock[\"width\"] {\n if (shown <= 0) return \"full\";\n return room !== undefined && shown >= room ? \"full\" : shown;\n}\n\nfunction convertImage(\n descriptor: BeeFreeeModuleDescriptor,\n columnWidth: number | undefined,\n): { block: Block; notes: string[] } {\n const image = descriptor.image;\n const styles = makeStyles(descriptor);\n if (!image) {\n return { block: createImageBlock({ styles }), notes: [] };\n }\n\n const room =\n columnWidth === undefined\n ? undefined\n : columnWidth - styles.padding.left - styles.padding.right;\n const { width, note } = resolveImageWidth(descriptor, room);\n\n // `image.width` × `image.height` is the file, so the height is never carried\n // over: the image keeps its aspect ratio at the width it is shown at. A\n // percentage radius resolves against that shown size, and only when BeeFree\n // stated a width.\n const fileWidth = parsePxValue(image.width);\n const fileHeight = parsePxValue(image.height);\n const shownWidth = width === \"full\" ? room : width;\n const stated = fileWidth > 0 || width !== \"full\";\n const shownHeight =\n shownWidth !== undefined && fileWidth > 0 && fileHeight > 0\n ? Math.round((fileHeight * shownWidth) / fileWidth)\n : undefined;\n\n const classes = computedClasses(descriptor);\n const classAlign = ([\"left\", \"center\", \"right\"] as const).find((side) =>\n classes.includes(side),\n );\n\n const block = createImageBlock({\n src: image.src || \"\",\n alt: image.alt || \"\",\n width,\n // The file's size feeds the editor's aspect-ratio lock; never rendered.\n ...(fileWidth > 0 && fileHeight > 0\n ? { naturalWidth: fileWidth, naturalHeight: fileHeight }\n : {}),\n borderRadius: parseImageBorderRadius(\n image.style?.[\"border-radius\"],\n stated ? shownWidth : undefined,\n shownHeight,\n ),\n // Exports keep the alignment in `computedStyle.class` (\"left fixedwidth\")\n // and often have no image `style` at all.\n align: toAlign(image.style?.[\"text-align\"] ?? classAlign, \"center\"),\n linkUrl: image.href || undefined,\n styles,\n });\n return { block, notes: note ? [note] : [] };\n}\n\nfunction convertButton(descriptor: BeeFreeeModuleDescriptor): Block {\n const button = descriptor.button;\n if (!button) {\n return createButtonBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = button.style ?? {};\n const label = button.label ? stripTagsPlain(button.label) : \"Button\";\n\n return createButtonBlock({\n text: label,\n url: button.href || \"#\",\n backgroundColor: parseColor(style[\"background-color\"]) || \"#4f46e5\",\n textColor: parseColor(style.color) || \"#ffffff\",\n borderRadius: parsePxValue(style[\"border-radius\"]),\n fontSize: parsePxValue(style[\"font-size\"]) || 16,\n fontFamily: canonicalFontStack(style[\"font-family\"]) || undefined,\n align: toAlign(style[\"text-align\"], \"center\"),\n buttonPadding: {\n top: parsePxValue(style[\"padding-top\"]) || 12,\n right: parsePxValue(style[\"padding-right\"]) || 24,\n bottom: parsePxValue(style[\"padding-bottom\"]) || 12,\n left: parsePxValue(style[\"padding-left\"]) || 24,\n },\n styles: makeStyles(descriptor),\n });\n}\n\n/**\n * `\"full\"` when the divider spans its column: no width, `100%`, or a px width\n * that reaches `contentWidth`. Without a `contentWidth` a px width stands as\n * stated. Any other percentage stays a percentage, clamped to 0–100%.\n */\nfunction resolveDividerWidth(\n value: string | undefined,\n contentWidth: number | undefined,\n notes: string[],\n): DividerBlock[\"width\"] {\n const raw = (value ?? \"\").trim();\n if (!raw) return \"full\";\n\n const parsed = parseDividerWidth(raw);\n if (!parsed) {\n notes.push(\n `Divider width \"${raw}\" could not be read; imported as full width.`,\n );\n return \"full\";\n }\n\n if (parsed.unit === \"%\") {\n const percent = Math.min(100, Math.max(0, parsed.value));\n if (percent !== parsed.value) {\n notes.push(`Divider width ${raw} was clamped to ${percent}%.`);\n }\n // Two decimals keep the value inside `DividerPercentWidth`'s pattern,\n // which a float printed in exponent form would leave.\n const share = Math.round(percent * 100) / 100;\n return share === 100 ? \"full\" : `${share}%`;\n }\n\n const px = Math.max(0, Math.round(parsed.value));\n if (px !== Math.round(parsed.value)) {\n notes.push(`Divider width ${raw} was clamped to 0px.`);\n }\n return contentWidth !== undefined && px >= contentWidth ? \"full\" : px;\n}\n\nfunction convertDivider(\n descriptor: BeeFreeeModuleDescriptor,\n columnWidth: number | undefined,\n): { block: Block; notes: string[] } {\n const style = descriptor.divider?.style ?? {};\n const border = parseBorderTop(style[\"border-top\"]);\n const styles = makeStyles(descriptor);\n const notes: string[] = [];\n\n // MJML draws a full divider across its column less the divider's own\n // padding, so a px width that reaches that renders the same as \"full\", and\n // \"full\" keeps narrowing with the column on a phone.\n const contentWidth =\n columnWidth === undefined\n ? undefined\n : columnWidth - styles.padding.left - styles.padding.right;\n const width = resolveDividerWidth(style.width, contentWidth, notes);\n\n const align = dividerAlign(descriptor);\n if (width !== \"full\" && (align === \"left\" || align === \"right\")) {\n notes.push(\n `BeeFree aligns this divider ${align}; Templatical centres every divider.`,\n );\n }\n\n return {\n block: createDividerBlock({\n lineStyle: toLineStyle(border.style),\n color: border.color,\n thickness: border.width || 1,\n width,\n styles,\n }),\n notes,\n };\n}\n\n/**\n * BeeFree keeps a divider's alignment in `computedStyle.align`; some exports\n * also write it to the module style's `text-align`.\n */\nfunction dividerAlign(\n descriptor: BeeFreeeModuleDescriptor,\n): string | undefined {\n const computed = descriptor.computedStyle?.align;\n return typeof computed === \"string\"\n ? computed\n : descriptor.style?.[\"text-align\"];\n}\n\n/**\n * The room a divider that draws no line takes: its top and bottom padding plus\n * the width of a transparent border. `undefined` when the line is drawn.\n * BeeFree templates space content this way.\n */\nfunction undrawnDividerHeight(\n descriptor: BeeFreeeModuleDescriptor,\n): number | undefined {\n const border = parseBorderTop(descriptor.divider?.style?.[\"border-top\"]);\n if (border.drawn) return undefined;\n const padding = extractPadding(descriptor.style);\n return padding.top + border.width + padding.bottom;\n}\n\n/**\n * A divider that draws no line, as a spacer of the same height. A spacer\n * renders no padding, so the divider's padding goes into the height.\n */\nfunction convertUndrawnDivider(\n descriptor: BeeFreeeModuleDescriptor,\n height: number,\n): Block {\n return createSpacerBlock({\n height,\n styles: {\n ...makeStyles(descriptor),\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n },\n });\n}\n\nfunction convertSpacer(descriptor: BeeFreeeModuleDescriptor): Block {\n const spacer = descriptor.spacer;\n const height = parsePxValue(spacer?.style?.height) || 24;\n\n return createSpacerBlock({\n height,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertHtml(descriptor: BeeFreeeModuleDescriptor): Block {\n const html = descriptor.html?.html ?? \"\";\n\n return createHtmlBlock({\n content: html,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertSocial(\n descriptor: BeeFreeeModuleDescriptor,\n warnings: string[],\n): Block {\n const iconsList = descriptor.iconsList;\n if (!iconsList?.icons) {\n return createSocialIconsBlock({ styles: makeStyles(descriptor) });\n }\n\n const icons: SocialIcon[] = [];\n\n // The Icons module keeps items of another shape under the same key.\n for (const beeIcon of iconsList.icons as BeeFreeeSocialIcon[]) {\n const id = (beeIcon.id ?? beeIcon.name ?? \"\").toLowerCase();\n const platform = SOCIAL_PLATFORM_MAP[id];\n\n if (!platform) {\n warnings.push(\n `Unrecognized social icon \"${beeIcon.name || id}\" was skipped.`,\n );\n continue;\n }\n\n icons.push({\n id: generateId(),\n platform,\n url: beeIcon.image?.href || \"#\",\n });\n }\n\n return createSocialIconsBlock({\n icons,\n styles: makeStyles(descriptor),\n });\n}\n\n/** Escape `& < > \"` for text content and attribute values. */\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\");\n}\n\nfunction stringField(value: unknown): string {\n return typeof value === \"string\" ? value : \"\";\n}\n\nfunction iconItems(descriptor: BeeFreeeModuleDescriptor): BeeFreeeIconItem[] {\n const icons = descriptor.iconsList?.icons;\n return Array.isArray(icons) ? (icons as BeeFreeeIconItem[]) : [];\n}\n\n/** The padding BeeFree keeps around each icon, `computedStyle.iconSpacing`. */\nfunction iconSpacing(descriptor: BeeFreeeModuleDescriptor): SpacingValue {\n const value = descriptor.computedStyle?.iconSpacing;\n if (typeof value !== \"object\" || value === null) return extractPadding({});\n return extractPadding(\n Object.fromEntries(\n Object.entries(value).filter(([, side]) => typeof side === \"string\"),\n ),\n );\n}\n\n/**\n * The height BeeFree draws every icon at, and an icon's width at that height,\n * from its file's size. The width is `undefined` when the size isn't stated.\n */\nfunction iconSize(\n descriptor: BeeFreeeModuleDescriptor,\n item: BeeFreeeIconItem,\n): { height: number; width: number | undefined } {\n const height = computedPx(descriptor.computedStyle?.iconHeight) || 32;\n const fileWidth = parsePxValue(stringField(item.width));\n const fileHeight = parsePxValue(stringField(item.height));\n return {\n height,\n width:\n fileWidth > 0 && fileHeight > 0\n ? Math.round((height * fileWidth) / fileHeight)\n : undefined,\n };\n}\n\n/**\n * A lone icon without text, as an image block at the icon height. `undefined`\n * when the module holds anything else, or the icon's file size is unknown.\n */\nfunction convertSingleIcon(\n descriptor: BeeFreeeModuleDescriptor,\n columnWidth: number | undefined,\n): Block | undefined {\n const items = iconItems(descriptor);\n if (items.length !== 1) return undefined;\n const [item] = items;\n const src = stringField(item.image);\n const { width } = iconSize(descriptor, item);\n if (!src || stringField(item.text) || width === undefined) return undefined;\n\n // The module's padding plus the space BeeFree keeps around the icon.\n const styles = makeStyles(descriptor);\n const spacing = iconSpacing(descriptor);\n const padding = {\n top: styles.padding.top + spacing.top,\n right: styles.padding.right + spacing.right,\n bottom: styles.padding.bottom + spacing.bottom,\n left: styles.padding.left + spacing.left,\n };\n const room =\n columnWidth === undefined\n ? undefined\n : columnWidth - padding.left - padding.right;\n\n return createImageBlock({\n src,\n alt: stringField(item.alt),\n width: shownWidth(width, room),\n naturalWidth: parsePxValue(stringField(item.width)),\n naturalHeight: parsePxValue(stringField(item.height)),\n align: toAlign(descriptor.style?.[\"text-align\"]),\n linkUrl: stringField(item.href) || undefined,\n styles: { ...styles, padding },\n });\n}\n\n/** The module's text style as CSS declarations, for the icons' text cells. */\nfunction iconTextStyle(style: Record<string, string>): string {\n const color = parseColor(style.color);\n const fontFamily = canonicalFontStack(style[\"font-family\"]);\n const fontSize = parsePxValue(style[\"font-size\"]);\n const fontWeight = style[\"font-weight\"];\n return [\n color ? `color: ${color};` : \"\",\n fontFamily ? `font-family: ${fontFamily};` : \"\",\n fontSize ? `font-size: ${fontSize}px;` : \"\",\n fontWeight ? `font-weight: ${fontWeight};` : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\n/**\n * The Icons module as the table BeeFree draws: the icons side by side, each at\n * the icon height inside its `iconSpacing`, with its text on the side\n * `textPosition` names, in the module's text style.\n */\nfunction iconsHtml(descriptor: BeeFreeeModuleDescriptor): string {\n const style = descriptor.style ?? {};\n const computed = descriptor.computedStyle ?? {};\n const align = toAlign(style[\"text-align\"]);\n const color = parseColor(style.color);\n const textStyle = iconTextStyle(style);\n const gap =\n computedPx(computed.itemsSpacing) || computedPx(computed.itemSpacing);\n const spacing = iconSpacing(descriptor);\n const iconPadding =\n spacing.top || spacing.right || spacing.bottom || spacing.left\n ? `padding: ${spacing.top}px ${spacing.right}px ${spacing.bottom}px ${spacing.left}px; `\n : \"\";\n\n const items = iconItems(descriptor).map((item, index) => {\n const position = stringField(item.textPosition);\n const stacked = position === \"top\" || position === \"bottom\";\n const cellAlign = stacked ? ' align=\"center\"' : \"\";\n const href = stringField(item.href);\n const target = stringField(item.target);\n const link = (inner: string, linkStyle: string) =>\n href\n ? `<a href=\"${escapeHtml(href)}\"${target ? ` target=\"${escapeHtml(target)}\"` : \"\"} style=\"${escapeHtml(linkStyle)}\">${inner}</a>`\n : inner;\n\n const src = stringField(item.image);\n const { height, width } = iconSize(descriptor, item);\n const title = stringField(item.title);\n const imgStyle = [\n \"display: block;\",\n stacked ? \"margin: 0 auto;\" : \"\",\n width === undefined ? \"\" : `width: ${width}px;`,\n `height: ${height}px;`,\n \"border: 0;\",\n ]\n .filter(Boolean)\n .join(\" \");\n const img = `<img src=\"${escapeHtml(src)}\" alt=\"${escapeHtml(stringField(item.alt))}\"${title ? ` title=\"${escapeHtml(title)}\"` : \"\"}${width === undefined ? \"\" : ` width=\"${width}\"`} height=\"${height}\" style=\"${imgStyle}\">`;\n const iconCell = src\n ? `<td${cellAlign} style=\"${iconPadding}vertical-align: middle;\">${link(img, \"text-decoration: none;\")}</td>`\n : \"\";\n\n const text = stringField(item.text);\n const textCell = text\n ? `<td${cellAlign} style=\"vertical-align: middle;${textStyle ? ` ${escapeHtml(textStyle)}` : \"\"}\">${link(\n escapeHtml(text),\n `${color ? `color: ${color}; ` : \"\"}text-decoration: none;`,\n )}</td>`\n : \"\";\n\n const rows =\n position === \"top\"\n ? [textCell, iconCell]\n : position === \"bottom\"\n ? [iconCell, textCell]\n : [position === \"left\" ? textCell + iconCell : iconCell + textCell];\n const body = rows\n .filter(Boolean)\n .map((row) => `<tr>${row}</tr>`)\n .join(\"\");\n const itemGap = index > 0 && gap ? `padding-left: ${gap}px; ` : \"\";\n return `<td style=\"${itemGap}vertical-align: middle;\"><table role=\"presentation\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"border-collapse: collapse;\">${body}</table></td>`;\n });\n\n const tableAlign = align === \"left\" ? \"\" : ` align=\"${align}\"`;\n return `<table role=\"presentation\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"${tableAlign} style=\"border-collapse: collapse;\"><tr>${items.join(\"\")}</tr></table>`;\n}\n\n/**\n * The Icons module's items without the link and image URLs the editor's HTML\n * policy rejects (`javascript:`, `vbscript:`, a non-image `data:`), each named\n * in `warnings`. Both outputs carry these URLs into markup, and an HTML block\n * renders unsanitized.\n */\nfunction safeIconItems(\n descriptor: BeeFreeeModuleDescriptor,\n warnings: string[],\n): BeeFreeeIconItem[] {\n return iconItems(descriptor).map((item) => {\n const safe = { ...item };\n const image = stringField(item.image);\n if (image && !isSafeHtmlUrl(image, \"src\")) {\n warnings.push(`Dropped the unsafe image \"${image}\" on an Icons item.`);\n safe.image = \"\";\n }\n const href = stringField(item.href);\n if (href && !isSafeHtmlUrl(href, \"href\")) {\n warnings.push(`Dropped the unsafe link \"${href}\" on an Icons item.`);\n safe.href = \"\";\n }\n return safe;\n });\n}\n\nfunction convertIcons(\n descriptor: BeeFreeeModuleDescriptor,\n columnWidth: number | undefined,\n warnings: string[],\n): { block: Block; rebuilt: boolean } {\n const safe = {\n ...descriptor,\n iconsList: { icons: safeIconItems(descriptor, warnings) },\n };\n const single = convertSingleIcon(safe, columnWidth);\n if (single) return { block: single, rebuilt: false };\n return {\n block: createHtmlBlock({\n content: iconsHtml(safe),\n styles: makeStyles(descriptor),\n }),\n rebuilt: true,\n };\n}\n\nfunction convertVideo(descriptor: BeeFreeeModuleDescriptor): Block {\n const video = descriptor.video;\n if (!video) {\n return createVideoBlock({ styles: makeStyles(descriptor) });\n }\n\n return createVideoBlock({\n url: video.src || \"\",\n thumbnailUrl: video.thumbnail || \"\",\n alt: video.thumbAlt ?? video.alt ?? \"\",\n width: parsePxValue(video.style?.width) || 600,\n height: parsePxValue(video.style?.height) || undefined,\n align: toAlign(video.style?.[\"text-align\"], \"center\"),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertMenu(descriptor: BeeFreeeModuleDescriptor): Block {\n const menu = descriptor.menu;\n if (!menu) {\n return createMenuBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = menu.style ?? {};\n\n const items: MenuItemData[] = (menu.items ?? []).map((item) => ({\n id: generateId(),\n text: item.text || \"\",\n url: item.link || item.href || \"#\",\n openInNewTab: item.target === \"_blank\",\n bold: false,\n underline: false,\n }));\n\n return createMenuBlock({\n items,\n separator: menu.separator || \"|\",\n separatorColor: parseColor(menu.separatorColor) || \"#999999\",\n fontSize: parsePxValue(style[\"font-size\"]) || 14,\n color: parseColor(style.color) || undefined,\n fontFamily: canonicalFontStack(style[\"font-family\"]) || undefined,\n textAlign: toAlign(style[\"text-align\"], \"center\"),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertTable(descriptor: BeeFreeeModuleDescriptor): {\n block: Block;\n approximated: boolean;\n} {\n const table = descriptor.table;\n if (!table) {\n return {\n block: createTableBlock({ styles: makeStyles(descriptor) }),\n approximated: false,\n };\n }\n\n const style = table.style ?? {};\n\n // Templatical table cells are a plain-text field (the editor stores the\n // cell's innerText), so strip any HTML a BeeFree cell carried the same way\n // button labels are stripped. If a strip actually removed markup, the cell\n // lost formatting or a link URL, so the conversion is an approximation.\n let approximated = false;\n const rows: TableRowData[] = (table.rows ?? []).map((row) => ({\n id: generateId(),\n cells: (row.cells ?? []).map((cell): TableCellData => {\n const raw = cell.content ?? cell.html ?? \"\";\n const content = stripTagsPlain(raw);\n if (content !== raw) {\n approximated = true;\n }\n return { id: generateId(), content };\n }),\n }));\n\n return {\n block: createTableBlock({\n rows,\n hasHeaderRow: table.hasHeaderRow ?? false,\n headerBackgroundColor:\n parseColor(table.headerBackgroundColor) || undefined,\n borderColor: parseColor(style[\"border-color\"]) || \"#dddddd\",\n borderWidth: parsePxValue(style[\"border-width\"]) || 1,\n cellPadding:\n typeof table.cellPadding === \"number\"\n ? table.cellPadding\n : parsePxValue(table.cellPadding as string) || 8,\n fontSize: parsePxValue(style[\"font-size\"]) || 14,\n color: parseColor(style.color) || undefined,\n textAlign: toAlign(style[\"text-align\"]),\n styles: makeStyles(descriptor),\n }),\n approximated,\n };\n}\n\nfunction convertHtmlFallback(module: BeeFreeeModule): Block {\n // Attempt to extract any HTML content from the descriptor\n const descriptor = module.descriptor;\n let html = \"\";\n\n // Try common content fields\n if (descriptor.text?.html) html = descriptor.text.html;\n else if (descriptor.html?.html) html = descriptor.html.html;\n else if (descriptor.heading?.text) html = descriptor.heading.text;\n else html = `<!-- Unsupported BeeFree module: ${module.type} -->`;\n\n return createHtmlBlock({\n content: html,\n styles: makeStyles(descriptor),\n });\n}\n\n/**\n * Converts a single BeeFree module to a Templatical block.\n * Returns the block and a report entry.\n */\nfunction convertModuleBase(\n module: BeeFreeeModule,\n warnings: string[],\n context: ModuleContext = {},\n): { block: Block; entry: ImportReportEntry } {\n const mappedType = moduleKind(module);\n const descriptor = module.descriptor;\n const textColor = context.textColor ?? FALLBACK_TEXT_COLOR;\n\n if (!mappedType) {\n return {\n block: convertHtmlFallback(module),\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n note:\n module.type === ADDON_MODULE\n ? \"The addon carries no content Templatical reads; converted to an HTML block.\"\n : `Unknown module type \"${module.type}\" converted to HTML block.`,\n },\n };\n }\n\n let block: Block;\n let isApproximation = false;\n let notes: string[] = [];\n\n switch (mappedType) {\n case \"paragraph\":\n case \"list\":\n block = convertText(descriptor, textColor);\n break;\n case \"title\":\n block = convertHeading(descriptor, textColor);\n break;\n case \"image\": {\n const result = convertImage(descriptor, context.columnWidth);\n block = result.block;\n notes = result.notes;\n isApproximation = notes.length > 0;\n break;\n }\n case \"button\":\n block = convertButton(descriptor);\n break;\n case \"divider\": {\n const height = undrawnDividerHeight(descriptor);\n if (height !== undefined) {\n block = convertUndrawnDivider(descriptor, height);\n notes = [\n `The divider draws no line; imported as a ${height}px spacer.`,\n ];\n break;\n }\n const result = convertDivider(descriptor, context.columnWidth);\n block = result.block;\n notes = result.notes;\n isApproximation = notes.length > 0;\n break;\n }\n case \"spacer\":\n block = convertSpacer(descriptor);\n break;\n case \"icons\": {\n const result = convertIcons(descriptor, context.columnWidth, warnings);\n if (result.rebuilt) {\n return {\n block: result.block,\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n note: \"Icons module rebuilt as an HTML table.\",\n },\n };\n }\n block = result.block;\n break;\n }\n case \"html\":\n block = convertHtml(descriptor);\n break;\n case \"social\":\n block = convertSocial(descriptor, warnings);\n break;\n case \"video\":\n block = convertVideo(descriptor);\n break;\n case \"menu\":\n block = convertMenu(descriptor);\n isApproximation = true; // menu styles are approximate\n break;\n case \"table\": {\n const result = convertTable(descriptor);\n block = result.block;\n if (result.approximated) {\n isApproximation = true;\n warnings.push(\n \"HTML inside one or more table cells was reduced to plain text; any cell formatting or links were dropped.\",\n );\n }\n break;\n }\n default:\n block = convertHtmlFallback(module);\n return {\n block,\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n },\n };\n }\n\n return {\n block,\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: block.type,\n status: isApproximation ? \"approximated\" : \"converted\",\n ...(notes.length > 0 ? { note: notes.join(\" \") } : {}),\n },\n };\n}\n\n/**\n * The report entry for a module that imports no block, or `undefined` when it\n * converts: an empty module, an Icons module with no icons, and a divider that\n * draws no line and takes no space.\n */\nexport function skippedModuleEntry(\n module: BeeFreeeModule,\n): ImportReportEntry | undefined {\n const skip = (note: string): ImportReportEntry => ({\n beeFreeModuleType: module.type,\n templaticalBlockType: null,\n status: \"skipped\",\n note,\n });\n if (module.type === EMPTY_MODULE) return skip(\"The module is empty.\");\n switch (moduleKind(module)) {\n case \"icons\":\n return iconItems(module.descriptor).length === 0\n ? skip(\"The Icons module has no icons.\")\n : undefined;\n case \"divider\":\n return undrawnDividerHeight(module.descriptor) === 0\n ? skip(\"The divider draws no line and takes no space.\")\n : undefined;\n default:\n return undefined;\n }\n}\n\nexport function convertModule(\n module: BeeFreeeModule,\n warnings: string[],\n context: ModuleContext = {},\n): { block: Block; entry: ImportReportEntry } {\n const result = convertModuleBase(module, warnings, context);\n const { block } = result;\n const descriptor = module.descriptor;\n const payloads = [\n [\"heading\", descriptor.heading],\n [\"text\", descriptor.text],\n [\"paragraph\", descriptor.paragraph],\n [\"list\", descriptor.list],\n [\"button\", descriptor.button],\n [\"image\", descriptor.image],\n [\"video\", descriptor.video],\n [\"menu\", descriptor.menu],\n ] as const;\n const active = payloads.find(([, payload]) => payload !== undefined);\n const sources = [\n module.translations,\n ...payloads.map(([, payload]) => payload?.translations),\n ];\n for (const translations of sources) {\n for (const [code, values] of Object.entries(translations ?? {})) {\n const locale = localeTag(code, warnings);\n if (!locale) continue;\n if (result.entry.status === \"html-fallback\" || block.type === \"html\") {\n warn(\n warnings,\n `Dropped language \"${locale}\" on module \"${module.type}\": target converted to HTML fallback.`,\n );\n continue;\n }\n const key = active?.[0];\n const field =\n block.type === \"title\"\n ? \"text\"\n : block.type === \"paragraph\"\n ? \"html\"\n : block.type === \"button\"\n ? \"label\"\n : block.type === \"image\"\n ? \"alt\"\n : block.type === \"video\"\n ? \"thumbAlt\"\n : block.type === \"menu\"\n ? \"items\"\n : undefined;\n for (const unknown of Object.keys(values).filter(\n (name) => name !== field,\n )) {\n warn(\n warnings,\n `Dropped language \"${locale}\" key \"${unknown}\": no language mapping for this format.`,\n );\n }\n if (!field || values[field] === undefined) continue;\n if (block.type === \"menu\" && Array.isArray(values.items)) {\n if (values.items.length !== block.items.length) {\n warn(\n warnings,\n `Dropped language \"${locale}\" menu translation: item count differs from the source.`,\n );\n continue;\n }\n values.items.forEach((item: { text?: unknown }, index: number) => {\n for (const key of Object.keys(item ?? {}).filter(\n (key) => key !== \"text\",\n )) {\n warn(\n warnings,\n `Dropped language \"${locale}\" key \"${key}\": no language mapping for this format.`,\n );\n }\n if (typeof item?.text === \"string\")\n text(\n block,\n locale,\n `items.${block.items[index].id}.text`,\n block.items[index].text,\n item.text,\n );\n });\n } else if (key && typeof values[field] === \"string\") {\n const translated = convertModuleBase(\n {\n ...module,\n descriptor: {\n ...descriptor,\n [key]: { ...descriptor[key], [field]: values[field] },\n },\n },\n [],\n context,\n ).block;\n if (\n (block.type === \"title\" || block.type === \"paragraph\") &&\n (translated.type === \"title\" || translated.type === \"paragraph\")\n )\n text(block, locale, \"content\", block.content, translated.content);\n if (block.type === \"button\" && translated.type === \"button\")\n text(block, locale, \"text\", block.text, translated.text);\n if (\n (block.type === \"image\" || block.type === \"video\") &&\n (translated.type === \"image\" || translated.type === \"video\")\n )\n text(block, locale, \"alt\", block.alt, translated.alt ?? \"\");\n }\n }\n }\n return result;\n}\n","import {\n defaultLocaleOption,\n localeTag,\n registerLocales,\n text,\n warn,\n} from \"./localization\";\nimport {\n canonicalFontStack,\n createSectionBlock,\n createDefaultTemplateContent,\n} from \"@templatical/types\";\nimport type {\n BackgroundImage,\n Block,\n ColumnLayout,\n TemplateContent,\n} from \"@templatical/types\";\nimport type {\n BeeFreeTemplate,\n BeeFreeeRow,\n BeeFreeeColumn,\n ImportResult,\n ImportReport,\n ImportReportEntry,\n} from \"./types\";\nimport {\n convertModule,\n FALLBACK_TEXT_COLOR,\n skippedModuleEntry,\n type ModuleContext,\n} from \"./block-mapper\";\nimport {\n parsePxValue,\n parseColor,\n readBeefreeBackgroundImage,\n} from \"./style-parser\";\n\nexport interface ConvertBeeFreeOptions {\n /** Used when the source declares no default language. */\n defaultLocale?: string;\n}\n\n/**\n * Determines the Templatical ColumnLayout from BeeFree column grid values.\n */\nfunction resolveColumnLayout(\n columns: BeeFreeeColumn[],\n warnings: string[],\n): ColumnLayout | null {\n if (columns.length === 1) return null; // Single column — no section wrapper needed\n if (columns.length === 3) return \"3\";\n\n if (columns.length === 2) {\n const left = columns[0][\"grid-columns\"] ?? 6;\n const right = columns[1][\"grid-columns\"] ?? 6;\n const total = left + right;\n const ratio = left / total;\n\n if (ratio > 0.58) return \"2-1\";\n if (ratio < 0.42) return \"1-2\";\n return \"2\";\n }\n\n if (columns.length >= 4) {\n warnings.push(\n `Row with ${columns.length} columns was flattened to a single column. BeeFree supports arbitrary columns, but Templatical supports up to 3.`,\n );\n return null; // Flatten to single column\n }\n\n return \"2\";\n}\n\n/**\n * Column widths in px for a layout, mirroring `renderer/src/columns.ts`, and\n * floored as the renderer floors the width it hands each column.\n */\nfunction columnPixels(layout: ColumnLayout, bodyWidth: number): number[] {\n switch (layout) {\n case \"2\":\n return [bodyWidth * 0.5, bodyWidth * 0.5].map(Math.floor);\n case \"3\":\n return [bodyWidth / 3, bodyWidth / 3, bodyWidth / 3].map(Math.floor);\n case \"1-2\":\n return [bodyWidth / 3, (bodyWidth * 2) / 3].map(Math.floor);\n case \"2-1\":\n return [(bodyWidth * 2) / 3, bodyWidth / 3].map(Math.floor);\n default:\n return [Math.floor(bodyWidth)];\n }\n}\n\n/**\n * Converts all modules in a column to Templatical blocks.\n */\nfunction convertColumnModules(\n column: BeeFreeeColumn,\n context: ModuleContext,\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const blocks: Block[] = [];\n\n for (const module of column.modules) {\n const skipped = skippedModuleEntry(module);\n if (skipped) {\n entries.push(skipped);\n continue;\n }\n const { block, entry } = convertModule(module, warnings, context);\n blocks.push(block);\n entries.push(entry);\n }\n\n return blocks;\n}\n\n/**\n * The image a row's section paints. `content.style` is the content area a\n * section paints, so its image maps exactly. `container.style` is the\n * full-width band: it shows through only while the content area has neither\n * an image nor a colour, and then the section paints it at the content\n * width; otherwise it's dropped. Losses go to `warnings`, since rows have no\n * report entry.\n */\nfunction resolveRowBackgroundImage(\n row: BeeFreeeRow,\n rowBg: string,\n width: number,\n warnings: string[],\n): BackgroundImage | undefined {\n const content = readBeefreeBackgroundImage(row.content?.style, \"Row\", width);\n const band = readBeefreeBackgroundImage(\n row.container?.style,\n \"Row container\",\n width,\n );\n\n if (content) {\n warnings.push(...content.notes);\n if (band) {\n warnings.push(\n `Row container background image \"${band.image.url}\" outside the content width was dropped; the section keeps the content background image.`,\n );\n }\n return content.image;\n }\n if (!band) return undefined;\n if (rowBg) {\n warnings.push(\n `Row container background image \"${band.image.url}\" outside the content width was dropped; the section keeps the content background ${rowBg}.`,\n );\n return undefined;\n }\n warnings.push(\n ...band.notes,\n `Row container background image \"${band.image.url}\" spans the full width in BeeFree; the section paints it at the content width.`,\n );\n return band.image;\n}\n\n/**\n * Processes a single BeeFree row into one or more Templatical blocks.\n */\nfunction processRow(\n row: BeeFreeeRow,\n settings: TemplateContent[\"settings\"],\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const columns = row.columns;\n if (!columns || columns.length === 0) return [];\n\n // Track locked/synced metadata\n if (row.locked) {\n warnings.push(\n \"A locked row was imported. Lock metadata was dropped; content is preserved.\",\n );\n }\n if (row.synced) {\n warnings.push(\n \"A synced row was imported. Sync metadata was dropped; content is preserved.\",\n );\n }\n\n const layout = resolveColumnLayout(columns, warnings);\n\n // Extract section-level background from row content styles.\n const rowBg = parseColor(row.content?.style?.[\"background-color\"]);\n const backgroundImage = resolveRowBackgroundImage(\n row,\n rowBg,\n settings.width,\n warnings,\n );\n\n if (!layout) {\n // Single column (or flattened 4+ columns) — return modules directly.\n // Either way the modules end up spanning the body.\n const blocks: Block[] = [];\n const context = {\n columnWidth: settings.width,\n textColor: settings.textColor,\n };\n for (const column of columns) {\n blocks.push(...convertColumnModules(column, context, entries, warnings));\n }\n // A row background — a colour or an image — can't survive on bare\n // modules; wrap them in a one-column section so it still renders. Mirrors\n // the multi-column path and the Unlayer importer (which wraps every row).\n if (rowBg || backgroundImage) {\n return [\n createSectionBlock({\n columns: \"1\",\n children: [blocks],\n styles: {\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n ...(rowBg ? { backgroundColor: rowBg } : {}),\n },\n ...(backgroundImage ? { backgroundImage } : {}),\n }),\n ];\n }\n return blocks;\n }\n\n // Multi-column — wrap in a SectionBlock\n const widths = columnPixels(layout, settings.width);\n const children: Block[][] = columns.map((col, index) =>\n convertColumnModules(\n col,\n { columnWidth: widths[index], textColor: settings.textColor },\n entries,\n warnings,\n ),\n );\n\n const section = createSectionBlock({\n columns: layout,\n children,\n styles: {\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n ...(rowBg ? { backgroundColor: rowBg } : {}),\n },\n ...(backgroundImage ? { backgroundImage } : {}),\n });\n\n return [section];\n}\n\n/**\n * Extracts template-level settings from the BeeFree body.\n */\nfunction extractSettings(\n template: BeeFreeTemplate,\n): TemplateContent[\"settings\"] {\n const body = template.page.body;\n const contentStyle = body?.content?.style ?? {};\n const computedStyle = body?.content?.computedStyle ?? {};\n const containerStyle = body?.container?.style ?? {};\n\n // Exports keep the body width in `computedStyle.messageWidth` and usually\n // carry no `style.width`.\n const width =\n parsePxValue(computedStyle.messageWidth) ||\n parsePxValue(contentStyle.width);\n const bgColor =\n parseColor(contentStyle[\"background-color\"]) ||\n parseColor(containerStyle[\"background-color\"]) ||\n \"#ffffff\";\n const fontFamily = canonicalFontStack(contentStyle[\"font-family\"]) || \"Arial\";\n const linkColor = parseColor(computedStyle.linkColor);\n\n return {\n width: width || 600,\n backgroundColor: bgColor,\n textColor: parseColor(contentStyle.color) || FALLBACK_TEXT_COLOR,\n ...(linkColor ? { linkColor } : {}),\n // BeeFree underlines per link, in the link's own markup, and has no\n // template-wide switch, so links take the browser default: underlined.\n linkUnderline: true,\n fontFamily,\n locale: \"en\",\n };\n}\n\n/**\n * Converts a BeeFree template JSON to Templatical TemplateContent.\n *\n * @param template - The parsed BeeFree JSON object\n * @returns An ImportResult with the converted content and a detailed report\n *\n * @example\n * ```ts\n * import { convertBeeFreeTemplate } from '@templatical/import-beefree';\n *\n * const beeFreeJson = JSON.parse(fileContent);\n * const { content, report } = convertBeeFreeTemplate(beeFreeJson);\n *\n * // Use the content with the editor\n * const editor = init({ container: '#editor', content });\n *\n * // Check the report for any issues\n * console.log(report.summary);\n * console.log(report.warnings);\n * ```\n */\nexport function convertBeeFreeTemplate(\n template: BeeFreeTemplate,\n options: ConvertBeeFreeOptions = {},\n): ImportResult {\n // Validate structure\n if (!template?.page?.rows) {\n throw new Error(\n \"Invalid BeeFree template: missing page.rows. Ensure you are passing a valid BeeFree JSON export.\",\n );\n }\n\n const entries: ImportReportEntry[] = [];\n const warnings: string[] = [];\n const blocks: Block[] = [];\n\n // Extract web font warnings\n const webFonts = template.page.body?.webFonts;\n if (webFonts && webFonts.length > 1) {\n warnings.push(\n `Template uses ${webFonts.length} web fonts. Only the primary font is preserved; additional fonts may need to be configured via the fonts option.`,\n );\n }\n\n // Rows are measured against the width the imported template renders at.\n const settings = extractSettings(template);\n const declared =\n template.page.body?.language?.value ??\n template.page.language?.value ??\n template.language?.value;\n settings.locale =\n (declared ? localeTag(declared, warnings) : null) ??\n defaultLocaleOption(options.defaultLocale, warnings) ??\n \"en\";\n const meta = template.head?.meta;\n if (typeof meta?.preheader === \"string\")\n settings.preheaderText = meta.preheader;\n for (const [code, values] of Object.entries(meta?.translations ?? {})) {\n const locale = localeTag(code, warnings);\n if (!locale) continue;\n for (const key of Object.keys(values)) {\n if (key === \"preheader\" && typeof values.preheader === \"string\") {\n text(\n settings,\n locale,\n \"preheaderText\",\n settings.preheaderText,\n values.preheader,\n );\n } else {\n warn(\n warnings,\n `Dropped language \"${locale}\" metadata \"${key}\": ${[\"subject\", \"title\", \"description\"].includes(key) ? \"the host owns this field\" : \"no language mapping for this format\"}.`,\n );\n }\n }\n }\n\n // Process rows\n for (const row of template.page.rows) {\n if (row.empty) continue;\n blocks.push(...processRow(row, settings, entries, warnings));\n }\n\n // Build template content\n const content: TemplateContent = {\n ...createDefaultTemplateContent(),\n blocks,\n settings,\n };\n\n registerLocales(content);\n\n // Build report summary\n const summary = {\n total: entries.length,\n converted: entries.filter((e) => e.status === \"converted\").length,\n approximated: entries.filter((e) => e.status === \"approximated\").length,\n htmlFallback: entries.filter((e) => e.status === \"html-fallback\").length,\n skipped: entries.filter((e) => e.status === \"skipped\").length,\n };\n\n const report: ImportReport = { entries, warnings, summary };\n\n return { content, report };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["BORDER_SIDES"],"sources":["../src/localization.ts","../src/merge-tokens.ts","../src/style-parser.ts","../src/block-mapper.ts","../src/converter.ts"],"sourcesContent":["import { isLocaleTag, sourceHash } from \"@templatical/types\";\nimport type {\n Block,\n BlockLocaleLayer,\n TemplateContent,\n} from \"@templatical/types\";\n\ntype Target = { l10n?: Record<string, BlockLocaleLayer> };\n\nexport function warn(warnings: string[], message: string): void {\n if (!warnings.includes(message)) warnings.push(message);\n}\n\nexport function localeTag(value: string, warnings: string[]): string | null {\n const locale = value.replaceAll(\"_\", \"-\");\n if (isLocaleTag(locale)) return locale;\n warn(warnings, `Dropped language \"${value}\": unsupported language tag.`);\n return null;\n}\n\n/** The `defaultLocale` option as a tag; `null`, with a warning, when it isn't one. */\nexport function defaultLocaleOption(\n value: string | undefined,\n warnings: string[],\n): string | null {\n if (!value) return null;\n const locale = value.replaceAll(\"_\", \"-\");\n if (isLocaleTag(locale)) return locale;\n warn(\n warnings,\n `Ignored defaultLocale \"${value}\": unsupported language tag. Used \"en\".`,\n );\n return null;\n}\n\nexport function text(\n target: Target,\n locale: string,\n path: string,\n base: string | undefined,\n value: string,\n): void {\n if (base === undefined) {\n set(target, locale, path, value);\n return;\n }\n const layer = ((target.l10n ??= {})[locale] ??= {});\n (layer.text ??= {})[path] = { value, sourceHash: sourceHash(base) };\n}\n\nexport function set(\n target: Target,\n locale: string,\n path: string,\n value: unknown,\n): void {\n const layer = ((target.l10n ??= {})[locale] ??= {});\n (layer.set ??= {})[path] = value;\n}\n\n/** Register only non-default versions, leaving single-language imports unchanged. */\nexport function registerLocales(content: TemplateContent): void {\n const locales = new Set<string>();\n const visit = (target: Target) => {\n if (!target.l10n) return;\n delete target.l10n[content.settings.locale];\n for (const locale of Object.keys(target.l10n)) locales.add(locale);\n if (Object.keys(target.l10n).length === 0) delete target.l10n;\n };\n visit(content.settings);\n const walk = (blocks: Block[]) => {\n for (const block of blocks) {\n visit(block);\n if (block.type === \"section\") block.children.forEach(walk);\n }\n };\n walk(content.blocks);\n if (locales.size) content.settings.locales = [...locales];\n}\n","/**\n * Character references Beefree writes inside `{{ }}`, `{% %}` and `{# #}`.\n * A sender parses those tokens before an HTML parser does, so `'` has to\n * be an apostrophe in the imported string. References outside a token stay\n * encoded. An opener with no closer is left as written. Each reference is\n * decoded once: `&quot;` becomes `"`.\n *\n * The three kinds are scanned with `indexOf`. The earliest opener wins, and\n * the match ends at that kind's first closer. A kind with no closer can never\n * match later in the string, so it is not searched again.\n */\nconst TOKEN_KINDS = [\n { opener: \"{{\", closer: \"}}\" },\n { opener: \"{%\", closer: \"%}\" },\n { opener: \"{#\", closer: \"#}\" },\n] as const;\n\ninterface TokenSeek {\n opener: string;\n closer: string;\n /** Next opener index, or -1 when none remains. */\n at: number;\n searched: boolean;\n /** No closer exists for this opener, or no opener remains. */\n dead: boolean;\n}\n\ninterface TokenSpan {\n start: number;\n end: number;\n}\n\nfunction tokenSeeks(): TokenSeek[] {\n return TOKEN_KINDS.map((kind) => ({\n opener: kind.opener,\n closer: kind.closer,\n at: -1,\n searched: false,\n dead: false,\n }));\n}\n\n/** Next opener of this kind at or after `from`, cached so each index is visited once. */\nfunction openerAt(value: string, seek: TokenSeek, from: number): number {\n if (seek.dead) return -1;\n if (seek.searched && (seek.at === -1 || seek.at >= from)) return seek.at;\n seek.at = value.indexOf(seek.opener, from);\n seek.searched = true;\n if (seek.at === -1) seek.dead = true;\n return seek.at;\n}\n\n/**\n * The next token at or after `from`, or `null` when none remain.\n * An unterminated opener stays in the text: the scan resumes one character\n * later, and that opener kind is not tried again.\n */\nfunction nextToken(\n value: string,\n from: number,\n seeks: TokenSeek[],\n): TokenSpan | null {\n let cursor = from;\n while (cursor < value.length) {\n let best = -1;\n let kind = -1;\n for (let i = 0; i < seeks.length; i++) {\n const at = openerAt(value, seeks[i], cursor);\n if (at === -1) continue;\n if (best === -1 || at < best) {\n best = at;\n kind = i;\n }\n }\n if (kind === -1 || best === -1) break;\n const seek = seeks[kind];\n const closeAt = value.indexOf(seek.closer, best + seek.opener.length);\n if (closeAt === -1) {\n seek.dead = true;\n cursor = best + 1;\n continue;\n }\n return { start: best, end: closeAt + seek.closer.length };\n }\n return null;\n}\n\nfunction tokenSpans(value: string): TokenSpan[] {\n const seeks = tokenSeeks();\n const spans: TokenSpan[] = [];\n let from = 0;\n while (from < value.length) {\n const span = nextToken(value, from, seeks);\n if (!span) break;\n spans.push(span);\n from = span.end;\n }\n return spans;\n}\n\nconst CHAR_REF = /&(?:amp|lt|gt|quot|apos|nbsp|#x[0-9a-f]+|#\\d+);/gi;\n\nconst NAMED: Record<string, string> = {\n amp: \"&\",\n lt: \"<\",\n gt: \">\",\n quot: '\"',\n apos: \"'\",\n nbsp: \"\\u00A0\",\n};\n\n/** A scalar character, or the reference itself when the code point is not one. */\nfunction decodeCharRef(entity: string): string {\n const body = entity.slice(1, -1);\n if (body[0] !== \"#\") return NAMED[body.toLowerCase()] ?? entity;\n\n const hex = body[1] === \"x\" || body[1] === \"X\";\n const code = Number.parseInt(body.slice(hex ? 2 : 1), hex ? 16 : 10);\n // `�` and a surrogate are not characters a token can use.\n if (\n !Number.isInteger(code) ||\n code < 1 ||\n code > 0x10ffff ||\n (code >= 0xd800 && code <= 0xdfff)\n ) {\n return entity;\n }\n return String.fromCodePoint(code);\n}\n\n/**\n * Encoded form of a decoded character that must not appear raw, or\n * `undefined` when the character is safe in this context.\n */\ntype Preserve = (char: string) => string | undefined;\n\nfunction decodeToken(token: string, preserve?: Preserve): string {\n CHAR_REF.lastIndex = 0;\n const decoded = token.replace(CHAR_REF, (entity) => {\n const char = decodeCharRef(entity);\n return preserve?.(char) ?? char;\n });\n // Twig's lexer does not treat U+00A0 as whitespace; Beefree's export uses a plain space.\n return decoded.replace(/\\u00A0/g, (char) => preserve?.(char) ?? \" \");\n}\n\nfunction decodeEntities(\n value: string,\n preserve?: Preserve,\n ctx?: Uint8Array,\n): string {\n const seeks = tokenSeeks();\n const parts: string[] = [];\n let i = 0;\n let from = 0;\n let found = false;\n while (from < value.length) {\n const span = nextToken(value, from, seeks);\n if (!span) break;\n found = true;\n if (span.start > i) parts.push(value.slice(i, span.start));\n parts.push(\n ctx\n ? decodeTokenAt(value, span.start, span.end, ctx)\n : decodeToken(value.slice(span.start, span.end), preserve),\n );\n i = span.end;\n from = span.end;\n }\n if (!found) return value;\n if (i < value.length) parts.push(value.slice(i));\n return parts.join(\"\");\n}\n\nexport function decodeEntitiesInTokens(value: string): string {\n return decodeEntities(value);\n}\n\n/** A quote stays `"` so it cannot end a double-quoted attribute. */\nconst preserveDoubleQuote: Preserve = (char) =>\n char === '\"' ? \""\" : undefined;\n\n/** An apostrophe stays `'` so it cannot end a single-quoted attribute. */\nconst preserveSingleQuote: Preserve = (char) =>\n char === \"'\" ? \"'\" : undefined;\n\n/**\n * Characters that end an unquoted attribute (`whitespace` or `>`) or that\n * a loose parser treats as a quote. A decoded ` ` is one of those spaces.\n */\nconst preserveUnquoted: Preserve = (char) => {\n switch (char) {\n case '\"':\n return \""\";\n case \"'\":\n return \"'\";\n case \">\":\n return \">\";\n case \" \":\n return \" \";\n case \"\\t\":\n return \"	\";\n case \"\\n\":\n return \" \";\n case \"\\r\":\n return \" \";\n case \"\\f\":\n return \"\";\n case \"\\u00A0\":\n return \" \";\n default:\n return undefined;\n }\n};\n\n/**\n * Decode references inside tokens that will sit in a double-quoted attribute.\n * `'` becomes `'`, `>` `>`, `<` `<`, `&` `&` and ` ` a\n * space. A quote (`"`, `"`, `"`, any case or leading zeros)\n * stays `"`, so the token cannot end the attribute.\n */\nexport function decodeEntitiesInTokensForAttribute(value: string): string {\n return decodeEntities(value, preserveDoubleQuote);\n}\n\n/** Text or a comment: decode a reference in full. */\nconst CTX_TEXT = 0;\n/** A double-quoted attribute value. */\nconst CTX_DQ = 1;\n/** A single-quoted attribute value. */\nconst CTX_SQ = 2;\n/** An unquoted attribute value. */\nconst CTX_UQ = 3;\n/** Tag markup outside an attribute value. A reference here stays encoded. */\nconst CTX_OPAQUE = 4;\n\nconst PRESERVE_BY_KIND: Array<Preserve | undefined> = [];\nPRESERVE_BY_KIND[CTX_TEXT] = undefined;\nPRESERVE_BY_KIND[CTX_DQ] = preserveDoubleQuote;\nPRESERVE_BY_KIND[CTX_SQ] = preserveSingleQuote;\nPRESERVE_BY_KIND[CTX_UQ] = preserveUnquoted;\n\nfunction replacementFor(char: string, kind: number): string {\n const preserve = PRESERVE_BY_KIND[kind];\n const kept = preserve?.(char);\n return kept ?? (char === \"\\u00A0\" ? \" \" : char);\n}\n\n/** Copy `slice[from, to)`, turning a literal U+00A0 into a space inside a token. */\nfunction copyPlain(\n slice: string,\n from: number,\n to: number,\n base: number,\n ctx: Uint8Array,\n): string {\n const nbsp = slice.indexOf(\"\\u00A0\", from);\n if (nbsp === -1 || nbsp >= to) return slice.slice(from, to);\n const parts: string[] = [];\n let i = from;\n while (i < to) {\n const at = slice.indexOf(\"\\u00A0\", i);\n if (at === -1 || at >= to) {\n parts.push(slice.slice(i, to));\n break;\n }\n if (at > i) parts.push(slice.slice(i, at));\n const kind = ctx[base + at];\n parts.push(kind === CTX_OPAQUE ? \"\\u00A0\" : replacementFor(\"\\u00A0\", kind));\n i = at + 1;\n }\n return parts.join(\"\");\n}\n\n/**\n * Decode references in `html[start, end)`. Each reference uses the context\n * of its own index, so one token can span a text node and an attribute.\n */\nfunction decodeTokenAt(\n html: string,\n start: number,\n end: number,\n ctx: Uint8Array,\n): string {\n const slice = html.slice(start, end);\n if (slice.indexOf(\"&\") === -1 && slice.indexOf(\"\\u00A0\") === -1) return slice;\n const parts: string[] = [];\n CHAR_REF.lastIndex = 0;\n let last = 0;\n let match: RegExpExecArray | null;\n while ((match = CHAR_REF.exec(slice))) {\n parts.push(copyPlain(slice, last, match.index, start, ctx));\n const kind = ctx[start + match.index];\n parts.push(\n kind === CTX_OPAQUE\n ? match[0]\n : replacementFor(decodeCharRef(match[0]), kind),\n );\n last = match.index + match[0].length;\n }\n parts.push(copyPlain(slice, last, slice.length, start, ctx));\n return parts.join(\"\");\n}\n\ninterface ValueSpan {\n start: number;\n end: number;\n kind: number;\n}\n\n/** Paint the tag opaque, then lay each attribute value back over it. */\nfunction paintTag(\n ctx: Uint8Array,\n start: number,\n end: number,\n values: ValueSpan[],\n): number {\n ctx.fill(CTX_OPAQUE, start, end);\n for (const value of values) ctx.fill(value.kind, value.start, value.end);\n return end;\n}\n\n/**\n * Mark attribute values on the tag at `start`. `null` when the tag never\n * closes: the caller leaves that tail as written.\n */\nfunction markTag(html: string, start: number, ctx: Uint8Array): number | null {\n const values: ValueSpan[] = [];\n let i = start + 1;\n let state: \"tag\" | \"before\" | \"quoted\" | \"unquoted\" = \"tag\";\n let quote = \"\";\n let valueStart = 0;\n\n while (i < html.length) {\n const char = html[i];\n if (state === \"quoted\") {\n if (char !== quote) {\n i++;\n continue;\n }\n values.push({\n start: valueStart,\n end: i,\n kind: quote === '\"' ? CTX_DQ : CTX_SQ,\n });\n state = \"tag\";\n i++;\n continue;\n }\n if (state === \"unquoted\") {\n if (char !== \">\" && !isSpace(char)) {\n i++;\n continue;\n }\n values.push({ start: valueStart, end: i, kind: CTX_UQ });\n state = \"tag\";\n if (char === \">\") return paintTag(ctx, start, i + 1, values);\n i++;\n continue;\n }\n if (state === \"before\") {\n if (isSpace(char)) {\n i++;\n continue;\n }\n if (char === \">\") return paintTag(ctx, start, i + 1, values);\n if (char === '\"' || char === \"'\") {\n quote = char;\n valueStart = i + 1;\n state = \"quoted\";\n i++;\n continue;\n }\n valueStart = i;\n state = \"unquoted\";\n continue;\n }\n if (char === \"=\") {\n state = \"before\";\n i++;\n continue;\n }\n if (char === \">\") return paintTag(ctx, start, i + 1, values);\n i++;\n }\n return null;\n}\n\ninterface HtmlContext {\n ctx: Uint8Array;\n /** Start of an unclosed tag, or `html.length` when every tag closes. */\n limit: number;\n}\n\n/**\n * Context of each index. Text and comments stay `CTX_TEXT`. An attribute\n * value is marked for its quotes. The rest of a closed tag is opaque.\n * `limit` stops the token scan at an unclosed tag, which is left as written.\n */\nfunction markHtmlContext(html: string): HtmlContext {\n const ctx = new Uint8Array(html.length);\n let i = 0;\n while (i < html.length) {\n const lt = html.indexOf(\"<\", i);\n if (lt === -1) break;\n if (html.startsWith(\"<!--\", lt)) {\n const end = html.indexOf(\"-->\", lt + 4);\n if (end === -1) break;\n i = end + 3;\n continue;\n }\n const next = markTag(html, lt, ctx);\n if (next === null) return { ctx, limit: lt };\n i = next;\n }\n return { ctx, limit: html.length };\n}\n\n/**\n * Decode tokens in HTML. A token is the earliest `{{`, `{%` or `{#` through\n * its first closer, and it may span tags. A reference in text or a comment\n * is decoded in full, so a quote there is a quote and U+00A0 is a space.\n * A reference inside an attribute is decoded for the quotes that wrap it:\n * a double-quoted value keeps `\"`, a single-quoted value keeps `'`, and an\n * unquoted value keeps the characters that end it. A reference in the tag\n * itself stays encoded. An unclosed tag is left as written, and a token\n * does not close inside it.\n */\nexport function decodeEntitiesInHtml(html: string): string {\n if (html.indexOf(\"<\") === -1) return decodeEntitiesInTokens(html);\n const marked = markHtmlContext(html);\n const head =\n marked.limit === html.length ? html : html.slice(0, marked.limit);\n const decoded = decodeEntities(head, undefined, marked.ctx);\n return marked.limit === html.length\n ? decoded\n : decoded + html.slice(marked.limit);\n}\n\n/**\n * Every character reference in plain text, decoded once. A button label is\n * not HTML: the renderer escapes it, so ` ` has to be the character or\n * the mail shows the letters `&nbsp;`.\n */\nexport function decodePlainTextEntities(value: string): string {\n CHAR_REF.lastIndex = 0;\n return value.replace(CHAR_REF, decodeCharRef);\n}\n\n/**\n * BeeFree writes a non-breaking space as `&nbsp;`. The extra `&`\n * leaves the letters ` ` in the mail. Put back the single reference.\n * Any other reference outside a token stays as written.\n */\nexport function restoreDoubledNbsp(html: string): string {\n return html.replace(/&(nbsp;|#0*160;|#x0*a0;)/gi, \"&$1\");\n}\n\n/** Whitespace, or a reference that decodes to whitespace, up to the extra `&` on `&nbsp;`. */\nfunction isSpacePadding(text: string): boolean {\n let current = text;\n for (let pass = 0; pass < 2; pass++) {\n CHAR_REF.lastIndex = 0;\n const next = current.replace(CHAR_REF, decodeCharRef);\n if (next === current) break;\n current = next;\n }\n return /^[\\s\\u00A0]*$/.test(current);\n}\n\n/**\n * A chip between two merge tags holds only a non-breaking space (kept as one\n * plain space), and a chip\n * around one token leads with plain spaces that are not part of the token.\n * A non-breaking space in front of that token stays: it is the space between\n * the previous word and the token. A chip\n * that also carries words, or more than one token, is left as written. A\n * space after the token stays: it is the space the author typed.\n */\n/** Plain spaces the editor pads in front of a token. A non-breaking space is not padding. */\nfunction isPlainSpacePadding(text: string): boolean {\n return /^[ \\t\\n\\r\\f]*$/.test(text);\n}\n\n/** Drop a plain leading space before the one token in `text`. A non-breaking space stays. */\nfunction withoutLeadingTokenPadding(text: string): string {\n const spans = tokenSpans(text);\n if (spans.length !== 1) return text;\n const start = spans[0].start;\n if (!isPlainSpacePadding(text.slice(0, start))) return text;\n return text.slice(start);\n}\n\n/**\n * What a mergetag chip keeps once nested chips are already unwrapped.\n * A chip that only holds a space between two tokens is that space. A plain\n * leading space before the one token is padding and drops.\n */\nfunction keptMergetagText(text: string): string {\n const spans = tokenSpans(text);\n if (spans.length !== 1) {\n return text !== \"\" && isSpacePadding(text) ? \" \" : text;\n }\n return withoutLeadingTokenPadding(text);\n}\n\nfunction fold(char: string): string {\n const code = char.charCodeAt(0);\n return code >= 65 && code <= 90 ? String.fromCharCode(code + 32) : char;\n}\n\nfunction equalsIgnoreCase(value: string, literal: string): boolean {\n if (value.length !== literal.length) return false;\n for (let i = 0; i < value.length; i++) {\n if (fold(value[i]) !== fold(literal[i])) return false;\n }\n return true;\n}\n\nfunction startsWithIgnoreCase(\n html: string,\n at: number,\n literal: string,\n): boolean {\n if (at < 0 || at + literal.length > html.length) return false;\n for (let i = 0; i < literal.length; i++) {\n if (fold(html[at + i]) !== fold(literal[i])) return false;\n }\n return true;\n}\n\nfunction isSpace(char: string | undefined): boolean {\n return (\n char === \" \" ||\n char === \"\\t\" ||\n char === \"\\n\" ||\n char === \"\\r\" ||\n char === \"\\f\"\n );\n}\n\n/** A character that continues an HTML tag name (`code` vs `codebook`). */\nfunction isNameChar(char: string | undefined): boolean {\n if (char === undefined) return false;\n const code = char.charCodeAt(0);\n return (\n (code >= 48 && code <= 57) ||\n (code >= 65 && code <= 90) ||\n (code >= 97 && code <= 122) ||\n char === \"-\" ||\n char === \":\" ||\n char === \"_\"\n );\n}\n\nconst CODE_TAG = \"code\";\n\n/**\n * Index of the next `<code` tag at or after `from` and before `limit`, or -1.\n * `<codebook` is not one. `limit` keeps a chip from scanning past its closer.\n */\nfunction indexOfCodeOpen(\n html: string,\n from: number,\n limit = html.length,\n): number {\n let i = from;\n while (i < limit) {\n const at = html.indexOf(\"<\", i);\n if (at === -1 || at >= limit) return -1;\n if (\n startsWithIgnoreCase(html, at + 1, CODE_TAG) &&\n !isNameChar(html[at + 1 + CODE_TAG.length])\n ) {\n return at;\n }\n i = at + 1;\n }\n return -1;\n}\n\n/**\n * Index just after the `>` that ends the tag at `open`. A quoted `>` is part\n * of an attribute (`data-bee-code=\"{% if n > 1 %}\"`), not the end of the tag.\n * -1 when the tag never closes.\n */\nfunction endOfTag(html: string, open: number): number {\n let quote: string | null = null;\n for (let i = open + 1; i < html.length; i++) {\n const char = html[i];\n if (quote) {\n if (char === quote) quote = null;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n continue;\n }\n if (char === \">\") return i + 1;\n }\n return -1;\n}\n\n/** `<code … />`, with whitespace allowed before the slash. */\nfunction isSelfClosing(html: string, openEnd: number): boolean {\n let i = openEnd - 2;\n while (i >= 0 && isSpace(html[i])) i--;\n return html[i] === \"/\";\n}\n\n/**\n * The open tag carries `data-bee-type=\"mergetag\"`. The attribute may sit\n * anywhere, in double quotes, single quotes, or none.\n */\nfunction isMergetagOpen(html: string, open: number, openEnd: number): boolean {\n let i = open + 1 + CODE_TAG.length;\n const end = openEnd - 1;\n while (i < end) {\n while (i < end && isSpace(html[i])) i++;\n if (i >= end || html[i] === \"/\") break;\n const nameStart = i;\n while (i < end && !isSpace(html[i]) && html[i] !== \"=\" && html[i] !== \"/\") {\n i++;\n }\n const name = html.slice(nameStart, i);\n while (i < end && isSpace(html[i])) i++;\n let value = \"\";\n if (html[i] === \"=\") {\n i++;\n while (i < end && isSpace(html[i])) i++;\n const quote = html[i];\n if (quote === '\"' || quote === \"'\") {\n i++;\n const valueStart = i;\n while (i < end && html[i] !== quote) i++;\n value = html.slice(valueStart, i);\n if (html[i] === quote) i++;\n } else {\n const valueStart = i;\n while (i < end && !isSpace(html[i]) && html[i] !== \"/\") i++;\n value = html.slice(valueStart, i);\n }\n }\n if (equalsIgnoreCase(name, \"data-bee-type\") && value === \"mergetag\") {\n return true;\n }\n }\n return false;\n}\n\ninterface CodeClose {\n start: number;\n end: number;\n}\n\n/** Index just after the `>` of a `</code>` at `at`, or -1 when `at` is not one. */\nfunction codeCloseEnd(html: string, at: number): number {\n if (!startsWithIgnoreCase(html, at + 1, `/${CODE_TAG}`)) return -1;\n let j = at + 2 + CODE_TAG.length;\n while (j < html.length && isSpace(html[j])) j++;\n return html[j] === \">\" ? j + 1 : -1;\n}\n\n/**\n * The matching `</code>` for every `<code>` that has one, counting nested\n * `<code>` elements. One forward pass: an unclosed tag does not make every\n * later tag scan the rest of the string.\n */\nfunction indexCodeCloses(html: string): Map<number, CodeClose> {\n const closes = new Map<number, CodeClose>();\n const stack: number[] = [];\n let i = 0;\n while (i < html.length) {\n const at = html.indexOf(\"<\", i);\n if (at === -1) break;\n const closeEnd = codeCloseEnd(html, at);\n if (closeEnd !== -1) {\n const open = stack.pop();\n if (open !== undefined) closes.set(open, { start: at, end: closeEnd });\n i = closeEnd;\n continue;\n }\n if (\n startsWithIgnoreCase(html, at + 1, CODE_TAG) &&\n !isNameChar(html[at + 1 + CODE_TAG.length])\n ) {\n const openEnd = endOfTag(html, at);\n if (openEnd === -1) break;\n if (!isSelfClosing(html, openEnd)) stack.push(at);\n i = openEnd;\n continue;\n }\n i = at + 1;\n }\n return closes;\n}\n\ninterface Rope {\n parts: Array<string | Rope>;\n brace: boolean;\n dirty: boolean;\n blank: boolean;\n len: number;\n}\n\ninterface PieceFlags {\n brace: boolean;\n dirty: boolean;\n blank: boolean;\n len: number;\n}\n\n/** `{` can open a token. `&` can be a character reference. Both need the joined text. */\nfunction pieceFlags(text: string): PieceFlags {\n let brace = false;\n let dirty = false;\n let blank = true;\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n if (char === \"{\") brace = true;\n else if (char === \"&\") dirty = true;\n if (blank && !/\\s/.test(char)) blank = false;\n if (brace && dirty && !blank) break;\n }\n if (text.length === 0) blank = true;\n return { brace, dirty, blank, len: text.length };\n}\n\nfunction flagsOf(parts: ReadonlyArray<string | Rope>): PieceFlags {\n let brace = false;\n let dirty = false;\n let blank = true;\n let len = 0;\n for (const part of parts) {\n const flags = typeof part === \"string\" ? pieceFlags(part) : part;\n brace = brace || flags.brace;\n dirty = dirty || flags.dirty;\n blank = blank && flags.blank;\n len += flags.len;\n }\n return { brace, dirty, blank, len };\n}\n\nfunction flattenRope(parts: ReadonlyArray<string | Rope>): string {\n const out: string[] = [];\n const lists: Array<ReadonlyArray<string | Rope>> = [parts];\n const index: number[] = [0];\n while (lists.length > 0) {\n const list = lists[lists.length - 1];\n const at = index[index.length - 1];\n if (at >= list.length) {\n lists.pop();\n index.pop();\n continue;\n }\n index[index.length - 1] = at + 1;\n const piece = list[at];\n if (typeof piece === \"string\") out.push(piece);\n else {\n lists.push(piece.parts);\n index.push(0);\n }\n }\n return out.join(\"\");\n}\n\n/**\n * A closed chip's text. Nested chips are already ropes, so a chain of chips\n * that is not a token or a padding space is not joined until the root.\n */\nfunction finishMergetag(parts: Array<string | Rope>): string | Rope {\n const flags = flagsOf(parts);\n if (!flags.brace && !flags.dirty) {\n if (flags.len === 0) return \"\";\n if (flags.blank) return \" \";\n if (parts.length === 1) return parts[0];\n return { parts, ...flags };\n }\n return keptMergetagText(flattenRope(parts));\n}\n\ninterface MergetagFrame {\n parts: Array<string | Rope>;\n closeStart: number;\n closeEnd: number;\n}\n\n/**\n * Remove a `<code data-bee-type=\"mergetag\">` wrapper and keep the text inside\n * it. The editor turns a bare `{{ … }}` or `{% … %}` token in rich text into\n * a merge-tag span when the template loads, which is the shape BeeFree's HTML\n * export already leaves. A `<code>` without that attribute stays, including an\n * inline code sample and a `data-bee-type=\"speciallink\"` wrapper. Run this\n * before `decodeEntitiesInTokens`: a token inside `data-bee-code` would\n * otherwise be decoded in the attribute and break its quotes. An opener with\n * no closer is left as written.\n */\nexport function unwrapMergeTagCode(html: string): string {\n if (html.indexOf(\"<\") === -1) return html;\n const closes = indexCodeCloses(html);\n const root: Array<string | Rope> = [];\n const stack: MergetagFrame[] = [];\n const dest = (): Array<string | Rope> =>\n stack.length > 0 ? stack[stack.length - 1].parts : root;\n\n let i = 0;\n while (i < html.length) {\n const frame = stack.length > 0 ? stack[stack.length - 1] : undefined;\n const open = indexOfCodeOpen(\n html,\n i,\n frame ? frame.closeStart : html.length,\n );\n if (frame && open === -1) {\n if (i < frame.closeStart)\n frame.parts.push(html.slice(i, frame.closeStart));\n const inner = finishMergetag(frame.parts);\n stack.pop();\n dest().push(inner);\n i = frame.closeEnd;\n continue;\n }\n if (open === -1) {\n dest().push(html.slice(i));\n break;\n }\n const openEnd = endOfTag(html, open);\n if (openEnd === -1) {\n dest().push(html.slice(i));\n break;\n }\n dest().push(html.slice(i, open));\n if (!isMergetagOpen(html, open, openEnd)) {\n dest().push(html.slice(open, openEnd));\n i = openEnd;\n continue;\n }\n if (isSelfClosing(html, openEnd)) {\n i = openEnd;\n continue;\n }\n const close = closes.get(open);\n if (close === undefined) {\n dest().push(html.slice(open, openEnd));\n i = openEnd;\n continue;\n }\n stack.push({ parts: [], closeStart: close.start, closeEnd: close.end });\n i = openEnd;\n }\n return flattenRope(root);\n}\n\n/**\n * A `<code>` that only highlights one token leads with plain spaces that are\n * not part of the token. A non-breaking space stays. The element stays, and\n * so does a space after the token.\n * Nested markup inside the element is left as written.\n */\nexport function trimHighlightedTokenPadding(html: string): string {\n if (html.indexOf(\"<\") === -1) return html;\n const closes = indexCodeCloses(html);\n const parts: string[] = [];\n let i = 0;\n while (i < html.length) {\n const open = indexOfCodeOpen(html, i);\n if (open === -1) {\n parts.push(html.slice(i));\n break;\n }\n const openEnd = endOfTag(html, open);\n if (openEnd === -1) {\n parts.push(html.slice(i));\n break;\n }\n parts.push(html.slice(i, openEnd));\n if (isSelfClosing(html, openEnd)) {\n i = openEnd;\n continue;\n }\n const close = closes.get(open);\n if (close === undefined) {\n i = openEnd;\n continue;\n }\n const inner = html.slice(openEnd, close.start);\n parts.push(inner.includes(\"<\") ? inner : withoutLeadingTokenPadding(inner));\n parts.push(html.slice(close.start, close.end));\n i = close.end;\n }\n return parts.join(\"\");\n}\n","import type {\n BackgroundImage,\n BackgroundPositionX,\n BackgroundPositionY,\n BackgroundSize,\n SpacingValue,\n} from \"@templatical/types\";\n\n/**\n * Parses CSS-like style values from BeeFree descriptors.\n */\n\n/**\n * The CSS-wide keywords. Each one defers to the cascade instead of naming a\n * value, and a block field that carried one would reach the renderer\n * verbatim, so the parsers read them as unset and the caller's fallback\n * applies.\n */\nconst CSS_WIDE_KEYWORDS = new Set([\"inherit\", \"initial\", \"unset\", \"revert\"]);\n\nfunction isCssWideKeyword(value: string): boolean {\n return CSS_WIDE_KEYWORDS.has(value.trim().toLowerCase());\n}\n\nexport function parsePxValue(value: string | undefined): number {\n if (!value) return 0;\n const match = value.match(/^(-?\\d+(?:\\.\\d+)?)\\s*px/);\n return match ? Math.round(parseFloat(match[1])) : 0;\n}\n\n/**\n * An image's corner radius in px, or `undefined` for square corners.\n *\n * Accepts a percentage as well as a px length, because `border-radius: 50%` is\n * the idiomatic way to write a circular avatar and the block stores px only. A\n * percentage resolves against the shorter rendered side, which is what turns a\n * square image into a circle and a wide one into a pill.\n *\n * `width` and `height` must be the dimensions actually read from the source. A\n * percentage with neither known is dropped rather than resolved against the\n * caller's fallback width, which would invent a radius the template never\n * expressed. A non-positive result is dropped for the same reason a px `0` is:\n * both mean square, and only absence keeps it out of the exported JSON.\n */\nexport function parseImageBorderRadius(\n value: string | undefined,\n width: number | undefined,\n height: number | undefined,\n): number | undefined {\n if (!value) return undefined;\n\n // Deliberately no `-?`: a negative percentage falls through to the px parse,\n // which rejects it too.\n const percent = value.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*%$/);\n if (percent) {\n const side = Math.min(width ?? Infinity, height ?? Infinity);\n if (!Number.isFinite(side)) return undefined;\n const radius = Math.round((parseFloat(percent[1]) / 100) * side);\n return radius > 0 ? radius : undefined;\n }\n\n const px = parsePxValue(value);\n return px > 0 ? px : undefined;\n}\n\n/**\n * A color as lowercase 6-digit hex where it is hex, otherwise as written.\n *\n * `\"\"` means unset: returned for transparent, `none` and the CSS-wide\n * keywords, so the caller's fallback applies.\n */\nexport function parseColor(value: string | undefined): string {\n if (!value) return \"\";\n\n const trimmed = value.trim();\n const keyword = trimmed.toLowerCase();\n if (\n keyword === \"transparent\" ||\n keyword === \"none\" ||\n isCssWideKeyword(keyword)\n )\n return \"\";\n\n // Already a valid hex color\n if (/^#[0-9a-fA-F]{6}$/.test(trimmed)) return trimmed.toLowerCase();\n\n // 3-digit hex → 6-digit\n if (/^#[0-9a-fA-F]{3}$/.test(trimmed)) {\n const r = trimmed[1];\n const g = trimmed[2];\n const b = trimmed[3];\n return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();\n }\n\n // Return as-is for rgb(), named colors, etc.\n return trimmed;\n}\n\n/**\n * Whether a CSS colour paints nothing: `transparent`, or an alpha of 0 in a\n * hex (`#rgba`, `#rrggbbaa`) or functional (`rgba()`, `hsl(… / 0%)`) colour.\n */\nexport function isTransparentColor(value: string | undefined): boolean {\n if (!value) return false;\n const color = value.trim().toLowerCase();\n if (color === \"transparent\") return true;\n\n const hex = color.match(\n /^#(?:[0-9a-f]{3}([0-9a-f])|[0-9a-f]{6}([0-9a-f]{2}))$/,\n );\n if (hex) return /^0+$/.test(hex[1] ?? hex[2]);\n\n const fn = color.match(/^(?:rgb|hsl)a?\\((.*)\\)$/);\n if (!fn) return false;\n const alpha = fn[1].includes(\"/\") ? fn[1].split(\"/\")[1] : fn[1].split(\",\")[3];\n if (alpha === undefined) return false;\n const opacity = parseFloat(alpha);\n return Number.isFinite(opacity) && opacity <= 0;\n}\n\nconst BORDER_STYLES = new Set([\n \"none\",\n \"hidden\",\n \"dotted\",\n \"dashed\",\n \"solid\",\n \"double\",\n \"groove\",\n \"ridge\",\n \"inset\",\n \"outset\",\n]);\n\nconst BORDER_WIDTH_KEYWORDS: Record<string, number> = {\n thin: 1,\n medium: 3,\n thick: 5,\n};\n\n/** Split on whitespace outside parentheses, so `rgba(0, 0, 0, 0)` is one part. */\nfunction splitShorthand(value: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let current = \"\";\n for (const ch of value.trim()) {\n if (ch === \"(\") depth++;\n if (ch === \")\") depth = Math.max(0, depth - 1);\n if (depth === 0 && /\\s/.test(ch)) {\n if (current) parts.push(current);\n current = \"\";\n continue;\n }\n current += ch;\n }\n if (current) parts.push(current);\n return parts;\n}\n\n/**\n * A `border-top` shorthand, its parts in any order. `width` is the room the\n * border takes, so a `none` or `hidden` border has none. `drawn` is false when\n * the border paints nothing: a stated 0 width, a `none` or `hidden` style, or a\n * transparent colour. A shorthand without a width reads as 0 wide but drawn.\n */\nexport function parseBorderTop(value: string | undefined): {\n width: number;\n style: string;\n color: string;\n drawn: boolean;\n} {\n if (!value)\n return { width: 0, style: \"solid\", color: \"#000000\", drawn: true };\n\n let width: number | undefined;\n let style: string | undefined;\n let colorPart: string | undefined;\n for (const part of splitShorthand(value)) {\n const lower = part.toLowerCase();\n // Each run of digits has one way to match, so a long one fails in linear\n // time; `\\d*\\.?\\d+` could split it anywhere.\n const length = lower.match(/^(\\d+(?:\\.\\d+)?|\\.\\d+)(px)?$/);\n if (\n width === undefined &&\n length &&\n (length[2] || Number(length[1]) === 0)\n ) {\n width = Number(length[1]);\n } else if (\n width === undefined &&\n Object.hasOwn(BORDER_WIDTH_KEYWORDS, lower)\n ) {\n width = BORDER_WIDTH_KEYWORDS[lower];\n } else if (style === undefined && BORDER_STYLES.has(lower)) {\n style = lower;\n } else {\n colorPart ??= part;\n }\n }\n\n const hidden = style === \"none\" || style === \"hidden\";\n return {\n width: hidden || width === undefined ? 0 : Math.round(width),\n style: style ?? \"solid\",\n color: parseColor(colorPart) || \"#000000\",\n drawn: width !== 0 && !hidden && !isTransparentColor(colorPart),\n };\n}\n\nexport function extractPadding(\n style: Record<string, string> | undefined,\n): SpacingValue {\n if (!style) return { top: 0, right: 0, bottom: 0, left: 0 };\n\n // CSS drops a padding declaration with a negative length: a shorthand with\n // a negative side leaves the longhands, and a negative longhand leaves 0.\n if (style.padding && !hasNegativeLength(style.padding)) {\n return parseShorthandPadding(style.padding);\n }\n\n return {\n top: paddingLonghand(style[\"padding-top\"]),\n right: paddingLonghand(style[\"padding-right\"]),\n bottom: paddingLonghand(style[\"padding-bottom\"]),\n left: paddingLonghand(style[\"padding-left\"]),\n };\n}\n\nfunction paddingLonghand(value: string | undefined): number {\n return Math.max(0, parsePxValue(value));\n}\n\n/**\n * Whether a padding value holds a negative length, read before rounding:\n * `-0.4px` rounds to `-0`, which would pass as valid. A literal `-0` is 0.\n */\nfunction hasNegativeLength(value: string): boolean {\n return value\n .trim()\n .split(/\\s+/)\n .some((part) => parseFloat(part) < 0);\n}\n\nfunction parseShorthandPadding(value: string): SpacingValue {\n const parts = value.trim().split(/\\s+/);\n const values = parts.map((p) => parsePxValue(p));\n\n switch (values.length) {\n case 1:\n return {\n top: values[0],\n right: values[0],\n bottom: values[0],\n left: values[0],\n };\n case 2:\n return {\n top: values[0],\n right: values[1],\n bottom: values[0],\n left: values[1],\n };\n case 3:\n return {\n top: values[0],\n right: values[1],\n bottom: values[2],\n left: values[1],\n };\n default:\n return {\n top: values[0],\n right: values[1],\n bottom: values[2],\n left: values[3],\n };\n }\n}\n\n/**\n * A divider's `width` as a number and its unit, or `undefined` when it is\n * neither a px nor a % length (`auto`, a keyword, anything unreadable).\n */\nexport function parseDividerWidth(\n value: string,\n): { value: number; unit: \"px\" | \"%\" } | undefined {\n const match = value.trim().match(/^(-?\\d+(?:\\.\\d+)?)\\s*(%|px)$/);\n if (!match) return undefined;\n return { value: parseFloat(match[1]), unit: match[2] === \"%\" ? \"%\" : \"px\" };\n}\n\n/** A background image read from the source, with a note for each value that had no exact keyword. */\nexport interface ReadBackgroundImage {\n image: BackgroundImage;\n notes: string[];\n}\n\nconst X_GRID = [\"left\", \"center\", \"right\"] as const;\nconst Y_GRID = [\"top\", \"center\", \"bottom\"] as const;\nconst PERCENT = /^(-?(?:\\d+(?:\\.\\d+)?|\\.\\d+))%$/;\nconst LENGTH = /^-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)[a-z]*$/;\n\n/**\n * `background-size` as a keyword. A size with a side at 100%, or a px width\n * spanning the box, fills it as `cover` does; any other length or percentage\n * draws the image at a size of its own, which `auto` is closest to.\n */\nfunction backgroundSizeKeyword(\n raw: string,\n boxWidth: number | undefined,\n): { size: BackgroundSize; exact: boolean } {\n const parts = raw.toLowerCase().split(/\\s+/);\n const [first] = parts;\n if (parts.length === 1 && (first === \"cover\" || first === \"contain\")) {\n return { size: first, exact: true };\n }\n if (parts.every((part) => part === \"auto\")) {\n return { size: \"auto\", exact: true };\n }\n const px = /^(\\d+(?:\\.\\d+)?|\\.\\d+)px$/.exec(first);\n const fills =\n parts.includes(\"100%\") ||\n (px !== null && boxWidth !== undefined && Number(px[1]) >= boxWidth);\n return { size: fills ? \"cover\" : \"auto\", exact: false };\n}\n\n/**\n * `background-position` split into x and y the way MJML and CSS read it: a\n * lone `top` / `bottom` names y and centres x, any other lone value is x\n * with y centred, and a pair is x then y unless it leads with `top` /\n * `bottom` (or with `center` before `left` / `right`). Three- and four-value\n * edge offsets keep their edge keywords only.\n */\nfunction splitBackgroundPosition(raw: string): {\n x: string;\n y: string;\n exact: boolean;\n} {\n const parts = raw.toLowerCase().split(/\\s+/);\n if (parts.length === 1) {\n const [only] = parts;\n return only === \"top\" || only === \"bottom\"\n ? { x: \"center\", y: only, exact: true }\n : { x: only, y: \"center\", exact: true };\n }\n if (parts.length === 2) {\n const [a, b] = parts;\n const yFirst =\n a === \"top\" ||\n a === \"bottom\" ||\n (a === \"center\" && (b === \"left\" || b === \"right\"));\n return yFirst ? { x: b, y: a, exact: true } : { x: a, y: b, exact: true };\n }\n return {\n x: parts.find((part) => part === \"left\" || part === \"right\") ?? \"center\",\n y: parts.find((part) => part === \"top\" || part === \"bottom\") ?? \"center\",\n exact: false,\n };\n}\n\n/**\n * One axis as a grid point: its keyword; the point nearest a percentage,\n * ties going to the centre; or the start edge for a length, which is an\n * offset from it. `null` when the token is unreadable.\n */\nfunction backgroundAxisPoint<T extends string>(\n token: string,\n grid: readonly [T, T, T],\n): { point: T; exact: boolean } | null {\n const keyword = grid.find((point) => point === token);\n if (keyword) return { point: keyword, exact: true };\n const percent = PERCENT.exec(token);\n if (percent) {\n const n = Number(percent[1]);\n return {\n point: n < 25 ? grid[0] : n > 75 ? grid[2] : grid[1],\n exact: n === 0 || n === 50 || n === 100,\n };\n }\n if (LENGTH.test(token)) {\n return { point: grid[0], exact: parseFloat(token) === 0 };\n }\n return null;\n}\n\n/**\n * `background-repeat`: unrepeated only when every axis is `no-repeat`.\n * Anything but plain `repeat` tiles too, inexactly.\n */\nfunction backgroundRepeatFlag(raw: string): {\n repeat: boolean;\n exact: boolean;\n} {\n const parts = raw.toLowerCase().split(/\\s+/);\n if (parts.every((part) => part === \"no-repeat\")) {\n return { repeat: false, exact: true };\n }\n return { repeat: true, exact: parts.every((part) => part === \"repeat\") };\n}\n\n/** CSS's initial values: what a browser paints for a longhand BeeFree leaves out. */\nconst CSS_BACKGROUND_DEFAULTS = {\n size: \"auto\",\n x: \"left\",\n y: \"top\",\n repeat: true,\n} as const;\n\n/**\n * The URL inside the first CSS `url(…)`, unquoted and trimmed; \"\" when there\n * is none or it is malformed. A forward scan rather than a regex, so a long\n * run of unclosed `url(` can't make it backtrack.\n */\nfunction cssUrl(value: string | undefined): string {\n const text = value ?? \"\";\n const start = text.search(/url\\(/i);\n if (start === -1) return \"\";\n let i = start + 4;\n while (i < text.length && /\\s/.test(text[i])) i++;\n const quote = text[i];\n if (quote === '\"' || quote === \"'\") {\n const close = text.indexOf(quote, i + 1);\n if (close === -1) return \"\";\n let j = close + 1;\n while (j < text.length && /\\s/.test(text[j])) j++;\n return text[j] === \")\" ? text.slice(i + 1, close).trim() : \"\";\n }\n const close = text.indexOf(\")\", i);\n if (close === -1) return \"\";\n const inner = text.slice(i, close);\n return /[\"']/.test(inner) ? \"\" : inner.trim();\n}\n\n/**\n * A row's background image from a BeeFree style map (`content.style` or\n * `container.style`), `null` when `background-image` holds no `url()`.\n * Unset longhands take CSS's initial values; a value with no exact keyword\n * takes the nearest one and adds a note naming it. `label` names the element\n * in each note, and a px `background-size` is measured against `boxWidth`.\n */\nexport function readBeefreeBackgroundImage(\n style: Record<string, string> | undefined,\n label: string,\n boxWidth: number | undefined,\n): ReadBackgroundImage | null {\n const url = cssUrl(style?.[\"background-image\"]);\n if (!url) return null;\n\n const notes: string[] = [];\n const lossy = (name: string, raw: string, shown: string): void => {\n notes.push(\n `${label} ${name} \"${raw}\" has no exact Templatical equivalent; imported as \"${shown}\".`,\n );\n };\n\n let size: BackgroundSize = CSS_BACKGROUND_DEFAULTS.size;\n const rawSize = style?.[\"background-size\"]?.trim();\n if (rawSize) {\n const parsed = backgroundSizeKeyword(rawSize, boxWidth);\n size = parsed.size;\n if (!parsed.exact) lossy(\"background-size\", rawSize, size);\n }\n\n let x: BackgroundPositionX = CSS_BACKGROUND_DEFAULTS.x;\n let y: BackgroundPositionY = CSS_BACKGROUND_DEFAULTS.y;\n const rawPosition = style?.[\"background-position\"]?.trim();\n if (rawPosition) {\n const split = splitBackgroundPosition(rawPosition);\n const readX = backgroundAxisPoint(split.x, X_GRID);\n const readY = backgroundAxisPoint(split.y, Y_GRID);\n x = readX?.point ?? x;\n y = readY?.point ?? y;\n if (!split.exact || !readX?.exact || !readY?.exact) {\n lossy(\"background-position\", rawPosition, `${x} ${y}`);\n }\n }\n\n let repeat: boolean = CSS_BACKGROUND_DEFAULTS.repeat;\n const rawRepeat = style?.[\"background-repeat\"]?.trim();\n if (rawRepeat) {\n const parsed = backgroundRepeatFlag(rawRepeat);\n repeat = parsed.repeat;\n if (!parsed.exact) {\n lossy(\"background-repeat\", rawRepeat, repeat ? \"repeat\" : \"no-repeat\");\n }\n }\n\n return { image: { url, size, position: { x, y }, repeat }, notes };\n}\n","import { localeTag, text, warn } from \"./localization\";\nimport {\n BORDER_SIDES,\n canonicalFontStack,\n findOpenTagEnd,\n isSafeHtmlUrl,\n HEADING_LEVEL_FONT_SIZE,\n createTitleBlock,\n createParagraphBlock,\n createImageBlock,\n createButtonBlock,\n createDividerBlock,\n createSpacerBlock,\n createHtmlBlock,\n createSocialIconsBlock,\n createMenuBlock,\n createTableBlock,\n createVideoBlock,\n generateId,\n} from \"@templatical/types\";\nimport type {\n Block,\n ButtonBlock,\n BorderStyle,\n BorderValue,\n DividerBlock,\n HeadingLevel,\n ImageBlock,\n SocialPlatform,\n SocialIcon,\n SocialIconSize,\n SocialIconStyle,\n SocialIconsBlock,\n SocialIconTone,\n MenuItemData,\n SpacingValue,\n TableRowData,\n TableCellData,\n} from \"@templatical/types\";\nimport type {\n BeeFreeeIconItem,\n BeeFreeeModule,\n BeeFreeeModuleDescriptor,\n BeeFreeeSocialIcon,\n ImportReportEntry,\n} from \"./types\";\nimport {\n decodeEntitiesInHtml,\n decodeEntitiesInTokens,\n decodePlainTextEntities,\n restoreDoubledNbsp,\n trimHighlightedTokenPadding,\n unwrapMergeTagCode,\n} from \"./merge-tokens\";\nimport {\n parseImageBorderRadius,\n parsePxValue,\n parseColor,\n parseBorderTop,\n extractPadding,\n parseDividerWidth,\n} from \"./style-parser\";\n\n/**\n * The template text color the import writes when the body sets none.\n */\nexport const FALLBACK_TEXT_COLOR = \"#1a1a1a\";\n\n/**\n * What the caller knows about where a module lands.\n */\nexport interface ModuleContext {\n /**\n * Width in px of the Templatical column the block renders in. Without it a\n * px divider width is kept as pixels.\n */\n columnWidth?: number;\n /**\n * The template's `textColor`, which every text block without a color of\n * its own inherits. Defaults to `FALLBACK_TEXT_COLOR`.\n */\n textColor?: string;\n /**\n * Padding a snapped column gives back, and the column padding folded onto\n * the module. Set on every column of a snapped row. Image, lone-icon and\n * divider rooms include padding that comes back and exclude column padding\n * the module keeps.\n */\n paddingReturn?: {\n deficit: number;\n sides: Array<\"left\" | \"right\">;\n columnPadding: Pick<SpacingValue, \"left\" | \"right\">;\n };\n}\n\n/**\n * Maps BeeFree module type strings to short keys.\n */\nconst MODULE_TYPE_MAP: Record<string, string> = {\n \"mailup-bee-newsletter-modules-text\": \"paragraph\",\n \"mailup-bee-newsletter-modules-paragraph\": \"paragraph\",\n \"mailup-bee-newsletter-modules-heading\": \"title\",\n \"mailup-bee-newsletter-modules-list\": \"list\",\n \"mailup-bee-newsletter-modules-image\": \"image\",\n \"mailup-bee-newsletter-modules-button\": \"button\",\n \"mailup-bee-newsletter-modules-divider\": \"divider\",\n \"mailup-bee-newsletter-modules-spacer\": \"spacer\",\n \"mailup-bee-newsletter-modules-html\": \"html\",\n \"mailup-bee-newsletter-modules-social\": \"social\",\n \"mailup-bee-newsletter-modules-video\": \"video\",\n \"mailup-bee-newsletter-modules-menu\": \"menu\",\n \"mailup-bee-newsletter-modules-table\": \"table\",\n \"mailup-bee-newsletter-modules-icons\": \"icons\",\n};\n\nconst ADDON_MODULE = \"mailup-bee-newsletter-modules-addon\";\nconst EMPTY_MODULE = \"mailup-bee-newsletter-modules-empty\";\n\n/**\n * An addon keeps the payload of the module it stands in for, so the payload it\n * carries names the converter. Checked in this order.\n */\nconst ADDON_PAYLOADS = [\n [\"image\", \"image\"],\n [\"html\", \"html\"],\n [\"heading\", \"title\"],\n [\"paragraph\", \"paragraph\"],\n [\"text\", \"paragraph\"],\n [\"list\", \"list\"],\n [\"button\", \"button\"],\n [\"divider\", \"divider\"],\n [\"menu\", \"menu\"],\n [\"iconsList\", \"icons\"],\n] as const;\n\n/** The converter a module goes to, or `undefined` when there is none. */\nfunction moduleKind(module: BeeFreeeModule): string | undefined {\n if (module.type !== ADDON_MODULE) return MODULE_TYPE_MAP[module.type];\n return ADDON_PAYLOADS.find(\n ([key]) => module.descriptor[key] !== undefined,\n )?.[1];\n}\n\nconst SOCIAL_PLATFORM_MAP: Record<string, SocialPlatform> = {\n facebook: \"facebook\",\n twitter: \"twitter\",\n x: \"twitter\",\n instagram: \"instagram\",\n linkedin: \"linkedin\",\n xing: \"xing\",\n youtube: \"youtube\",\n tiktok: \"tiktok\",\n pinterest: \"pinterest\",\n email: \"email\",\n whatsapp: \"whatsapp\",\n telegram: \"telegram\",\n discord: \"discord\",\n snapchat: \"snapchat\",\n reddit: \"reddit\",\n github: \"github\",\n dribbble: \"dribbble\",\n behance: \"behance\",\n};\n\ntype Align = \"left\" | \"center\" | \"right\";\ntype LineStyle = \"solid\" | \"dashed\" | \"dotted\";\n\nfunction toAlign(value: string | undefined, fallback: Align = \"left\"): Align {\n if (value === \"left\" || value === \"center\" || value === \"right\") return value;\n return fallback;\n}\n\nfunction toLineStyle(\n value: string | undefined,\n fallback: LineStyle = \"solid\",\n): LineStyle {\n if (value === \"solid\" || value === \"dashed\" || value === \"dotted\")\n return value;\n return fallback;\n}\n\n/**\n * Strip every `<…>` from a button label and reject any stray `<` or `>`\n * left behind (e.g. a truncated `<script`). The original\n * `value.replace(/<[^>]*>/g, \"\")` was both polynomial-ReDoS over\n * `<<<<…` inputs and an incomplete sanitizer — an unterminated `<script`\n * would survive the strip. Downstream HTML-escapes the label at render\n * time, but stripping here keeps the imported JSON clean.\n */\nfunction stripTagsPlain(text: string): string {\n let out = \"\";\n let i = 0;\n while (i < text.length) {\n if (text[i] === \"<\") {\n const close = text.indexOf(\">\", i + 1);\n if (close === -1) {\n // Unterminated tag — discard the rest.\n break;\n }\n i = close + 1;\n continue;\n }\n if (text[i] === \">\") {\n i++;\n continue;\n }\n out += text[i];\n i++;\n }\n return out;\n}\n\n/**\n * Rich text keeps the markup around a merge tag. Unwrap the BeeFree `<code>`\n * before decoding, so a token quoted inside `data-bee-code` is not decoded\n * in the attribute. A quote inside a token stays encoded in an attribute\n * and is decoded in a text node.\n */\nfunction importedHtml(html: string): string {\n return restoreDoubledNbsp(\n decodeEntitiesInHtml(trimHighlightedTokenPadding(unwrapMergeTagCode(html))),\n );\n}\n\n/**\n * A button label or table cell is plain text. Unwrap before stripping, so a\n * `>` inside a mergetag `<code>` attribute is not the end of the tag, and\n * strip before decoding, so a `>` inside a token is not a stray `>`.\n * Decode references outside tokens too: the renderer escapes the whole label.\n */\nfunction importedPlainText(value: string): string {\n return decodePlainTextEntities(\n stripTagsPlain(trimHighlightedTokenPadding(unwrapMergeTagCode(value))),\n );\n}\n\nfunction makeStyles(descriptor: BeeFreeeModuleDescriptor): Block[\"styles\"] {\n const padding = extractPadding(descriptor.style);\n const bg = parseColor(descriptor.style?.[\"background-color\"]);\n return {\n padding,\n ...(bg ? { backgroundColor: bg } : {}),\n };\n}\n\n/**\n * Pixels taken from `padding` on `sides`, at most `deficit`, in that order.\n * Nothing is taken past 0.\n */\nfunction paddingReturned(\n padding: Pick<SpacingValue, \"left\" | \"right\">,\n deficit: number,\n sides: Array<\"left\" | \"right\">,\n): number {\n let returned = 0;\n let remaining = deficit;\n for (const side of sides) {\n if (remaining <= 0) break;\n const have = padding[side];\n if (have <= 0) continue;\n const give = Math.min(remaining, have);\n returned += give;\n remaining -= give;\n }\n return returned;\n}\n\n/**\n * The room an image, a lone icon or a divider is measured in: the column\n * less the side padding the block keeps. A snapped column gives inner\n * padding back after the width is chosen. Those pixels are part of the room.\n * Column padding the block keeps, on either side, is not, whether or not any\n * padding comes back.\n */\nfunction measuredRoom(\n columnWidth: number | undefined,\n padding: SpacingValue,\n giveBack: ModuleContext[\"paddingReturn\"],\n): number | undefined {\n if (columnWidth === undefined) return undefined;\n const room = columnWidth - padding.left - padding.right;\n if (!giveBack) return room;\n const folded = {\n left: padding.left + giveBack.columnPadding.left,\n right: padding.right + giveBack.columnPadding.right,\n };\n const returned = paddingReturned(folded, giveBack.deficit, giveBack.sides);\n return (\n room - giveBack.columnPadding.left - giveBack.columnPadding.right + returned\n );\n}\n\ninterface StyleDecl {\n name: string;\n value: string;\n}\n\n/**\n * A block BeeFree's text markup uses as a root. `ul` / `ol` carry the module's\n * alignment and line-height; their items carry the text styles.\n */\nconst TEXT_ROOTS = new Set([\n \"p\",\n \"li\",\n \"div\",\n \"ul\",\n \"ol\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n]);\n\n/**\n * BeeFree stores a text module's line-height as a percentage (`120%`, `200%`)\n * or a unitless number, and renders that — not the px value TinyMCE writes\n * into the blob. The paragraph editor stores the unitless ratio.\n */\nfunction moduleLineHeight(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (!trimmed || /^(inherit|initial|unset|revert)$/i.test(trimmed))\n return undefined;\n const percent = /^(\\d+(?:\\.\\d+)?)\\s*%$/.exec(trimmed);\n if (percent) {\n const ratio = Number(percent[1]) / 100;\n if (!Number.isFinite(ratio) || ratio <= 0) return undefined;\n return String(Math.round(ratio * 1000) / 1000);\n }\n if (/^\\d+(?:\\.\\d+)?$/.test(trimmed)) {\n const ratio = Number(trimmed);\n return Number.isFinite(ratio) && ratio > 0 ? String(ratio) : undefined;\n }\n const length = /^(\\d+(?:\\.\\d+)?)\\s*(px|em|rem)$/i.exec(trimmed);\n if (length) return `${length[1]}${length[2].toLowerCase()}`;\n if (/^normal$/i.test(trimmed)) return \"normal\";\n return undefined;\n}\n\n/** `0` and `normal` are the CSS initial value, so they add no declaration. */\nfunction moduleLetterSpacing(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const compact = value.trim().replace(/\\s+/g, \"\");\n if (!compact || /^(normal|inherit|initial|unset|revert)$/i.test(compact))\n return undefined;\n if (/^0+(?:\\.0+)?(?:px|em|rem|%)?$/i.test(compact)) return undefined;\n return compact;\n}\n\n/**\n * The colour BeeFree paints on a text module's links: `linkColor` or\n * `link-color` on the module style, then the same keys on `computedStyle`.\n */\nfunction moduleLinkColor(\n content:\n | { style?: Record<string, string>; computedStyle?: Record<string, string> }\n | undefined,\n): string {\n if (!content) return \"\";\n return (\n parseColor(content.style?.linkColor) ||\n parseColor(content.style?.[\"link-color\"]) ||\n parseColor(content.computedStyle?.linkColor) ||\n parseColor(content.computedStyle?.[\"link-color\"]) ||\n \"\"\n );\n}\n\ninterface StyleAttrLoc {\n /** Index of the whitespace before `style`, so removing the attribute leaves no gap. */\n attrStart: number;\n /** First character after the attribute. A separating space stays when another attribute follows. */\n attrEnd: number;\n /** First character of the value, inside the quotes when the value is quoted. */\n valueStart: number;\n /** The closing quote when quoted; otherwise `attrEnd`. */\n valueEnd: number;\n /** Decoded, so a `;` inside an entity is not a declaration break. */\n value: string;\n quote?: '\"' | \"'\";\n}\n\nfunction attrWhitespaceStart(tag: string, nameStart: number): number {\n let attrStart = nameStart;\n while (attrStart > 0 && /\\s/.test(tag[attrStart - 1])) attrStart--;\n return attrStart;\n}\n\n/**\n * Exclusive end of the attribute. Whitespace after it belongs to the attribute\n * only when the tag ends there; a following attribute keeps its separator.\n */\nfunction styleAttrEnd(tag: string, end: number): number {\n let i = end;\n while (i < tag.length && /\\s/.test(tag[i])) i++;\n if (i >= tag.length || tag[i] === \">\" || tag[i] === \"/\") return i;\n return end;\n}\n\nfunction styleLoc(\n tag: string,\n nameStart: number,\n valueStart: number,\n rawEnd: number,\n value: string,\n quote?: '\"' | \"'\",\n): StyleAttrLoc {\n const attrEnd = styleAttrEnd(tag, rawEnd);\n return {\n attrStart: attrWhitespaceStart(tag, nameStart),\n attrEnd,\n valueStart,\n valueEnd: quote ? rawEnd - 1 : attrEnd,\n value,\n ...(quote ? { quote } : {}),\n };\n}\n\n/** The first `style` attribute on an open tag, ignoring `data-mce-style`. */\nexport function findStyleAttr(tag: string): StyleAttrLoc | undefined {\n let i = 1;\n if (tag[i] === \"/\") i++;\n while (i < tag.length && /[a-z0-9]/i.test(tag[i])) i++;\n for (;;) {\n while (i < tag.length && /\\s/.test(tag[i])) i++;\n if (i >= tag.length || tag[i] === \">\" || tag[i] === \"/\") return undefined;\n const nameStart = i;\n while (i < tag.length && !/[\\s=/>]/.test(tag[i])) i++;\n const name = tag.slice(nameStart, i).toLowerCase();\n const nameEnd = i;\n while (i < tag.length && /\\s/.test(tag[i])) i++;\n if (i >= tag.length || tag[i] !== \"=\") {\n if (name === \"style\")\n return styleLoc(tag, nameStart, nameEnd, nameEnd, \"\");\n continue;\n }\n i++;\n while (i < tag.length && /\\s/.test(tag[i])) i++;\n if (i >= tag.length) return undefined;\n const quote = tag[i];\n if (quote !== '\"' && quote !== \"'\") {\n const valueStart = i;\n while (i < tag.length && !/\\s/.test(tag[i]) && tag[i] !== \">\") i++;\n if (name === \"style\") {\n return styleLoc(\n tag,\n nameStart,\n valueStart,\n i,\n decodePlainTextEntities(tag.slice(valueStart, i)),\n );\n }\n continue;\n }\n const valueStart = i + 1;\n const valueEnd = tag.indexOf(quote, valueStart);\n if (valueEnd === -1) return undefined;\n if (name === \"style\") {\n return styleLoc(\n tag,\n nameStart,\n valueStart,\n valueEnd + 1,\n decodePlainTextEntities(tag.slice(valueStart, valueEnd)),\n quote,\n );\n }\n i = valueEnd + 1;\n }\n}\n\n/**\n * `additions` are appended when the declaration is absent. Names in `strip`\n * are removed first, so a module line-height replaces the blob's px value.\n * `undefined` means the attribute is empty and should be removed.\n */\nfunction mergeStyleValue(\n existing: string,\n additions: readonly StyleDecl[],\n strip: ReadonlySet<string>,\n): string | undefined {\n const kept: string[] = [];\n const present = new Set<string>();\n for (const part of existing.split(\";\")) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n const colon = trimmed.indexOf(\":\");\n const name = (colon === -1 ? trimmed : trimmed.slice(0, colon))\n .trim()\n .toLowerCase();\n present.add(name);\n if (strip.has(name)) continue;\n kept.push(trimmed);\n }\n for (const add of additions) {\n if (strip.has(add.name) || !present.has(add.name)) {\n kept.push(`${add.name}: ${add.value}`);\n }\n }\n return kept.length > 0 ? kept.join(\"; \") : undefined;\n}\n\n/**\n * Double quotes. `\"` and a bare `&` are escaped, then `<` and `>`, so the\n * attribute stays one value. An entity already in the value is left as\n * written. {@link decodePlainTextEntities} reads the escapes back.\n */\nfunction quoteStyleValue(value: string): string {\n const escaped = value\n .replace(/&(?![A-Za-z][A-Za-z0-9]+;|#[0-9]+;|#x[0-9A-Fa-f]+;)/g, \"&\")\n .replaceAll('\"', \""\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\");\n return `\"${escaped}\"`;\n}\n\nfunction rewriteOpenTag(\n openTag: string,\n additions: readonly StyleDecl[],\n strip: ReadonlySet<string>,\n): string {\n if (additions.length === 0 && strip.size === 0) return openTag;\n const loc = findStyleAttr(openTag);\n if (!loc) {\n if (additions.length === 0) return openTag;\n const value = additions\n .map((decl) => `${decl.name}: ${decl.value}`)\n .join(\"; \");\n const at = openTag.endsWith(\"/>\") ? openTag.length - 2 : openTag.length - 1;\n return `${openTag.slice(0, at)} style=${quoteStyleValue(value)}${openTag.slice(at)}`;\n }\n const merged = mergeStyleValue(loc.value, additions, strip);\n if (merged === undefined) {\n return openTag.slice(0, loc.attrStart) + openTag.slice(loc.attrEnd);\n }\n if (loc.quote && merged === loc.value) return openTag;\n return (\n openTag.slice(0, loc.attrStart) +\n ` style=${quoteStyleValue(merged)}` +\n openTag.slice(loc.attrEnd)\n );\n}\n\n/** A string, or the nested pieces of a child frame. Joined once at the root. */\ntype Chunk = string | Chunk[];\n\ninterface TextFrame {\n name: string;\n openTag: string;\n parts: Chunk[];\n blockChild: boolean;\n /** `ul` / `ol` ancestors, counting this frame when it is one. */\n listDepth: number;\n}\n\nfunction flattenChunks(chunks: Chunk[]): string {\n const out: string[] = [];\n const lists: Chunk[][] = [chunks];\n const index: number[] = [0];\n while (lists.length > 0) {\n const list = lists[lists.length - 1];\n const at = index[index.length - 1];\n if (at >= list.length) {\n lists.pop();\n index.pop();\n continue;\n }\n index[index.length - 1] = at + 1;\n const chunk = list[at];\n if (typeof chunk === \"string\") {\n if (chunk !== \"\") out.push(chunk);\n } else {\n lists.push(chunk);\n index.push(0);\n }\n }\n return out.join(\"\");\n}\n\nfunction chunkText(chunks: Chunk[]): string {\n const bits: string[] = [];\n for (const chunk of chunks) {\n if (typeof chunk === \"string\") bits.push(chunk);\n }\n return bits.join(\"\");\n}\n\n/**\n * The list box BeeFree renders, in px.\n *\n * `liIndent` is the indent (`40px` when it is absent or not a px length, the\n * UA indent). The export wraps the outer list in a -half margin against that\n * padding, so the text and bullet sit at half the indent; a nested list's\n * wrapper margin is 0, so it keeps the full indent. The head's `padding-left:\n * 20px` rule does not match a document rendered on its own.\n */\ninterface ListBox {\n outer: number;\n nested: number;\n rtl: boolean;\n}\n\nfunction listIndentPx(\n content:\n | {\n computedStyle?: Record<string, string>;\n }\n | undefined,\n): number {\n const stated = content?.computedStyle?.liIndent?.trim();\n const match = stated ? /^(\\d+(?:\\.\\d+)?)\\s*px$/i.exec(stated) : null;\n if (!match) return 40;\n return Math.round(Number(match[1]));\n}\n\nfunction listBoxFor(content: {\n computedStyle?: Record<string, string>;\n style?: Record<string, string>;\n}): ListBox {\n const indent = listIndentPx(content);\n return {\n outer: Math.round(indent / 2),\n nested: indent,\n rtl: content.style?.direction?.trim().toLowerCase() === \"rtl\",\n };\n}\n\n/**\n * Apply a BeeFree text module's style as TipTap-compatible inline markup.\n *\n * `text-align`, `line-height` and `font-size` go on each block root (`p`,\n * `li`, `h1`–`h6`, `div`, `ul`, `ol`). The line box uses that element's font\n * size, so a size that lives only on an inner span leaves the root at the\n * rendered text default of 14px. Color, weight, family, letter-spacing and\n * the same font size wrap the text of a root that holds no nested block. A\n * declaration the blob already sets stays; the module line-height replaces\n * one, because that is the value BeeFree renders.\n *\n * An `<a>` with no colour of its own takes `linkColor` inline, so it wins over\n * the document link colour. An anchor that already states a colour keeps it.\n *\n * `listBox` is set for a list module. It writes that box inline on `<ul>`,\n * `<ol>` and `<li>` — zero vertical margin, the indent padding, and\n * `list-style-type: revert` — so it beats the renderer's list spacing, which\n * juice would otherwise inline on top. A `margin` shorthand already on the\n * element stands, and so does a padding or marker it already sets. An item\n * margin of `0` is the shorthand: that is the property the renderer sets.\n *\n * A block with no text, break, image, or non-breaking space stays empty.\n * The renderer fills `<p></p>` with one line; a span inside it is content\n * and that line collapses.\n *\n * One forward scan. A regex over `[\\s\\S]*?</p>` is polynomial-ReDoS on\n * `<p>a<p>a<p>a…` with no closer; every cursor here only moves forward.\n * Unclosed roots stay nested. Their pieces are joined once at the root, so\n * a chain of them copies each character once.\n */\nfunction isWordChar(char: string | undefined): boolean {\n if (char === undefined) return false;\n const code = char.charCodeAt(0);\n return (\n (code >= 48 && code <= 57) ||\n (code >= 65 && code <= 90) ||\n (code >= 97 && code <= 122) ||\n char === \"_\"\n );\n}\n\n/** `<br` or `<img` with a word boundary after the name, as `/<br\\b/i` does. */\nfunction hasBreakOrImage(inner: string): boolean {\n let i = 0;\n while (i < inner.length) {\n const at = inner.indexOf(\"<\", i);\n if (at === -1) return false;\n if (namedTagAt(inner, at, \"br\") || namedTagAt(inner, at, \"img\"))\n return true;\n i = at + 1;\n }\n return false;\n}\n\nfunction namedTagAt(html: string, at: number, name: string): boolean {\n if (at + 1 + name.length > html.length) return false;\n for (let i = 0; i < name.length; i++) {\n const char = html[at + 1 + i];\n const expect = name[i];\n if (char !== expect && char !== expect.toUpperCase()) return false;\n }\n return !isWordChar(html[at + 1 + name.length]);\n}\n\n/**\n * Drop each `<…>` that has at least one character before `>`. The result is\n * only an emptiness check: it is never written back into the markup. `<` with\n * no closer, and `<>`, stay.\n */\nfunction withoutTags(value: string): string {\n const parts: string[] = [];\n let i = 0;\n let start = 0;\n while (i < value.length) {\n if (value[i] !== \"<\") {\n i++;\n continue;\n }\n let j = i + 1;\n while (j < value.length && value[j] !== \">\") j++;\n if (j >= value.length || j === i + 1) {\n i++;\n continue;\n }\n if (start < i) parts.push(value.slice(start, i));\n i = j + 1;\n start = i;\n }\n if (parts.length === 0) return start === 0 ? value : value.slice(start);\n if (start < value.length) parts.push(value.slice(start));\n return parts.join(\"\");\n}\n\n/** Text, a break, an image, or a non-breaking space inside a block. */\nfunction frameHasInk(inner: string): boolean {\n if (hasBreakOrImage(inner)) return true;\n const text = withoutTags(inner)\n .replace(/ | |\\u00a0/gi, \"x\")\n .trim();\n return text.length > 0;\n}\n\nfunction inlineStylesToHtml(\n html: string,\n style: Record<string, string | undefined>,\n textColor: string,\n linkColor: string,\n listBox?: ListBox,\n): string {\n const spanDecls: StyleDecl[] = [];\n const fontSize = parsePxValue(style[\"font-size\"]);\n if (fontSize && fontSize !== 16)\n spanDecls.push({ name: \"font-size\", value: `${fontSize}px` });\n const color = parseColor(style.color);\n // A paragraph inherits the template's text color, so only a different\n // color needs a span to survive.\n if (color && color !== textColor)\n spanDecls.push({ name: \"color\", value: color });\n const fontWeight = style[\"font-weight\"];\n // \"400\" is the numeric synonym for \"normal\" — neither needs an explicit\n // span (matches the import-unlayer importer).\n if (fontWeight && fontWeight !== \"normal\" && fontWeight !== \"400\")\n spanDecls.push({ name: \"font-weight\", value: fontWeight });\n const fontFamily = canonicalFontStack(style[\"font-family\"]);\n if (fontFamily) spanDecls.push({ name: \"font-family\", value: fontFamily });\n const letterSpacing = moduleLetterSpacing(style[\"letter-spacing\"]);\n if (letterSpacing)\n spanDecls.push({ name: \"letter-spacing\", value: letterSpacing });\n\n const blockDecls: StyleDecl[] = [];\n // On the root, not only the span: the line box follows the element's size.\n if (fontSize > 0)\n blockDecls.push({ name: \"font-size\", value: `${fontSize}px` });\n const textAlign = style[\"text-align\"];\n if (textAlign && textAlign !== \"left\")\n blockDecls.push({ name: \"text-align\", value: textAlign });\n const lineHeight = moduleLineHeight(style[\"line-height\"]);\n if (lineHeight) blockDecls.push({ name: \"line-height\", value: lineHeight });\n\n const spanStyle = spanDecls\n .map((decl) => `${decl.name}: ${decl.value}`)\n .join(\"; \");\n const strip = new Set<string>();\n if (lineHeight) strip.add(\"line-height\");\n const anchorDecls: StyleDecl[] = linkColor\n ? [{ name: \"color\", value: linkColor }]\n : [];\n\n if (\n blockDecls.length === 0 &&\n spanDecls.length === 0 &&\n anchorDecls.length === 0 &&\n !listBox\n )\n return html;\n\n const root: Chunk[] = [];\n const stack: TextFrame[] = [];\n const parts = (): Chunk[] =>\n stack.length > 0 ? stack[stack.length - 1].parts : root;\n\n const tagAdditions = (name: string, kind: \"block\" | \"all\"): StyleDecl[] => {\n const decls = kind === \"block\" ? blockDecls : [...blockDecls, ...spanDecls];\n return name === \"a\" ? [...decls, ...anchorDecls] : decls;\n };\n\n const declNames = (openTag: string): Set<string> => {\n const loc = findStyleAttr(openTag);\n const names = new Set<string>();\n if (!loc) return names;\n for (const part of loc.value.split(\";\")) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n const colon = trimmed.indexOf(\":\");\n const name = (colon === -1 ? trimmed : trimmed.slice(0, colon))\n .trim()\n .toLowerCase();\n if (name) names.add(name);\n }\n return names;\n };\n\n // `depth` counts this list and its list ancestors. It is stored when the\n // frame is pushed, so emitting a chain of unclosed lists stays linear.\n const listBoxDecls = (\n name: string,\n openTag: string,\n depth: number,\n ): StyleDecl[] => {\n if (!listBox) return [];\n const present = declNames(openTag);\n if (name === \"li\") {\n const hasMargin = [...present].some(\n (decl) => decl === \"margin\" || decl.startsWith(\"margin-\"),\n );\n return hasMargin ? [] : [{ name: \"margin\", value: \"0\" }];\n }\n if (name !== \"ul\" && name !== \"ol\") return [];\n const decls: StyleDecl[] = [];\n if (!present.has(\"margin\") && !present.has(\"margin-top\"))\n decls.push({ name: \"margin-top\", value: \"0\" });\n if (!present.has(\"margin\") && !present.has(\"margin-bottom\"))\n decls.push({ name: \"margin-bottom\", value: \"0\" });\n const padding = listBox.rtl ? \"padding-right\" : \"padding-left\";\n if (!present.has(\"padding\") && !present.has(padding)) {\n const px = depth === 1 ? listBox.outer : listBox.nested;\n decls.push({ name: padding, value: `${px}px` });\n }\n if (!present.has(\"list-style\") && !present.has(\"list-style-type\"))\n decls.push({ name: \"list-style-type\", value: \"revert\" });\n return decls;\n };\n\n const emitFrame = (frame: TextFrame, rawClose: string): void => {\n const leaf = !frame.blockChild;\n const listRoot = frame.name === \"ul\" || frame.name === \"ol\";\n const wrap = leaf && !listRoot && spanStyle !== \"\";\n const parent = stack.length > 0 ? stack[stack.length - 1] : undefined;\n if (parent) parent.blockChild = true;\n const dest = parent ? parent.parts : root;\n const open = (kind: \"block\" | \"all\"): string =>\n rewriteOpenTag(\n frame.openTag,\n [\n ...tagAdditions(frame.name, kind),\n ...listBoxDecls(frame.name, frame.openTag, frame.listDepth),\n ],\n strip,\n );\n const chunk: Chunk[] = [];\n if (leaf && !listRoot && !frameHasInk(chunkText(frame.parts))) {\n chunk.push(open(\"block\"));\n if (rawClose !== \"\") chunk.push(rawClose);\n } else if (wrap) {\n chunk.push(\n open(\"block\"),\n `<span style=${quoteStyleValue(spanStyle)}>`,\n frame.parts,\n \"</span>\",\n );\n if (rawClose !== \"\") chunk.push(rawClose);\n } else {\n // A list root and a div that wraps other blocks inherit into their\n // children, which carry the text styles themselves. A paragraph or item\n // with a nested block cannot take a span around that block, so the text\n // styles go on the element.\n const kind = !leaf && !listRoot && frame.name !== \"div\" ? \"all\" : \"block\";\n chunk.push(open(kind), frame.parts);\n if (rawClose !== \"\") chunk.push(rawClose);\n }\n dest.push(chunk);\n };\n\n const closeFrame = (name: string, rawClose: string): void => {\n let idx = -1;\n for (let s = stack.length - 1; s >= 0; s--) {\n if (stack[s].name === name) {\n idx = s;\n break;\n }\n }\n if (idx === -1) {\n parts().push(rawClose);\n return;\n }\n while (stack.length - 1 > idx) emitFrame(stack.pop()!, \"\");\n emitFrame(stack.pop()!, rawClose);\n };\n\n let i = 0;\n while (i < html.length) {\n const lt = html.indexOf(\"<\", i);\n if (lt === -1) {\n parts().push(html.slice(i));\n break;\n }\n parts().push(html.slice(i, lt));\n if (html.startsWith(\"<!--\", lt)) {\n const end = html.indexOf(\"-->\", lt + 4);\n if (end === -1) {\n parts().push(html.slice(lt));\n break;\n }\n parts().push(html.slice(lt, end + 3));\n i = end + 3;\n continue;\n }\n const isClose = html[lt + 1] === \"/\";\n const nameStart = lt + (isClose ? 2 : 1);\n if (!/[a-z]/i.test(html[nameStart] ?? \"\")) {\n parts().push(\"<\");\n i = lt + 1;\n continue;\n }\n let nameEnd = nameStart;\n while (nameEnd < html.length && /[a-z0-9]/i.test(html[nameEnd])) nameEnd++;\n const boundary = html[nameEnd];\n if (boundary !== undefined && !/[\\s>/]/.test(boundary)) {\n parts().push(html.slice(lt, nameEnd));\n i = nameEnd;\n continue;\n }\n const name = html.slice(nameStart, nameEnd).toLowerCase();\n if (isClose) {\n const end = html.indexOf(\">\", nameEnd);\n if (end === -1) {\n parts().push(html.slice(lt));\n break;\n }\n closeFrame(name, html.slice(lt, end + 1));\n i = end + 1;\n continue;\n }\n const end = findOpenTagEnd(html, nameEnd);\n if (end === -1) {\n parts().push(html.slice(lt));\n break;\n }\n const openTag = html.slice(lt, end + 1);\n const selfClosing = html[end - 1] === \"/\";\n if (selfClosing || !TEXT_ROOTS.has(name)) {\n parts().push(\n rewriteOpenTag(openTag, name === \"a\" ? anchorDecls : [], strip),\n );\n i = end + 1;\n continue;\n }\n const parentDepth =\n stack.length > 0 ? stack[stack.length - 1].listDepth : 0;\n stack.push({\n name,\n openTag,\n parts: [],\n blockChild: false,\n listDepth: name === \"ul\" || name === \"ol\" ? parentDepth + 1 : parentDepth,\n });\n i = end + 1;\n }\n while (stack.length > 0) emitFrame(stack.pop()!, \"\");\n return flattenChunks(root);\n}\n\n/**\n * A px length, rounded like {@link parsePxValue}, or `undefined` when it is\n * not one. Unitless `0` is `0`: CSS treats it as a length. A negative length\n * is not a gap.\n */\nfunction explicitPx(value: string): number | undefined {\n const trimmed = value.trim();\n if (/^0+(?:\\.0+)?$/.test(trimmed)) return 0;\n if (!/^\\d+(?:\\.\\d+)?\\s*px$/i.test(trimmed)) return undefined;\n return parsePxValue(trimmed);\n}\n\n/** The bottom length of a `margin` shorthand, when that side is a px length. */\nfunction shorthandMarginBottom(value: string): number | undefined {\n const parts = value.trim().split(/\\s+/);\n if (parts.length < 1 || parts.length > 4) return undefined;\n const bottom = parts.length <= 2 ? parts[0] : parts[2];\n return explicitPx(bottom);\n}\n\n/**\n * The px `margin-bottom` an opening tag states, after a `margin` shorthand\n * and a later `margin-bottom` the way CSS applies them. `undefined` when the\n * tag states none, or the winning value is not a px length.\n */\nfunction tagMarginBottom(tag: string): number | undefined {\n const style = findStyleAttr(tag)?.value;\n if (style === undefined) return undefined;\n let gap: number | undefined;\n let set = false;\n for (const part of style.split(\";\")) {\n const colon = part.indexOf(\":\");\n if (colon === -1) continue;\n const prop = part.slice(0, colon).trim().toLowerCase();\n if (prop !== \"margin\" && prop !== \"margin-bottom\") continue;\n const value = part.slice(colon + 1).trim();\n const bottom =\n prop === \"margin\" ? shorthandMarginBottom(value) : explicitPx(value);\n if (bottom === undefined) {\n set = false;\n gap = undefined;\n } else {\n set = true;\n gap = bottom;\n }\n }\n return set ? gap : undefined;\n}\n\nfunction isParagraphOpen(html: string, open: number): boolean {\n const name = html[open + 1];\n const next = html[open + 2];\n return (\n (name === \"p\" || name === \"P\") &&\n (next === \">\" ||\n next === \" \" ||\n next === \"\\t\" ||\n next === \"\\n\" ||\n next === \"\\r\" ||\n next === \"/\")\n );\n}\n\n/**\n * The gap between this block's paragraphs.\n *\n * BeeFree paragraphs sit at margin 0, so the gap is 0 unless a `<p>` states a\n * px `margin-bottom` or the bottom of a `margin` shorthand. The first such\n * length wins; one block has one gap.\n */\nfunction paragraphSpacingFromHtml(html: string): number {\n let i = 0;\n while (i < html.length) {\n const open = html.indexOf(\"<\", i);\n if (open === -1) return 0;\n if (!isParagraphOpen(html, open)) {\n i = open + 1;\n continue;\n }\n const openEnd = html.indexOf(\">\", open + 2);\n if (openEnd === -1) return 0;\n const gap = tagMarginBottom(html.slice(open, openEnd + 1));\n if (gap !== undefined) return gap;\n i = openEnd + 1;\n }\n return 0;\n}\n\n/**\n * A paragraph module's gap, in px. BeeFree stores it on\n * `computedStyle.paragraphSpacing` and renders it as `margin-bottom` on every\n * paragraph but the last. That wins over a margin written into the HTML. A\n * missing or non-px value falls back to the HTML.\n */\nfunction paragraphModuleSpacing(\n content: { computedStyle?: Record<string, string> } | undefined,\n html: string,\n): number {\n const stated = content?.computedStyle?.paragraphSpacing?.trim();\n const match = stated ? /^(\\d+(?:\\.\\d+)?)\\s*px$/i.exec(stated) : null;\n if (!match) return paragraphSpacingFromHtml(html);\n return Math.round(Number(match[1]));\n}\n\nfunction convertText(\n descriptor: BeeFreeeModuleDescriptor,\n textColor: string,\n): Block {\n const textContent =\n descriptor.text ?? descriptor.paragraph ?? descriptor.list;\n const html = textContent?.html ?? \"\";\n const style = textContent?.style ?? {};\n\n const listBox =\n textContent !== undefined && textContent === descriptor.list\n ? listBoxFor(textContent)\n : undefined;\n\n return createParagraphBlock({\n content: importedHtml(\n inlineStylesToHtml(\n html,\n style,\n textColor,\n moduleLinkColor(textContent),\n listBox,\n ),\n ),\n paragraphSpacing: paragraphModuleSpacing(textContent, html),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction parseHeadingLevel(tag: string): HeadingLevel {\n const match = tag.match(/^h(\\d)$/i);\n if (match) {\n const num = Number(match[1]);\n if (num >= 1 && num <= 4) return num as HeadingLevel;\n }\n return 2;\n}\n\nconst TITLE_LEVELS: readonly HeadingLevel[] = [1, 2, 3, 4];\n\n/**\n * The title level whose renderer size is nearest `px`.\n *\n * Sizes are `HEADING_LEVEL_FONT_SIZE` in `@templatical/types`, the table\n * `renderTitle` writes onto the title's `mj-text`. That size is the line\n * box. A tie stays on the level nearer `source`.\n */\nfunction headingLevelForSize(px: number, source: HeadingLevel): HeadingLevel {\n let best = source;\n let bestSize = Infinity;\n let bestSource = Infinity;\n for (const level of TITLE_LEVELS) {\n const size = Math.abs(HEADING_LEVEL_FONT_SIZE[level] - px);\n const toward = Math.abs(level - source);\n if (size < bestSize || (size === bestSize && toward < bestSource)) {\n best = level;\n bestSize = size;\n bestSource = toward;\n }\n }\n return best;\n}\n\n/**\n * Set when the chosen level's size is more than 1px off BeeFree's font size,\n * so the line box is not the source size. Names the source level when the\n * chosen level is a different one.\n */\nfunction headingLevelNote(\n px: number,\n source: HeadingLevel,\n chosen: HeadingLevel,\n): string | undefined {\n if (Math.abs(HEADING_LEVEL_FONT_SIZE[chosen] - px) <= 1) return undefined;\n const sourceNote = chosen === source ? \"\" : ` (source h${source})`;\n return `h${chosen} chosen for ${px}px${sourceNote}; line box differs`;\n}\n\n/** `text-align` inside a CSS declaration list, when it is left, center or right. */\nfunction alignInStyle(css: string | undefined): string | undefined {\n if (!css) return undefined;\n const match = /(?:^|;)\\s*text-align\\s*:\\s*(left|center|right)\\b/i.exec(css);\n return match?.[1].toLowerCase();\n}\n\n/**\n * Alignment on a heading tag BeeFree wrapped the text in\n * (`<h1 style=\"text-align: center\">`). The tag is stripped before the text\n * is stored, so the alignment has to be read first.\n */\nfunction headingTagCss(text: string): string | undefined {\n const open = /^<h\\d\\b([^>]*)>/i.exec(text.trim());\n if (!open) return undefined;\n const quoted = /\\bstyle\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/i.exec(open[1]);\n return quoted?.[1] ?? quoted?.[2];\n}\n\n/** One declaration from a CSS list, or `undefined` when it is absent. */\nfunction cssDecl(css: string | undefined, name: string): string | undefined {\n if (!css) return undefined;\n const match = new RegExp(`(?:^|;)\\\\s*${name}\\\\s*:\\\\s*([^;]+)`, \"i\").exec(css);\n const value = match?.[1]?.trim();\n return value || undefined;\n}\n\n/**\n * The heading style wins over the same declaration on the heading tag.\n * The tag is stripped before the text is stored.\n */\nfunction headingSourceDecl(\n style: Record<string, string>,\n tagCss: string | undefined,\n name: string,\n): string | undefined {\n const fromStyle = style[name]?.trim();\n return fromStyle || cssDecl(tagCss, name);\n}\n\n/**\n * Typography the title block cannot store. The renderer sizes a title from\n * its level (an `h1` is 36px), paints it bold and sets line-height 1.3, so\n * the heading's own values go on the text and override those.\n * `letter-spacing` of `0` or `normal` adds nothing.\n */\nfunction headingTypographyStyle(\n style: Record<string, string>,\n tagCss: string | undefined,\n): string | undefined {\n const decls: string[] = [];\n const fontSize = parsePxValue(headingSourceDecl(style, tagCss, \"font-size\"));\n if (fontSize > 0) decls.push(`font-size: ${fontSize}px`);\n const lineHeight = moduleLineHeight(\n headingSourceDecl(style, tagCss, \"line-height\"),\n );\n if (lineHeight) decls.push(`line-height: ${lineHeight}`);\n const weight = headingSourceDecl(style, tagCss, \"font-weight\");\n if (weight && !/^(inherit|initial|unset|revert)$/i.test(weight)) {\n decls.push(`font-weight: ${weight}`);\n }\n const letterSpacing = moduleLetterSpacing(\n headingSourceDecl(style, tagCss, \"letter-spacing\"),\n );\n if (letterSpacing) decls.push(`letter-spacing: ${letterSpacing}`);\n return decls.length > 0 ? decls.join(\"; \") : undefined;\n}\n\nfunction convertHeading(\n descriptor: BeeFreeeModuleDescriptor,\n textColor: string,\n): { block: Block; note?: string } {\n const heading = descriptor.heading;\n if (!heading) return { block: convertText(descriptor, textColor) };\n\n const style = heading.style ?? {};\n const tag = heading.title ?? \"h2\";\n const text = heading.text ?? \"\";\n // Strip heading tags — content goes inside TipTap, heading tag is rendered by the block.\n // Decode after the strip: a `{% if a > 1 %}` token must keep its `>`.\n const content = text.startsWith(\"<\")\n ? text.replace(/^<h\\d[^>]*>|<\\/h\\d>$/gi, \"\")\n : text;\n const tagCss = headingTagCss(text);\n const typography = headingTypographyStyle(style, tagCss);\n const inner = typography\n ? `<span style=${quoteStyleValue(typography)}>${content}</span>`\n : content;\n\n // BeeFree's effective size is the module style, then the font-size on the\n // heading tag. With neither, the tag has no published pixel default\n // (`titleDefaultStyles` is `{}`), so the level stays the source tag.\n const source = parseHeadingLevel(tag);\n const px = parsePxValue(headingSourceDecl(style, tagCss, \"font-size\"));\n const level = px > 0 ? headingLevelForSize(px, source) : source;\n\n // Alignment is on the heading style, the heading tag, or only the module.\n // The first one set wins.\n return {\n block: createTitleBlock({\n content: importedHtml(\n content || typography ? `<p>${inner}</p>` : \"<p></p>\",\n ),\n level,\n color: parseColor(style.color) || undefined,\n textAlign: toAlign(\n style[\"text-align\"] ??\n alignInStyle(tagCss) ??\n descriptor.style?.[\"text-align\"],\n ),\n fontFamily: canonicalFontStack(style[\"font-family\"]) || undefined,\n styles: makeStyles(descriptor),\n }),\n note: px > 0 ? headingLevelNote(px, source, level) : undefined,\n };\n}\n\n/**\n * The classes BeeFree records in `computedStyle.class` for an image: its\n * alignment, `autowidth` / `fixedwidth`, and in older exports `fullwidth`.\n */\nfunction computedClasses(descriptor: BeeFreeeModuleDescriptor): string[] {\n const value = descriptor.computedStyle?.class;\n return typeof value === \"string\" ? value.trim().split(/\\s+/) : [];\n}\n\n/**\n * A px length BeeFree computed: `\"172.5px\"`, or a bare number in older\n * exports. 0 when it isn't one.\n */\nfunction computedPx(value: unknown): number {\n if (typeof value === \"number\") {\n return Number.isFinite(value) && value > 0 ? Math.round(value) : 0;\n }\n return typeof value === \"string\" ? parsePxValue(value) : 0;\n}\n\n/**\n * The width BeeFree shows an image at, as `ImageBlock.width`. BeeFree records\n * it in `computedStyle.width` for both classes: a `fixedwidth` image at the\n * width the author set, an `autowidth` one at its file's width capped at the\n * column. `image.width` and `image.height` are the file's own size, the\n * fallback for an export without `computedStyle`. No width, or one that\n * reaches `room` (the column less the image's side padding), is `\"full\"`.\n * Older exports class an image that fills its column `fullwidth`. Its computed\n * width leaves out the column padding, so the class decides. A computed\n * percentage under 100% becomes px of `room`, with a note:\n * px keeps its size on a phone, where the percentage would shrink.\n */\nfunction resolveImageWidth(\n descriptor: BeeFreeeModuleDescriptor,\n room: number | undefined,\n): { width: ImageBlock[\"width\"]; note?: string } {\n if (computedClasses(descriptor).includes(\"fullwidth\")) {\n return { width: \"full\" };\n }\n const percent = computedPercent(descriptor.computedStyle?.width);\n if (percent !== undefined) {\n if (percent >= 100) return { width: \"full\" };\n const width =\n room === undefined\n ? \"full\"\n : shownWidth(Math.round((room * percent) / 100), room);\n const label = width === \"full\" ? \"full width\" : `${width}px`;\n return {\n width,\n note: `Image width ${percent}% was converted to ${label}.`,\n };\n }\n const shown =\n computedPx(descriptor.computedStyle?.width) ||\n parsePxValue(descriptor.image?.width);\n return { width: shownWidth(shown, room) };\n}\n\n/** A percentage BeeFree computed (`\"50%\"`), or `undefined` when it isn't one. */\nfunction computedPercent(value: unknown): number | undefined {\n if (typeof value !== \"string\") return undefined;\n const match = /^(\\d+(?:\\.\\d+)?|\\.\\d+)%$/.exec(value.trim());\n return match ? parseFloat(match[1]) : undefined;\n}\n\n/** A shown px width as `ImageBlock.width`: `\"full\"` when unknown or at `room`. */\nfunction shownWidth(\n shown: number,\n room: number | undefined,\n): ImageBlock[\"width\"] {\n if (shown <= 0) return \"full\";\n return room !== undefined && shown >= room ? \"full\" : shown;\n}\n\nfunction convertImage(\n descriptor: BeeFreeeModuleDescriptor,\n columnWidth: number | undefined,\n paddingReturn: ModuleContext[\"paddingReturn\"],\n): { block: Block; notes: string[] } {\n const image = descriptor.image;\n const styles = makeStyles(descriptor);\n if (!image) {\n return { block: createImageBlock({ styles }), notes: [] };\n }\n\n const room = measuredRoom(columnWidth, styles.padding, paddingReturn);\n const { width, note } = resolveImageWidth(descriptor, room);\n\n // `image.width` × `image.height` is the file, so the height is never carried\n // over: the image keeps its aspect ratio at the width it is shown at. A\n // percentage radius resolves against that shown size, and only when BeeFree\n // stated a width.\n const fileWidth = parsePxValue(image.width);\n const fileHeight = parsePxValue(image.height);\n const shownWidth = width === \"full\" ? room : width;\n const stated = fileWidth > 0 || width !== \"full\";\n const shownHeight =\n shownWidth !== undefined && fileWidth > 0 && fileHeight > 0\n ? Math.round((fileHeight * shownWidth) / fileWidth)\n : undefined;\n\n const classes = computedClasses(descriptor);\n const classAlign = ([\"left\", \"center\", \"right\"] as const).find((side) =>\n classes.includes(side),\n );\n\n const block = createImageBlock({\n src: decodeEntitiesInTokens(image.src || \"\"),\n alt: decodeEntitiesInTokens(image.alt || \"\"),\n width,\n // The file's size feeds the editor's aspect-ratio lock; never rendered.\n ...(fileWidth > 0 && fileHeight > 0\n ? { naturalWidth: fileWidth, naturalHeight: fileHeight }\n : {}),\n borderRadius: parseImageBorderRadius(\n image.style?.[\"border-radius\"],\n stated ? shownWidth : undefined,\n shownHeight,\n ),\n // Exports keep the alignment in `computedStyle.class` (\"left fixedwidth\")\n // and often have no image `style` at all.\n align: toAlign(image.style?.[\"text-align\"] ?? classAlign, \"center\"),\n linkUrl: image.href ? decodeEntitiesInTokens(image.href) : undefined,\n styles,\n });\n return { block, notes: note ? [note] : [] };\n}\n\n/**\n * A button label's line-height in px. BeeFree writes a percentage of the font\n * size (`200%`), a unitless ratio (`2`) or a px length. Anything else is\n * unread, and the padding stays as BeeFree wrote it.\n */\nfunction buttonLineHeightPx(\n value: string | undefined,\n fontSize: number,\n): number | undefined {\n if (!value || fontSize <= 0) return undefined;\n const trimmed = value.trim();\n const percent = /^(\\d+(?:\\.\\d+)?)\\s*%$/.exec(trimmed);\n if (percent) {\n const ratio = Number(percent[1]) / 100;\n return Number.isFinite(ratio) && ratio > 0 ? fontSize * ratio : undefined;\n }\n if (/^\\d+(?:\\.\\d+)?$/.test(trimmed)) {\n const ratio = Number(trimmed);\n return Number.isFinite(ratio) && ratio > 0 ? fontSize * ratio : undefined;\n }\n const px = /^(\\d+(?:\\.\\d+)?)\\s*px$/i.exec(trimmed);\n if (!px) return undefined;\n const length = Number(px[1]);\n return Number.isFinite(length) && length > 0 ? length : undefined;\n}\n\n/**\n * How many px to add to the button's top and bottom padding so the label's\n * line box matches BeeFree. The rendered label is 1.2× the font size, so a\n * taller line-height is split across the two sides. The result is an integer\n * and never negative: a line-height at or under 1.2 adds nothing.\n */\nfunction lineHeightPadding(lineHeightPx: number, fontSize: number): number {\n const extra = (lineHeightPx - 1.2 * fontSize) / 2;\n if (!Number.isFinite(extra) || extra <= 0) return 0;\n return Math.round(extra);\n}\n\n/**\n * A CSS font-weight as a number. `normal` is 400. `bold` and `bolder` are\n * 700 — `bolder` is relative, and with no parent weight the absolute step\n * it names is bold. Anything else unreadable is dropped.\n */\nfunction cssFontWeightNumber(value: unknown): number | undefined {\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? value : undefined;\n }\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim().toLowerCase();\n if (!trimmed) return undefined;\n if (trimmed === \"normal\") return 400;\n if (trimmed === \"bold\" || trimmed === \"bolder\") return 700;\n if (!/^[+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+)$/.test(trimmed)) return undefined;\n const numeric = Number(trimmed);\n return Number.isFinite(numeric) ? numeric : undefined;\n}\n\n/**\n * The nearest of 400, 500 and 700. The stops are lightest first and a tie\n * keeps the lighter one, so 450 is regular and 600 is medium.\n */\nfunction nearestButtonWeight(\n weight: number,\n): NonNullable<ButtonBlock[\"fontWeight\"]> {\n const stops = [\n [\"regular\", 400],\n [\"medium\", 500],\n [\"bold\", 700],\n ] as const;\n let best: NonNullable<ButtonBlock[\"fontWeight\"]> = \"regular\";\n let bestDistance = Infinity;\n for (const [name, stop] of stops) {\n const distance = Math.abs(weight - stop);\n if (distance < bestDistance) {\n best = name;\n bestDistance = distance;\n }\n }\n return best;\n}\n\n/**\n * BeeFree's weight as the button field. Bold is what an omitted field\n * renders, so that step is left unset. An unreadable weight is dropped.\n */\nfunction buttonFontWeight(\n value: unknown,\n): ButtonBlock[\"fontWeight\"] | undefined {\n const numeric = cssFontWeightNumber(value);\n if (numeric === undefined) return undefined;\n const mapped = nearestButtonWeight(numeric);\n return mapped === \"bold\" ? undefined : mapped;\n}\n\n/**\n * A letter-spacing worth naming. `0` and `normal` are the CSS initial value,\n * so they are not a difference. CSS-wide keywords are unread the same way.\n */\nfunction uncarriedLetterSpacing(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n const lower = trimmed.toLowerCase();\n if (\n lower === \"normal\" ||\n lower === \"0\" ||\n /^(?:inherit|initial|unset|revert)$/.test(lower) ||\n /^0+(?:\\.0+)?px$/.test(lower)\n ) {\n return undefined;\n }\n return trimmed;\n}\n\n/**\n * `100%` fills the column. Any other percentage has no field to land in, so\n * the button sizes to its label and the caller names that width. A px width\n * is that many pixels. `auto` and anything unreadable leave the width unset.\n */\nfunction buttonWidth(value: string | undefined): {\n width?: ButtonBlock[\"width\"];\n uncarried?: string;\n} {\n if (!value) return {};\n const raw = value.trim();\n if (!raw || /^auto$/i.test(raw)) return {};\n\n const percent = /^(\\d+(?:\\.\\d+)?)\\s*%$/.exec(raw);\n if (percent) {\n if (Number(percent[1]) === 100) return { width: \"full\" };\n return { uncarried: `width ${raw}` };\n }\n\n const px = /^(\\d+(?:\\.\\d+)?)\\s*px$/i.exec(raw);\n if (!px) return {};\n const width = Math.round(Number(px[1]));\n return width > 0 ? { width } : {};\n}\n\n/**\n * One note naming what this button does not carry: a letter-spacing, and a\n * percentage width other than 100%. Empty when nothing was left out. Weight\n * is mapped, so it is not named here.\n */\nfunction buttonApproximationNote(\n style: Record<string, string>,\n widthUncarried: string | undefined,\n): string | undefined {\n const parts: string[] = [];\n const spacing = uncarriedLetterSpacing(style[\"letter-spacing\"]);\n if (spacing) parts.push(`letter spacing ${spacing}`);\n\n if (widthUncarried) parts.push(widthUncarried);\n\n if (parts.length === 0) return undefined;\n const verb = parts.length === 1 ? \"is\" : \"are\";\n return `${parts.join(\", \")} ${verb} not carried`;\n}\n\nfunction toButtonBorderStyle(value: string | undefined): BorderStyle {\n if (value === \"dashed\" || value === \"dotted\" || value === \"solid\")\n return value;\n return \"solid\";\n}\n\n/**\n * The button's border. A side that paints nothing has width 0. `undefined`\n * when no side is drawn. A style other than solid, dashed or dotted is solid.\n */\nfunction buttonBorder(style: Record<string, string>): BorderValue | undefined {\n let drawn = false;\n const border = {} as BorderValue;\n for (const side of BORDER_SIDES) {\n const raw = style[`border-${side}`];\n const parsed = raw ? parseBorderTop(raw) : undefined;\n const paints = parsed !== undefined && parsed.drawn && parsed.width > 0;\n if (paints) drawn = true;\n border[side] = {\n width: paints ? parsed.width : 0,\n style: toButtonBorderStyle(parsed?.style),\n color: parsed?.color || \"#000000\",\n };\n }\n return drawn ? border : undefined;\n}\n\nfunction convertButton(descriptor: BeeFreeeModuleDescriptor): {\n block: Block;\n notes: string[];\n} {\n const button = descriptor.button;\n if (!button) {\n return {\n block: createButtonBlock({ styles: makeStyles(descriptor) }),\n notes: [],\n };\n }\n\n const style = button.style ?? {};\n const label = button.label ? importedPlainText(button.label) : \"Button\";\n const fontSize = parsePxValue(style[\"font-size\"]) || 16;\n const lineHeightPx = buttonLineHeightPx(style[\"line-height\"], fontSize);\n const linePad =\n lineHeightPx === undefined ? 0 : lineHeightPadding(lineHeightPx, fontSize);\n const { width, uncarried: widthUncarried } = buttonWidth(style.width);\n const border = buttonBorder(style);\n const fontWeight = buttonFontWeight(style[\"font-weight\"]);\n const note = buttonApproximationNote(style, widthUncarried);\n\n return {\n block: createButtonBlock({\n text: label,\n url: button.href ? decodeEntitiesInTokens(button.href) : \"#\",\n backgroundColor: parseColor(style[\"background-color\"]) || \"#4f46e5\",\n textColor: parseColor(style.color) || \"#ffffff\",\n borderRadius: parsePxValue(style[\"border-radius\"]),\n fontSize,\n fontFamily: canonicalFontStack(style[\"font-family\"]) || undefined,\n ...(fontWeight ? { fontWeight } : {}),\n // The module style places the button in the column. The button style's\n // text-align is the label, used when the module sets none.\n align: toAlign(\n descriptor.style?.[\"text-align\"] ?? style[\"text-align\"],\n \"center\",\n ),\n ...(width !== undefined ? { width } : {}),\n ...(border ? { border } : {}),\n buttonPadding: {\n top: (parsePxValue(style[\"padding-top\"]) || 12) + linePad,\n right: parsePxValue(style[\"padding-right\"]) || 24,\n bottom: (parsePxValue(style[\"padding-bottom\"]) || 12) + linePad,\n left: parsePxValue(style[\"padding-left\"]) || 24,\n },\n styles: makeStyles(descriptor),\n }),\n notes: note ? [note] : [],\n };\n}\n\n/**\n * `\"full\"` when the divider spans its column: no width, `100%`, or a px width\n * that reaches `contentWidth`. Without a `contentWidth` a px width stands as\n * stated. Any other percentage stays a percentage, clamped to 0–100%.\n */\nfunction resolveDividerWidth(\n value: string | undefined,\n contentWidth: number | undefined,\n notes: string[],\n): DividerBlock[\"width\"] {\n const raw = (value ?? \"\").trim();\n if (!raw) return \"full\";\n\n const parsed = parseDividerWidth(raw);\n if (!parsed) {\n notes.push(\n `Divider width \"${raw}\" could not be read; imported as full width.`,\n );\n return \"full\";\n }\n\n if (parsed.unit === \"%\") {\n const percent = Math.min(100, Math.max(0, parsed.value));\n if (percent !== parsed.value) {\n notes.push(`Divider width ${raw} was clamped to ${percent}%.`);\n }\n // Two decimals keep the value inside `DividerPercentWidth`'s pattern,\n // which a float printed in exponent form would leave.\n const share = Math.round(percent * 100) / 100;\n return share === 100 ? \"full\" : `${share}%`;\n }\n\n const px = Math.max(0, Math.round(parsed.value));\n if (px !== Math.round(parsed.value)) {\n notes.push(`Divider width ${raw} was clamped to 0px.`);\n }\n return contentWidth !== undefined && px >= contentWidth ? \"full\" : px;\n}\n\nfunction convertDivider(\n descriptor: BeeFreeeModuleDescriptor,\n columnWidth: number | undefined,\n paddingReturn: ModuleContext[\"paddingReturn\"],\n): { block: Block; notes: string[] } {\n const style = descriptor.divider?.style ?? {};\n const border = parseBorderTop(style[\"border-top\"]);\n const styles = makeStyles(descriptor);\n const notes: string[] = [];\n\n // MJML draws a full divider across its column less the divider's own\n // padding, so a px width that reaches that renders the same as \"full\", and\n // \"full\" keeps narrowing with the column on a phone.\n const contentWidth = measuredRoom(columnWidth, styles.padding, paddingReturn);\n const width = resolveDividerWidth(style.width, contentWidth, notes);\n\n const align = dividerAlign(descriptor);\n if (width !== \"full\" && (align === \"left\" || align === \"right\")) {\n notes.push(\n `BeeFree aligns this divider ${align}; Templatical centres every divider.`,\n );\n }\n\n return {\n block: createDividerBlock({\n lineStyle: toLineStyle(border.style),\n color: border.color,\n thickness: border.width || 1,\n width,\n styles,\n }),\n notes,\n };\n}\n\n/**\n * BeeFree keeps a divider's alignment in `computedStyle.align`; some exports\n * also write it to the module style's `text-align`.\n */\nfunction dividerAlign(\n descriptor: BeeFreeeModuleDescriptor,\n): string | undefined {\n const computed = descriptor.computedStyle?.align;\n return typeof computed === \"string\"\n ? computed\n : descriptor.style?.[\"text-align\"];\n}\n\n/**\n * The room a divider that draws no line takes: its top and bottom padding plus\n * the width of a transparent border. `undefined` when the line is drawn.\n * BeeFree templates space content this way.\n */\nfunction undrawnDividerHeight(\n descriptor: BeeFreeeModuleDescriptor,\n): number | undefined {\n const border = parseBorderTop(descriptor.divider?.style?.[\"border-top\"]);\n if (border.drawn) return undefined;\n const padding = extractPadding(descriptor.style);\n return padding.top + border.width + padding.bottom;\n}\n\n/**\n * A divider that draws no line, as a spacer of the same height. A spacer\n * renders no padding, so the divider's padding goes into the height.\n */\nfunction convertUndrawnDivider(\n descriptor: BeeFreeeModuleDescriptor,\n height: number,\n): Block {\n return createSpacerBlock({\n height,\n styles: {\n ...makeStyles(descriptor),\n padding: { top: 0, right: 0, bottom: 0, left: 0 },\n },\n });\n}\n\nfunction convertSpacer(descriptor: BeeFreeeModuleDescriptor): Block {\n const spacer = descriptor.spacer;\n const height = parsePxValue(spacer?.style?.height) || 24;\n\n return createSpacerBlock({\n height,\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertHtml(descriptor: BeeFreeeModuleDescriptor): Block {\n const html = descriptor.html?.html ?? \"\";\n\n return createHtmlBlock({\n content: importedHtml(html),\n styles: makeStyles(descriptor),\n });\n}\n\n/** `\"E-Mail\"` and `\"YouTube\"` are network names; a blank id is not one. */\nfunction socialKey(value: string | undefined): string {\n return (value ?? \"\").toLowerCase().replace(/[^a-z0-9]+/g, \"\");\n}\n\nfunction platformFromKey(\n value: string | undefined,\n): SocialPlatform | undefined {\n const key = socialKey(value);\n return key ? SOCIAL_PLATFORM_MAP[key] : undefined;\n}\n\nconst SOCIAL_HOSTS: readonly (readonly [string, SocialPlatform])[] = [\n [\"youtube.com\", \"youtube\"],\n [\"youtu.be\", \"youtube\"],\n [\"facebook.com\", \"facebook\"],\n [\"fb.com\", \"facebook\"],\n [\"instagram.com\", \"instagram\"],\n [\"linkedin.com\", \"linkedin\"],\n [\"xing.com\", \"xing\"],\n [\"twitter.com\", \"twitter\"],\n [\"x.com\", \"twitter\"],\n [\"tiktok.com\", \"tiktok\"],\n [\"pinterest.com\", \"pinterest\"],\n [\"pin.it\", \"pinterest\"],\n [\"whatsapp.com\", \"whatsapp\"],\n [\"wa.me\", \"whatsapp\"],\n [\"t.me\", \"telegram\"],\n [\"telegram.me\", \"telegram\"],\n [\"telegram.org\", \"telegram\"],\n [\"discord.com\", \"discord\"],\n [\"discord.gg\", \"discord\"],\n [\"snapchat.com\", \"snapchat\"],\n [\"reddit.com\", \"reddit\"],\n [\"github.com\", \"github\"],\n [\"dribbble.com\", \"dribbble\"],\n [\"behance.net\", \"behance\"],\n];\n\n/** The link's host when the icon's id and name are not a network. */\nfunction platformFromHref(\n href: string | undefined,\n): SocialPlatform | undefined {\n const raw = (href ?? \"\").trim();\n if (!raw) return undefined;\n if (/^mailto:/i.test(raw)) return \"email\";\n let host: string;\n try {\n host = new URL(raw).hostname.toLowerCase();\n } catch {\n return undefined;\n }\n if (host.startsWith(\"www.\")) host = host.slice(4);\n for (const [domain, platform] of SOCIAL_HOSTS) {\n if (host === domain || host.endsWith(`.${domain}`)) return platform;\n }\n return undefined;\n}\n\n/**\n * BeeFree stores a custom icon's id as a UUID and the network in `name`, or\n * the other way around. A blank id is not a name. The link's host is the\n * last place the network is written.\n */\nfunction socialPlatform(icon: BeeFreeeSocialIcon): SocialPlatform | undefined {\n return (\n platformFromKey(icon.id) ??\n platformFromKey(icon.name) ??\n platformFromKey(icon.image?.alt) ??\n platformFromKey(icon.image?.title) ??\n platformFromHref(icon.image?.href)\n );\n}\n\nfunction isUuid(value: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(\n value.trim(),\n );\n}\n\nfunction positivePx(value: unknown): number {\n if (typeof value === \"number\" && Number.isFinite(value) && value > 0) {\n return Math.round(value);\n }\n if (typeof value === \"string\") return parsePxValue(value);\n return 0;\n}\n\n/** A name to put in the note: the alt text, or a name that is not a UUID. */\nfunction networkLabel(icon: BeeFreeeSocialIcon, href: string): string {\n const alt = icon.image?.alt?.trim();\n if (alt) return alt;\n const title = icon.image?.title?.trim();\n if (title) return title;\n const name = icon.name?.trim();\n if (name && !isUuid(name)) return name;\n const id = icon.id?.trim();\n if (id && !isUuid(id)) return id;\n try {\n const host = new URL(href).hostname.replace(/^www\\./, \"\");\n if (host) return host;\n } catch {\n // The href is not a URL. The note still names the icon.\n }\n return \"custom\";\n}\n\nfunction safeCopiedUrl(\n value: string,\n kind: \"src\" | \"href\",\n warnings: string[],\n): string {\n if (!value) return \"\";\n if (isSafeHtmlUrl(value, kind)) return value;\n warnings.push(\n kind === \"src\"\n ? `Dropped the unsafe image \"${value}\" on a social icon.`\n : `Dropped the unsafe link \"${value}\" on a social icon.`,\n );\n return \"\";\n}\n\n/**\n * A network Templatical does not draw. The file and the link stay, as an\n * image when there is a file and as a link when there is not.\n */\nfunction unknownSocialBlock(\n descriptor: BeeFreeeModuleDescriptor,\n icon: BeeFreeeSocialIcon,\n warnings: string[],\n): { block: Block; note: string } | undefined {\n const href = safeCopiedUrl(\n decodeEntitiesInTokens(icon.image?.href ?? \"\"),\n \"href\",\n warnings,\n );\n const src = safeCopiedUrl(\n decodeEntitiesInTokens(icon.image?.src ?? \"\"),\n \"src\",\n warnings,\n );\n const label = networkLabel(icon, href || icon.image?.href || \"\");\n if (!src && !href) {\n const note = `Social network \"${label}\" has no Templatical icon and no image or link to keep.`;\n warnings.push(note);\n return {\n block: createHtmlBlock({ content: \"\", styles: makeStyles(descriptor) }),\n note,\n };\n }\n const asLink = !src;\n const note = `Social network \"${label}\" has no Templatical icon; imported as ${asLink ? \"a link\" : \"an image\"}.`;\n warnings.push(note);\n if (asLink) {\n return {\n block: createHtmlBlock({\n content: decodeEntitiesInHtml(\n `<a href=\"${escapeHtml(href)}\">${escapeHtml(decodeEntitiesInTokens(label))}</a>`,\n ),\n styles: makeStyles(descriptor),\n }),\n note,\n };\n }\n const fileWidth = positivePx(icon.image?.width);\n const fileHeight = positivePx(icon.image?.height);\n const shown =\n positivePx(descriptor.computedStyle?.iconsDefaultWidth) || fileWidth || 32;\n return {\n block: createImageBlock({\n src,\n alt: decodeEntitiesInTokens(icon.image?.alt ?? \"\"),\n width: shown,\n ...(fileWidth > 0 && fileHeight > 0\n ? { naturalWidth: fileWidth, naturalHeight: fileHeight }\n : {}),\n align: toAlign(descriptor.style?.[\"text-align\"], \"center\"),\n linkUrl: href || undefined,\n ...(icon.image?.target === \"_blank\" ? { linkOpenInNewTab: true } : {}),\n styles: makeStyles(descriptor),\n }),\n note,\n };\n}\n\n/**\n * BeeFree names an icon set in the file URL\n * (`…/social-networks-icon-sets/circle-dark-gray/facebook.png`).\n * A gray set uses the dark tone: the block's monochrome dark is `#1f1f1f`,\n * the nearest circle that is not a brand-coloured solid. A set whose shape\n * or tone has no match is absent, and the block keeps solid brand icons.\n */\nconst SOCIAL_ICON_SETS: Record<\n string,\n { iconStyle: SocialIconStyle; iconTone?: SocialIconTone }\n> = {\n \"circle-color\": { iconStyle: \"circle\" },\n \"circle-colored\": { iconStyle: \"circle\" },\n \"circle-colour\": { iconStyle: \"circle\" },\n \"circle-black\": { iconStyle: \"circle\", iconTone: \"dark\" },\n \"circle-dark\": { iconStyle: \"circle\", iconTone: \"dark\" },\n \"circle-dark-gray\": { iconStyle: \"circle\", iconTone: \"dark\" },\n \"circle-dark-grey\": { iconStyle: \"circle\", iconTone: \"dark\" },\n \"circle-gray\": { iconStyle: \"circle\", iconTone: \"dark\" },\n \"circle-grey\": { iconStyle: \"circle\", iconTone: \"dark\" },\n \"circle-white\": { iconStyle: \"circle\", iconTone: \"light\" },\n \"circle-light\": { iconStyle: \"circle\", iconTone: \"light\" },\n \"rounded-color\": { iconStyle: \"rounded\" },\n \"rounded-colored\": { iconStyle: \"rounded\" },\n \"rounded-black\": { iconStyle: \"rounded\", iconTone: \"dark\" },\n \"rounded-dark\": { iconStyle: \"rounded\", iconTone: \"dark\" },\n \"rounded-dark-gray\": { iconStyle: \"rounded\", iconTone: \"dark\" },\n \"rounded-dark-grey\": { iconStyle: \"rounded\", iconTone: \"dark\" },\n \"rounded-white\": { iconStyle: \"rounded\", iconTone: \"light\" },\n \"rounded-light\": { iconStyle: \"rounded\", iconTone: \"light\" },\n \"square-color\": { iconStyle: \"square\" },\n \"square-colored\": { iconStyle: \"square\" },\n \"squared-color\": { iconStyle: \"square\" },\n \"squared-colored\": { iconStyle: \"square\" },\n \"square-black\": { iconStyle: \"square\", iconTone: \"dark\" },\n \"square-dark\": { iconStyle: \"square\", iconTone: \"dark\" },\n \"squared-black\": { iconStyle: \"square\", iconTone: \"dark\" },\n \"squared-dark\": { iconStyle: \"square\", iconTone: \"dark\" },\n \"square-dark-gray\": { iconStyle: \"square\", iconTone: \"dark\" },\n \"square-dark-grey\": { iconStyle: \"square\", iconTone: \"dark\" },\n \"squared-dark-gray\": { iconStyle: \"square\", iconTone: \"dark\" },\n \"squared-dark-grey\": { iconStyle: \"square\", iconTone: \"dark\" },\n \"square-white\": { iconStyle: \"square\", iconTone: \"light\" },\n \"square-light\": { iconStyle: \"square\", iconTone: \"light\" },\n \"squared-white\": { iconStyle: \"square\", iconTone: \"light\" },\n \"squared-light\": { iconStyle: \"square\", iconTone: \"light\" },\n};\n\nfunction socialIconSet(\n descriptor: BeeFreeeModuleDescriptor,\n): string | undefined {\n // A malformed percent-escape in one icon URL must not abort the import.\n const decodeSetName = (segment: string): string => {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n };\n const icons = descriptor.iconsList?.icons;\n if (!Array.isArray(icons)) return undefined;\n for (const icon of icons) {\n if (!icon || typeof icon !== \"object\") continue;\n const src = (icon as BeeFreeeSocialIcon).image?.src;\n if (typeof src !== \"string\") continue;\n const match = /social-networks-icon-sets\\/([^/?#]+)\\//i.exec(src);\n if (match) return decodeSetName(match[1]).toLowerCase();\n }\n return undefined;\n}\n\n/**\n * The gap between icons. BeeFree's padding is the space on each side of an\n * icon, so two neighbours contribute both sides. Rounded once, after the sum.\n * `undefined` when the padding isn't a length, and the block keeps 10.\n */\nfunction socialSpacing(\n descriptor: BeeFreeeModuleDescriptor,\n): number | undefined {\n const padding = descriptor.computedStyle?.padding;\n if (typeof padding !== \"string\" || padding.trim() === \"\") return undefined;\n const parts = padding.trim().split(/\\s+/);\n if (parts.length > 4) return undefined;\n const values: number[] = [];\n for (const part of parts) {\n const match = /^(\\d+(?:\\.\\d+)?|\\.\\d+)(px)?$/i.exec(part);\n if (!match) return undefined;\n values.push(parseFloat(match[1]));\n }\n // 1 value: every side. 2 or 3: the second is both horizontals. 4: the fourth is left.\n const right = values.length === 1 ? values[0] : values[1];\n const left = values.length === 4 ? values[3] : right;\n return Math.round(left + right);\n}\n\n/** Nearest of the block's 24 / 32 / 48px presets. */\nfunction socialIconSizeFromWidth(width: number): SocialIconSize | undefined {\n if (width <= 0) return undefined;\n if (width < 28) return \"small\";\n if (width < 40) return \"medium\";\n return \"large\";\n}\n\nfunction socialAppearance(\n descriptor: BeeFreeeModuleDescriptor,\n): Partial<\n Pick<\n SocialIconsBlock,\n \"align\" | \"spacing\" | \"iconSize\" | \"iconStyle\" | \"iconTone\"\n >\n> {\n const spacing = socialSpacing(descriptor);\n const size = socialIconSizeFromWidth(\n computedPx(descriptor.computedStyle?.iconsDefaultWidth),\n );\n const theme = SOCIAL_ICON_SETS[socialIconSet(descriptor) ?? \"\"];\n return {\n align: toAlign(descriptor.style?.[\"text-align\"], \"center\"),\n ...(spacing !== undefined ? { spacing } : {}),\n ...(size ? { iconSize: size } : {}),\n ...(theme\n ? {\n iconStyle: theme.iconStyle,\n ...(theme.iconTone ? { iconTone: theme.iconTone } : {}),\n }\n : {}),\n };\n}\n\nfunction convertSocial(\n descriptor: BeeFreeeModuleDescriptor,\n warnings: string[],\n): { block: Block; extras: Block[]; notes: string[] } {\n const iconsList = descriptor.iconsList;\n const styles = makeStyles(descriptor);\n const appearance = socialAppearance(descriptor);\n if (!iconsList?.icons) {\n return {\n block: createSocialIconsBlock({ styles, ...appearance }),\n extras: [],\n notes: [],\n };\n }\n\n const icons: SocialIcon[] = [];\n const extras: Block[] = [];\n const notes: string[] = [];\n\n // The Icons module keeps items of another shape under the same key.\n for (const beeIcon of iconsList.icons as BeeFreeeSocialIcon[]) {\n const platform = socialPlatform(beeIcon);\n if (!platform) {\n const kept = unknownSocialBlock(descriptor, beeIcon, warnings);\n if (!kept) continue;\n // An empty HTML block is the note for an icon with nothing to keep.\n if (kept.block.type === \"html\" && kept.block.content === \"\") {\n notes.push(kept.note);\n continue;\n }\n extras.push(kept.block);\n notes.push(kept.note);\n continue;\n }\n\n const href = safeCopiedUrl(\n decodeEntitiesInTokens(beeIcon.image?.href ?? \"\"),\n \"href\",\n warnings,\n );\n icons.push({\n id: generateId(),\n platform,\n url: href || \"#\",\n });\n }\n\n // A module of only custom icons is those images. An empty social block\n // would render nothing beside them.\n if (icons.length === 0 && extras.length > 0) {\n const [block, ...rest] = extras;\n return { block, extras: rest, notes };\n }\n\n return {\n block: createSocialIconsBlock({ icons, styles, ...appearance }),\n extras,\n notes,\n };\n}\n\n/** Escape `& < > \"` for text content and attribute values. */\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\");\n}\n\nfunction stringField(value: unknown): string {\n return typeof value === \"string\" ? value : \"\";\n}\n\nfunction iconItems(descriptor: BeeFreeeModuleDescriptor): BeeFreeeIconItem[] {\n const icons = descriptor.iconsList?.icons;\n return Array.isArray(icons) ? (icons as BeeFreeeIconItem[]) : [];\n}\n\n/** The padding BeeFree keeps around each icon, `computedStyle.iconSpacing`. */\nfunction iconSpacing(descriptor: BeeFreeeModuleDescriptor): SpacingValue {\n const value = descriptor.computedStyle?.iconSpacing;\n if (typeof value !== \"object\" || value === null) return extractPadding({});\n return extractPadding(\n Object.fromEntries(\n Object.entries(value).filter(([, side]) => typeof side === \"string\"),\n ),\n );\n}\n\n/**\n * The height BeeFree draws every icon at, and an icon's width at that height,\n * from its file's size. The width is `undefined` when the size isn't stated.\n */\nfunction iconSize(\n descriptor: BeeFreeeModuleDescriptor,\n item: BeeFreeeIconItem,\n): { height: number; width: number | undefined } {\n const height = computedPx(descriptor.computedStyle?.iconHeight) || 32;\n const fileWidth = parsePxValue(stringField(item.width));\n const fileHeight = parsePxValue(stringField(item.height));\n return {\n height,\n width:\n fileWidth > 0 && fileHeight > 0\n ? Math.round((height * fileWidth) / fileHeight)\n : undefined,\n };\n}\n\n/**\n * A lone icon without text, as an image block at the icon height. `undefined`\n * when the module holds anything else, or the icon's file size is unknown.\n */\nfunction convertSingleIcon(\n descriptor: BeeFreeeModuleDescriptor,\n columnWidth: number | undefined,\n paddingReturn: ModuleContext[\"paddingReturn\"],\n): Block | undefined {\n const items = iconItems(descriptor);\n if (items.length !== 1) return undefined;\n const [item] = items;\n const src = stringField(item.image);\n const { width } = iconSize(descriptor, item);\n if (!src || stringField(item.text) || width === undefined) return undefined;\n\n // The module's padding plus the space BeeFree keeps around the icon.\n const styles = makeStyles(descriptor);\n const spacing = iconSpacing(descriptor);\n const padding = {\n top: styles.padding.top + spacing.top,\n right: styles.padding.right + spacing.right,\n bottom: styles.padding.bottom + spacing.bottom,\n left: styles.padding.left + spacing.left,\n };\n const room = measuredRoom(columnWidth, padding, paddingReturn);\n\n return createImageBlock({\n src,\n alt: stringField(item.alt),\n width: shownWidth(width, room),\n naturalWidth: parsePxValue(stringField(item.width)),\n naturalHeight: parsePxValue(stringField(item.height)),\n align: toAlign(descriptor.style?.[\"text-align\"]),\n linkUrl: stringField(item.href) || undefined,\n styles: { ...styles, padding },\n });\n}\n\n/** The module's text style as CSS declarations, for the icons' text cells. */\nfunction iconTextStyle(style: Record<string, string>): string {\n const color = parseColor(style.color);\n const fontFamily = canonicalFontStack(style[\"font-family\"]);\n const fontSize = parsePxValue(style[\"font-size\"]);\n const fontWeight = style[\"font-weight\"];\n return [\n color ? `color: ${color};` : \"\",\n fontFamily ? `font-family: ${fontFamily};` : \"\",\n fontSize ? `font-size: ${fontSize}px;` : \"\",\n fontWeight ? `font-weight: ${fontWeight};` : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\n/**\n * The Icons module as the table BeeFree draws: the icons side by side, each at\n * the icon height inside its `iconSpacing`, with its text on the side\n * `textPosition` names, in the module's text style.\n */\nfunction iconsHtml(descriptor: BeeFreeeModuleDescriptor): string {\n const style = descriptor.style ?? {};\n const computed = descriptor.computedStyle ?? {};\n const align = toAlign(style[\"text-align\"]);\n const color = parseColor(style.color);\n const textStyle = iconTextStyle(style);\n const gap =\n computedPx(computed.itemsSpacing) || computedPx(computed.itemSpacing);\n const spacing = iconSpacing(descriptor);\n const iconPadding =\n spacing.top || spacing.right || spacing.bottom || spacing.left\n ? `padding: ${spacing.top}px ${spacing.right}px ${spacing.bottom}px ${spacing.left}px; `\n : \"\";\n\n const items = iconItems(descriptor).map((item, index) => {\n const position = stringField(item.textPosition);\n const stacked = position === \"top\" || position === \"bottom\";\n const cellAlign = stacked ? ' align=\"center\"' : \"\";\n const href = stringField(item.href);\n const target = stringField(item.target);\n const link = (inner: string, linkStyle: string) =>\n href\n ? `<a href=\"${escapeHtml(href)}\"${target ? ` target=\"${escapeHtml(target)}\"` : \"\"} style=${quoteStyleValue(linkStyle)}>${inner}</a>`\n : inner;\n\n const src = stringField(item.image);\n const { height, width } = iconSize(descriptor, item);\n const title = stringField(item.title);\n const imgStyle = [\n \"display: block;\",\n stacked ? \"margin: 0 auto;\" : \"\",\n width === undefined ? \"\" : `width: ${width}px;`,\n `height: ${height}px;`,\n \"border: 0;\",\n ]\n .filter(Boolean)\n .join(\" \");\n const img = `<img src=\"${escapeHtml(src)}\" alt=\"${escapeHtml(stringField(item.alt))}\"${title ? ` title=\"${escapeHtml(title)}\"` : \"\"}${width === undefined ? \"\" : ` width=\"${width}\"`} height=\"${height}\" style=${quoteStyleValue(imgStyle)}>`;\n const iconCell = src\n ? `<td${cellAlign} style=${quoteStyleValue(`${iconPadding}vertical-align: middle;`)}>${link(img, \"text-decoration: none;\")}</td>`\n : \"\";\n\n const text = stringField(item.text);\n const textCell = text\n ? `<td${cellAlign} style=${quoteStyleValue(`vertical-align: middle;${textStyle ? ` ${textStyle}` : \"\"}`)}>${link(\n escapeHtml(text),\n `${color ? `color: ${color}; ` : \"\"}text-decoration: none;`,\n )}</td>`\n : \"\";\n\n const rows =\n position === \"top\"\n ? [textCell, iconCell]\n : position === \"bottom\"\n ? [iconCell, textCell]\n : [position === \"left\" ? textCell + iconCell : iconCell + textCell];\n const body = rows\n .filter(Boolean)\n .map((row) => `<tr>${row}</tr>`)\n .join(\"\");\n const itemGap = index > 0 && gap ? `padding-left: ${gap}px; ` : \"\";\n return `<td style=${quoteStyleValue(`${itemGap}vertical-align: middle;`)}><table role=\"presentation\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"border-collapse: collapse;\">${body}</table></td>`;\n });\n\n const tableAlign = align === \"left\" ? \"\" : ` align=\"${align}\"`;\n // `escapeHtml` re-encodes `&` and `>`. Decoding the finished table puts\n // those characters back inside tokens, and a quote in an attribute stays\n // `"`.\n return decodeEntitiesInHtml(\n `<table role=\"presentation\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"${tableAlign} style=\"border-collapse: collapse;\"><tr>${items.join(\"\")}</tr></table>`,\n );\n}\n\n/**\n * The Icons module's items without the link and image URLs the editor's HTML\n * policy rejects (`javascript:`, `vbscript:`, a non-image `data:`), each named\n * in `warnings`. Both outputs carry these URLs into markup, and an HTML block\n * renders unsanitized.\n */\nfunction safeIconItems(\n descriptor: BeeFreeeModuleDescriptor,\n warnings: string[],\n): BeeFreeeIconItem[] {\n return iconItems(descriptor).map((item) => {\n // Decode before the URL check and before `escapeHtml`. The table decodes\n // again after escaping: a text node in full, an attribute with a quote\n // left encoded.\n const safe: BeeFreeeIconItem = {\n ...item,\n image: decodeEntitiesInTokens(stringField(item.image)),\n alt: decodeEntitiesInTokens(stringField(item.alt)),\n href: decodeEntitiesInTokens(stringField(item.href)),\n text: decodeEntitiesInTokens(stringField(item.text)),\n title: decodeEntitiesInTokens(stringField(item.title)),\n target: decodeEntitiesInTokens(stringField(item.target)),\n };\n const image = stringField(safe.image);\n if (image && !isSafeHtmlUrl(image, \"src\")) {\n warnings.push(`Dropped the unsafe image \"${image}\" on an Icons item.`);\n safe.image = \"\";\n }\n const href = stringField(safe.href);\n if (href && !isSafeHtmlUrl(href, \"href\")) {\n warnings.push(`Dropped the unsafe link \"${href}\" on an Icons item.`);\n safe.href = \"\";\n }\n return safe;\n });\n}\n\nfunction convertIcons(\n descriptor: BeeFreeeModuleDescriptor,\n columnWidth: number | undefined,\n paddingReturn: ModuleContext[\"paddingReturn\"],\n warnings: string[],\n): { block: Block; rebuilt: boolean } {\n const safe = {\n ...descriptor,\n iconsList: { icons: safeIconItems(descriptor, warnings) },\n };\n const single = convertSingleIcon(safe, columnWidth, paddingReturn);\n if (single) return { block: single, rebuilt: false };\n return {\n block: createHtmlBlock({\n content: iconsHtml(safe),\n styles: makeStyles(descriptor),\n }),\n rebuilt: true,\n };\n}\n\nfunction convertVideo(descriptor: BeeFreeeModuleDescriptor): Block {\n const video = descriptor.video;\n if (!video) {\n return createVideoBlock({ styles: makeStyles(descriptor) });\n }\n\n return createVideoBlock({\n url: decodeEntitiesInTokens(video.src || \"\"),\n thumbnailUrl: decodeEntitiesInTokens(video.thumbnail || \"\"),\n alt: decodeEntitiesInTokens(video.thumbAlt ?? video.alt ?? \"\"),\n width: parsePxValue(video.style?.width) || 600,\n height: parsePxValue(video.style?.height) || undefined,\n align: toAlign(video.style?.[\"text-align\"], \"center\"),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertMenu(descriptor: BeeFreeeModuleDescriptor): Block {\n const menu = descriptor.menu;\n if (!menu) {\n return createMenuBlock({ styles: makeStyles(descriptor) });\n }\n\n const style = menu.style ?? {};\n\n const items: MenuItemData[] = (menu.items ?? []).map((item) => ({\n id: generateId(),\n text: decodeEntitiesInTokens(item.text || \"\"),\n url: decodeEntitiesInTokens(item.link || item.href || \"#\"),\n openInNewTab: item.target === \"_blank\",\n bold: false,\n underline: false,\n }));\n\n return createMenuBlock({\n items,\n separator: decodeEntitiesInTokens(menu.separator || \"|\"),\n separatorColor: parseColor(menu.separatorColor) || \"#999999\",\n fontSize: parsePxValue(style[\"font-size\"]) || 14,\n color: parseColor(style.color) || undefined,\n fontFamily: canonicalFontStack(style[\"font-family\"]) || undefined,\n textAlign: toAlign(style[\"text-align\"], \"center\"),\n styles: makeStyles(descriptor),\n });\n}\n\nfunction convertTable(descriptor: BeeFreeeModuleDescriptor): {\n block: Block;\n approximated: boolean;\n} {\n const table = descriptor.table;\n if (!table) {\n return {\n block: createTableBlock({ styles: makeStyles(descriptor) }),\n approximated: false,\n };\n }\n\n const style = table.style ?? {};\n\n // Templatical table cells are a plain-text field (the editor stores the\n // cell's innerText), so strip any HTML a BeeFree cell carried the same way\n // button labels are stripped. If a strip actually removed markup, the cell\n // lost formatting or a link URL, so the conversion is an approximation.\n let approximated = false;\n const rows: TableRowData[] = (table.rows ?? []).map((row) => ({\n id: generateId(),\n cells: (row.cells ?? []).map((cell): TableCellData => {\n const raw = cell.content ?? cell.html ?? \"\";\n const content = importedPlainText(raw);\n if (content !== raw) {\n approximated = true;\n }\n return { id: generateId(), content };\n }),\n }));\n\n return {\n block: createTableBlock({\n rows,\n hasHeaderRow: table.hasHeaderRow ?? false,\n headerBackgroundColor:\n parseColor(table.headerBackgroundColor) || undefined,\n borderColor: parseColor(style[\"border-color\"]) || \"#dddddd\",\n borderWidth: parsePxValue(style[\"border-width\"]) || 1,\n cellPadding:\n typeof table.cellPadding === \"number\"\n ? table.cellPadding\n : parsePxValue(table.cellPadding as string) || 8,\n fontSize: parsePxValue(style[\"font-size\"]) || 14,\n color: parseColor(style.color) || undefined,\n textAlign: toAlign(style[\"text-align\"]),\n styles: makeStyles(descriptor),\n }),\n approximated,\n };\n}\n\nfunction convertHtmlFallback(module: BeeFreeeModule): Block {\n // Attempt to extract any HTML content from the descriptor\n const descriptor = module.descriptor;\n let html = \"\";\n\n // Try common content fields\n if (descriptor.text?.html) html = descriptor.text.html;\n else if (descriptor.html?.html) html = descriptor.html.html;\n else if (descriptor.heading?.text) html = descriptor.heading.text;\n else html = `<!-- Unsupported BeeFree module: ${module.type} -->`;\n\n return createHtmlBlock({\n content: importedHtml(html),\n styles: makeStyles(descriptor),\n });\n}\n\n/**\n * Converts a single BeeFree module to a Templatical block.\n * Returns the block and a report entry.\n */\nfunction convertModuleBase(\n module: BeeFreeeModule,\n warnings: string[],\n context: ModuleContext = {},\n): { block: Block; entry: ImportReportEntry } {\n const mappedType = moduleKind(module);\n const descriptor = module.descriptor;\n const textColor = context.textColor ?? FALLBACK_TEXT_COLOR;\n\n if (!mappedType) {\n return {\n block: convertHtmlFallback(module),\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n note:\n module.type === ADDON_MODULE\n ? \"The addon carries no content Templatical reads; converted to an HTML block.\"\n : `Unknown module type \"${module.type}\" converted to HTML block.`,\n },\n };\n }\n\n let block: Block;\n let extras: Block[] = [];\n let isApproximation = false;\n let notes: string[] = [];\n\n switch (mappedType) {\n case \"paragraph\":\n case \"list\":\n block = convertText(descriptor, textColor);\n break;\n case \"title\": {\n const result = convertHeading(descriptor, textColor);\n block = result.block;\n if (result.note) {\n notes = [result.note];\n isApproximation = true;\n }\n break;\n }\n case \"image\": {\n const result = convertImage(\n descriptor,\n context.columnWidth,\n context.paddingReturn,\n );\n block = result.block;\n notes = result.notes;\n isApproximation = notes.length > 0;\n break;\n }\n case \"button\": {\n const result = convertButton(descriptor);\n block = result.block;\n notes = result.notes;\n isApproximation = notes.length > 0;\n break;\n }\n case \"divider\": {\n const height = undrawnDividerHeight(descriptor);\n if (height !== undefined) {\n block = convertUndrawnDivider(descriptor, height);\n notes = [\n `The divider draws no line; imported as a ${height}px spacer.`,\n ];\n break;\n }\n const result = convertDivider(\n descriptor,\n context.columnWidth,\n context.paddingReturn,\n );\n block = result.block;\n notes = result.notes;\n isApproximation = notes.length > 0;\n break;\n }\n case \"spacer\":\n block = convertSpacer(descriptor);\n break;\n case \"icons\": {\n const result = convertIcons(\n descriptor,\n context.columnWidth,\n context.paddingReturn,\n warnings,\n );\n if (result.rebuilt) {\n return {\n block: result.block,\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n note: \"Icons module rebuilt as an HTML table.\",\n },\n };\n }\n block = result.block;\n break;\n }\n case \"html\":\n block = convertHtml(descriptor);\n break;\n case \"social\": {\n const result = convertSocial(descriptor, warnings);\n block = result.block;\n extras = result.extras;\n notes = result.notes;\n isApproximation = notes.length > 0;\n break;\n }\n case \"video\":\n block = convertVideo(descriptor);\n break;\n case \"menu\":\n block = convertMenu(descriptor);\n isApproximation = true; // menu styles are approximate\n break;\n case \"table\": {\n const result = convertTable(descriptor);\n block = result.block;\n if (result.approximated) {\n isApproximation = true;\n warnings.push(\n \"HTML inside one or more table cells was reduced to plain text; any cell formatting or links were dropped.\",\n );\n }\n break;\n }\n default:\n block = convertHtmlFallback(module);\n return {\n block,\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n },\n };\n }\n\n return {\n block,\n ...(extras.length > 0 ? { extras } : {}),\n entry: {\n beeFreeModuleType: module.type,\n templaticalBlockType: block.type,\n status: isApproximation ? \"approximated\" : \"converted\",\n ...(notes.length > 0 ? { note: notes.join(\" \") } : {}),\n },\n };\n}\n\n/**\n * The report entry for a module that imports no block, or `undefined` when it\n * converts: an empty module, an Icons module with no icons, and a divider that\n * draws no line and takes no space.\n */\nexport function skippedModuleEntry(\n module: BeeFreeeModule,\n): ImportReportEntry | undefined {\n const skip = (note: string): ImportReportEntry => ({\n beeFreeModuleType: module.type,\n templaticalBlockType: null,\n status: \"skipped\",\n note,\n });\n if (module.type === EMPTY_MODULE) return skip(\"The module is empty.\");\n switch (moduleKind(module)) {\n case \"icons\":\n return iconItems(module.descriptor).length === 0\n ? skip(\"The Icons module has no icons.\")\n : undefined;\n case \"divider\":\n return undrawnDividerHeight(module.descriptor) === 0\n ? skip(\"The divider draws no line and takes no space.\")\n : undefined;\n default:\n return undefined;\n }\n}\n\nexport function convertModule(\n module: BeeFreeeModule,\n warnings: string[],\n context: ModuleContext = {},\n): { block: Block; extras?: Block[]; entry: ImportReportEntry } {\n const result = convertModuleBase(module, warnings, context);\n const { block } = result;\n const descriptor = module.descriptor;\n const payloads = [\n [\"heading\", descriptor.heading],\n [\"text\", descriptor.text],\n [\"paragraph\", descriptor.paragraph],\n [\"list\", descriptor.list],\n [\"button\", descriptor.button],\n [\"image\", descriptor.image],\n [\"video\", descriptor.video],\n [\"menu\", descriptor.menu],\n ] as const;\n const active = payloads.find(([, payload]) => payload !== undefined);\n const sources = [\n module.translations,\n ...payloads.map(([, payload]) => payload?.translations),\n ];\n for (const translations of sources) {\n for (const [code, values] of Object.entries(translations ?? {})) {\n const locale = localeTag(code, warnings);\n if (!locale) continue;\n if (result.entry.status === \"html-fallback\" || block.type === \"html\") {\n warn(\n warnings,\n `Dropped language \"${locale}\" on module \"${module.type}\": target converted to HTML fallback.`,\n );\n continue;\n }\n const key = active?.[0];\n const field =\n block.type === \"title\"\n ? \"text\"\n : block.type === \"paragraph\"\n ? \"html\"\n : block.type === \"button\"\n ? \"label\"\n : block.type === \"image\"\n ? \"alt\"\n : block.type === \"video\"\n ? \"thumbAlt\"\n : block.type === \"menu\"\n ? \"items\"\n : undefined;\n for (const unknown of Object.keys(values).filter(\n (name) => name !== field,\n )) {\n warn(\n warnings,\n `Dropped language \"${locale}\" key \"${unknown}\": no language mapping for this format.`,\n );\n }\n if (!field || values[field] === undefined) continue;\n if (block.type === \"menu\" && Array.isArray(values.items)) {\n if (values.items.length !== block.items.length) {\n warn(\n warnings,\n `Dropped language \"${locale}\" menu translation: item count differs from the source.`,\n );\n continue;\n }\n values.items.forEach((item: { text?: unknown }, index: number) => {\n for (const key of Object.keys(item ?? {}).filter(\n (key) => key !== \"text\",\n )) {\n warn(\n warnings,\n `Dropped language \"${locale}\" key \"${key}\": no language mapping for this format.`,\n );\n }\n if (typeof item?.text === \"string\")\n text(\n block,\n locale,\n `items.${block.items[index].id}.text`,\n block.items[index].text,\n decodeEntitiesInTokens(item.text),\n );\n });\n } else if (key && typeof values[field] === \"string\") {\n const translated = convertModuleBase(\n {\n ...module,\n descriptor: {\n ...descriptor,\n [key]: { ...descriptor[key], [field]: values[field] },\n },\n },\n [],\n context,\n ).block;\n if (\n (block.type === \"title\" || block.type === \"paragraph\") &&\n (translated.type === \"title\" || translated.type === \"paragraph\")\n )\n text(block, locale, \"content\", block.content, translated.content);\n if (block.type === \"button\" && translated.type === \"button\")\n text(block, locale, \"text\", block.text, translated.text);\n if (\n (block.type === \"image\" || block.type === \"video\") &&\n (translated.type === \"image\" || translated.type === \"video\")\n )\n text(block, locale, \"alt\", block.alt, translated.alt ?? \"\");\n }\n }\n }\n return result;\n}\n","import {\n defaultLocaleOption,\n localeTag,\n registerLocales,\n text,\n warn,\n} from \"./localization\";\nimport {\n BUILT_IN_FONT_STACKS,\n canonicalFontStack,\n createSectionBlock,\n createDefaultTemplateContent,\n isGenericFontFamily,\n isImage,\n parseFontFamilies,\n toBorderCss,\n} from \"@templatical/types\";\nimport type {\n BackgroundImage,\n Block,\n BlockVisibility,\n BorderStyle,\n BorderValue,\n ColumnLayout,\n CustomFont,\n ImageBlock,\n SpacingValue,\n TemplateContent,\n} from \"@templatical/types\";\nimport type {\n BeeFreeTemplate,\n BeeFreeeRow,\n BeeFreeeColumn,\n BeeFreeeWebFont,\n ImportResult,\n ImportReport,\n ImportReportEntry,\n} from \"./types\";\nimport {\n convertModule,\n FALLBACK_TEXT_COLOR,\n skippedModuleEntry,\n type ModuleContext,\n} from \"./block-mapper\";\nimport { decodeEntitiesInTokens } from \"./merge-tokens\";\nimport {\n parsePxValue,\n parseColor,\n parseBorderTop,\n extractPadding,\n isTransparentColor,\n readBeefreeBackgroundImage,\n} from \"./style-parser\";\n\nexport interface ConvertBeeFreeOptions {\n /** Used when the source declares no default language. */\n defaultLocale?: string;\n}\n\n/**\n * A column's share of BeeFree's 12-column grid. An omitted value counts as 6,\n * half the grid, which is what a 2-column row uses when neither side states one.\n */\nfunction columnUnits(column: BeeFreeeColumn): number {\n const value = column[\"grid-columns\"];\n return typeof value === \"number\" && Number.isFinite(value) ? value : 6;\n}\n\nfunction gridLabel(columns: BeeFreeeColumn[]): string {\n return columns.map(columnUnits).join(\"-\");\n}\n\nfunction columnsEqual(columns: BeeFreeeColumn[]): boolean {\n const first = columnUnits(columns[0]);\n return columns.every((column) => columnUnits(column) === first);\n}\n\n/**\n * Thousandths of the left column's share. 8/12 and 2/3 both land on 667 and\n * 7/12 lands on 583, so an exact layout and a near one stay apart.\n */\nfunction ratioMilli(left: number, total: number): number {\n return Math.round((left / total) * 1000);\n}\n\nfunction isExactLayout(\n layout: Exclude<ColumnLayout, \"1\" | \"3\">,\n left: number,\n total: number,\n): boolean {\n const milli = ratioMilli(left, total);\n if (layout === \"2\") return milli === 500;\n if (layout === \"2-1\") return milli === 667;\n return milli === 333;\n}\n\nfunction noteSnappedRatio(\n columns: BeeFreeeColumn[],\n layout: ColumnLayout,\n warnings: string[],\n): void {\n warnings.push(\n `Column ratio ${gridLabel(columns)} was mapped to the nearest layout \"${layout}\".`,\n );\n}\n\n/**\n * Nearest two-column layout, in the same thousandths as `isExactLayout`.\n * `2` is listed first, so an equal distance stays on the even split. 7/12\n * rounds to 583: 83 from even, 84 from 2/3, so the narrower share is not\n * squeezed to a third.\n */\nfunction nearestTwoColumn(\n left: number,\n total: number,\n): Exclude<ColumnLayout, \"1\" | \"3\"> {\n const milli = ratioMilli(left, total);\n const choices: Array<[Exclude<ColumnLayout, \"1\" | \"3\">, number]> = [\n [\"2\", 500],\n [\"2-1\", 667],\n [\"1-2\", 333],\n ];\n let best: Exclude<ColumnLayout, \"1\" | \"3\"> = \"2\";\n let bestDistance = Math.abs(milli - 500);\n for (const [layout, target] of choices) {\n const distance = Math.abs(milli - target);\n if (distance < bestDistance) {\n best = layout;\n bestDistance = distance;\n }\n }\n return best;\n}\n\n/**\n * Determines the Templatical ColumnLayout from BeeFree column grid values.\n * A split that is not exactly `2`, `1-2`, `2-1` or an even `3` keeps the\n * nearest of those and records one warning naming the source ratio. Four or\n * more columns flatten to one column, with that ratio in the same warning.\n */\nfunction resolveColumnLayout(\n columns: BeeFreeeColumn[],\n warnings: string[],\n): ColumnLayout | null {\n if (columns.length === 1) return null; // Single column — no section wrapper needed\n if (columns.length === 3) {\n if (!columnsEqual(columns)) noteSnappedRatio(columns, \"3\", warnings);\n return \"3\";\n }\n\n if (columns.length === 2) {\n const left = columnUnits(columns[0]);\n const right = columnUnits(columns[1]);\n const total = left + right;\n if (total <= 0) {\n noteSnappedRatio(columns, \"2\", warnings);\n return \"2\";\n }\n const layout = nearestTwoColumn(left, total);\n if (!isExactLayout(layout, left, total)) {\n noteSnappedRatio(columns, layout, warnings);\n }\n return layout;\n }\n\n if (columns.length >= 4) {\n warnings.push(\n `Row with ${columns.length} columns (${gridLabel(columns)}) was flattened to a single column. BeeFree supports arbitrary columns, but Templatical supports up to 3.`,\n );\n return null; // Flatten to single column\n }\n\n return \"2\";\n}\n\n/**\n * Column widths in px for a layout, mirroring `renderer/src/columns.ts`, and\n * floored as the renderer floors the width it hands each column.\n */\nfunction columnPixels(layout: ColumnLayout, bodyWidth: number): number[] {\n switch (layout) {\n case \"2\":\n return [bodyWidth * 0.5, bodyWidth * 0.5].map(Math.floor);\n case \"3\":\n return [bodyWidth / 3, bodyWidth / 3, bodyWidth / 3].map(Math.floor);\n case \"1-2\":\n return [bodyWidth / 3, (bodyWidth * 2) / 3].map(Math.floor);\n case \"2-1\":\n return [(bodyWidth * 2) / 3, bodyWidth / 3].map(Math.floor);\n default:\n return [Math.floor(bodyWidth)];\n }\n}\n\n/**\n * Converts all modules in a column to Templatical blocks.\n */\nfunction convertColumnModules(\n column: BeeFreeeColumn,\n context: ModuleContext,\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const blocks: Block[] = [];\n\n for (const module of column.modules) {\n const skipped = skippedModuleEntry(module);\n if (skipped) {\n entries.push(skipped);\n continue;\n }\n const { block, entry, extras } = convertModule(module, warnings, context);\n blocks.push(block);\n if (extras?.length) blocks.push(...extras);\n entries.push(entry);\n }\n\n return blocks;\n}\n\n/**\n * The image a row's section paints. `content.style` is the content area a\n * section paints, so its image maps exactly. `container.style` is the\n * full-width band: it shows through only while the content area has neither\n * an image nor a colour, and then the section paints it at the content\n * width; otherwise it's dropped. Losses go to `warnings`, since rows have no\n * report entry.\n */\nfunction resolveRowBackgroundImage(\n row: BeeFreeeRow,\n rowBg: string,\n width: number,\n warnings: string[],\n): BackgroundImage | undefined {\n const content = readBeefreeBackgroundImage(row.content?.style, \"Row\", width);\n const band = readBeefreeBackgroundImage(\n row.container?.style,\n \"Row container\",\n width,\n );\n // A background URL is a copied string and can carry a merge tag.\n if (content) content.image.url = decodeEntitiesInTokens(content.image.url);\n if (band) band.image.url = decodeEntitiesInTokens(band.image.url);\n\n if (content) {\n warnings.push(...content.notes);\n if (band) {\n warnings.push(\n `Row container background image \"${band.image.url}\" outside the content width was dropped; the section keeps the content background image.`,\n );\n }\n return content.image;\n }\n if (!band) return undefined;\n if (rowBg) {\n warnings.push(\n `Row container background image \"${band.image.url}\" outside the content width was dropped; the section keeps the content background ${rowBg}.`,\n );\n return undefined;\n }\n warnings.push(\n ...band.notes,\n `Row container background image \"${band.image.url}\" spans the full width in BeeFree; the section paints it at the content width.`,\n );\n return band.image;\n}\n\nfunction zeroPadding(): SpacingValue {\n return { top: 0, right: 0, bottom: 0, left: 0 };\n}\n\nfunction addPadding(base: SpacingValue, extra: SpacingValue): SpacingValue {\n return {\n top: base.top + extra.top,\n right: base.right + extra.right,\n bottom: base.bottom + extra.bottom,\n left: base.left + extra.left,\n };\n}\n\nfunction hasPadding(padding: SpacingValue): boolean {\n return (\n padding.top !== 0 ||\n padding.right !== 0 ||\n padding.bottom !== 0 ||\n padding.left !== 0\n );\n}\n\nconst BORDER_SIDES = [\"top\", \"right\", \"bottom\", \"left\"] as const;\n\nfunction toBorderStyle(value: string | undefined): BorderStyle {\n if (value === \"dashed\" || value === \"dotted\" || value === \"solid\")\n return value;\n return \"solid\";\n}\n\n/**\n * A column background that paints. Fully transparent is unset, the same way\n * a border that paints nothing is.\n */\nfunction columnBackgroundColor(\n style: Record<string, string> | undefined,\n): string {\n const raw = style?.[\"background-color\"];\n if (isTransparentColor(raw)) return \"\";\n return parseColor(raw);\n}\n\n/**\n * A column or row style's border as a section border. A side that paints\n * nothing has width 0. `undefined` when no side is drawn.\n */\nfunction columnBorder(\n style: Record<string, string> | undefined,\n): BorderValue | undefined {\n if (!style) return undefined;\n let drawn = false;\n const border = {} as BorderValue;\n for (const side of BORDER_SIDES) {\n const raw = style[`border-${side}`];\n const parsed = raw ? parseBorderTop(raw) : undefined;\n const paints = parsed !== undefined && parsed.drawn && parsed.width > 0;\n if (paints) drawn = true;\n border[side] = {\n width: paints ? parsed.width : 0,\n style: toBorderStyle(parsed?.style),\n color: parsed?.color || \"#000000\",\n };\n }\n return drawn ? border : undefined;\n}\n\nfunction isFlag(value: string | boolean | undefined): boolean {\n return value === true || value === \"true\";\n}\n\nfunction rowVisibility(row: BeeFreeeRow): BlockVisibility | undefined {\n const computed = row.content?.computedStyle;\n const hideMobile = isFlag(computed?.hideContentOnMobile);\n const hideDesktop = isFlag(computed?.hideContentOnDesktop);\n if (!hideMobile && !hideDesktop) return undefined;\n return { desktop: !hideDesktop, mobile: !hideMobile };\n}\n\nfunction rowOptsOutOfStack(row: BeeFreeeRow): boolean {\n const value = row.content?.computedStyle?.rowColStackOnMobile;\n return value === false || value === \"false\";\n}\n\nfunction sameBorder(a: BorderValue, b: BorderValue): boolean {\n return BORDER_SIDES.every(\n (side) =>\n a[side].width === b[side].width &&\n a[side].style === b[side].style &&\n a[side].color === b[side].color,\n );\n}\n\nconst ROW_BORDER_DROPPED =\n \"Row border was dropped; the column border is kept on the section.\";\n\nconst ROW_STACK_DROPPED =\n \"rowColStackOnMobile false was dropped; Templatical keeps columns side by side only on a 2- or 3-column section.\";\n\ninterface RowFrame {\n visibility?: BlockVisibility;\n stackOnMobile?: false;\n wrapper?: { backgroundColor: string };\n border?: BorderValue;\n}\n\n/**\n * Row chrome the section can hold. The container colour is the band outside\n * the content box (`wrapper`); the section fill stays the content colour the\n * caller already chose. A band the same colour as that fill adds nothing. A\n * column border already chosen for the section wins over the row border.\n */\nfunction rowFrame(\n row: BeeFreeeRow,\n sectionBackground: string,\n columnBorderValue: BorderValue | undefined,\n applyStack: boolean,\n warnings: string[],\n): RowFrame {\n const visibility = rowVisibility(row);\n const band = parseColor(row.container?.style?.[\"background-color\"]);\n const wrapper =\n band && band !== sectionBackground ? { backgroundColor: band } : undefined;\n\n let border = columnBorderValue;\n const rowBorder = columnBorder(row.content?.style);\n if (rowBorder) {\n if (!border) border = rowBorder;\n else if (!sameBorder(border, rowBorder)) warnings.push(ROW_BORDER_DROPPED);\n }\n\n let stackOnMobile: false | undefined;\n if (rowOptsOutOfStack(row)) {\n if (applyStack) stackOnMobile = false;\n else warnings.push(ROW_STACK_DROPPED);\n }\n\n return {\n ...(visibility ? { visibility } : {}),\n ...(stackOnMobile === false ? { stackOnMobile } : {}),\n ...(wrapper ? { wrapper } : {}),\n ...(border ? { border } : {}),\n };\n}\n\nfunction frameNeedsSection(frame: RowFrame): boolean {\n return (\n frame.visibility !== undefined ||\n frame.wrapper !== undefined ||\n frame.border !== undefined\n );\n}\n\n/**\n * `content.style.width` is the content box. A section has no width of its\n * own, so a value other than the email width is reported and left.\n */\nfunction warnIfContentWidthDiffers(\n row: BeeFreeeRow,\n emailWidth: number,\n warnings: string[],\n): void {\n const raw = row.content?.style?.width;\n if (typeof raw !== \"string\" || raw.trim() === \"\") return;\n const px = parsePxValue(raw);\n if (px > 0 && px === emailWidth) return;\n const shown = px > 0 ? `${px}px` : `\"${raw.trim()}\"`;\n warnings.push(\n `Row content width ${shown} differs from the email width ${emailWidth}px. A section has no width of its own, so the row keeps the email width.`,\n );\n}\n\nconst COLUMN_BOX_DROPPED =\n \"Column background/border was dropped; a multi-column row has no per-column box.\";\n\n/**\n * The percentages the renderer emits for a multi-column section\n * (`getWidthPercentages`). 33.33% of 600 is 199; the last column is 33.34%.\n */\nconst COLUMN_CONTENT_PERCENTS: Record<Exclude<ColumnLayout, \"1\">, string[]> = {\n \"2\": [\"50%\", \"50%\"],\n \"3\": [\"33.33%\", \"33.33%\", \"33.34%\"],\n \"1-2\": [\"33.33%\", \"66.67%\"],\n \"2-1\": [\"66.67%\", \"33.33%\"],\n};\n\nfunction drawnSide(side: BorderValue[\"left\"] | undefined): number {\n return toBorderCss(side) === null ? 0 : Math.trunc(side!.width);\n}\n\n/**\n * BeeFree's grid share of the section box, in whole pixels. The same floor\n * the renderer uses, so an exact layout and this share differ only where\n * the percentage rounding does.\n */\nfunction columnShareWidths(columns: BeeFreeeColumn[], box: number): number[] {\n const units = columns.map(columnUnits);\n const total = units.reduce((sum, share) => sum + share, 0);\n if (total <= 0) {\n const each = Math.floor(box / Math.max(columns.length, 1));\n return columns.map(() => each);\n }\n return units.map((share) => Math.floor((box * share) / total));\n}\n\n/** True when `layout` is not the source ratio, so a column may be narrower. */\nfunction layoutSnaps(\n columns: BeeFreeeColumn[],\n layout: Exclude<ColumnLayout, \"1\">,\n): boolean {\n if (layout === \"3\") return !columnsEqual(columns);\n const total = columns.reduce((sum, column) => sum + columnUnits(column), 0);\n return !isExactLayout(layout, columnUnits(columns[0]!), total);\n}\n\n/**\n * A snapped column is narrower than its grid share. The missing pixels come\n * back from the padding that faces the next column, and the outer edge stays.\n * Nothing is taken past 0, and a wider column is left alone. Image, lone-icon\n * and divider widths are measured with this padding already returned.\n */\nfunction giveBackInnerPadding(\n blocks: Block[],\n deficit: number,\n sides: Array<\"left\" | \"right\">,\n): void {\n if (deficit <= 0) return;\n for (const block of blocks) {\n const padding = block.styles.padding;\n let remaining = deficit;\n for (const side of sides) {\n if (remaining <= 0) break;\n const have = padding[side];\n if (have <= 0) continue;\n const give = Math.min(remaining, have);\n padding[side] = have - give;\n remaining -= give;\n }\n }\n}\n\n/**\n * Whole pixels MJML gives each column's content. A multi-column section\n * imported here has no padding of its own; a row border still shrinks the box.\n */\nfunction renderedColumnContentWidths(\n layout: Exclude<ColumnLayout, \"1\">,\n bodyWidth: number,\n border: BorderValue | undefined,\n): number[] {\n const sectionBox =\n Math.floor(bodyWidth) - drawnSide(border?.left) - drawnSide(border?.right);\n return COLUMN_CONTENT_PERCENTS[layout].map((width) =>\n Math.floor((sectionBox * parseFloat(width)) / 100),\n );\n}\n\n/**\n * True when the renderer would emit `fluid-on-mobile` on its own: `\"full\"`,\n * or a pixel width at or above the room inside the image's side padding and\n * border.\n */\nfunction imageFillsColumn(\n block: ImageBlock,\n columnContentWidth: number,\n): boolean {\n const padding = block.styles.padding;\n const room =\n Math.floor(columnContentWidth) -\n Math.trunc(padding.left) -\n Math.trunc(padding.right) -\n drawnSide(block.border?.left) -\n drawnSide(block.border?.right);\n return block.width === \"full\" || block.width >= room;\n}\n\n/**\n * BeeFree does not widen an image on a phone when the image sits in a column\n * narrower than the email. Pin those that fill their column, which is when\n * the renderer would stretch them. A full-width row stays on the automatic\n * rule.\n */\nfunction keepColumnImagesAtDesktopWidth(\n blocks: Block[],\n columnContentWidth: number,\n): void {\n for (const block of blocks) {\n if (!isImage(block) || block.fluidOnMobile !== undefined) continue;\n if (imageFillsColumn(block, columnContentWidth)) {\n block.fluidOnMobile = false;\n }\n }\n}\n\n/** One warning per row when a column's background or border has nowhere to go. */\nfunction warnIfColumnBoxDropped(\n columns: BeeFreeeColumn[],\n warnings: string[],\n): void {\n const dropped = columns.some((column) => {\n const style = column.style;\n return (\n columnBackgroundColor(style) !== \"\" || columnBorder(style) !== undefined\n );\n });\n if (dropped) warnings.push(COLUMN_BOX_DROPPED);\n}\n\n/**\n * Column padding has no per-column box. Left and right sit on every module,\n * top on the first and bottom on the last, so the stack keeps the column's\n * inset.\n */\nfunction foldColumnPadding(blocks: Block[], padding: SpacingValue): void {\n if (blocks.length === 0 || !hasPadding(padding)) return;\n const last = blocks.length - 1;\n blocks.forEach((block, index) => {\n const own = block.styles.padding;\n own.left += padding.left;\n own.right += padding.right;\n if (index === 0) own.top += padding.top;\n if (index === last) own.bottom += padding.bottom;\n });\n}\n\n/**\n * Processes a single BeeFree row into one or more Templatical blocks.\n */\nfunction processRow(\n row: BeeFreeeRow,\n settings: TemplateContent[\"settings\"],\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const columns = row.columns;\n if (!columns || columns.length === 0) return [];\n\n // Track locked/synced metadata\n if (row.locked) {\n warnings.push(\n \"A locked row was imported. Lock metadata was dropped; content is preserved.\",\n );\n }\n if (row.synced) {\n warnings.push(\n \"A synced row was imported. Sync metadata was dropped; content is preserved.\",\n );\n }\n\n warnIfContentWidthDiffers(row, settings.width, warnings);\n\n const layout = resolveColumnLayout(columns, warnings);\n\n // The content colour is the inner box. The container colour, when it\n // differs, is the band outside that box.\n const rowBg = parseColor(row.content?.style?.[\"background-color\"]);\n const backgroundImage = resolveRowBackgroundImage(\n row,\n rowBg,\n settings.width,\n warnings,\n );\n\n if (layout === null || layout === \"1\") {\n // Single column, or 4+ columns flattened onto the body width.\n const context = {\n columnWidth: settings.width,\n textColor: settings.textColor,\n };\n if (columns.length === 1) {\n const column = columns[0];\n const blocks = convertColumnModules(column, context, entries, warnings);\n // The column is the inner box: its padding adds to the row's (none is\n // mapped, so the section starts at 0) and its background replaces the\n // row's where it is set.\n const padding = addPadding(zeroPadding(), extractPadding(column.style));\n const backgroundColor = columnBackgroundColor(column.style) || rowBg;\n const frame = rowFrame(\n row,\n backgroundColor,\n columnBorder(column.style),\n false,\n warnings,\n );\n // A background, a border, padding or row chrome can't survive on bare modules.\n if (\n backgroundColor ||\n backgroundImage ||\n hasPadding(padding) ||\n frameNeedsSection(frame)\n ) {\n return [\n createSectionBlock({\n columns: \"1\",\n children: [blocks],\n styles: {\n padding,\n ...(backgroundColor ? { backgroundColor } : {}),\n },\n ...(backgroundImage ? { backgroundImage } : {}),\n ...frame,\n }),\n ];\n }\n return blocks;\n }\n\n const blocks: Block[] = [];\n for (const column of columns) {\n const converted = convertColumnModules(\n column,\n context,\n entries,\n warnings,\n );\n foldColumnPadding(converted, extractPadding(column.style));\n blocks.push(...converted);\n }\n warnIfColumnBoxDropped(columns, warnings);\n const frame = rowFrame(row, rowBg, undefined, false, warnings);\n if (rowBg || backgroundImage || frameNeedsSection(frame)) {\n return [\n createSectionBlock({\n columns: \"1\",\n children: [blocks],\n styles: {\n padding: zeroPadding(),\n ...(rowBg ? { backgroundColor: rowBg } : {}),\n },\n ...(backgroundImage ? { backgroundImage } : {}),\n ...frame,\n }),\n ];\n }\n return blocks;\n }\n\n // Multi-column — wrap in a SectionBlock. Each column's padding folds into\n // its modules; a column background or border has no per-column box.\n const widths = columnPixels(layout, settings.width);\n const frame = rowFrame(row, rowBg, undefined, true, warnings);\n const contentWidths = renderedColumnContentWidths(\n layout,\n settings.width,\n frame.border,\n );\n const sectionBox =\n Math.floor(settings.width) -\n drawnSide(frame.border?.left) -\n drawnSide(frame.border?.right);\n const sourceWidths = layoutSnaps(columns, layout)\n ? columnShareWidths(columns, sectionBox)\n : null;\n const facing = (index: number): Array<\"left\" | \"right\"> => {\n const last = columns.length - 1;\n if (index === 0) return [\"right\"];\n if (index === last) return [\"left\"];\n return [\"right\", \"left\"];\n };\n const children: Block[][] = columns.map((col, index) => {\n const deficit = sourceWidths\n ? sourceWidths[index]! - (contentWidths[index] ?? 0)\n : 0;\n const columnPadding = extractPadding(col.style);\n const blocks = convertColumnModules(\n col,\n {\n columnWidth: widths[index],\n textColor: settings.textColor,\n ...(sourceWidths\n ? {\n paddingReturn: {\n deficit: Math.max(0, deficit),\n sides: facing(index),\n columnPadding,\n },\n }\n : {}),\n },\n entries,\n warnings,\n );\n foldColumnPadding(blocks, columnPadding);\n return blocks;\n });\n warnIfColumnBoxDropped(columns, warnings);\n // Widths that are a length of this room — an image, a lone icon, a px\n // divider — are chosen with the padding already returned, so giving it\n // back does not resize them. A full button, a percentage divider, a menu\n // and an HTML block are a share of the column; the returned padding is\n // what makes that share the source column. A video keeps its stated px\n // width and a social row keeps its icon size.\n children.forEach((column, index) => {\n if (sourceWidths) {\n giveBackInnerPadding(\n column,\n sourceWidths[index]! - (contentWidths[index] ?? 0),\n facing(index),\n );\n }\n keepColumnImagesAtDesktopWidth(column, contentWidths[index] ?? 0);\n });\n\n const section = createSectionBlock({\n columns: layout,\n children,\n styles: {\n padding: zeroPadding(),\n ...(rowBg ? { backgroundColor: rowBg } : {}),\n },\n ...(backgroundImage ? { backgroundImage } : {}),\n ...frame,\n });\n\n return [section];\n}\n\n/**\n * Extracts template-level settings from the BeeFree body.\n */\nfunction extractSettings(\n template: BeeFreeTemplate,\n): TemplateContent[\"settings\"] {\n const body = template.page.body;\n const contentStyle = body?.content?.style ?? {};\n const computedStyle = body?.content?.computedStyle ?? {};\n const containerStyle = body?.container?.style ?? {};\n\n // Exports keep the body width in `computedStyle.messageWidth` and usually\n // carry no `style.width`.\n const width =\n parsePxValue(computedStyle.messageWidth) ||\n parsePxValue(contentStyle.width);\n const bgColor =\n parseColor(contentStyle[\"background-color\"]) ||\n parseColor(containerStyle[\"background-color\"]) ||\n \"#ffffff\";\n const fontFamily = canonicalFontStack(contentStyle[\"font-family\"]) || \"Arial\";\n const linkColor = parseColor(computedStyle.linkColor);\n\n return {\n width: width || 600,\n backgroundColor: bgColor,\n textColor: parseColor(contentStyle.color) || FALLBACK_TEXT_COLOR,\n ...(linkColor ? { linkColor } : {}),\n // BeeFree underlines per link, in the link's own markup, and has no\n // template-wide switch, so links take the browser default: underlined.\n linkUnderline: true,\n fontFamily,\n locale: \"en\",\n };\n}\n\n/**\n * Converts a BeeFree template JSON to Templatical TemplateContent.\n *\n * @param template - The parsed BeeFree JSON object\n * @returns An ImportResult with the converted content and a detailed report\n *\n * @example\n * ```ts\n * import { convertBeeFreeTemplate } from '@templatical/import-beefree';\n *\n * const beeFreeJson = JSON.parse(fileContent);\n * const { content, report } = convertBeeFreeTemplate(beeFreeJson);\n *\n * // Use the content with the editor\n * const editor = init({ container: '#editor', content });\n *\n * // Check the report for any issues\n * console.log(report.summary);\n * console.log(report.warnings);\n * ```\n */\nexport function convertBeeFreeTemplate(\n template: BeeFreeTemplate,\n options: ConvertBeeFreeOptions = {},\n): ImportResult {\n // Validate structure\n if (!template?.page?.rows) {\n throw new Error(\n \"Invalid BeeFree template: missing page.rows. Ensure you are passing a valid BeeFree JSON export.\",\n );\n }\n\n const entries: ImportReportEntry[] = [];\n const warnings: string[] = [];\n const blocks: Block[] = [];\n\n // Faces the host has to load. A system stack needs no file, and a face\n // that nothing in the template uses draws no warning.\n const customFonts = collectCustomFonts(template.page.body?.webFonts);\n warnForMissingFontUrls(template, customFonts, warnings);\n\n // Rows are measured against the width the imported template renders at.\n const settings = extractSettings(template);\n const declared =\n template.page.body?.language?.value ??\n template.page.language?.value ??\n template.language?.value;\n settings.locale =\n (declared ? localeTag(declared, warnings) : null) ??\n defaultLocaleOption(options.defaultLocale, warnings) ??\n \"en\";\n const meta = template.head?.meta;\n if (typeof meta?.preheader === \"string\")\n settings.preheaderText = decodeEntitiesInTokens(meta.preheader);\n for (const [code, values] of Object.entries(meta?.translations ?? {})) {\n const locale = localeTag(code, warnings);\n if (!locale) continue;\n for (const key of Object.keys(values)) {\n if (key === \"preheader\" && typeof values.preheader === \"string\") {\n text(\n settings,\n locale,\n \"preheaderText\",\n settings.preheaderText,\n decodeEntitiesInTokens(values.preheader),\n );\n } else {\n warn(\n warnings,\n `Dropped language \"${locale}\" metadata \"${key}\": ${[\"subject\", \"title\", \"description\"].includes(key) ? \"the host owns this field\" : \"no language mapping for this format\"}.`,\n );\n }\n }\n }\n\n // Process rows\n for (const row of template.page.rows) {\n if (row.empty) continue;\n blocks.push(...processRow(row, settings, entries, warnings));\n }\n\n // Build template content\n const content: TemplateContent = {\n ...createDefaultTemplateContent(),\n blocks,\n settings,\n };\n\n registerLocales(content);\n\n // Build report summary\n const summary = {\n total: entries.length,\n converted: entries.filter((e) => e.status === \"converted\").length,\n approximated: entries.filter((e) => e.status === \"approximated\").length,\n htmlFallback: entries.filter((e) => e.status === \"html-fallback\").length,\n skipped: entries.filter((e) => e.status === \"skipped\").length,\n };\n\n const report: ImportReport = { entries, warnings, summary };\n\n return { content, report, customFonts };\n}\n\n/**\n * Families BeeFree ships as system stacks, beyond the built-in web-safe set.\n * They show up as the face itself or as a fallback (`Helvetica Neue`,\n * `Lucida Grande`) and have nothing to download.\n */\nconst WEB_SAFE_FONTS = new Set<string>([\n ...Object.keys(BUILT_IN_FONT_STACKS),\n \"helvetica neue\",\n \"lucida grande\",\n \"lucida sans unicode\",\n \"lucida sans\",\n \"geneva\",\n \"times\",\n \"courier\",\n \"segoe\",\n \"segoe ui\",\n \"baskerville\",\n]);\n\n/** The first real family in a `font-family` value. `\"\"` for inherit or a generic. */\nfunction declaredFontName(value: string | undefined): string {\n if (!value) return \"\";\n const named = parseFontFamilies(value).find(\n (family) => !isGenericFontFamily(family),\n );\n return named?.name ?? \"\";\n}\n\nfunction isWebSafeFont(name: string): boolean {\n return WEB_SAFE_FONTS.has(name.toLowerCase());\n}\n\n/**\n * `webFonts` entries a host can load. The name is the first family of\n * `fontFamily` (what the template's CSS names), then `name`. A duplicate\n * name keeps the first URL. A system face, `inherit`, or a blank URL is\n * skipped.\n */\nfunction collectCustomFonts(\n webFonts: BeeFreeeWebFont[] | undefined,\n): CustomFont[] {\n const fonts: CustomFont[] = [];\n const seen = new Set<string>();\n for (const font of webFonts ?? []) {\n const url = typeof font.url === \"string\" ? font.url.trim() : \"\";\n if (!url) continue;\n const name =\n declaredFontName(font.fontFamily) || declaredFontName(font.name);\n if (!name || isWebSafeFont(name)) continue;\n const key = name.toLowerCase();\n if (seen.has(key)) continue;\n seen.add(key);\n fonts.push({ name, url });\n }\n return fonts;\n}\n\n/** `font-family` values on the body and in modules, not the `webFonts` list. */\nfunction collectUsedFontValues(template: BeeFreeTemplate): string[] {\n const found: string[] = [];\n const take = (value: unknown): void => {\n if (typeof value === \"string\") {\n // Stop at the attribute's closing quote. A family name may itself be quoted.\n for (const match of value.matchAll(\n /font-family\\s*:\\s*((?:[^;}\"]|\"[^\"]*\")+)/gi,\n )) {\n found.push(match[1].trim());\n }\n return;\n }\n if (!value || typeof value !== \"object\") return;\n if (Array.isArray(value)) {\n for (const item of value) take(item);\n return;\n }\n for (const [key, child] of Object.entries(value)) {\n if (key === \"webFonts\") continue;\n if (key === \"font-family\" && typeof child === \"string\") found.push(child);\n else take(child);\n }\n };\n take(template.page.body?.content);\n take(template.page.rows);\n return found;\n}\n\nfunction warnForMissingFontUrls(\n template: BeeFreeTemplate,\n customFonts: readonly CustomFont[],\n warnings: string[],\n): void {\n const loaded = new Set(customFonts.map((font) => font.name.toLowerCase()));\n for (const value of collectUsedFontValues(template)) {\n const name = declaredFontName(value);\n if (!name || isWebSafeFont(name)) continue;\n const key = name.toLowerCase();\n if (loaded.has(key)) continue;\n loaded.add(key);\n warn(\n warnings,\n `Font \"${name}\" is used but BeeFree provides no URL for it.`,\n );\n }\n}\n"],"mappings":"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"}
|