@templatical/import-unlayer
Advanced tools
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","names":[],"sources":["../src/style-parser.ts","../src/block-mapper.ts","../src/converter.ts"],"sourcesContent":["import type { SpacingValue } from \"@templatical/types\";\nimport type { UnlayerBorder, UnlayerFontFamily } from \"./types\";\n\n/**\n * Parses CSS-like style values from Unlayer content values.\n */\n\nexport function parsePxValue(value: string | number | undefined): number {\n if (value === undefined || value === null) return 0;\n if (typeof value === \"number\") return Math.round(value);\n // Single trailing-whitespace group with an optional `px` inside it. The\n // original `\\s*(?:px)?\\s*` had two `\\s*` quantifiers around an optional\n // group, which is the textbook polynomial-ReDoS shape (\"how should the\n // whitespace split across the two quantifiers?\") over inputs like\n // `9 ` with no `px`.\n const match = value.match(/^(-?\\d+(?:\\.\\d+)?)\\s*(?:px\\s*)?$/);\n return match ? Math.round(parseFloat(match[1])) : 0;\n}\n\nexport function parseColor(value: string | undefined): string {\n if (!value || value === \"transparent\") return \"\";\n\n const trimmed = value.trim();\n\n if (/^#[0-9a-fA-F]{6}$/.test(trimmed)) return trimmed.toLowerCase();\n\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 trimmed;\n}\n\nexport function parsePaddingShorthand(value: string | undefined): SpacingValue {\n if (!value) return { top: 0, right: 0, bottom: 0, left: 0 };\n\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\nexport function parseBorderObject(border: UnlayerBorder | undefined): {\n width: number;\n style: string;\n color: string;\n} {\n if (!border) return { width: 0, style: \"solid\", color: \"#000000\" };\n return {\n width: parsePxValue(border.borderTopWidth),\n style: border.borderTopStyle || \"solid\",\n color: parseColor(border.borderTopColor) || \"#000000\",\n };\n}\n\nexport function parseWidthPercent(value: string | undefined): number {\n if (!value) return 100;\n const match = value.match(/^(\\d+(?:\\.\\d+)?)\\s*%/);\n if (match) return Math.round(parseFloat(match[1]));\n return 100;\n}\n\nexport function parseFontFamily(\n value: UnlayerFontFamily | string | undefined,\n): string {\n if (!value) return \"\";\n if (typeof value === \"string\") {\n return value.split(\",\")[0].trim().replace(/['\"]/g, \"\");\n }\n if (value.value) return value.value.split(\",\")[0].trim().replace(/['\"]/g, \"\");\n if (value.label) return value.label;\n return \"\";\n}\n","import {\n createTitleBlock,\n createParagraphBlock,\n createImageBlock,\n createButtonBlock,\n createDividerBlock,\n createSpacerBlock,\n createHtmlBlock,\n createSocialIconsBlock,\n createMenuBlock,\n createVideoBlock,\n generateId,\n} from \"@templatical/types\";\nimport type {\n Block,\n HeadingLevel,\n SocialPlatform,\n SocialIcon,\n MenuItemData,\n} from \"@templatical/types\";\nimport type {\n UnlayerContent,\n UnlayerContentValues,\n ImportReportEntry,\n} from \"./types\";\nimport {\n parsePxValue,\n parseColor,\n parseFontFamily,\n parsePaddingShorthand,\n parseBorderObject,\n parseWidthPercent,\n} from \"./style-parser\";\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 mail: \"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\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 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\nfunction makeStyles(values: UnlayerContentValues): Block[\"styles\"] {\n const padding = parsePaddingShorthand(values.containerPadding);\n return {\n padding,\n };\n}\n\n/**\n * Apply Unlayer text-level styles as TipTap-compatible inline markup.\n * Mirrors the BeeFree importer's helper but reads from Unlayer's flat\n * values shape rather than a CSS style record.\n */\nfunction inlineStylesToHtml(\n html: string,\n values: UnlayerContentValues,\n): string {\n const spanParts: string[] = [];\n const fontSize = parsePxValue(values.fontSize);\n if (fontSize && fontSize !== 16) spanParts.push(`font-size: ${fontSize}px`);\n const color = parseColor(values.color);\n if (color && color !== \"#1a1a1a\") spanParts.push(`color: ${color}`);\n const fontWeight = values.fontWeight;\n if (\n fontWeight !== undefined &&\n fontWeight !== null &&\n String(fontWeight) !== \"normal\" &&\n String(fontWeight) !== \"400\"\n ) {\n spanParts.push(`font-weight: ${fontWeight}`);\n }\n const fontFamily = parseFontFamily(values.fontFamily);\n if (fontFamily) spanParts.push(`font-family: ${fontFamily}`);\n\n const textAlign = values.textAlign;\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 let result = html;\n\n if (pStyle) {\n result = result\n .replace(/<p style=\"([^\"]*)\">/g, `<p style=\"$1; ${pStyle}\">`)\n .replaceAll(\"<p>\", `<p style=\"${pStyle}\">`);\n }\n\n if (spanStyle) {\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 ensureParagraphWrapped(html: string): string {\n if (!html) return \"<p></p>\";\n if (/<p[\\s>]/i.test(html)) return html;\n return `<p>${html}</p>`;\n}\n\nfunction convertText(values: UnlayerContentValues): Block {\n const html = ensureParagraphWrapped(values.text ?? \"\");\n\n return createParagraphBlock({\n content: inlineStylesToHtml(html, values),\n styles: makeStyles(values),\n });\n}\n\nfunction parseHeadingLevel(tag: string | undefined): HeadingLevel {\n if (!tag) return 2;\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(values: UnlayerContentValues): Block {\n const text = values.text ?? \"\";\n const stripped = text.replace(/^<h\\d[^>]*>|<\\/h\\d>$/gi, \"\");\n const content = stripped ? `<p>${stripped}</p>` : \"<p></p>\";\n\n return createTitleBlock({\n content,\n level: parseHeadingLevel(values.headingType),\n color: parseColor(values.color) || \"#1a1a1a\",\n textAlign: toAlign(values.textAlign),\n fontFamily: parseFontFamily(values.fontFamily) || undefined,\n styles: makeStyles(values),\n });\n}\n\nfunction convertImage(values: UnlayerContentValues): Block {\n const src = values.src;\n const action = values.action?.values;\n\n return createImageBlock({\n src: src?.url || \"\",\n alt: values.altText || \"\",\n width: src?.width ? Math.round(src.width) : 600,\n align: toAlign(values.textAlign, \"center\"),\n linkUrl: action?.href || undefined,\n linkOpenInNewTab: action?.target === \"_blank\" || undefined,\n styles: makeStyles(values),\n });\n}\n\nfunction convertButton(values: UnlayerContentValues): Block {\n const colors = values.buttonColors ?? {};\n const padding = values.padding\n ? parsePaddingShorthand(values.padding)\n : { top: 12, right: 24, bottom: 12, left: 24 };\n const label = stripTagsPlain(values.text ?? \"Button\");\n const linkValues = values.href?.values;\n\n return createButtonBlock({\n text: label,\n url: linkValues?.href || \"#\",\n openInNewTab: linkValues?.target === \"_blank\" || undefined,\n backgroundColor: parseColor(colors.backgroundColor) || \"#4f46e5\",\n textColor: parseColor(colors.color) || \"#ffffff\",\n borderRadius: parsePxValue(values.borderRadius),\n fontSize: parsePxValue(values.fontSize) || 16,\n fontFamily: parseFontFamily(values.fontFamily) || undefined,\n buttonPadding: padding,\n styles: makeStyles(values),\n });\n}\n\nfunction convertDivider(values: UnlayerContentValues): Block {\n const border = parseBorderObject(values.border);\n\n return createDividerBlock({\n lineStyle: toLineStyle(border.style),\n color: border.color,\n thickness: border.width || 1,\n width: parseWidthPercent(values.width),\n styles: makeStyles(values),\n });\n}\n\nfunction convertSpacer(values: UnlayerContentValues): Block {\n const padding = parsePaddingShorthand(values.containerPadding);\n const height =\n parsePxValue((values as { height?: string | number }).height) ||\n padding.top + padding.bottom ||\n 24;\n\n return createSpacerBlock({\n height,\n styles: makeStyles(values),\n });\n}\n\nfunction convertHtml(values: UnlayerContentValues): Block {\n return createHtmlBlock({\n content: values.html ?? \"\",\n styles: makeStyles(values),\n });\n}\n\nfunction convertSocial(\n values: UnlayerContentValues,\n warnings: string[],\n): Block {\n const iconList = values.icons?.icons ?? [];\n const icons: SocialIcon[] = [];\n\n for (const unlayerIcon of iconList) {\n const id = (unlayerIcon.name ?? \"\").toLowerCase();\n const platform = SOCIAL_PLATFORM_MAP[id];\n\n if (!platform) {\n warnings.push(\n `Unrecognized social icon \"${unlayerIcon.name || id}\" was skipped.`,\n );\n continue;\n }\n\n icons.push({\n id: generateId(),\n platform,\n url: unlayerIcon.url || \"#\",\n });\n }\n\n return createSocialIconsBlock({\n icons,\n align: toAlign(values.textAlign, \"center\"),\n styles: makeStyles(values),\n });\n}\n\nfunction convertVideo(values: UnlayerContentValues): Block {\n return createVideoBlock({\n url: values.videoUrl || \"\",\n thumbnailUrl: values.thumbnailUrl || \"\",\n alt: values.altText || \"\",\n width: 600,\n align: toAlign(values.textAlign, \"center\"),\n styles: makeStyles(values),\n });\n}\n\nfunction convertMenu(values: UnlayerContentValues): Block {\n const menu = values.menu;\n const items: MenuItemData[] = (menu?.items ?? []).map((item) => ({\n id: generateId(),\n text: item.text || \"\",\n url: item.link?.values?.href || \"#\",\n openInNewTab: item.link?.values?.target === \"_blank\",\n bold: false,\n underline: false,\n }));\n\n return createMenuBlock({\n items,\n separator: values.separator || \"|\",\n separatorColor: \"#999999\",\n fontSize: parsePxValue(values.fontSize) || 14,\n color: parseColor(values.color) || \"#1a1a1a\",\n fontFamily: parseFontFamily(values.fontFamily) || undefined,\n textAlign: toAlign(values.textAlign, \"center\"),\n styles: makeStyles(values),\n });\n}\n\nfunction convertHtmlFallback(content: UnlayerContent, comment: string): Block {\n const safe = comment.replace(/</g, \"<\").replace(/>/g, \">\");\n return createHtmlBlock({\n content: `<div style=\"padding:12px;border:1px dashed #d1d5db;border-radius:6px;background:#fafafa;color:#6b7280;font-family:sans-serif;font-size:13px;\">${safe}</div>`,\n styles: makeStyles(content.values),\n });\n}\n\n/**\n * Converts a single Unlayer content node to a Templatical block.\n * Returns the block and a report entry.\n */\nexport function convertContent(\n content: UnlayerContent,\n warnings: string[],\n): { block: Block; entry: ImportReportEntry } {\n const type = content.type;\n const values = content.values ?? ({} as UnlayerContentValues);\n\n switch (type) {\n case \"text\":\n return {\n block: convertText(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"paragraph\",\n status: \"converted\",\n },\n };\n case \"heading\":\n return {\n block: convertHeading(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"title\",\n status: \"converted\",\n },\n };\n case \"image\":\n return {\n block: convertImage(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"image\",\n status: \"converted\",\n },\n };\n case \"button\":\n return {\n block: convertButton(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"button\",\n status: \"converted\",\n },\n };\n case \"divider\":\n return {\n block: convertDivider(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"divider\",\n status: \"converted\",\n },\n };\n case \"spacer\":\n return {\n block: convertSpacer(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"spacer\",\n status: \"converted\",\n },\n };\n case \"html\":\n return {\n block: convertHtml(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"html\",\n status: \"converted\",\n },\n };\n case \"menu\":\n return {\n block: convertMenu(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"menu\",\n status: \"approximated\",\n note: \"Menu styles map approximately; review spacing and separator color.\",\n },\n };\n case \"social\":\n return {\n block: convertSocial(values, warnings),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"social\",\n status: \"converted\",\n },\n };\n case \"video\":\n return {\n block: convertVideo(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"video\",\n status: \"converted\",\n },\n };\n case \"timer\":\n return {\n block: convertHtmlFallback(\n content,\n \"Unlayer timer block: rebuild manually in Templatical\",\n ),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n note: \"Timer modules have no direct Templatical equivalent; placeholder HTML inserted.\",\n },\n };\n case \"form\":\n return {\n block: convertHtmlFallback(\n content,\n \"Unlayer form block: not supported in Templatical (most email clients block form submission)\",\n ),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: null,\n status: \"skipped\",\n note: \"Unlayer forms have no Templatical equivalent and are skipped. Most email clients block form submission anyway.\",\n },\n };\n default:\n return {\n block: convertHtmlFallback(\n content,\n `Unsupported Unlayer content type: ${type}`,\n ),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n note: `Unknown content type \"${type}\" converted to HTML block.`,\n },\n };\n }\n}\n","import {\n createSectionBlock,\n createDefaultTemplateContent,\n} from \"@templatical/types\";\nimport type { Block, ColumnLayout, TemplateContent } from \"@templatical/types\";\nimport type {\n UnlayerTemplate,\n UnlayerRow,\n UnlayerColumn,\n ImportResult,\n ImportReport,\n ImportReportEntry,\n} from \"./types\";\nimport { convertContent } from \"./block-mapper\";\nimport {\n parsePxValue,\n parseColor,\n parseFontFamily,\n parsePaddingShorthand,\n} from \"./style-parser\";\n\nfunction resolveColumnLayout(\n cells: number[],\n warnings: string[],\n): ColumnLayout {\n if (cells.length <= 1) return \"1\";\n if (cells.length === 3) return \"3\";\n\n if (cells.length === 2) {\n const left = cells[0] ?? 1;\n const right = cells[1] ?? 1;\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 warnings.push(\n `Row with ${cells.length} columns was flattened to a single column. Unlayer supports arbitrary columns, but Templatical supports up to 3.`,\n );\n return \"1\";\n}\n\n/**\n * Converts all contents in a column to Templatical blocks.\n */\nfunction convertColumnContents(\n column: UnlayerColumn,\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const blocks: Block[] = [];\n\n for (const content of column.contents ?? []) {\n const { block, entry } = convertContent(content, warnings);\n blocks.push(block);\n entries.push(entry);\n }\n\n return blocks;\n}\n\n/**\n * Processes a single Unlayer row into one or more Templatical blocks.\n */\nfunction processRow(\n row: UnlayerRow,\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const columns = row.columns;\n if (!columns || columns.length === 0) return [];\n\n const cells = row.cells ?? columns.map(() => 1);\n const layout = resolveColumnLayout(cells, warnings);\n\n let children: Block[][];\n if (layout === \"1\") {\n const merged: Block[] = [];\n for (const column of columns) {\n merged.push(...convertColumnContents(column, entries, warnings));\n }\n children = [merged];\n } else {\n children = columns.map((col) =>\n convertColumnContents(col, entries, warnings),\n );\n }\n\n const rowBg = parseColor(row.values?.backgroundColor);\n const padding = parsePaddingShorthand(row.values?.padding);\n\n const section = createSectionBlock({\n columns: layout,\n children,\n styles: {\n padding,\n ...(rowBg ? { backgroundColor: rowBg } : {}),\n },\n });\n\n return [section];\n}\n\n/**\n * Extracts template-level settings from the Unlayer body values.\n */\nfunction extractSettings(\n template: UnlayerTemplate,\n): TemplateContent[\"settings\"] {\n const values = template.body?.values ?? {};\n\n const width = parsePxValue(values.contentWidth);\n const bgColor = parseColor(values.backgroundColor) || \"#ffffff\";\n const fontFamily = parseFontFamily(values.fontFamily) || \"Arial\";\n\n return {\n width: width || 600,\n backgroundColor: bgColor,\n fontFamily,\n locale: \"en\",\n };\n}\n\n/**\n * Converts an Unlayer design JSON to Templatical TemplateContent.\n *\n * @param template - The parsed Unlayer JSON object (the result of `editor.saveDesign(...)`)\n * @returns An ImportResult with the converted content and a detailed report\n *\n * @example\n * ```ts\n * import { convertUnlayerTemplate } from '@templatical/import-unlayer';\n *\n * const unlayerJson = JSON.parse(fileContent);\n * const { content, report } = convertUnlayerTemplate(unlayerJson);\n *\n * const editor = init({ container: '#editor', content });\n *\n * console.log(report.summary);\n * console.log(report.warnings);\n * ```\n */\nexport function convertUnlayerTemplate(\n template: UnlayerTemplate,\n): ImportResult {\n if (!template?.body?.rows) {\n throw new Error(\n \"Invalid Unlayer template: missing body.rows. Ensure you are passing a valid Unlayer JSON design (the output of editor.saveDesign).\",\n );\n }\n\n const entries: ImportReportEntry[] = [];\n const warnings: string[] = [];\n const blocks: Block[] = [];\n\n const headers = template.body.headers ?? [];\n const footers = template.body.footers ?? [];\n\n if (headers.length > 0) {\n warnings.push(\n `${headers.length} Unlayer header row(s) were imported as regular rows at the top of the template.`,\n );\n for (const row of headers) {\n blocks.push(...processRow(row, entries, warnings));\n }\n }\n\n for (const row of template.body.rows) {\n blocks.push(...processRow(row, entries, warnings));\n }\n\n if (footers.length > 0) {\n warnings.push(\n `${footers.length} Unlayer footer row(s) were imported as regular rows at the bottom of the template.`,\n );\n for (const row of footers) {\n blocks.push(...processRow(row, entries, warnings));\n }\n }\n\n const content: TemplateContent = {\n ...createDefaultTemplateContent(),\n blocks,\n settings: extractSettings(template),\n };\n\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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"} | ||
| {"version":3,"file":"index.js","names":[],"sources":["../src/style-parser.ts","../src/block-mapper.ts","../src/converter.ts"],"sourcesContent":["import type { SpacingValue } from \"@templatical/types\";\nimport type { UnlayerBorder, UnlayerFontFamily } from \"./types\";\n\n/**\n * Parses CSS-like style values from Unlayer content values.\n */\n\nexport function parsePxValue(value: string | number | undefined): number {\n if (value === undefined || value === null) return 0;\n if (typeof value === \"number\") return Math.round(value);\n // Single trailing-whitespace group with an optional `px` inside it. The\n // original `\\s*(?:px)?\\s*` had two `\\s*` quantifiers around an optional\n // group, which is the textbook polynomial-ReDoS shape (\"how should the\n // whitespace split across the two quantifiers?\") over inputs like\n // `9 ` with no `px`.\n const match = value.match(/^(-?\\d+(?:\\.\\d+)?)\\s*(?:px\\s*)?$/);\n return match ? Math.round(parseFloat(match[1])) : 0;\n}\n\nexport function parseColor(value: string | undefined): string {\n if (!value || value === \"transparent\") return \"\";\n\n const trimmed = value.trim();\n\n if (/^#[0-9a-fA-F]{6}$/.test(trimmed)) return trimmed.toLowerCase();\n\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 trimmed;\n}\n\nexport function parsePaddingShorthand(value: string | undefined): SpacingValue {\n if (!value) return { top: 0, right: 0, bottom: 0, left: 0 };\n\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\nexport function parseBorderObject(border: UnlayerBorder | undefined): {\n width: number;\n style: string;\n color: string;\n} {\n if (!border) return { width: 0, style: \"solid\", color: \"#000000\" };\n return {\n width: parsePxValue(border.borderTopWidth),\n style: border.borderTopStyle || \"solid\",\n color: parseColor(border.borderTopColor) || \"#000000\",\n };\n}\n\nexport function parseWidthPercent(value: string | undefined): number {\n if (!value) return 100;\n const match = value.match(/^(\\d+(?:\\.\\d+)?)\\s*%/);\n if (match) return Math.round(parseFloat(match[1]));\n return 100;\n}\n\nexport function parseFontFamily(\n value: UnlayerFontFamily | string | undefined,\n): string {\n if (!value) return \"\";\n if (typeof value === \"string\") {\n return value.split(\",\")[0].trim().replace(/['\"]/g, \"\");\n }\n if (value.value) return value.value.split(\",\")[0].trim().replace(/['\"]/g, \"\");\n if (value.label) return value.label;\n return \"\";\n}\n","import {\n createTitleBlock,\n createParagraphBlock,\n createImageBlock,\n createButtonBlock,\n createDividerBlock,\n createSpacerBlock,\n createHtmlBlock,\n createSocialIconsBlock,\n createMenuBlock,\n createVideoBlock,\n generateId,\n} from \"@templatical/types\";\nimport type {\n Block,\n HeadingLevel,\n SocialPlatform,\n SocialIcon,\n MenuItemData,\n} from \"@templatical/types\";\nimport type {\n UnlayerContent,\n UnlayerContentValues,\n ImportReportEntry,\n} from \"./types\";\nimport {\n parsePxValue,\n parseColor,\n parseFontFamily,\n parsePaddingShorthand,\n parseBorderObject,\n parseWidthPercent,\n} from \"./style-parser\";\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 mail: \"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\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 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\nfunction makeStyles(values: UnlayerContentValues): Block[\"styles\"] {\n const padding = parsePaddingShorthand(values.containerPadding);\n return {\n padding,\n };\n}\n\n/**\n * Apply Unlayer text-level styles as TipTap-compatible inline markup.\n * Mirrors the BeeFree importer's helper but reads from Unlayer's flat\n * values shape rather than a CSS style record.\n */\nfunction inlineStylesToHtml(\n html: string,\n values: UnlayerContentValues,\n): string {\n const spanParts: string[] = [];\n const fontSize = parsePxValue(values.fontSize);\n if (fontSize && fontSize !== 16) spanParts.push(`font-size: ${fontSize}px`);\n const color = parseColor(values.color);\n if (color && color !== \"#1a1a1a\") spanParts.push(`color: ${color}`);\n const fontWeight = values.fontWeight;\n if (\n fontWeight !== undefined &&\n fontWeight !== null &&\n String(fontWeight) !== \"normal\" &&\n String(fontWeight) !== \"400\"\n ) {\n spanParts.push(`font-weight: ${fontWeight}`);\n }\n const fontFamily = parseFontFamily(values.fontFamily);\n if (fontFamily) spanParts.push(`font-family: ${fontFamily}`);\n\n const textAlign = values.textAlign;\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 let result = html;\n\n if (pStyle) {\n result = result\n .replace(/<p style=\"([^\"]*)\">/g, `<p style=\"$1; ${pStyle}\">`)\n .replaceAll(\"<p>\", `<p style=\"${pStyle}\">`);\n }\n\n if (spanStyle) {\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 ensureParagraphWrapped(html: string): string {\n if (!html) return \"<p></p>\";\n if (/<p[\\s>]/i.test(html)) return html;\n return `<p>${html}</p>`;\n}\n\nfunction convertText(values: UnlayerContentValues): Block {\n const html = ensureParagraphWrapped(values.text ?? \"\");\n\n return createParagraphBlock({\n content: inlineStylesToHtml(html, values),\n styles: makeStyles(values),\n });\n}\n\nfunction parseHeadingLevel(tag: string | undefined): HeadingLevel {\n if (!tag) return 2;\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(values: UnlayerContentValues): Block {\n const text = values.text ?? \"\";\n const stripped = text.replace(/^<h\\d[^>]*>|<\\/h\\d>$/gi, \"\");\n const content = stripped ? `<p>${stripped}</p>` : \"<p></p>\";\n\n return createTitleBlock({\n content,\n level: parseHeadingLevel(values.headingType),\n color: parseColor(values.color) || \"#1a1a1a\",\n textAlign: toAlign(values.textAlign),\n fontFamily: parseFontFamily(values.fontFamily) || undefined,\n styles: makeStyles(values),\n });\n}\n\nfunction convertImage(values: UnlayerContentValues): Block {\n const src = values.src;\n const action = values.action?.values;\n\n return createImageBlock({\n src: src?.url || \"\",\n alt: values.altText || \"\",\n width: src?.width ? Math.round(src.width) : 600,\n align: toAlign(values.textAlign, \"center\"),\n linkUrl: action?.href || undefined,\n linkOpenInNewTab: action?.target === \"_blank\" || undefined,\n styles: makeStyles(values),\n });\n}\n\nfunction convertButton(values: UnlayerContentValues): Block {\n const colors = values.buttonColors ?? {};\n const padding = values.padding\n ? parsePaddingShorthand(values.padding)\n : { top: 12, right: 24, bottom: 12, left: 24 };\n const label = stripTagsPlain(values.text ?? \"Button\");\n const linkValues = values.href?.values;\n\n return createButtonBlock({\n text: label,\n url: linkValues?.href || \"#\",\n openInNewTab: linkValues?.target === \"_blank\" || undefined,\n backgroundColor: parseColor(colors.backgroundColor) || \"#4f46e5\",\n textColor: parseColor(colors.color) || \"#ffffff\",\n borderRadius: parsePxValue(values.borderRadius),\n fontSize: parsePxValue(values.fontSize) || 16,\n fontFamily: parseFontFamily(values.fontFamily) || undefined,\n buttonPadding: padding,\n styles: makeStyles(values),\n });\n}\n\nfunction convertDivider(values: UnlayerContentValues): Block {\n const border = parseBorderObject(values.border);\n\n return createDividerBlock({\n lineStyle: toLineStyle(border.style),\n color: border.color,\n thickness: border.width || 1,\n width: parseWidthPercent(values.width),\n styles: makeStyles(values),\n });\n}\n\nfunction convertSpacer(values: UnlayerContentValues): Block {\n const padding = parsePaddingShorthand(values.containerPadding);\n const height =\n parsePxValue((values as { height?: string | number }).height) ||\n padding.top + padding.bottom ||\n 24;\n\n return createSpacerBlock({\n height,\n styles: makeStyles(values),\n });\n}\n\nfunction convertHtml(values: UnlayerContentValues): Block {\n return createHtmlBlock({\n content: values.html ?? \"\",\n styles: makeStyles(values),\n });\n}\n\nfunction convertSocial(\n values: UnlayerContentValues,\n warnings: string[],\n): Block {\n const iconList = values.icons?.icons ?? [];\n const icons: SocialIcon[] = [];\n\n for (const unlayerIcon of iconList) {\n const id = (unlayerIcon.name ?? \"\").toLowerCase();\n const platform = SOCIAL_PLATFORM_MAP[id];\n\n if (!platform) {\n warnings.push(\n `Unrecognized social icon \"${unlayerIcon.name || id}\" was skipped.`,\n );\n continue;\n }\n\n icons.push({\n id: generateId(),\n platform,\n url: unlayerIcon.url || \"#\",\n });\n }\n\n return createSocialIconsBlock({\n icons,\n align: toAlign(values.textAlign, \"center\"),\n styles: makeStyles(values),\n });\n}\n\nfunction convertVideo(values: UnlayerContentValues): Block {\n return createVideoBlock({\n url: values.videoUrl || \"\",\n thumbnailUrl: values.thumbnailUrl || \"\",\n alt: values.altText || \"\",\n width: 600,\n align: toAlign(values.textAlign, \"center\"),\n styles: makeStyles(values),\n });\n}\n\nfunction convertMenu(values: UnlayerContentValues): Block {\n const menu = values.menu;\n const items: MenuItemData[] = (menu?.items ?? []).map((item) => ({\n id: generateId(),\n text: item.text || \"\",\n url: item.link?.values?.href || \"#\",\n openInNewTab: item.link?.values?.target === \"_blank\",\n bold: false,\n underline: false,\n }));\n\n return createMenuBlock({\n items,\n separator: values.separator || \"|\",\n separatorColor: \"#999999\",\n fontSize: parsePxValue(values.fontSize) || 14,\n color: parseColor(values.color) || \"#1a1a1a\",\n fontFamily: parseFontFamily(values.fontFamily) || undefined,\n textAlign: toAlign(values.textAlign, \"center\"),\n styles: makeStyles(values),\n });\n}\n\nfunction convertHtmlFallback(content: UnlayerContent, comment: string): Block {\n const safe = comment.replace(/</g, \"<\").replace(/>/g, \">\");\n return createHtmlBlock({\n content: `<div style=\"padding:12px;border:1px dashed #d1d5db;border-radius:6px;background:#fafafa;color:#6b7280;font-family:sans-serif;font-size:13px;\">${safe}</div>`,\n styles: makeStyles(content.values),\n });\n}\n\n/**\n * Converts a single Unlayer content node to a Templatical block.\n * Returns the block and a report entry.\n */\nexport function convertContent(\n content: UnlayerContent,\n warnings: string[],\n): { block: Block; entry: ImportReportEntry } {\n const type = content.type;\n const values = content.values ?? ({} as UnlayerContentValues);\n\n switch (type) {\n case \"text\":\n return {\n block: convertText(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"paragraph\",\n status: \"converted\",\n },\n };\n case \"heading\":\n return {\n block: convertHeading(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"title\",\n status: \"converted\",\n },\n };\n case \"image\":\n return {\n block: convertImage(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"image\",\n status: \"converted\",\n },\n };\n case \"button\":\n return {\n block: convertButton(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"button\",\n status: \"converted\",\n },\n };\n case \"divider\":\n return {\n block: convertDivider(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"divider\",\n status: \"converted\",\n },\n };\n case \"spacer\":\n return {\n block: convertSpacer(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"spacer\",\n status: \"converted\",\n },\n };\n case \"html\":\n return {\n block: convertHtml(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"html\",\n status: \"converted\",\n },\n };\n case \"menu\":\n return {\n block: convertMenu(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"menu\",\n status: \"approximated\",\n note: \"Menu styles map approximately; review spacing and separator color.\",\n },\n };\n case \"social\":\n return {\n block: convertSocial(values, warnings),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"social\",\n status: \"converted\",\n },\n };\n case \"video\":\n return {\n block: convertVideo(values),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"video\",\n status: \"converted\",\n },\n };\n case \"timer\":\n return {\n block: convertHtmlFallback(\n content,\n \"Unlayer timer block: rebuild manually in Templatical\",\n ),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n note: \"Timer modules have no direct Templatical equivalent; placeholder HTML inserted.\",\n },\n };\n case \"form\":\n return {\n block: convertHtmlFallback(\n content,\n \"Unlayer form block: not supported in Templatical (most email clients block form submission)\",\n ),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: null,\n status: \"skipped\",\n note: \"Unlayer forms have no Templatical equivalent and are skipped. Most email clients block form submission anyway.\",\n },\n };\n default:\n return {\n block: convertHtmlFallback(\n content,\n `Unsupported Unlayer content type: ${type}`,\n ),\n entry: {\n unlayerContentType: type,\n templaticalBlockType: \"html\",\n status: \"html-fallback\",\n note: `Unknown content type \"${type}\" converted to HTML block.`,\n },\n };\n }\n}\n","import {\n createSectionBlock,\n createDefaultTemplateContent,\n} from \"@templatical/types\";\nimport type { Block, ColumnLayout, TemplateContent } from \"@templatical/types\";\nimport type {\n UnlayerTemplate,\n UnlayerRow,\n UnlayerColumn,\n ImportResult,\n ImportReport,\n ImportReportEntry,\n} from \"./types\";\nimport { convertContent } from \"./block-mapper\";\nimport {\n parsePxValue,\n parseColor,\n parseFontFamily,\n parsePaddingShorthand,\n} from \"./style-parser\";\n\nfunction resolveColumnLayout(\n cells: number[],\n warnings: string[],\n): ColumnLayout {\n if (cells.length <= 1) return \"1\";\n if (cells.length === 3) return \"3\";\n\n if (cells.length === 2) {\n const left = cells[0] ?? 1;\n const right = cells[1] ?? 1;\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 warnings.push(\n `Row with ${cells.length} columns was flattened to a single column. Unlayer supports arbitrary columns, but Templatical supports up to 3.`,\n );\n return \"1\";\n}\n\n/**\n * Converts all contents in a column to Templatical blocks.\n */\nfunction convertColumnContents(\n column: UnlayerColumn,\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const blocks: Block[] = [];\n\n for (const content of column.contents ?? []) {\n const { block, entry } = convertContent(content, warnings);\n blocks.push(block);\n entries.push(entry);\n }\n\n return blocks;\n}\n\n/**\n * Processes a single Unlayer row into one or more Templatical blocks.\n */\nfunction processRow(\n row: UnlayerRow,\n entries: ImportReportEntry[],\n warnings: string[],\n): Block[] {\n const columns = row.columns;\n if (!columns || columns.length === 0) return [];\n\n const cells = row.cells ?? columns.map(() => 1);\n const layout = resolveColumnLayout(cells, warnings);\n\n let children: Block[][];\n if (layout === \"1\") {\n const merged: Block[] = [];\n for (const column of columns) {\n merged.push(...convertColumnContents(column, entries, warnings));\n }\n children = [merged];\n } else {\n children = columns.map((col) =>\n convertColumnContents(col, entries, warnings),\n );\n }\n\n const rowBg = parseColor(row.values?.backgroundColor);\n const padding = parsePaddingShorthand(row.values?.padding);\n\n const section = createSectionBlock({\n columns: layout,\n children,\n styles: {\n padding,\n ...(rowBg ? { backgroundColor: rowBg } : {}),\n },\n });\n\n return [section];\n}\n\n/**\n * Extracts template-level settings from the Unlayer body values.\n */\nfunction extractSettings(\n template: UnlayerTemplate,\n): TemplateContent[\"settings\"] {\n const values = template.body?.values ?? {};\n\n const width = parsePxValue(values.contentWidth);\n const bgColor = parseColor(values.backgroundColor) || \"#ffffff\";\n const fontFamily = parseFontFamily(values.fontFamily) || \"Arial\";\n\n return {\n width: width || 600,\n backgroundColor: bgColor,\n fontFamily,\n locale: \"en\",\n };\n}\n\n/**\n * Converts an Unlayer design JSON to Templatical TemplateContent.\n *\n * @param template - The parsed Unlayer JSON object (the result of `editor.saveDesign(...)`)\n * @returns An ImportResult with the converted content and a detailed report\n *\n * @example\n * ```ts\n * import { convertUnlayerTemplate } from '@templatical/import-unlayer';\n *\n * const unlayerJson = JSON.parse(fileContent);\n * const { content, report } = convertUnlayerTemplate(unlayerJson);\n *\n * const editor = init({ container: '#editor', content });\n *\n * console.log(report.summary);\n * console.log(report.warnings);\n * ```\n */\nexport function convertUnlayerTemplate(\n template: UnlayerTemplate,\n): ImportResult {\n if (!template?.body?.rows) {\n throw new Error(\n \"Invalid Unlayer template: missing body.rows. Ensure you are passing a valid Unlayer JSON design (the output of editor.saveDesign).\",\n );\n }\n\n const entries: ImportReportEntry[] = [];\n const warnings: string[] = [];\n const blocks: Block[] = [];\n\n const headers = template.body.headers ?? [];\n const footers = template.body.footers ?? [];\n\n if (headers.length > 0) {\n warnings.push(\n `${headers.length} Unlayer header row(s) were imported as regular rows at the top of the template.`,\n );\n for (const row of headers) {\n blocks.push(...processRow(row, entries, warnings));\n }\n }\n\n for (const row of template.body.rows) {\n blocks.push(...processRow(row, entries, warnings));\n }\n\n if (footers.length > 0) {\n warnings.push(\n `${footers.length} Unlayer footer row(s) were imported as regular rows at the bottom of the template.`,\n );\n for (const row of footers) {\n blocks.push(...processRow(row, entries, warnings));\n }\n }\n\n const content: TemplateContent = {\n ...createDefaultTemplateContent(),\n blocks,\n settings: extractSettings(template),\n };\n\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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"} |
+3
-3
| { | ||
| "name": "@templatical/import-unlayer", | ||
| "description": "Convert Unlayer email templates to Templatical format", | ||
| "version": "0.10.1", | ||
| "version": "0.10.2", | ||
| "bugs": "https://github.com/templatical/sdk/issues", | ||
| "dependencies": { | ||
| "@templatical/types": "0.10.1" | ||
| "@templatical/types": "0.10.2" | ||
| }, | ||
| "devDependencies": { | ||
| "typescript": "^6.0.3", | ||
| "vitest": "^4.1.7" | ||
| "vitest": "^4.1.8" | ||
| }, | ||
@@ -13,0 +13,0 @@ "exports": { |
64184
0.13%+ Added
- Removed
Updated