@templatical/import-easy-email-pro 0.46.0 → 0.48.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 CHANGED
@@ -36,9 +36,9 @@ Each entry in `report.entries` carries a `status`:
36
36
  - `converted` — mapped to a Templatical block with no loss of fidelity.
37
37
  - `approximated` — mapped to a Templatical block, but something had to be
38
38
  resolved or clamped (e.g. a 4+ column row folded to three, an outlined
39
- button, a hero overlay stacked as a leading image, a countdown GIF, a
40
- widget whose children converted without its chrome, logic whose children
41
- converted without their expression).
39
+ button, a hero's `inner-padding` dropped, a countdown GIF, a widget whose
40
+ children converted without its chrome, logic whose children converted
41
+ without their expression).
42
42
  - `html-fallback` — no Templatical block exists for this `type`; the raw node
43
43
  is preserved as JSON inside an `HtmlBlock`.
44
44
  - `skipped` — empty `logic`; there were no children to convert.
package/dist/index.js CHANGED
@@ -225,6 +225,282 @@ function readPadding(read) {
225
225
  left: side("padding-left")
226
226
  };
227
227
  }
228
+ const X_GRID = [
229
+ "left",
230
+ "center",
231
+ "right"
232
+ ];
233
+ const Y_GRID = [
234
+ "top",
235
+ "center",
236
+ "bottom"
237
+ ];
238
+ const PERCENT = /^(-?(?:\d+(?:\.\d+)?|\.\d+))%$/;
239
+ const LENGTH = /^-?(?:\d+(?:\.\d+)?|\.\d+)[a-z]*$/;
240
+ /** What MJML paints for a `background-*` attribute an `mj-section` / `mj-wrapper` leaves out. */
241
+ const MJML_BACKGROUND_DEFAULTS = {
242
+ size: "auto",
243
+ x: "center",
244
+ y: "top",
245
+ repeat: true
246
+ };
247
+ /**
248
+ * `background-size` as a keyword. A size with a side at 100%, or a px width
249
+ * spanning the box, fills it as `cover` does; any other length or percentage
250
+ * draws the image at a size of its own, which `auto` is closest to.
251
+ */
252
+ function backgroundSizeKeyword(raw, boxWidth) {
253
+ const parts = raw.toLowerCase().split(/\s+/);
254
+ const [first] = parts;
255
+ if (parts.length === 1 && (first === "cover" || first === "contain")) return {
256
+ size: first,
257
+ exact: true
258
+ };
259
+ if (parts.every((part) => part === "auto")) return {
260
+ size: "auto",
261
+ exact: true
262
+ };
263
+ const px = /^(\d+(?:\.\d+)?|\.\d+)px$/.exec(first);
264
+ return {
265
+ size: parts.includes("100%") || px !== null && boxWidth !== void 0 && Number(px[1]) >= boxWidth ? "cover" : "auto",
266
+ exact: false
267
+ };
268
+ }
269
+ /**
270
+ * `background-position` split into x and y the way MJML and CSS read it: a
271
+ * lone `top` / `bottom` names y and centres x, any other lone value is x
272
+ * with y centred, and a pair is x then y unless it leads with `top` /
273
+ * `bottom` (or with `center` before `left` / `right`). Three- and four-value
274
+ * edge offsets keep their edge keywords only.
275
+ */
276
+ function splitBackgroundPosition(raw) {
277
+ const parts = raw.toLowerCase().split(/\s+/);
278
+ if (parts.length === 1) {
279
+ const [only] = parts;
280
+ return only === "top" || only === "bottom" ? {
281
+ x: "center",
282
+ y: only,
283
+ exact: true
284
+ } : {
285
+ x: only,
286
+ y: "center",
287
+ exact: true
288
+ };
289
+ }
290
+ if (parts.length === 2) {
291
+ const [a, b] = parts;
292
+ return a === "top" || a === "bottom" || a === "center" && (b === "left" || b === "right") ? {
293
+ x: b,
294
+ y: a,
295
+ exact: true
296
+ } : {
297
+ x: a,
298
+ y: b,
299
+ exact: true
300
+ };
301
+ }
302
+ return {
303
+ x: parts.find((part) => part === "left" || part === "right") ?? "center",
304
+ y: parts.find((part) => part === "top" || part === "bottom") ?? "center",
305
+ exact: false
306
+ };
307
+ }
308
+ /**
309
+ * One axis as a grid point: its keyword; the point nearest a percentage,
310
+ * ties going to the centre; or the start edge for a length, which is an
311
+ * offset from it. `null` when the token is unreadable.
312
+ */
313
+ function backgroundAxisPoint(token, grid) {
314
+ const keyword = grid.find((point) => point === token);
315
+ if (keyword) return {
316
+ point: keyword,
317
+ exact: true
318
+ };
319
+ const percent = PERCENT.exec(token);
320
+ if (percent) {
321
+ const n = Number(percent[1]);
322
+ return {
323
+ point: n < 25 ? grid[0] : n > 75 ? grid[2] : grid[1],
324
+ exact: n === 0 || n === 50 || n === 100
325
+ };
326
+ }
327
+ if (LENGTH.test(token)) return {
328
+ point: grid[0],
329
+ exact: parseFloat(token) === 0
330
+ };
331
+ return null;
332
+ }
333
+ /**
334
+ * `background-repeat`: unrepeated only when every axis is `no-repeat`.
335
+ * Anything but plain `repeat` tiles too, inexactly.
336
+ */
337
+ function backgroundRepeatFlag(raw) {
338
+ const parts = raw.toLowerCase().split(/\s+/);
339
+ if (parts.every((part) => part === "no-repeat")) return {
340
+ repeat: false,
341
+ exact: true
342
+ };
343
+ return {
344
+ repeat: true,
345
+ exact: parts.every((part) => part === "repeat")
346
+ };
347
+ }
348
+ /**
349
+ * A section or wrapper background image, `null` when `background-url` is
350
+ * unset. Easy Email Pro renders through MJML, so unset attributes take
351
+ * MJML's own defaults and the import paints what the editor painted; a value
352
+ * with no exact keyword takes the nearest one and adds a note naming it.
353
+ * `read` returns an attribute's cascaded value (`readAttr`); `label` names
354
+ * the element in each note, and a px `background-size` is measured against
355
+ * `boxWidth`.
356
+ */
357
+ function readMjmlBackgroundImage(read, label, boxWidth) {
358
+ const value = (name) => {
359
+ const raw = read(name);
360
+ return isUnset(raw) ? void 0 : String(raw).trim();
361
+ };
362
+ const url = value("background-url") ?? "";
363
+ if (!url) return null;
364
+ const notes = [];
365
+ const lossy = (name, raw, shown) => {
366
+ notes.push(`${label} ${name} "${raw}" has no exact Templatical equivalent; imported as "${shown}".`);
367
+ };
368
+ let size = MJML_BACKGROUND_DEFAULTS.size;
369
+ const rawSize = value("background-size");
370
+ if (rawSize) {
371
+ const parsed = backgroundSizeKeyword(rawSize, boxWidth);
372
+ size = parsed.size;
373
+ if (!parsed.exact) lossy("background-size", rawSize, size);
374
+ }
375
+ let x = MJML_BACKGROUND_DEFAULTS.x;
376
+ let y = MJML_BACKGROUND_DEFAULTS.y;
377
+ let lossyX = false;
378
+ let lossyY = false;
379
+ const rawPosition = value("background-position");
380
+ if (rawPosition) {
381
+ const split = splitBackgroundPosition(rawPosition);
382
+ const readX = backgroundAxisPoint(split.x, X_GRID);
383
+ const readY = backgroundAxisPoint(split.y, Y_GRID);
384
+ x = readX?.point ?? x;
385
+ y = readY?.point ?? y;
386
+ lossyX = !split.exact || !readX?.exact;
387
+ lossyY = !split.exact || !readY?.exact;
388
+ }
389
+ const rawX = value("background-position-x");
390
+ const overrideX = rawX ? backgroundAxisPoint(rawX.toLowerCase(), X_GRID) : null;
391
+ if (overrideX) {
392
+ x = overrideX.point;
393
+ lossyX = false;
394
+ }
395
+ const rawY = value("background-position-y");
396
+ const overrideY = rawY ? backgroundAxisPoint(rawY.toLowerCase(), Y_GRID) : null;
397
+ if (overrideY) {
398
+ y = overrideY.point;
399
+ lossyY = false;
400
+ }
401
+ if (rawPosition && (lossyX || lossyY)) lossy("background-position", rawPosition, `${x} ${y}`);
402
+ if (rawX && !overrideX?.exact) lossy("background-position-x", rawX, x);
403
+ if (rawY && !overrideY?.exact) lossy("background-position-y", rawY, y);
404
+ let repeat = MJML_BACKGROUND_DEFAULTS.repeat;
405
+ const rawRepeat = value("background-repeat");
406
+ if (rawRepeat) {
407
+ const parsed = backgroundRepeatFlag(rawRepeat);
408
+ repeat = parsed.repeat;
409
+ if (!parsed.exact) lossy("background-repeat", rawRepeat, repeat ? "repeat" : "no-repeat");
410
+ }
411
+ return {
412
+ image: {
413
+ url,
414
+ size,
415
+ position: {
416
+ x,
417
+ y
418
+ },
419
+ repeat
420
+ },
421
+ notes
422
+ };
423
+ }
424
+ const HERO_ALIGNS = [
425
+ "top",
426
+ "middle",
427
+ "bottom"
428
+ ];
429
+ const HERO_DROPPED_ATTRIBUTES = [
430
+ "inner-padding",
431
+ "inner-padding-top",
432
+ "inner-padding-right",
433
+ "inner-padding-bottom",
434
+ "inner-padding-left",
435
+ "inner-background-color"
436
+ ];
437
+ /**
438
+ * A `standard-hero`'s mode, height and background. Easy Email Pro renders it
439
+ * as an MJML `mj-hero`, so unset attributes take mj-hero's defaults
440
+ * (`fixed-height`, `0px`, `center center`, `vertical-align: top`), and its
441
+ * image is always `cover` and unrepeated. `background-width` /
442
+ * `background-height` are stored as the image's `naturalWidth` /
443
+ * `naturalHeight`, though they are often the hero box's size rather than the
444
+ * file's: only their ratio is used. A `fixed-height` hero without a positive
445
+ * `height` is as tall as its content, exactly what a regular section with the
446
+ * same background paints, so it comes back without `hero`.
447
+ */
448
+ function readMjmlHero(read, label, boxWidth) {
449
+ const value = (name) => {
450
+ const raw = read(name);
451
+ return isUnset(raw) ? void 0 : String(raw).trim();
452
+ };
453
+ const notes = [];
454
+ const background = readMjmlBackgroundImage((name) => {
455
+ if (name === "background-size") return "cover";
456
+ if (name === "background-repeat") return "no-repeat";
457
+ if (name === "background-position") return value(name) ?? "center center";
458
+ if (name === "background-position-x" || name === "background-position-y") return;
459
+ return read(name);
460
+ }, label, boxWidth);
461
+ if (background) notes.push(...background.notes);
462
+ const width = parsePx(value("background-width"));
463
+ const height = parsePx(value("background-height"));
464
+ const sized = width !== void 0 && height !== void 0 && width > 0 && height > 0;
465
+ const image = background ? {
466
+ ...background.image,
467
+ ...sized ? {
468
+ naturalWidth: width,
469
+ naturalHeight: height
470
+ } : {}
471
+ } : null;
472
+ const rawAlign = value("vertical-align");
473
+ const verticalAlign = HERO_ALIGNS.find((align) => align === rawAlign?.toLowerCase()) ?? "top";
474
+ if (rawAlign && verticalAlign !== rawAlign.toLowerCase()) notes.push(`${label} vertical-align "${rawAlign}" has no Templatical equivalent; imported as "top".`);
475
+ const rawMode = value("mode");
476
+ const mode = rawMode ? rawMode.toLowerCase() : "fixed-height";
477
+ let hero = null;
478
+ if (mode === "fluid-height") {
479
+ hero = {
480
+ height: "image",
481
+ verticalAlign
482
+ };
483
+ if (!sized) notes.push(`${label} fluid-height has no background-width / background-height, so its image size is unknown; it renders as a regular section until it has a size or a fixed height.`);
484
+ } else {
485
+ if (mode !== "fixed-height") notes.push(`${label} mode "${rawMode}" has no Templatical equivalent; imported as "fixed-height".`);
486
+ const fixed = parsePx(value("height"));
487
+ if (fixed !== void 0 && fixed > 0) hero = {
488
+ height: Math.round(fixed),
489
+ verticalAlign
490
+ };
491
+ }
492
+ if (hero && !image) notes.push(`${label} has no background-url, so it renders as a regular section until it has a background image.`);
493
+ for (const name of HERO_DROPPED_ATTRIBUTES) {
494
+ const raw = value(name);
495
+ if (raw === void 0) continue;
496
+ notes.push(`${label} ${name} "${raw}" has no Templatical equivalent; dropped.`);
497
+ }
498
+ return {
499
+ hero,
500
+ image,
501
+ notes
502
+ };
503
+ }
228
504
  //#endregion
229
505
  //#region src/rich-text.ts
230
506
  /** Escape `& < > "` for text content and attribute values. */
@@ -486,15 +762,46 @@ function convertImage(node, map) {
486
762
  const radius = parsePx(readAttr(node, "border-radius", map.resolve));
487
763
  const align = parseAlign(readAttr(node, "align", map.resolve));
488
764
  const target = setString(readAttr(node, "target", map.resolve));
765
+ const styles = leafStyles(node, map);
766
+ const { left, right } = styles.styles.padding;
767
+ const room = map.contentWidth === void 0 ? void 0 : map.contentWidth - left - right;
768
+ const notes = [];
769
+ const width = imageWidth(readAttr(node, "width", map.resolve), room, notes);
489
770
  return finish(createImageBlock({
490
771
  src,
491
772
  alt,
773
+ width,
492
774
  ...align ? { align } : {},
493
775
  ...radius !== void 0 && radius > 0 ? { borderRadius: radius } : {},
494
776
  ...linkUrl ? { linkUrl } : {},
495
777
  ...linkUrl && target === "_blank" ? { linkOpenInNewTab: true } : {},
496
- ...leafStyles(node, map)
497
- }), node, report("standard-image", "image", "converted"));
778
+ ...styles
779
+ }), node, notes.length > 0 ? report("standard-image", "image", "approximated", notes.join(" ")) : report("standard-image", "image", "converted"));
780
+ }
781
+ /**
782
+ * An image's `width` as `ImageBlock.width`. A missing, unreadable or `100%`
783
+ * width is `"full"`, MJML's default. A px width stays px until it fills `room`,
784
+ * the column less the image's own side padding, and then it is `"full"`. A
785
+ * percentage under 100% becomes px of `room` and pushes a note, since a px
786
+ * width keeps its size on a phone where a percentage shrinks with the column.
787
+ */
788
+ function imageWidth(value, room, notes) {
789
+ if (isUnset(value)) return "full";
790
+ if (typeof value === "string" && value.trim().endsWith("%")) {
791
+ const percent = parsePercent(value);
792
+ if (percent === null || percent <= 0 || percent >= 100) return "full";
793
+ if (room === void 0) {
794
+ notes.push(`Image width ${value.trim()} has no known column to resolve against; imported as full width.`);
795
+ return "full";
796
+ }
797
+ const px = Math.round(room * percent / 100);
798
+ if (px >= room) return "full";
799
+ notes.push(`Image width ${value.trim()} imported as ${px}px, which keeps its size on a phone.`);
800
+ return px;
801
+ }
802
+ const px = parsePx(value);
803
+ if (px === void 0 || px <= 0) return "full";
804
+ return room !== void 0 && px >= room ? "full" : px;
498
805
  }
499
806
  function convertDivider(node, map) {
500
807
  const color = parseColor(readAttr(node, "border-color", map.resolve));
@@ -1003,38 +1310,39 @@ function buildSection(node, map) {
1003
1310
  section.columns = layout;
1004
1311
  section.children = children;
1005
1312
  paintSection(section, node, map, { stackOnMobile: plan.grouped ? false : void 0 });
1313
+ const background = readMjmlBackgroundImage((name) => readAttr(node, name, map.resolve), "Section", map.contentWidth);
1314
+ if (background) {
1315
+ section.backgroundImage = background.image;
1316
+ reasons.push(...background.notes);
1317
+ }
1006
1318
  entries.unshift(sectionEntry(node, reasons.length > 0 ? "approximated" : "converted", reasons.length > 0 ? reasons.join(" ") : void 0));
1007
1319
  return {
1008
1320
  blocks: [section],
1009
1321
  entries
1010
1322
  };
1011
1323
  }
1324
+ /**
1325
+ * A `standard-hero` as a one-column section: its children walk into the one
1326
+ * column, and its mode, height and background map onto `hero` and
1327
+ * `backgroundImage` (`readMjmlHero`). Its fill follows `paintSection`; where
1328
+ * that finds none and the source leaves `background-color` out, it is
1329
+ * mj-hero's own white.
1330
+ */
1012
1331
  function buildHero(node, map) {
1013
- const slot = [];
1014
1332
  const entries = [];
1015
- const url = readAttr(node, "background-url", map.resolve);
1016
- if (typeof url === "string" && !isUnset(url)) {
1017
- slot.push(createImageBlock({ src: url }));
1018
- entries.push({
1019
- sourceTag: "standard-hero",
1020
- templaticalBlockType: "image",
1021
- status: "approximated",
1022
- note: "hero background-url stacked as a leading image (overlay is the loss)"
1023
- });
1024
- }
1025
1333
  const inner = convertFlow(node.children ?? [], withContentWidth(map, insideWidth(map.contentWidth, node, map)));
1026
- slot.push(...inner.blocks);
1027
1334
  for (const entry of inner.entries) entries.push(entry);
1028
1335
  const section = createSectionBlock();
1029
1336
  section.columns = "1";
1030
- section.children = [slot];
1337
+ section.children = [inner.blocks];
1031
1338
  paintSection(section, node, map);
1032
- entries.unshift({
1033
- sourceTag: "standard-hero",
1034
- templaticalBlockType: "section",
1035
- status: "approximated",
1036
- note: "standard-hero overlay is stacked as a 1-column section; background-url becomes a leading image."
1037
- });
1339
+ const ownFill = readAttr(node, "background-color", map.resolve);
1340
+ const fillAbsent = ownFill === void 0 || ownFill === null || typeof ownFill === "string" && ownFill.trim() === "";
1341
+ if (!section.styles.backgroundColor && fillAbsent) section.styles.backgroundColor = "#ffffff";
1342
+ const read = readMjmlHero((name) => readAttr(node, name, map.resolve), "Hero", map.contentWidth);
1343
+ if (read.image) section.backgroundImage = read.image;
1344
+ if (read.hero) section.hero = read.hero;
1345
+ entries.unshift(sectionEntry(node, read.notes.length > 0 ? "approximated" : "converted", read.notes.length > 0 ? read.notes.join(" ") : void 0));
1038
1346
  return {
1039
1347
  blocks: [section],
1040
1348
  entries
@@ -1068,13 +1376,21 @@ function buildWrapper(node, map) {
1068
1376
  /**
1069
1377
  * Paint `node`'s `mj-wrapper` band onto every section in `blocks`. A section
1070
1378
  * holds one band, so a band around several sections is copied onto each and
1071
- * their `converted` entries become `approximated`.
1379
+ * their `converted` entries become `approximated`. A band image value with no
1380
+ * exact keyword is noted on every section entry, or on one entry of the
1381
+ * band's own when its sections (bare leaves) have none.
1072
1382
  */
1073
1383
  function applyWrapper(node, blocks, entries, map) {
1074
1384
  const sections = blocks.filter(isSection);
1075
1385
  if (sections.length === 0) return;
1076
- const wrapper = readWrapper(node, map);
1077
- for (const section of sections) section.wrapper = { ...wrapper };
1386
+ const { wrapper, notes } = readWrapper(node, map);
1387
+ for (const section of sections) section.wrapper = {
1388
+ ...wrapper,
1389
+ ...wrapper.backgroundImage ? { backgroundImage: {
1390
+ ...wrapper.backgroundImage,
1391
+ position: { ...wrapper.backgroundImage.position }
1392
+ } } : {}
1393
+ };
1078
1394
  if (sections.length > 1) {
1079
1395
  const note = `${node.type ?? "standard-wrapper"} holding ${sections.length} sections was applied to each of them — Templatical has no multi-section band.`;
1080
1396
  for (const entry of entries) {
@@ -1084,6 +1400,19 @@ function applyWrapper(node, blocks, entries, map) {
1084
1400
  entry.note = note;
1085
1401
  }
1086
1402
  }
1403
+ if (notes.length > 0) {
1404
+ const sectionEntries = entries.filter((entry) => entry.templaticalBlockType === "section");
1405
+ if (sectionEntries.length === 0) entries.push({
1406
+ sourceTag: node.type ?? "standard-wrapper",
1407
+ templaticalBlockType: "section",
1408
+ status: "approximated",
1409
+ note: notes.join(" ")
1410
+ });
1411
+ for (const entry of sectionEntries) {
1412
+ entry.status = "approximated";
1413
+ entry.note = [entry.note, ...notes].filter(Boolean).join(" ");
1414
+ }
1415
+ }
1087
1416
  }
1088
1417
  /** `width` less `node`'s own left and right padding; unknown stays unknown. */
1089
1418
  function insideWidth(width, node, map) {
@@ -1201,10 +1530,15 @@ function readWrapper(node, map) {
1201
1530
  const backgroundColor = parseColor(readAttr(node, "background-color", map.resolve));
1202
1531
  const padding = readPadding((key) => readAttr(node, key, map.resolve));
1203
1532
  const radius = parsePx(readAttr(node, "border-radius", map.resolve));
1533
+ const background = readMjmlBackgroundImage((name) => readAttr(node, name, map.resolve), "Wrapper", map.contentWidth);
1204
1534
  return {
1205
- ...backgroundColor ? { backgroundColor } : {},
1206
- padding,
1207
- ...radius !== void 0 && radius > 0 ? { borderRadius: radius } : {}
1535
+ wrapper: {
1536
+ ...backgroundColor ? { backgroundColor } : {},
1537
+ padding,
1538
+ ...radius !== void 0 && radius > 0 ? { borderRadius: radius } : {},
1539
+ ...background ? { backgroundImage: background.image } : {}
1540
+ },
1541
+ notes: background?.notes ?? []
1208
1542
  };
1209
1543
  }
1210
1544
  function sectionEntry(node, status, note) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["isPlainObject","empty","isElement","readVisibility","isElement"],"sources":["../src/normalize.ts","../src/attribute-parser.ts","../src/rich-text.ts","../src/block-mapper.ts","../src/column-layout.ts","../src/section-builder.ts","../src/converter.ts"],"sourcesContent":["import type {\n EasyEmailProDocument,\n EasyEmailProNode,\n EasyEmailProVariable,\n} from \"./types\";\n\nconst VAR_PREFIX = \"$var(\";\n\n/** Spec §3.3 category map — unknown types skip the category layer. */\nexport const CATEGORY_BY_TYPE: Record<string, string> = {\n \"standard-paragraph\": \"TEXT\",\n \"standard-text\": \"TEXT\",\n \"standard-h1\": \"TEXT\",\n \"standard-h2\": \"TEXT\",\n \"standard-h3\": \"TEXT\",\n \"standard-h4\": \"TEXT\",\n \"standard-button\": \"BUTTON\",\n \"standard-image\": \"IMAGE\",\n \"standard-navbar\": \"NAVBAR\",\n \"standard-navbar-link\": \"NAVBAR\",\n \"standard-social\": \"SOCIAL\",\n \"standard-social-element\": \"SOCIAL\",\n \"standard-spacer\": \"SPACER\",\n \"standard-divider\": \"DIVIDER\",\n \"standard-hero\": \"HERO\",\n \"standard-wrapper\": \"WRAPPER\",\n \"standard-section\": \"SECTION\",\n \"standard-column\": \"COLUMN\",\n \"standard-group\": \"GROUP\",\n};\n\nexport interface VarStats {\n resolved: number;\n unresolved: number;\n}\n\nexport interface ResolveContext {\n variables: Record<string, string>;\n blockAttributes: Record<string, Record<string, unknown>>;\n categoryAttributes: Record<string, Record<string, unknown>>;\n globalAttributes: Record<string, unknown>;\n /** Page node — section fill falls back to `content-background-color`. */\n page: EasyEmailProNode;\n stats: VarStats;\n /**\n * Per-node attribute cache so a repeated `readAttr` (button fill vs\n * outlined check, section fill fallback) does not double-count `$var`.\n */\n attrCache: WeakMap<EasyEmailProNode, Map<string, unknown>>;\n}\n\n/**\n * `null`, `\"\"`, `\"url()\"`, `\"transparent\"`, and leftover `$var(` after\n * substitution are unset. Presence-guards that treat these as set write\n * illegal empties.\n */\nexport function isUnset(value: unknown): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value !== \"string\") return false;\n const trimmed = value.trim();\n return (\n trimmed === \"\" ||\n trimmed === \"url()\" ||\n trimmed.toLowerCase() === \"transparent\" ||\n trimmed.includes(VAR_PREFIX)\n );\n}\n\n/** Index `data.variables[]` by name for `$var` lookup. */\nexport function buildVariableTable(\n variables: EasyEmailProVariable[] | undefined,\n): Record<string, string> {\n const out: Record<string, string> = {};\n if (!variables) return out;\n for (const entry of variables) {\n if (typeof entry.name !== \"string\" || entry.name === \"\") continue;\n if (typeof entry.value !== \"string\") continue;\n out[entry.name] = entry.value;\n }\n return out;\n}\n\n/**\n * Replace `$var(name)` tokens via a linear scan (no regex — CodeQL\n * `js/polynomial-redos`). Unknown names are left in place and flagged.\n */\nexport function substituteVars(\n value: string,\n variables: Record<string, string>,\n): { value: string; resolved: number; unresolved: number } {\n let out = \"\";\n let i = 0;\n let resolved = 0;\n let unresolved = 0;\n\n while (i < value.length) {\n const start = value.indexOf(VAR_PREFIX, i);\n if (start === -1) {\n out += value.slice(i);\n break;\n }\n out += value.slice(i, start);\n const nameStart = start + VAR_PREFIX.length;\n const nameEnd = findMatchingParen(value, nameStart);\n if (nameEnd === -1) {\n // Unclosed `$var(` — keep the rest verbatim and mark unresolved.\n out += value.slice(start);\n unresolved += 1;\n break;\n }\n const name = value.slice(nameStart, nameEnd);\n if (Object.prototype.hasOwnProperty.call(variables, name)) {\n out += variables[name];\n resolved += 1;\n } else {\n out += value.slice(start, nameEnd + 1);\n unresolved += 1;\n }\n i = nameEnd + 1;\n }\n\n return { value: out, resolved, unresolved };\n}\n\n/** Walk from `openIdx` (char after `(`) to the matching `)`. */\nfunction findMatchingParen(value: string, openIdx: number): number {\n let depth = 1;\n for (let i = openIdx; i < value.length; i++) {\n const ch = value[i];\n if (ch === \"(\") depth += 1;\n else if (ch === \")\") {\n depth -= 1;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\nexport function contextFromPage(page: EasyEmailProNode): ResolveContext {\n const data = isPlainObject(page.data) ? page.data : {};\n return {\n variables: buildVariableTable(\n Array.isArray(data.variables)\n ? (data.variables as EasyEmailProVariable[])\n : undefined,\n ),\n blockAttributes: asNestedAttrMap(data.blockAttributes),\n categoryAttributes: asNestedAttrMap(data.categoryAttributes),\n globalAttributes: asAttrMap(data.globalAttributes),\n page,\n stats: { resolved: 0, unresolved: 0 },\n attrCache: new WeakMap(),\n };\n}\n\n/** Widget `data.input` overrides page variables for `$var` resolution. */\nexport function withWidgetInput(\n ctx: ResolveContext,\n input: Record<string, unknown> | undefined,\n): ResolveContext {\n if (!input) return ctx;\n const variables = { ...ctx.variables };\n for (const [key, value] of Object.entries(input)) {\n if (typeof value === \"string\") variables[key] = value;\n }\n // New cache: widget `data.input` can resolve the same node keys differently.\n return { ...ctx, variables, attrCache: new WeakMap() };\n}\n\n/**\n * Cascade: element → blockAttributes[type] → categoryAttributes[cat] →\n * globalAttributes. Missing keys fall through. String hits run through\n * `substituteVars`. Keys stay kebab-case MJML.\n */\nexport function readAttr(\n node: EasyEmailProNode,\n key: string,\n ctx: ResolveContext,\n): unknown {\n let cached = ctx.attrCache.get(node);\n if (cached?.has(key)) return cached.get(key);\n\n const raw = lookupAttr(node, key, ctx);\n let value: unknown = raw;\n if (typeof raw === \"string\") {\n const result = substituteVars(raw, ctx.variables);\n ctx.stats.resolved += result.resolved;\n ctx.stats.unresolved += result.unresolved;\n value = result.value;\n }\n\n if (!cached) {\n cached = new Map();\n ctx.attrCache.set(node, cached);\n }\n cached.set(key, value);\n return value;\n}\n\nfunction lookupAttr(\n node: EasyEmailProNode,\n key: string,\n ctx: ResolveContext,\n): unknown {\n const fromElement = node.attributes?.[key];\n if (fromElement !== undefined) return fromElement;\n\n if (typeof node.type === \"string\") {\n const fromBlock = ctx.blockAttributes[node.type]?.[key];\n if (fromBlock !== undefined) return fromBlock;\n\n const category = CATEGORY_BY_TYPE[node.type];\n if (category) {\n const fromCategory = ctx.categoryAttributes[category]?.[key];\n if (fromCategory !== undefined) return fromCategory;\n }\n }\n\n return ctx.globalAttributes[key];\n}\n\n/**\n * Envelope unwrap. Never throws — the converter owns invalid-shape errors.\n * Returns `{ page, subject }` when a page is visible; caller checks\n * `page.type === \"page\"`.\n */\nexport function unwrapDocument(root: unknown): {\n page: EasyEmailProNode;\n subject?: string;\n} {\n if (!isPlainObject(root)) {\n return { page: {} };\n }\n\n if (root.type === \"page\") {\n return { page: root as EasyEmailProNode };\n }\n\n const doc = root as EasyEmailProDocument;\n const page = isPlainObject(doc.content)\n ? (doc.content as EasyEmailProNode)\n : (root as EasyEmailProNode);\n const subject = typeof doc.subject === \"string\" ? doc.subject : undefined;\n return subject === undefined ? { page } : { page, subject };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asAttrMap(value: unknown): Record<string, unknown> {\n return isPlainObject(value) ? value : {};\n}\n\nfunction asNestedAttrMap(\n value: unknown,\n): Record<string, Record<string, unknown>> {\n if (!isPlainObject(value)) return {};\n const out: Record<string, Record<string, unknown>> = {};\n for (const [key, entry] of Object.entries(value)) {\n if (isPlainObject(entry)) out[key] = entry;\n }\n return out;\n}\n","import { isUnset } from \"./normalize\";\n\n/** Strip a trailing `px` (case-insensitive) and coerce to number. Unset/NaN → undefined. */\nexport function parsePx(value: unknown): number | undefined {\n if (isUnset(value)) return undefined;\n let raw = String(value).trim();\n if (raw.toLowerCase().endsWith(\"px\")) raw = raw.slice(0, -2).trimEnd();\n const n = Number(raw);\n return Number.isNaN(n) ? undefined : n;\n}\n\n/**\n * Strip a trailing `%` and coerce to number. Unset/NaN → `null` so\n * `matchColumnLayout` can tell \"missing width\" from `0%`.\n */\nexport function parsePercent(value: unknown): number | null {\n if (isUnset(value)) return null;\n let raw = String(value).trim();\n if (raw.endsWith(\"%\")) raw = raw.slice(0, -1).trimEnd();\n const n = Number(raw);\n return Number.isNaN(n) ? null : n;\n}\n\n/** Return the colour string as-is when set. No named-colour expansion. */\nexport function parseColor(value: unknown): string | undefined {\n if (isUnset(value)) return undefined;\n if (typeof value !== \"string\") return undefined;\n return value;\n}\n\n/** Read the four padding sides via a callback (typically wrapping `readAttr`). Missing → 0. */\nexport function readPadding(read: (key: string) => unknown): {\n top: number;\n right: number;\n bottom: number;\n left: number;\n} {\n const side = (key: string) => parsePx(read(key)) ?? 0;\n return {\n top: side(\"padding-top\"),\n right: side(\"padding-right\"),\n bottom: side(\"padding-bottom\"),\n left: side(\"padding-left\"),\n };\n}\n","import type { EasyEmailProNode, EasyEmailProTextNode } from \"./types\";\n\n/** Escape `& < > \"` for text content and attribute values. */\nfunction escapeHtml(value: string): string {\n let out = \"\";\n for (let i = 0; i < value.length; i++) {\n const ch = value[i]!;\n if (ch === \"&\") out += \"&amp;\";\n else if (ch === \"<\") out += \"&lt;\";\n else if (ch === \">\") out += \"&gt;\";\n else if (ch === '\"') out += \"&quot;\";\n else out += ch;\n }\n return out;\n}\n\nfunction isTextNode(\n node: EasyEmailProNode | EasyEmailProTextNode,\n): node is EasyEmailProTextNode {\n return typeof (node as EasyEmailProTextNode).text === \"string\";\n}\n\n/**\n * Nesting (outer → inner): link → color/bgColor span → underline → strike →\n * em → strong. Matches the Task 4 brief / design §8.1 mark order.\n */\nfunction serialiseTextNode(node: EasyEmailProTextNode): string {\n let html = escapeHtml(node.text);\n\n if (node.bold) html = `<strong>${html}</strong>`;\n if (node.italic) html = `<em>${html}</em>`;\n if (node.strikethrough) html = `<s>${html}</s>`;\n if (node.underline) html = `<u>${html}</u>`;\n\n const styles: string[] = [];\n if (typeof node.color === \"string\" && node.color !== \"\") {\n styles.push(`color: ${escapeHtml(node.color)}`);\n }\n if (typeof node.bgColor === \"string\" && node.bgColor !== \"\") {\n styles.push(`background-color: ${escapeHtml(node.bgColor)}`);\n }\n if (styles.length > 0) {\n html = `<span style=\"${styles.join(\"; \")}\">${html}</span>`;\n }\n\n if (node.link) {\n const href = escapeHtml(node.link.href ?? \"\");\n const blank = node.link.blank === true ? ' target=\"_blank\"' : \"\";\n html = `<a href=\"${href}\"${blank}>${html}</a>`;\n }\n\n return html;\n}\n\n/** Easy Email Pro's `HTML_NODE_VOID_TAGS`: rendered `<tag />`, children ignored. */\nconst VOID_TAGS = new Set([\n \"img\",\n \"br\",\n \"hr\",\n \"area\",\n \"base\",\n \"col\",\n \"embed\",\n \"input\",\n \"link\",\n \"meta\",\n \"source\",\n]);\n\nconst TAG_NAME = /^[a-z][a-z0-9-]*$/;\nconst ATTRIBUTE_NAME = /^[a-z_:][a-z0-9_:.-]*$/i;\n\n/**\n * An inline `html-node` renders as `<tagName attrs>children</tagName>`. Only\n * non-empty string attributes are written, as Easy Email Pro does. A tag or\n * attribute name that could break out of the markup is dropped, the tag\n * falling back to `span`.\n */\nfunction serialiseHtmlNode(node: EasyEmailProNode): string {\n const rawTag = node.data?.[\"tagName\"];\n const lowered = typeof rawTag === \"string\" ? rawTag.toLowerCase() : \"\";\n const tagName = TAG_NAME.test(lowered) ? lowered : \"span\";\n\n let attrs = \"\";\n for (const [name, value] of Object.entries(node.attributes ?? {})) {\n if (typeof value !== \"string\" || !ATTRIBUTE_NAME.test(name)) continue;\n const trimmed = value.trim();\n if (trimmed === \"\") continue;\n attrs += ` ${name}=\"${escapeHtml(trimmed)}\"`;\n }\n\n if (VOID_TAGS.has(tagName)) return `<${tagName}${attrs} />`;\n return `<${tagName}${attrs}>${serialiseChildren(node.children)}</${tagName}>`;\n}\n\n/**\n * Easy Email Pro renders a `mergetag` as `{{ name }}`, the name being its\n * first text child and the marks on that child applying to the token.\n * `data.default` is not part of that output. A blank name has no variable to\n * keep.\n */\nfunction serialiseMergetag(node: EasyEmailProNode): string {\n const first = node.children?.[0];\n if (!first || !isTextNode(first)) return \"\";\n const name = first.text.trim();\n if (name === \"\") return \"\";\n return serialiseTextNode({ ...first, text: `{{ ${name} }}` });\n}\n\nfunction serialiseNode(node: EasyEmailProNode | EasyEmailProTextNode): string {\n if (node.type === \"line-break\") return \"<br>\";\n\n if (node.type === \"html-block-node\") {\n const element = node as EasyEmailProNode;\n const rawTag = element.data?.[\"tagName\"];\n const tagName =\n typeof rawTag === \"string\" && rawTag !== \"\" ? rawTag : \"div\";\n const inner = serialiseChildren(element.children);\n return `<${tagName}>${inner}</${tagName}>`;\n }\n\n if (node.type === \"html-node\") {\n return serialiseHtmlNode(node as EasyEmailProNode);\n }\n\n if (node.type === \"mergetag\")\n return serialiseMergetag(node as EasyEmailProNode);\n\n // Any other typed element has no inline rendering here and is dropped.\n if (typeof node.type === \"string\" && node.type !== \"\") return \"\";\n\n if (isTextNode(node)) return serialiseTextNode(node);\n\n return \"\";\n}\n\n/** Slate children → HTML for TitleBlock / ParagraphBlock content. */\nexport function serialiseChildren(\n children: Array<EasyEmailProNode | EasyEmailProTextNode> | undefined,\n): string {\n if (!children || children.length === 0) return \"\";\n let out = \"\";\n for (const child of children) {\n out += serialiseNode(child);\n }\n return out;\n}\n","import {\n createButtonBlock,\n createDividerBlock,\n createHtmlBlock,\n createImageBlock,\n createMenuBlock,\n createParagraphBlock,\n createSocialIconsBlock,\n createSpacerBlock,\n createTableBlock,\n createTitleBlock,\n createVideoBlock,\n findOpenTagEnd,\n generateId,\n} from \"@templatical/types\";\nimport type {\n Block,\n BlockStyles,\n BlockVisibility,\n ButtonBlock,\n DividerBlock,\n HeadingLevel,\n MenuItemData,\n SocialIcon,\n SocialPlatform,\n TableCellData,\n TableRowData,\n} from \"@templatical/types\";\nimport {\n parseColor,\n parsePercent,\n parsePx,\n readPadding,\n} from \"./attribute-parser\";\nimport { isUnset, readAttr, type ResolveContext } from \"./normalize\";\nimport { serialiseChildren } from \"./rich-text\";\nimport type {\n ConversionStatus,\n EasyEmailProNode,\n EasyEmailProTextNode,\n ImportReportEntry,\n} from \"./types\";\n\nexport interface MapContext {\n resolve: ResolveContext;\n warnings: string[];\n /**\n * Width in px of the box the current node lays out in: the page, the inside\n * of a wrapper, band or hero, or a column's content box. Absent where the\n * converter cannot tell, and then no width is judged against it.\n */\n contentWidth?: number;\n}\n\nexport interface Converted {\n blocks: Block[];\n entries: ImportReportEntry[];\n}\n\nconst LEAF_TYPES = new Set([\n \"standard-paragraph\",\n \"standard-text\",\n \"standard-h1\",\n \"standard-h2\",\n \"standard-h3\",\n \"standard-h4\",\n \"standard-button\",\n \"standard-image\",\n \"standard-divider\",\n \"standard-spacer\",\n \"standard-navbar\",\n \"standard-social\",\n \"standard-table2\",\n \"marketing-countdown\",\n \"placeholder\",\n \"common-video\",\n \"raw\",\n]);\n\nconst SOCIAL_PLATFORMS = [\n \"facebook\",\n \"instagram\",\n \"twitter\",\n \"linkedin\",\n \"youtube\",\n \"tiktok\",\n \"pinterest\",\n \"whatsapp\",\n \"telegram\",\n \"github\",\n] as const satisfies ReadonlyArray<SocialPlatform>;\n\nconst ENTITIES: Record<string, string> = {\n \"&amp;\": \"&\",\n \"&lt;\": \"<\",\n \"&gt;\": \">\",\n \"&quot;\": '\"',\n \"&#39;\": \"'\",\n \"&apos;\": \"'\",\n \"&nbsp;\": \" \",\n};\n\n/**\n * Easy Email Pro writes `standard-table2-tr` / `standard-table2-td`; the plain\n * `tr` / `td` / `th` shape is read too.\n */\nconst TABLE_CELL_TYPES = new Set([\"standard-table2-td\", \"td\", \"th\"]);\n\nconst COUNTDOWN_NOTE =\n \"marketing-countdown GIF is the timer; Templatical countdown is Cloud-only\";\n\nexport function isLeafType(type: string | undefined): boolean {\n if (typeof type !== \"string\") return false;\n if (LEAF_TYPES.has(type)) return true;\n return headingLevelFromType(type) !== null;\n}\n\nexport function convertLeaf(\n node: EasyEmailProNode,\n map: MapContext,\n): Converted {\n const type = node.type;\n if (type === \"placeholder\") return empty();\n if (type === \"standard-paragraph\" || type === \"standard-text\") {\n return convertParagraph(node, map);\n }\n\n const heading = typeof type === \"string\" ? headingLevelFromType(type) : null;\n if (heading) return convertHeading(node, map, heading);\n\n switch (type) {\n case \"standard-button\":\n return convertButton(node, map);\n case \"standard-image\":\n return convertImage(node, map);\n case \"standard-divider\":\n return convertDivider(node, map);\n case \"standard-spacer\":\n return convertSpacer(node, map);\n case \"standard-navbar\":\n return convertNavbar(node, map);\n case \"standard-social\":\n return convertSocial(node, map);\n case \"standard-table2\":\n return convertTable(node, map);\n case \"marketing-countdown\":\n return convertCountdown(node, map);\n case \"common-video\":\n return convertVideo(node, map);\n case \"raw\":\n return convertRaw(node, map);\n default:\n return convertUnknown(node, map);\n }\n}\n\n/**\n * `standard-text` (the default text block) and `standard-paragraph` share one\n * shape and one MJML renderer, so both land here.\n */\nfunction convertParagraph(node: EasyEmailProNode, map: MapContext): Converted {\n return finish(\n createParagraphBlock({\n content: paragraphHtml(node, map),\n ...leafStyles(node, map),\n }),\n node,\n report(node.type ?? \"standard-paragraph\", \"paragraph\", \"converted\"),\n );\n}\n\n/**\n * ParagraphBlock has no color / fontSize / textAlign. Bake the cascaded\n * values into a wrapping `<p style>` (single wrapper, Unlayer/BeeFree class).\n */\nfunction paragraphHtml(node: EasyEmailProNode, map: MapContext): string {\n const html = serialiseChildren(node.children);\n const parts: string[] = [];\n const color = parseColor(readAttr(node, \"color\", map.resolve));\n if (color) parts.push(`color: ${escapeAttr(color)}`);\n const fontSize = setString(readAttr(node, \"font-size\", map.resolve));\n if (fontSize) parts.push(`font-size: ${escapeAttr(fontSize)}`);\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n if (align) parts.push(`text-align: ${align}`);\n if (parts.length === 0) return html;\n return `<p style=\"${parts.join(\"; \")}\">${html}</p>`;\n}\n\nfunction escapeAttr(value: string): string {\n let out = \"\";\n for (let i = 0; i < value.length; i++) {\n const ch = value[i];\n if (ch === \"&\") out += \"&amp;\";\n else if (ch === \"<\") out += \"&lt;\";\n else if (ch === \">\") out += \"&gt;\";\n else if (ch === '\"') out += \"&quot;\";\n else out += ch;\n }\n return out;\n}\n\nfunction convertHeading(\n node: EasyEmailProNode,\n map: MapContext,\n heading: { level: HeadingLevel; source: number },\n): Converted {\n const color = parseColor(readAttr(node, \"color\", map.resolve));\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n const clamped = heading.source > 4;\n return finish(\n createTitleBlock({\n content: serialiseChildren(node.children),\n level: heading.level,\n ...(color ? { color } : {}),\n ...(align ? { textAlign: align } : {}),\n ...leafStyles(node, map),\n }),\n node,\n clamped\n ? report(\n node.type ?? \"standard-h4\",\n \"title\",\n \"approximated\",\n `Heading level h${heading.source} clamped to 4 — Templatical titles support h1-h4.`,\n )\n : report(node.type ?? \"standard-h1\", \"title\", \"converted\"),\n );\n}\n\nfunction convertButton(node: EasyEmailProNode, map: MapContext): Converted {\n const fill = parseColor(readAttr(node, \"background-color\", map.resolve));\n const textColor = parseColor(readAttr(node, \"color\", map.resolve));\n const href = readAttr(node, \"href\", map.resolve);\n const width = buttonWidth(readAttr(node, \"width\", map.resolve));\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n const outlined =\n isBorderEnabled(readAttr(node, \"border-enabled\", map.resolve)) &&\n isUnset(readAttr(node, \"background-color\", map.resolve));\n\n const block: ButtonBlock = createButtonBlock({\n text: stripTags(serialiseChildren(node.children)),\n url: setString(href) ?? \"\",\n ...(fill ? { backgroundColor: fill } : {}),\n ...(textColor ? { textColor } : {}),\n ...(width !== undefined ? { width } : {}),\n ...(align ? { align } : {}),\n ...leafStyles(node, map),\n });\n // createButtonBlock defaults fill to #333333; an unset Pro fill with\n // border-enabled is an outlined button, which has no Templatical equivalent.\n if (outlined) block.backgroundColor = \"#ffffff\";\n\n return finish(\n block,\n node,\n outlined\n ? report(\n \"standard-button\",\n \"button\",\n \"approximated\",\n \"outlined button has no Templatical equivalent\",\n )\n : report(\"standard-button\", \"button\", \"converted\"),\n );\n}\n\nfunction convertImage(node: EasyEmailProNode, map: MapContext): Converted {\n const src = setString(readAttr(node, \"src\", map.resolve)) ?? \"\";\n const alt = setString(readAttr(node, \"alt\", map.resolve)) ?? \"\";\n const href = readAttr(node, \"href\", map.resolve);\n const linkUrl = setString(href);\n const radius = parsePx(readAttr(node, \"border-radius\", map.resolve));\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n const target = setString(readAttr(node, \"target\", map.resolve));\n\n return finish(\n createImageBlock({\n src,\n alt,\n ...(align ? { align } : {}),\n ...(radius !== undefined && radius > 0 ? { borderRadius: radius } : {}),\n ...(linkUrl ? { linkUrl } : {}),\n ...(linkUrl && target === \"_blank\" ? { linkOpenInNewTab: true } : {}),\n ...leafStyles(node, map),\n }),\n node,\n report(\"standard-image\", \"image\", \"converted\"),\n );\n}\n\nfunction convertDivider(node: EasyEmailProNode, map: MapContext): Converted {\n const color = parseColor(readAttr(node, \"border-color\", map.resolve));\n const thickness = parsePx(readAttr(node, \"border-width\", map.resolve));\n const lineStyle = asLineStyle(readAttr(node, \"border-style\", map.resolve));\n const styles = leafStyles(node, map);\n const { left, right } = styles.styles.padding;\n const room =\n map.contentWidth === undefined\n ? undefined\n : map.contentWidth - left - right;\n return finish(\n createDividerBlock({\n ...(color ? { color } : {}),\n ...(thickness !== undefined ? { thickness } : {}),\n ...(lineStyle ? { lineStyle } : {}),\n width: dividerWidth(readAttr(node, \"width\", map.resolve), room),\n ...styles,\n }),\n node,\n report(\"standard-divider\", \"divider\", \"converted\"),\n );\n}\n\n/**\n * A missing or `100%` width is `\"full\"`. Any other percentage stays a share of\n * the column, clamped to 0-100 and rounded to two decimals so it stays a\n * `DividerPercentWidth`. A px width stays px until it fills `room`, the space\n * the column leaves the line once the divider's own padding is off, and then\n * it is `\"full\"`. An unreadable width falls back to `\"full\"`, MJML's default.\n */\nfunction dividerWidth(\n value: unknown,\n room: number | undefined,\n): DividerBlock[\"width\"] {\n if (isUnset(value)) return \"full\";\n if (typeof value === \"string\" && value.trim().endsWith(\"%\")) {\n const percent = parsePercent(value);\n if (percent === null) return \"full\";\n const clamped = Math.min(100, Math.max(0, percent));\n const rounded = Math.round(clamped * 100) / 100;\n return rounded >= 100 ? \"full\" : `${rounded}%`;\n }\n const px = parsePx(value);\n if (px === undefined) return \"full\";\n return room !== undefined && px >= room ? \"full\" : px;\n}\n\nfunction convertSpacer(node: EasyEmailProNode, map: MapContext): Converted {\n const height = parsePx(readAttr(node, \"height\", map.resolve));\n return finish(\n createSpacerBlock({\n ...(height !== undefined ? { height } : {}),\n ...leafStyles(node, map),\n }),\n node,\n report(\"standard-spacer\", \"spacer\", \"converted\"),\n );\n}\n\nfunction convertNavbar(node: EasyEmailProNode, map: MapContext): Converted {\n const items: MenuItemData[] = [];\n for (const child of node.children ?? []) {\n if (!isElement(child) || child.type !== \"standard-navbar-link\") continue;\n const href = readAttr(child, \"href\", map.resolve);\n const target = setString(readAttr(child, \"target\", map.resolve));\n const color = parseColor(readAttr(child, \"color\", map.resolve));\n const weight = setString(readAttr(child, \"font-weight\", map.resolve));\n const deco = setString(readAttr(child, \"text-decoration\", map.resolve));\n items.push({\n id: generateId(),\n text: stripTags(serialiseChildren(child.children)),\n url: setString(href) ?? \"\",\n openInNewTab: target === \"_blank\",\n bold: weight === \"bold\" || weight === \"700\",\n underline: deco !== undefined && deco.includes(\"underline\"),\n ...(color ? { color } : {}),\n });\n }\n if (items.length === 0) return empty();\n\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n return finish(\n createMenuBlock({\n items,\n ...(align ? { textAlign: align } : {}),\n ...leafStyles(node, map),\n }),\n node,\n report(\"standard-navbar\", \"menu\", \"converted\"),\n );\n}\n\nfunction convertSocial(node: EasyEmailProNode, map: MapContext): Converted {\n const icons: SocialIcon[] = [];\n let customSrc = false;\n for (const child of node.children ?? []) {\n if (!isElement(child) || child.type !== \"standard-social-element\") continue;\n const href = readAttr(child, \"href\", map.resolve);\n const src = readAttr(child, \"src\", map.resolve);\n if (typeof src === \"string\" && !isUnset(src)) customSrc = true;\n icons.push({\n id: generateId(),\n platform: inferPlatform(href, src),\n url: setString(href) ?? \"\",\n });\n }\n if (icons.length === 0) return empty();\n\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n return finish(\n createSocialIconsBlock({\n icons,\n ...(align ? { align } : {}),\n ...leafStyles(node, map),\n }),\n node,\n customSrc\n ? report(\n \"standard-social\",\n \"social\",\n \"approximated\",\n \"custom src was present; SocialIconsBlock has no custom PNG\",\n )\n : report(\"standard-social\", \"social\", \"converted\"),\n );\n}\n\nfunction convertTable(node: EasyEmailProNode, map: MapContext): Converted {\n const rows: TableRowData[] = [];\n let hasHeaderRow = false;\n let first = true;\n for (const row of collectRows(node)) {\n const cells: TableCellData[] = [];\n let rowHasTh = false;\n for (const cell of row.children ?? []) {\n if (!isElement(cell) || !TABLE_CELL_TYPES.has(cell.type ?? \"\")) continue;\n if (cell.type === \"th\") rowHasTh = true;\n cells.push({\n id: generateId(),\n content: serialiseChildren(cell.children),\n });\n }\n if (cells.length === 0) continue;\n if (first) {\n hasHeaderRow = rowHasTh;\n first = false;\n }\n rows.push({ id: generateId(), cells });\n }\n if (rows.length === 0) return empty();\n\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n const color = parseColor(readAttr(node, \"color\", map.resolve));\n return finish(\n createTableBlock({\n rows,\n hasHeaderRow,\n ...(align ? { textAlign: align } : {}),\n ...(color ? { color } : {}),\n ...leafStyles(node, map),\n }),\n node,\n report(\"standard-table2\", \"table\", \"converted\"),\n );\n}\n\nfunction convertCountdown(node: EasyEmailProNode, map: MapContext): Converted {\n const blocks: Block[] = [];\n const entries: ImportReportEntry[] = [];\n\n for (const child of node.children ?? []) {\n if (!isElement(child)) continue;\n const remapped = remapOverlay(child);\n if (!remapped) continue;\n const inner = convertLeaf(remapped, map);\n for (const block of inner.blocks) blocks.push(block);\n for (const entry of inner.entries) {\n entries.push({\n sourceTag: \"marketing-countdown\",\n templaticalBlockType: entry.templaticalBlockType,\n status: \"approximated\",\n note: entry.note ? `${entry.note} marketing-countdown` : COUNTDOWN_NOTE,\n });\n }\n }\n\n const src = readAttr(node, \"src\", map.resolve);\n if (typeof src === \"string\" && !isUnset(src)) {\n const image = createImageBlock({\n src,\n ...leafStyles(node, map),\n });\n const visibility = readVisibility(node);\n if (visibility) image.visibility = visibility;\n blocks.push(image);\n entries.push({\n sourceTag: \"marketing-countdown\",\n templaticalBlockType: \"image\",\n status: \"approximated\",\n note: COUNTDOWN_NOTE,\n });\n }\n\n return { blocks, entries };\n}\n\nfunction convertVideo(node: EasyEmailProNode, map: MapContext): Converted {\n const url = firstUrl(node, map);\n if (!url) return convertUnknown(node, map);\n return finish(\n createVideoBlock({\n url,\n ...leafStyles(node, map),\n }),\n node,\n report(\"common-video\", \"video\", \"converted\"),\n );\n}\n\n/** `raw` is `<mj-raw>{data.content}</mj-raw>`: the markup moves across as is. */\nfunction convertRaw(node: EasyEmailProNode, map: MapContext): Converted {\n const content = node.data?.[\"content\"];\n if (typeof content !== \"string\") return convertUnknown(node, map);\n return finish(\n createHtmlBlock({\n content,\n ...leafStyles(node, map),\n }),\n node,\n report(\"raw\", \"html\", \"converted\"),\n );\n}\n\nfunction convertUnknown(node: EasyEmailProNode, map: MapContext): Converted {\n const sourceTag = node.type ?? \"unknown\";\n return finish(\n createHtmlBlock({\n content: JSON.stringify(node),\n ...leafStyles(node, map),\n }),\n node,\n report(\n sourceTag,\n \"html\",\n \"html-fallback\",\n `Unknown Easy Email Pro type \"${sourceTag}\"; preserved as HTML.`,\n ),\n );\n}\n\nfunction remapOverlay(child: EasyEmailProNode): EasyEmailProNode | null {\n if (child.type === \"text\") {\n return { ...child, type: \"standard-paragraph\" };\n }\n if (child.type === \"standard-paragraph\" || child.type === \"standard-text\") {\n return child;\n }\n if (typeof child.type === \"string\" && headingLevelFromType(child.type)) {\n return child;\n }\n return null;\n}\n\nfunction collectRows(node: EasyEmailProNode): EasyEmailProNode[] {\n const rows: EasyEmailProNode[] = [];\n for (const child of node.children ?? []) {\n if (!isElement(child)) continue;\n if (isTableRow(child)) {\n rows.push(child);\n continue;\n }\n for (const inner of child.children ?? []) {\n if (isElement(inner) && isTableRow(inner)) rows.push(inner);\n }\n }\n return rows;\n}\n\nfunction isTableRow(node: EasyEmailProNode): boolean {\n return node.type === \"standard-table2-tr\" || node.type === \"tr\";\n}\n\nfunction firstUrl(node: EasyEmailProNode, map: MapContext): string | undefined {\n for (const key of [\"src\", \"href\", \"url\"] as const) {\n const value = readAttr(node, key, map.resolve);\n if (typeof value === \"string\" && !isUnset(value)) return value;\n }\n return undefined;\n}\n\nfunction inferPlatform(href: unknown, src: unknown): SocialPlatform {\n const host = hostname(typeof href === \"string\" ? href : \"\");\n for (const platform of SOCIAL_PLATFORMS) {\n if (host.includes(platform)) return platform;\n }\n const path = pathOf(typeof src === \"string\" ? src : \"\");\n for (const platform of SOCIAL_PLATFORMS) {\n if (path.includes(platform)) return platform;\n }\n return \"website\";\n}\n\nfunction hostname(href: string): string {\n const lower = href.toLowerCase();\n const scheme = lower.indexOf(\"://\");\n const rest = scheme === -1 ? lower : lower.slice(scheme + 3);\n const slash = rest.indexOf(\"/\");\n const hostport = slash === -1 ? rest : rest.slice(0, slash);\n const colon = hostport.indexOf(\":\");\n return colon === -1 ? hostport : hostport.slice(0, colon);\n}\n\nfunction pathOf(src: string): string {\n const lower = src.toLowerCase();\n const scheme = lower.indexOf(\"://\");\n const rest = scheme === -1 ? lower : lower.slice(scheme + 3);\n const slash = rest.indexOf(\"/\");\n return slash === -1 ? rest : rest.slice(slash);\n}\n\nfunction headingLevelFromType(\n type: string,\n): { level: HeadingLevel; source: number } | null {\n if (!type.startsWith(\"standard-h\")) return null;\n const raw = type.slice(\"standard-h\".length);\n if (raw.length === 0) return null;\n for (let i = 0; i < raw.length; i++) {\n const code = raw.charCodeAt(i);\n if (code < 48 || code > 57) return null;\n }\n const source = Number(raw);\n if (!Number.isFinite(source) || source < 1) return null;\n const level = (source > 4 ? 4 : source) as HeadingLevel;\n return { level, source };\n}\n\nfunction leafStyles(\n node: EasyEmailProNode,\n map: MapContext,\n): { styles: BlockStyles } {\n return {\n styles: {\n padding: readPadding((key) => readAttr(node, key, map.resolve)),\n },\n };\n}\n\nfunction finish(\n block: Block,\n node: EasyEmailProNode,\n entry: ImportReportEntry,\n): Converted {\n const visibility = readVisibility(node);\n if (visibility) block.visibility = visibility;\n return { blocks: [block], entries: [entry] };\n}\n\nfunction readVisibility(node: EasyEmailProNode): BlockVisibility | undefined {\n if (node.visible === \"desktop\") return { desktop: true, mobile: false };\n if (node.visible === \"mobile\") return { desktop: false, mobile: true };\n return undefined;\n}\n\nfunction report(\n sourceTag: string,\n templaticalBlockType: string,\n status: ConversionStatus,\n note?: string,\n): ImportReportEntry {\n return {\n sourceTag,\n templaticalBlockType,\n status,\n ...(note ? { note } : {}),\n };\n}\n\nfunction empty(): Converted {\n return { blocks: [], entries: [] };\n}\n\nfunction isElement(\n node: EasyEmailProNode | EasyEmailProTextNode,\n): node is EasyEmailProNode {\n return typeof node.type === \"string\" && node.type !== \"\";\n}\n\nfunction isBorderEnabled(value: unknown): boolean {\n return value === true || value === \"true\";\n}\n\nfunction buttonWidth(value: unknown): number | \"full\" | undefined {\n if (isUnset(value)) return undefined;\n if (typeof value === \"string\" && value.trim() === \"100%\") return \"full\";\n return parsePx(value);\n}\n\nfunction parseAlign(value: unknown): \"left\" | \"center\" | \"right\" | undefined {\n if (typeof value !== \"string\") return undefined;\n const align = value.trim().toLowerCase();\n if (align === \"left\" || align === \"center\" || align === \"right\") return align;\n return undefined;\n}\n\nfunction asLineStyle(\n value: unknown,\n): \"solid\" | \"dashed\" | \"dotted\" | undefined {\n if (typeof value !== \"string\") return undefined;\n const style = value.trim().toLowerCase();\n if (style === \"solid\" || style === \"dashed\" || style === \"dotted\") {\n return style;\n }\n return undefined;\n}\n\nfunction setString(value: unknown): string | undefined {\n if (typeof value !== \"string\" || isUnset(value)) return undefined;\n return value;\n}\n\n/** Button labels are plain text — strip tags the serialiser may have emitted. */\nfunction stripTags(html: string): string {\n if (html === \"\") return \"\";\n return decodeEntities(removeTags(html)).trim();\n}\n\nfunction removeTags(html: string): string {\n let out = \"\";\n let i = 0;\n while (i < html.length) {\n const open = html.indexOf(\"<\", i);\n if (open === -1) {\n out += html.slice(i);\n break;\n }\n out += html.slice(i, open);\n const tagEnd = findOpenTagEnd(html, open + 1);\n if (tagEnd === -1) {\n out += html.slice(open);\n break;\n }\n i = tagEnd + 1;\n }\n return out;\n}\n\nfunction decodeEntities(text: string): string {\n let out = \"\";\n let i = 0;\n while (i < text.length) {\n if (text[i] === \"&\") {\n const semi = text.indexOf(\";\", i + 1);\n if (semi !== -1 && semi - i <= 6) {\n const mapped = ENTITIES[text.slice(i, semi + 1)];\n if (mapped !== undefined) {\n out += mapped;\n i = semi + 1;\n continue;\n }\n }\n }\n out += text[i];\n i++;\n }\n return out;\n}\n","import type { ColumnLayout } from \"@templatical/types\";\n\nconst LAYOUT_SHAPES: Array<{ layout: ColumnLayout; percents: number[] }> = [\n { layout: \"1\", percents: [100] },\n { layout: \"2\", percents: [50, 50] },\n { layout: \"1-2\", percents: [33.33, 66.67] },\n { layout: \"2-1\", percents: [66.67, 33.33] },\n { layout: \"3\", percents: [33.33, 33.33, 33.34] },\n];\n\nconst WIDTH_TOLERANCE = 2;\n\nexport const COLUMN_COUNT: Record<ColumnLayout, number> = {\n \"1\": 1,\n \"2\": 2,\n \"3\": 3,\n \"2-1\": 2,\n \"1-2\": 2,\n};\n\nexport function columnPixels(\n layout: ColumnLayout,\n container: number,\n): number[] {\n switch (layout) {\n case \"2\":\n return [container / 2, container / 2];\n case \"3\":\n return [container / 3, container / 3, container / 3];\n case \"1-2\":\n return [container / 3, (container * 2) / 3];\n case \"2-1\":\n return [(container * 2) / 3, container / 3];\n default:\n return [container];\n }\n}\n\n/**\n * Resolve column widths to one of the five layouts `ColumnLayout` allows.\n *\n * `exact: false` means the caller reports `approximated` — Chamaileon permits\n * any column count at any width and this union permits five shapes, so this is\n * the importer's main irreducible loss.\n */\nexport function matchColumnLayout(percents: Array<number | null>): {\n layout: ColumnLayout;\n exact: boolean;\n} {\n const count = percents.length;\n if (count === 0) return { layout: \"1\", exact: true };\n\n // All-unset is \"distribute equally\", which is exactly what the n-column\n // layout means — not a missing value to approximate around.\n if (percents.every((p) => p === null)) {\n if (count === 1) return { layout: \"1\", exact: true };\n if (count === 2) return { layout: \"2\", exact: true };\n if (count === 3) return { layout: \"3\", exact: true };\n return { layout: \"3\", exact: false };\n }\n\n const known = percents.filter((p): p is number => p !== null);\n const unsetCount = count - known.length;\n const remainder =\n unsetCount === 0\n ? 0\n : Math.max(0, 100 - known.reduce((a, b) => a + b, 0)) / unsetCount;\n const resolved = percents.map((p) => p ?? remainder);\n\n const sameCount = LAYOUT_SHAPES.filter((s) => s.percents.length === count);\n\n for (const shape of sameCount) {\n if (\n shape.percents.every(\n (want, i) => Math.abs(want - resolved[i]) <= WIDTH_TOLERANCE,\n )\n ) {\n return { layout: shape.layout, exact: true };\n }\n }\n\n const candidates =\n sameCount.length > 0\n ? sameCount\n : LAYOUT_SHAPES.filter((s) => s.layout === \"3\");\n\n let best = candidates[0];\n let bestError = Infinity;\n for (const shape of candidates) {\n const error = shape.percents.reduce(\n (sum, want, i) => sum + Math.abs(want - (resolved[i] ?? 0)),\n 0,\n );\n if (error < bestError) {\n bestError = error;\n best = shape;\n }\n }\n\n return { layout: best.layout, exact: false };\n}\n\n/** Convert absolute px column widths to percents of `bodyWidth`. */\nexport function widthsToPercents(\n widthsPx: Array<number | undefined>,\n bodyWidth: number,\n): Array<number | null> {\n return widthsPx.map((w) => (w === undefined ? null : (w / bodyWidth) * 100));\n}\n","import { createImageBlock, createSectionBlock } from \"@templatical/types\";\nimport type {\n Block,\n BlockVisibility,\n SectionBlock,\n SectionWrapper,\n} from \"@templatical/types\";\nimport {\n parseColor,\n parsePercent,\n parsePx,\n readPadding,\n} from \"./attribute-parser\";\nimport { convertLeaf, type Converted, type MapContext } from \"./block-mapper\";\nimport { COLUMN_COUNT, columnPixels, matchColumnLayout } from \"./column-layout\";\nimport { isUnset, readAttr } from \"./normalize\";\nimport type {\n ConversionStatus,\n EasyEmailProNode,\n EasyEmailProTextNode,\n ImportReportEntry,\n} from \"./types\";\n\nexport function buildTopLevel(\n node: EasyEmailProNode,\n map: MapContext,\n): Converted {\n switch (node.type) {\n case \"standard-wrapper\":\n return buildWrapper(node, map);\n case \"standard-hero\":\n return buildHero(node, map);\n case \"standard-section\":\n return buildSection(node, map);\n default:\n return empty();\n }\n}\n\nfunction buildSection(node: EasyEmailProNode, map: MapContext): Converted {\n const plan = collectSlots(node);\n const rawWidths = plan.columns.map((column) =>\n readAttr(column, \"width\", map.resolve),\n );\n const { layout, exact } = matchColumnLayout(\n rawWidths.map((width) => parsePercent(width)),\n );\n const slots = COLUMN_COUNT[layout];\n const sectionWidth = insideWidth(map.contentWidth, node, map);\n const slotWidths =\n sectionWidth === undefined ? undefined : columnPixels(layout, sectionWidth);\n const leftover = convertFlow(\n plan.leftovers,\n withContentWidth(map, slotWidths?.[0]),\n );\n const children: Block[][] = Array.from({ length: slots }, () => []);\n if (leftover.blocks.length > 0) {\n children[0].push(...leftover.blocks);\n }\n\n const entries = leftover.entries;\n plan.columns.forEach((column, index) => {\n const slot = Math.min(index, slots - 1);\n const inner = convertFlow(\n column.children ?? [],\n withContentWidth(map, insideWidth(slotWidths?.[slot], column, map)),\n );\n children[slot].push(...inner.blocks);\n for (const entry of inner.entries) entries.push(entry);\n });\n\n const reasons: string[] = [];\n if (plan.mixed) {\n reasons.push(\n \"Section mixed columns and groups; flattened into the column flow.\",\n );\n }\n if (!exact) {\n if (plan.columns.length > slots) {\n reasons.push(\n `${plan.columns.length}-column layout has no exact Templatical equivalent; folded onto \"${layout}\".`,\n );\n } else {\n const shown = rawWidths\n .map((width) =>\n typeof width === \"string\" && !isUnset(width) ? width : \"auto\",\n )\n .join(\", \");\n reasons.push(\n `Column widths ${shown} have no exact Templatical layout; resolved to \"${layout}\".`,\n );\n }\n }\n\n const section = createSectionBlock();\n section.columns = layout;\n section.children = children;\n paintSection(section, node, map, {\n stackOnMobile: plan.grouped ? false : undefined,\n });\n entries.unshift(\n sectionEntry(\n node,\n reasons.length > 0 ? \"approximated\" : \"converted\",\n reasons.length > 0 ? reasons.join(\" \") : undefined,\n ),\n );\n return { blocks: [section], entries };\n}\n\nfunction buildHero(node: EasyEmailProNode, map: MapContext): Converted {\n const slot: Block[] = [];\n const entries: ImportReportEntry[] = [];\n const url = readAttr(node, \"background-url\", map.resolve);\n if (typeof url === \"string\" && !isUnset(url)) {\n slot.push(createImageBlock({ src: url }));\n entries.push({\n sourceTag: \"standard-hero\",\n templaticalBlockType: \"image\",\n status: \"approximated\",\n note: \"hero background-url stacked as a leading image (overlay is the loss)\",\n });\n }\n const inner = convertFlow(\n node.children ?? [],\n withContentWidth(map, insideWidth(map.contentWidth, node, map)),\n );\n slot.push(...inner.blocks);\n for (const entry of inner.entries) entries.push(entry);\n\n const section = createSectionBlock();\n section.columns = \"1\";\n section.children = [slot];\n paintSection(section, node, map);\n entries.unshift({\n sourceTag: \"standard-hero\",\n templaticalBlockType: \"section\",\n status: \"approximated\",\n note: \"standard-hero overlay is stacked as a 1-column section; background-url becomes a leading image.\",\n });\n return { blocks: [section], entries };\n}\n\nfunction buildWrapper(node: EasyEmailProNode, map: MapContext): Converted {\n const blocks: Block[] = [];\n const entries: ImportReportEntry[] = [];\n const childMap = withContentWidth(\n map,\n insideWidth(map.contentWidth, node, map),\n );\n for (const child of elements(node)) {\n if (child.type === \"placeholder\") continue;\n const inner = buildTopLevel(child, childMap);\n for (const block of inner.blocks) blocks.push(block);\n for (const entry of inner.entries) entries.push(entry);\n }\n\n if (!blocks.some(isSection)) {\n return {\n blocks: [],\n entries: [\n {\n sourceTag: \"standard-wrapper\",\n templaticalBlockType: null,\n status: \"skipped\",\n note: \"An empty standard-wrapper produces nothing.\",\n },\n ],\n };\n }\n\n applyWrapper(node, blocks, entries, map);\n return { blocks, entries };\n}\n\n/**\n * Paint `node`'s `mj-wrapper` band onto every section in `blocks`. A section\n * holds one band, so a band around several sections is copied onto each and\n * their `converted` entries become `approximated`.\n */\nexport function applyWrapper(\n node: EasyEmailProNode,\n blocks: Block[],\n entries: ImportReportEntry[],\n map: MapContext,\n): void {\n const sections = blocks.filter(isSection);\n if (sections.length === 0) return;\n\n const wrapper = readWrapper(node, map);\n for (const section of sections) {\n section.wrapper = { ...wrapper };\n }\n if (sections.length > 1) {\n const note = `${node.type ?? \"standard-wrapper\"} holding ${sections.length} sections was applied to each of them — Templatical has no multi-section band.`;\n for (const entry of entries) {\n if (entry.templaticalBlockType !== \"section\") continue;\n if (entry.status !== \"converted\") continue;\n entry.status = \"approximated\";\n entry.note = note;\n }\n }\n}\n\n/** `width` less `node`'s own left and right padding; unknown stays unknown. */\nexport function insideWidth(\n width: number | undefined,\n node: EasyEmailProNode,\n map: MapContext,\n): number | undefined {\n if (width === undefined) return undefined;\n const padding = readPadding((key) => readAttr(node, key, map.resolve));\n return Math.max(0, width - padding.left - padding.right);\n}\n\nexport function withContentWidth(\n map: MapContext,\n contentWidth: number | undefined,\n): MapContext {\n return { ...map, contentWidth };\n}\n\nfunction isSection(block: Block): block is SectionBlock {\n return block.type === \"section\";\n}\n\n/**\n * Direct columns become slots. A sole `standard-group` of columns becomes\n * those slots with `stackOnMobile: false`. Mixed group + columns flatten\n * into the slot list and are approximated.\n */\nfunction collectSlots(section: EasyEmailProNode): {\n columns: EasyEmailProNode[];\n leftovers: EasyEmailProNode[];\n grouped: boolean;\n mixed: boolean;\n} {\n const kids = structuralChildren(section);\n\n if (kids.every((kid) => kid.type === \"standard-column\")) {\n return { columns: kids, leftovers: [], grouped: false, mixed: false };\n }\n\n if (kids.length === 1 && kids[0].type === \"standard-group\") {\n const groupKids = structuralChildren(kids[0]);\n if (groupKids.every((kid) => kid.type === \"standard-column\")) {\n return {\n columns: groupKids,\n leftovers: [],\n grouped: true,\n mixed: false,\n };\n }\n }\n\n const columns: EasyEmailProNode[] = [];\n const leftovers: EasyEmailProNode[] = [];\n let grouped = false;\n for (const kid of kids) {\n if (kid.type === \"standard-column\") {\n columns.push(kid);\n continue;\n }\n if (kid.type === \"standard-group\") {\n grouped = true;\n for (const inner of structuralChildren(kid)) {\n if (inner.type === \"standard-column\") columns.push(inner);\n else leftovers.push(inner);\n }\n continue;\n }\n leftovers.push(kid);\n }\n return { columns, leftovers, grouped, mixed: true };\n}\n\nfunction convertFlow(\n nodes: Array<EasyEmailProNode | EasyEmailProTextNode> | undefined,\n map: MapContext,\n): Converted {\n const blocks: Block[] = [];\n const entries: ImportReportEntry[] = [];\n for (const child of nodes ?? []) {\n if (!isElement(child)) continue;\n if (child.type === \"placeholder\") continue;\n if (child.type === \"standard-group\") {\n const innerColumns = structuralChildren(child).filter(\n (node) => node.type === \"standard-column\",\n );\n entries.push({\n sourceTag: \"standard-group\",\n templaticalBlockType: null,\n status: \"approximated\",\n note: `nested group flattened (${innerColumns.length} columns)`,\n });\n for (const column of innerColumns) {\n const inner = convertFlow(column.children, map);\n for (const block of inner.blocks) blocks.push(block);\n for (const entry of inner.entries) entries.push(entry);\n }\n continue;\n }\n if (child.type === \"standard-column\") {\n const inner = convertFlow(child.children, map);\n for (const block of inner.blocks) blocks.push(block);\n for (const entry of inner.entries) entries.push(entry);\n continue;\n }\n const converted = convertLeaf(child, map);\n for (const block of converted.blocks) blocks.push(block);\n for (const entry of converted.entries) entries.push(entry);\n }\n return { blocks, entries };\n}\n\n/** `createSectionBlock()` first, then mutate fill — never a partial `styles`. */\nfunction paintSection(\n section: SectionBlock,\n node: EasyEmailProNode,\n map: MapContext,\n extras?: { stackOnMobile?: boolean },\n): void {\n section.styles.padding = readPadding((key) =>\n readAttr(node, key, map.resolve),\n );\n const fill = sectionFill(node, map);\n if (fill) section.styles.backgroundColor = fill;\n const radius = parsePx(readAttr(node, \"border-radius\", map.resolve));\n if (radius !== undefined && radius > 0) section.borderRadius = radius;\n if (extras?.stackOnMobile === false) section.stackOnMobile = false;\n const visibility = readVisibility(node);\n if (visibility) section.visibility = visibility;\n}\n\nfunction sectionFill(\n node: EasyEmailProNode,\n map: MapContext,\n): string | undefined {\n const own = parseColor(readAttr(node, \"background-color\", map.resolve));\n if (own) return own;\n return parseColor(\n readAttr(map.resolve.page, \"content-background-color\", map.resolve),\n );\n}\n\nfunction readWrapper(node: EasyEmailProNode, map: MapContext): SectionWrapper {\n const backgroundColor = parseColor(\n readAttr(node, \"background-color\", map.resolve),\n );\n const padding = readPadding((key) => readAttr(node, key, map.resolve));\n const radius = parsePx(readAttr(node, \"border-radius\", map.resolve));\n return {\n ...(backgroundColor ? { backgroundColor } : {}),\n padding,\n ...(radius !== undefined && radius > 0 ? { borderRadius: radius } : {}),\n };\n}\n\nfunction sectionEntry(\n node: EasyEmailProNode,\n status: ConversionStatus,\n note?: string,\n): ImportReportEntry {\n return {\n sourceTag: node.type ?? \"standard-section\",\n templaticalBlockType: \"section\",\n status,\n ...(note ? { note } : {}),\n };\n}\n\nfunction readVisibility(node: EasyEmailProNode): BlockVisibility | undefined {\n if (node.visible === \"desktop\") return { desktop: true, mobile: false };\n if (node.visible === \"mobile\") return { desktop: false, mobile: true };\n return undefined;\n}\n\nfunction structuralChildren(node: EasyEmailProNode): EasyEmailProNode[] {\n return elements(node).filter((child) => child.type !== \"placeholder\");\n}\n\nfunction elements(node: EasyEmailProNode): EasyEmailProNode[] {\n const out: EasyEmailProNode[] = [];\n for (const child of node.children ?? []) {\n if (isElement(child)) out.push(child);\n }\n return out;\n}\n\nfunction isElement(\n node: EasyEmailProNode | EasyEmailProTextNode,\n): node is EasyEmailProNode {\n return typeof node.type === \"string\" && node.type !== \"\";\n}\n\nfunction empty(): Converted {\n return { blocks: [], entries: [] };\n}\n","import {\n canonicalFontStack,\n createDefaultTemplateContent,\n createSectionBlock,\n DEFAULT_TEMPLATE_DEFAULTS,\n} from \"@templatical/types\";\nimport type {\n Block,\n TemplateContent,\n TemplateSettings,\n} from \"@templatical/types\";\nimport { parseColor, parsePx } from \"./attribute-parser\";\nimport { convertLeaf, isLeafType, type MapContext } from \"./block-mapper\";\nimport {\n contextFromPage,\n isUnset,\n readAttr,\n unwrapDocument,\n withWidgetInput,\n} from \"./normalize\";\nimport {\n applyWrapper,\n buildTopLevel,\n insideWidth,\n withContentWidth,\n} from \"./section-builder\";\nimport type {\n EasyEmailProDocument,\n EasyEmailProNode,\n EasyEmailProPage,\n EasyEmailProTextNode,\n ImportReportEntry,\n ImportResult,\n} from \"./types\";\n\nconst INVALID_MESSAGE =\n \"Invalid Easy Email Pro template: expected a page JSON object (EmailTemplate { subject, content } or the page element).\";\nconst OSS_MESSAGE =\n \"Invalid Easy Email Pro template: this looks like open-source Easy Email JSON, not Easy Email Pro (expected standard-* children).\";\nconst EMPTY_WARNING =\n \"No convertible content was found in the Easy Email Pro page. Check that page.children holds at least one standard-section.\";\nconst MOBILE_WARNING =\n \"mobileAttributes were dropped; Templatical has no per-viewport padding.\";\n\nfunction varWarning(resolved: number, unresolved: number): string {\n return `Resolved ${resolved} $var() values, ${unresolved} left unresolved.`;\n}\n\nconst OSS_CHILD_TYPES = new Set([\n \"section\",\n \"column\",\n \"text\",\n \"button\",\n \"image\",\n \"wrapper\",\n \"hero\",\n \"navbar\",\n \"social\",\n]);\n\nconst STRUCTURE_TYPES = new Set([\n \"standard-section\",\n \"standard-wrapper\",\n \"standard-hero\",\n]);\n\nconst WIDGET_TYPES = new Set([\"section_widget\", \"wrapper_widget\"]);\n\n/**\n * Header and footer bands. Easy Email Pro renders each as an `mj-wrapper`\n * carrying the node's own attributes around `data.content`, whose items are\n * page children.\n */\nconst PAGE_BAND_TYPES = new Set([\"page-header\", \"page-footer\"]);\n\n/**\n * `DEFAULT_TEMPLATE_DEFAULTS` is typed `Partial<TemplateSettings>` so a\n * consumer can override any subset, but its own literal always sets the six\n * required fields. Narrowing once here is what lets each fallback come out as\n * `number`/`string`/`boolean` rather than `| undefined`.\n */\nconst REQUIRED_DEFAULTS = DEFAULT_TEMPLATE_DEFAULTS as Required<\n Pick<\n TemplateSettings,\n | \"width\"\n | \"backgroundColor\"\n | \"textColor\"\n | \"linkUnderline\"\n | \"fontFamily\"\n | \"locale\"\n >\n>;\n\n/**\n * Convert an Easy Email Pro page (or EmailTemplate envelope) into a\n * Templatical template. Accepts a bare `page` element, an\n * `EmailTemplate { subject, content }` envelope, or a JSON string of either.\n */\nexport function convertEasyEmailProTemplate(\n doc: EasyEmailProDocument | EasyEmailProPage | string,\n): ImportResult {\n const root: unknown = typeof doc === \"string\" ? safeParse(doc) : doc;\n\n if (typeof root !== \"object\" || root === null || Array.isArray(root)) {\n throw new Error(INVALID_MESSAGE);\n }\n\n const unwrapped = unwrapDocument(root);\n if (unwrapped.page.type !== \"page\") {\n throw new Error(INVALID_MESSAGE);\n }\n const page = unwrapped.page as EasyEmailProPage;\n const subject = unwrapped.subject;\n assertNotOss(page);\n\n const warnings: string[] = [];\n const entries: ImportReportEntry[] = [];\n const blocks: Block[] = [];\n const resolve = contextFromPage(page);\n const data = isPlainObject(page.data) ? page.data : {};\n const settings = readSettings(page, data, resolve);\n const map: MapContext = { resolve, warnings, contentWidth: settings.width };\n\n const subjectRaw = typeof subject === \"string\" ? subject.trim() : \"\";\n if (subjectRaw) {\n warnings.push(\n `Document subject \"${subject}\" has no TemplateSettings field and was dropped.`,\n );\n }\n if (Array.isArray(data.fonts) && data.fonts.length > 0) {\n warnings.push(\n \"Dropped fonts[] — Templatical templates have no document-level font table.\",\n );\n }\n if (isNonEmptyHeadStyles(data.headStyles)) {\n warnings.push(\n \"Dropped headStyles — Templatical templates have no document-level head-style table.\",\n );\n }\n if (\n isPlainObject(data.classAttributes) &&\n Object.keys(data.classAttributes).length > 0\n ) {\n warnings.push(\n \"Dropped classAttributes — class-based MJML attribute cascade is not applied.\",\n );\n }\n\n for (const child of page.children ?? []) {\n if (!isElement(child)) continue;\n walkNode(child, map, entries, blocks);\n }\n\n if (hasMobileAttributes(page)) {\n warnings.push(MOBILE_WARNING);\n }\n\n if (resolve.stats.resolved > 0 || resolve.stats.unresolved > 0) {\n warnings.push(varWarning(resolve.stats.resolved, resolve.stats.unresolved));\n }\n\n if (blocks.length === 0) {\n warnings.push(EMPTY_WARNING);\n }\n\n const defaults = createDefaultTemplateContent();\n const content: TemplateContent = {\n ...defaults,\n blocks,\n settings: {\n ...defaults.settings,\n ...settings,\n },\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 return { content, report: { entries, warnings, summary } };\n}\n\nfunction readSettings(\n page: EasyEmailProPage,\n data: Record<string, unknown>,\n resolve: MapContext[\"resolve\"],\n): TemplateSettings {\n const width =\n parsePx(readAttr(page, \"width\", resolve)) ?? REQUIRED_DEFAULTS.width;\n // Page `background-color` is the viewport band. `content-background-color`\n // is the section fill fallback (section-builder), never a settings field.\n const backgroundColor =\n parseColor(readAttr(page, \"background-color\", resolve)) ??\n REQUIRED_DEFAULTS.backgroundColor;\n const fontFamilyRaw = readAttr(page, \"font-family\", resolve);\n const fontFamily =\n (typeof fontFamilyRaw === \"string\" && !isUnset(fontFamilyRaw)\n ? canonicalFontStack(fontFamilyRaw)\n : \"\") || REQUIRED_DEFAULTS.fontFamily;\n const textColor =\n parseColor(readAttr(page, \"color\", resolve)) ?? REQUIRED_DEFAULTS.textColor;\n const linkColor = parseColor(readAttr(page, \"link-color\", resolve));\n const deco = readAttr(page, \"link-text-decoration\", resolve);\n const linkUnderline =\n deco === \"underline\"\n ? true\n : deco === \"none\"\n ? false\n : REQUIRED_DEFAULTS.linkUnderline;\n const preheaderRaw =\n typeof data.preheader === \"string\" ? data.preheader.trim() : \"\";\n\n return {\n width,\n backgroundColor,\n textColor,\n fontFamily,\n linkUnderline,\n locale: REQUIRED_DEFAULTS.locale,\n ...(linkColor ? { linkColor } : {}),\n ...(preheaderRaw ? { preheaderText: preheaderRaw } : {}),\n };\n}\n\nfunction walkNode(\n node: EasyEmailProNode,\n map: MapContext,\n entries: ImportReportEntry[],\n blocks: Block[],\n): void {\n if (node.type === \"placeholder\") return;\n\n const logic = node.logic;\n const logicOn = hasLogic(logic);\n if (logicOn && !hasTypedContent(node)) {\n entries.push({\n sourceTag: node.type ?? \"logic\",\n templaticalBlockType: null,\n status: \"skipped\",\n note: `Skipped empty logic (${logicExpression(logic)})`,\n });\n return;\n }\n\n if (typeof node.type === \"string\" && WIDGET_TYPES.has(node.type)) {\n const from = entries.length;\n const data = isPlainObject(node.data) ? node.data : {};\n const input = isPlainObject(data.input) ? data.input : undefined;\n const inner: MapContext = {\n ...map,\n resolve: withWidgetInput(map.resolve, input),\n };\n for (const child of node.children ?? []) {\n if (!isElement(child)) continue;\n walkNode(child, inner, entries, blocks);\n }\n markApproximated(\n entries,\n from,\n `${node.type} flattened; $var resolved from data.input`,\n {\n sourceTag: node.type,\n },\n );\n if (logicOn) {\n markApproximated(entries, from, `logic ${logicExpression(logic)}`);\n }\n return;\n }\n\n const from = entries.length;\n if (typeof node.type === \"string\" && STRUCTURE_TYPES.has(node.type)) {\n const converted = buildTopLevel(node, map);\n for (const block of converted.blocks) blocks.push(block);\n for (const entry of converted.entries) entries.push(entry);\n } else if (isPageBand(node)) {\n walkBand(node, map, entries, blocks);\n } else {\n const converted = convertLeaf(node, map);\n for (const entry of converted.entries) entries.push(entry);\n if (converted.blocks.length > 0) {\n if (isLeafType(node.type)) {\n blocks.push(wrapInSection(converted.blocks));\n } else {\n blocks.push(...converted.blocks);\n }\n }\n }\n\n if (logicOn) {\n markApproximated(entries, from, `logic ${logicExpression(logic)}`);\n }\n}\n\n/**\n * A band's content walks as page children, so sections, wrappers, widgets and\n * bare leaves all convert as they would at the top. The band's own paint then\n * lands on the resulting sections, the way a `standard-wrapper`'s does.\n */\nfunction walkBand(\n node: PageBand,\n map: MapContext,\n entries: ImportReportEntry[],\n blocks: Block[],\n): void {\n const inner = withContentWidth(map, insideWidth(map.contentWidth, node, map));\n const bandBlocks: Block[] = [];\n const bandEntries: ImportReportEntry[] = [];\n for (const child of bandContent(node)) {\n walkNode(child, inner, bandEntries, bandBlocks);\n }\n if (bandBlocks.length === 0 && bandEntries.length === 0) {\n entries.push({\n sourceTag: node.type,\n templaticalBlockType: null,\n status: \"skipped\",\n note: `An empty ${node.type} produces nothing.`,\n });\n return;\n }\n applyWrapper(node, bandBlocks, bandEntries, map);\n for (const block of bandBlocks) blocks.push(block);\n for (const entry of bandEntries) entries.push(entry);\n}\n\ntype PageBand = EasyEmailProNode & { type: string };\n\nfunction isPageBand(node: EasyEmailProNode): node is PageBand {\n return typeof node.type === \"string\" && PAGE_BAND_TYPES.has(node.type);\n}\n\nfunction bandContent(node: EasyEmailProNode): EasyEmailProNode[] {\n const content = isPlainObject(node.data) ? node.data.content : undefined;\n if (!Array.isArray(content)) return [];\n return content.filter(\n (child): child is EasyEmailProNode =>\n isPlainObject(child) && isElement(child as EasyEmailProNode),\n );\n}\n\nfunction wrapInSection(blocks: Block[]): Block {\n const section = createSectionBlock();\n section.columns = \"1\";\n section.children = [blocks];\n return section;\n}\n\nfunction markApproximated(\n entries: ImportReportEntry[],\n from: number,\n extra: string,\n rewrite?: { sourceTag: string },\n): void {\n for (let i = from; i < entries.length; i++) {\n const entry = entries[i];\n if (rewrite) entry.sourceTag = rewrite.sourceTag;\n if (entry.status === \"converted\") entry.status = \"approximated\";\n entry.note = entry.note ? `${entry.note} ${extra}` : extra;\n }\n}\n\nfunction hasLogic(\n logic: EasyEmailProNode[\"logic\"],\n): logic is NonNullable<EasyEmailProNode[\"logic\"]> {\n if (logic == null || typeof logic !== \"object\") return false;\n return logic.condition != null || logic.iteration != null;\n}\n\nfunction logicExpression(\n logic: NonNullable<EasyEmailProNode[\"logic\"]>,\n): string {\n const parts: string[] = [];\n if (logic.condition != null) {\n parts.push(\n typeof logic.condition === \"string\"\n ? logic.condition\n : JSON.stringify(logic.condition),\n );\n }\n if (logic.iteration != null) {\n const iteration = logic.iteration;\n if (typeof iteration === \"string\") {\n parts.push(iteration);\n } else if (\n isPlainObject(iteration) &&\n typeof iteration.dataSource === \"string\"\n ) {\n parts.push(iteration.dataSource);\n } else {\n parts.push(JSON.stringify(iteration));\n }\n }\n return parts.join(\" \");\n}\n\nfunction hasTypedContent(node: EasyEmailProNode): boolean {\n const kids = isPageBand(node) ? bandContent(node) : (node.children ?? []);\n for (const child of kids) {\n if (!isElement(child)) continue;\n if (child.type === \"placeholder\") continue;\n return true;\n }\n return false;\n}\n\nfunction hasMobileAttributes(node: unknown): boolean {\n if (!isPlainObject(node)) return false;\n const mobile = node.mobileAttributes;\n if (isPlainObject(mobile) && Object.keys(mobile).length > 0) return true;\n const band = isPageBand(node as EasyEmailProNode)\n ? bandContent(node as EasyEmailProNode)\n : [];\n const children = Array.isArray(node.children) ? node.children : [];\n for (const child of [...children, ...band]) {\n if (hasMobileAttributes(child)) return true;\n }\n return false;\n}\n\nfunction assertNotOss(page: EasyEmailProPage): void {\n const children = page.children ?? [];\n for (const child of children) {\n if (!child || typeof child !== \"object\") continue;\n const type = (child as EasyEmailProNode).type;\n if (typeof type !== \"string\") continue;\n if (OSS_CHILD_TYPES.has(type)) {\n throw new Error(OSS_MESSAGE);\n }\n break;\n }\n}\n\nfunction isElement(\n node: EasyEmailProNode | EasyEmailProTextNode,\n): node is EasyEmailProNode {\n return typeof node.type === \"string\" && node.type !== \"\";\n}\n\nfunction isNonEmptyHeadStyles(value: unknown): boolean {\n if (Array.isArray(value)) return value.length > 0;\n return isPlainObject(value) && Object.keys(value).length > 0;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction safeParse(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n throw new Error(INVALID_MESSAGE);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["isPlainObject","empty","isElement","readVisibility","isElement"],"sources":["../src/normalize.ts","../src/attribute-parser.ts","../src/rich-text.ts","../src/block-mapper.ts","../src/column-layout.ts","../src/section-builder.ts","../src/converter.ts"],"sourcesContent":["import type {\n EasyEmailProDocument,\n EasyEmailProNode,\n EasyEmailProVariable,\n} from \"./types\";\n\nconst VAR_PREFIX = \"$var(\";\n\n/** Spec §3.3 category map — unknown types skip the category layer. */\nexport const CATEGORY_BY_TYPE: Record<string, string> = {\n \"standard-paragraph\": \"TEXT\",\n \"standard-text\": \"TEXT\",\n \"standard-h1\": \"TEXT\",\n \"standard-h2\": \"TEXT\",\n \"standard-h3\": \"TEXT\",\n \"standard-h4\": \"TEXT\",\n \"standard-button\": \"BUTTON\",\n \"standard-image\": \"IMAGE\",\n \"standard-navbar\": \"NAVBAR\",\n \"standard-navbar-link\": \"NAVBAR\",\n \"standard-social\": \"SOCIAL\",\n \"standard-social-element\": \"SOCIAL\",\n \"standard-spacer\": \"SPACER\",\n \"standard-divider\": \"DIVIDER\",\n \"standard-hero\": \"HERO\",\n \"standard-wrapper\": \"WRAPPER\",\n \"standard-section\": \"SECTION\",\n \"standard-column\": \"COLUMN\",\n \"standard-group\": \"GROUP\",\n};\n\nexport interface VarStats {\n resolved: number;\n unresolved: number;\n}\n\nexport interface ResolveContext {\n variables: Record<string, string>;\n blockAttributes: Record<string, Record<string, unknown>>;\n categoryAttributes: Record<string, Record<string, unknown>>;\n globalAttributes: Record<string, unknown>;\n /** Page node — section fill falls back to `content-background-color`. */\n page: EasyEmailProNode;\n stats: VarStats;\n /**\n * Per-node attribute cache so a repeated `readAttr` (button fill vs\n * outlined check, section fill fallback) does not double-count `$var`.\n */\n attrCache: WeakMap<EasyEmailProNode, Map<string, unknown>>;\n}\n\n/**\n * `null`, `\"\"`, `\"url()\"`, `\"transparent\"`, and leftover `$var(` after\n * substitution are unset. Presence-guards that treat these as set write\n * illegal empties.\n */\nexport function isUnset(value: unknown): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value !== \"string\") return false;\n const trimmed = value.trim();\n return (\n trimmed === \"\" ||\n trimmed === \"url()\" ||\n trimmed.toLowerCase() === \"transparent\" ||\n trimmed.includes(VAR_PREFIX)\n );\n}\n\n/** Index `data.variables[]` by name for `$var` lookup. */\nexport function buildVariableTable(\n variables: EasyEmailProVariable[] | undefined,\n): Record<string, string> {\n const out: Record<string, string> = {};\n if (!variables) return out;\n for (const entry of variables) {\n if (typeof entry.name !== \"string\" || entry.name === \"\") continue;\n if (typeof entry.value !== \"string\") continue;\n out[entry.name] = entry.value;\n }\n return out;\n}\n\n/**\n * Replace `$var(name)` tokens via a linear scan (no regex — CodeQL\n * `js/polynomial-redos`). Unknown names are left in place and flagged.\n */\nexport function substituteVars(\n value: string,\n variables: Record<string, string>,\n): { value: string; resolved: number; unresolved: number } {\n let out = \"\";\n let i = 0;\n let resolved = 0;\n let unresolved = 0;\n\n while (i < value.length) {\n const start = value.indexOf(VAR_PREFIX, i);\n if (start === -1) {\n out += value.slice(i);\n break;\n }\n out += value.slice(i, start);\n const nameStart = start + VAR_PREFIX.length;\n const nameEnd = findMatchingParen(value, nameStart);\n if (nameEnd === -1) {\n // Unclosed `$var(` — keep the rest verbatim and mark unresolved.\n out += value.slice(start);\n unresolved += 1;\n break;\n }\n const name = value.slice(nameStart, nameEnd);\n if (Object.prototype.hasOwnProperty.call(variables, name)) {\n out += variables[name];\n resolved += 1;\n } else {\n out += value.slice(start, nameEnd + 1);\n unresolved += 1;\n }\n i = nameEnd + 1;\n }\n\n return { value: out, resolved, unresolved };\n}\n\n/** Walk from `openIdx` (char after `(`) to the matching `)`. */\nfunction findMatchingParen(value: string, openIdx: number): number {\n let depth = 1;\n for (let i = openIdx; i < value.length; i++) {\n const ch = value[i];\n if (ch === \"(\") depth += 1;\n else if (ch === \")\") {\n depth -= 1;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\nexport function contextFromPage(page: EasyEmailProNode): ResolveContext {\n const data = isPlainObject(page.data) ? page.data : {};\n return {\n variables: buildVariableTable(\n Array.isArray(data.variables)\n ? (data.variables as EasyEmailProVariable[])\n : undefined,\n ),\n blockAttributes: asNestedAttrMap(data.blockAttributes),\n categoryAttributes: asNestedAttrMap(data.categoryAttributes),\n globalAttributes: asAttrMap(data.globalAttributes),\n page,\n stats: { resolved: 0, unresolved: 0 },\n attrCache: new WeakMap(),\n };\n}\n\n/** Widget `data.input` overrides page variables for `$var` resolution. */\nexport function withWidgetInput(\n ctx: ResolveContext,\n input: Record<string, unknown> | undefined,\n): ResolveContext {\n if (!input) return ctx;\n const variables = { ...ctx.variables };\n for (const [key, value] of Object.entries(input)) {\n if (typeof value === \"string\") variables[key] = value;\n }\n // New cache: widget `data.input` can resolve the same node keys differently.\n return { ...ctx, variables, attrCache: new WeakMap() };\n}\n\n/**\n * Cascade: element → blockAttributes[type] → categoryAttributes[cat] →\n * globalAttributes. Missing keys fall through. String hits run through\n * `substituteVars`. Keys stay kebab-case MJML.\n */\nexport function readAttr(\n node: EasyEmailProNode,\n key: string,\n ctx: ResolveContext,\n): unknown {\n let cached = ctx.attrCache.get(node);\n if (cached?.has(key)) return cached.get(key);\n\n const raw = lookupAttr(node, key, ctx);\n let value: unknown = raw;\n if (typeof raw === \"string\") {\n const result = substituteVars(raw, ctx.variables);\n ctx.stats.resolved += result.resolved;\n ctx.stats.unresolved += result.unresolved;\n value = result.value;\n }\n\n if (!cached) {\n cached = new Map();\n ctx.attrCache.set(node, cached);\n }\n cached.set(key, value);\n return value;\n}\n\nfunction lookupAttr(\n node: EasyEmailProNode,\n key: string,\n ctx: ResolveContext,\n): unknown {\n const fromElement = node.attributes?.[key];\n if (fromElement !== undefined) return fromElement;\n\n if (typeof node.type === \"string\") {\n const fromBlock = ctx.blockAttributes[node.type]?.[key];\n if (fromBlock !== undefined) return fromBlock;\n\n const category = CATEGORY_BY_TYPE[node.type];\n if (category) {\n const fromCategory = ctx.categoryAttributes[category]?.[key];\n if (fromCategory !== undefined) return fromCategory;\n }\n }\n\n return ctx.globalAttributes[key];\n}\n\n/**\n * Envelope unwrap. Never throws — the converter owns invalid-shape errors.\n * Returns `{ page, subject }` when a page is visible; caller checks\n * `page.type === \"page\"`.\n */\nexport function unwrapDocument(root: unknown): {\n page: EasyEmailProNode;\n subject?: string;\n} {\n if (!isPlainObject(root)) {\n return { page: {} };\n }\n\n if (root.type === \"page\") {\n return { page: root as EasyEmailProNode };\n }\n\n const doc = root as EasyEmailProDocument;\n const page = isPlainObject(doc.content)\n ? (doc.content as EasyEmailProNode)\n : (root as EasyEmailProNode);\n const subject = typeof doc.subject === \"string\" ? doc.subject : undefined;\n return subject === undefined ? { page } : { page, subject };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asAttrMap(value: unknown): Record<string, unknown> {\n return isPlainObject(value) ? value : {};\n}\n\nfunction asNestedAttrMap(\n value: unknown,\n): Record<string, Record<string, unknown>> {\n if (!isPlainObject(value)) return {};\n const out: Record<string, Record<string, unknown>> = {};\n for (const [key, entry] of Object.entries(value)) {\n if (isPlainObject(entry)) out[key] = entry;\n }\n return out;\n}\n","import type {\n BackgroundImage,\n BackgroundPositionX,\n BackgroundPositionY,\n BackgroundSize,\n SectionHero,\n} from \"@templatical/types\";\nimport { isUnset } from \"./normalize\";\n\n/** Strip a trailing `px` (case-insensitive) and coerce to number. Unset/NaN → undefined. */\nexport function parsePx(value: unknown): number | undefined {\n if (isUnset(value)) return undefined;\n let raw = String(value).trim();\n if (raw.toLowerCase().endsWith(\"px\")) raw = raw.slice(0, -2).trimEnd();\n const n = Number(raw);\n return Number.isNaN(n) ? undefined : n;\n}\n\n/**\n * Strip a trailing `%` and coerce to number. Unset/NaN → `null` so\n * `matchColumnLayout` can tell \"missing width\" from `0%`.\n */\nexport function parsePercent(value: unknown): number | null {\n if (isUnset(value)) return null;\n let raw = String(value).trim();\n if (raw.endsWith(\"%\")) raw = raw.slice(0, -1).trimEnd();\n const n = Number(raw);\n return Number.isNaN(n) ? null : n;\n}\n\n/** Return the colour string as-is when set. No named-colour expansion. */\nexport function parseColor(value: unknown): string | undefined {\n if (isUnset(value)) return undefined;\n if (typeof value !== \"string\") return undefined;\n return value;\n}\n\n/** Read the four padding sides via a callback (typically wrapping `readAttr`). Missing → 0. */\nexport function readPadding(read: (key: string) => unknown): {\n top: number;\n right: number;\n bottom: number;\n left: number;\n} {\n const side = (key: string) => parsePx(read(key)) ?? 0;\n return {\n top: side(\"padding-top\"),\n right: side(\"padding-right\"),\n bottom: side(\"padding-bottom\"),\n left: side(\"padding-left\"),\n };\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/** What MJML paints for a `background-*` attribute an `mj-section` / `mj-wrapper` leaves out. */\nconst MJML_BACKGROUND_DEFAULTS = {\n size: \"auto\",\n x: \"center\",\n y: \"top\",\n repeat: true,\n} as const;\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/**\n * A section or wrapper background image, `null` when `background-url` is\n * unset. Easy Email Pro renders through MJML, so unset attributes take\n * MJML's own defaults and the import paints what the editor painted; a value\n * with no exact keyword takes the nearest one and adds a note naming it.\n * `read` returns an attribute's cascaded value (`readAttr`); `label` names\n * the element in each note, and a px `background-size` is measured against\n * `boxWidth`.\n */\nexport function readMjmlBackgroundImage(\n read: (name: string) => unknown,\n label: string,\n boxWidth: number | undefined,\n): ReadBackgroundImage | null {\n const value = (name: string): string | undefined => {\n const raw = read(name);\n return isUnset(raw) ? undefined : String(raw).trim();\n };\n\n const url = value(\"background-url\") ?? \"\";\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 = MJML_BACKGROUND_DEFAULTS.size;\n const rawSize = value(\"background-size\");\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 = MJML_BACKGROUND_DEFAULTS.x;\n let y: BackgroundPositionY = MJML_BACKGROUND_DEFAULTS.y;\n let lossyX = false;\n let lossyY = false;\n const rawPosition = value(\"background-position\");\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 lossyX = !split.exact || !readX?.exact;\n lossyY = !split.exact || !readY?.exact;\n }\n // A readable `-x` / `-y` replaces its axis, and with it whatever the\n // position lost there; the position's note then names what was imported.\n const rawX = value(\"background-position-x\");\n const overrideX = rawX\n ? backgroundAxisPoint(rawX.toLowerCase(), X_GRID)\n : null;\n if (overrideX) {\n x = overrideX.point;\n lossyX = false;\n }\n const rawY = value(\"background-position-y\");\n const overrideY = rawY\n ? backgroundAxisPoint(rawY.toLowerCase(), Y_GRID)\n : null;\n if (overrideY) {\n y = overrideY.point;\n lossyY = false;\n }\n if (rawPosition && (lossyX || lossyY)) {\n lossy(\"background-position\", rawPosition, `${x} ${y}`);\n }\n if (rawX && !overrideX?.exact) lossy(\"background-position-x\", rawX, x);\n if (rawY && !overrideY?.exact) lossy(\"background-position-y\", rawY, y);\n\n let repeat: boolean = MJML_BACKGROUND_DEFAULTS.repeat;\n const rawRepeat = value(\"background-repeat\");\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\n/** A section hero read from a `standard-hero`, with a note for each value it couldn't carry. */\nexport interface ReadHero {\n /** `null` for a content-height hero, which a regular section paints exactly. */\n hero: SectionHero | null;\n image: BackgroundImage | null;\n notes: string[];\n}\n\nconst HERO_ALIGNS = [\"top\", \"middle\", \"bottom\"] as const;\n\nconst HERO_DROPPED_ATTRIBUTES = [\n \"inner-padding\",\n \"inner-padding-top\",\n \"inner-padding-right\",\n \"inner-padding-bottom\",\n \"inner-padding-left\",\n \"inner-background-color\",\n];\n\n/**\n * A `standard-hero`'s mode, height and background. Easy Email Pro renders it\n * as an MJML `mj-hero`, so unset attributes take mj-hero's defaults\n * (`fixed-height`, `0px`, `center center`, `vertical-align: top`), and its\n * image is always `cover` and unrepeated. `background-width` /\n * `background-height` are stored as the image's `naturalWidth` /\n * `naturalHeight`, though they are often the hero box's size rather than the\n * file's: only their ratio is used. A `fixed-height` hero without a positive\n * `height` is as tall as its content, exactly what a regular section with the\n * same background paints, so it comes back without `hero`.\n */\nexport function readMjmlHero(\n read: (name: string) => unknown,\n label: string,\n boxWidth: number | undefined,\n): ReadHero {\n const value = (name: string): string | undefined => {\n const raw = read(name);\n return isUnset(raw) ? undefined : String(raw).trim();\n };\n const notes: string[] = [];\n\n const background = readMjmlBackgroundImage(\n (name) => {\n if (name === \"background-size\") return \"cover\";\n if (name === \"background-repeat\") return \"no-repeat\";\n if (name === \"background-position\") {\n return value(name) ?? \"center center\";\n }\n if (\n name === \"background-position-x\" ||\n name === \"background-position-y\"\n ) {\n return undefined;\n }\n return read(name);\n },\n label,\n boxWidth,\n );\n if (background) notes.push(...background.notes);\n\n const width = parsePx(value(\"background-width\"));\n const height = parsePx(value(\"background-height\"));\n const sized =\n width !== undefined && height !== undefined && width > 0 && height > 0;\n const image = background\n ? {\n ...background.image,\n ...(sized ? { naturalWidth: width, naturalHeight: height } : {}),\n }\n : null;\n\n const rawAlign = value(\"vertical-align\");\n const verticalAlign =\n HERO_ALIGNS.find((align) => align === rawAlign?.toLowerCase()) ?? \"top\";\n if (rawAlign && verticalAlign !== rawAlign.toLowerCase()) {\n notes.push(\n `${label} vertical-align \"${rawAlign}\" has no Templatical equivalent; imported as \"top\".`,\n );\n }\n\n const rawMode = value(\"mode\");\n const mode = rawMode ? rawMode.toLowerCase() : \"fixed-height\";\n let hero: SectionHero | null = null;\n if (mode === \"fluid-height\") {\n hero = { height: \"image\", verticalAlign };\n if (!sized) {\n notes.push(\n `${label} fluid-height has no background-width / background-height, so its image size is unknown; it renders as a regular section until it has a size or a fixed height.`,\n );\n }\n } else {\n if (mode !== \"fixed-height\") {\n notes.push(\n `${label} mode \"${rawMode}\" has no Templatical equivalent; imported as \"fixed-height\".`,\n );\n }\n const fixed = parsePx(value(\"height\"));\n if (fixed !== undefined && fixed > 0) {\n hero = { height: Math.round(fixed), verticalAlign };\n }\n }\n\n if (hero && !image) {\n notes.push(\n `${label} has no background-url, so it renders as a regular section until it has a background image.`,\n );\n }\n\n for (const name of HERO_DROPPED_ATTRIBUTES) {\n const raw = value(name);\n if (raw === undefined) continue;\n notes.push(\n `${label} ${name} \"${raw}\" has no Templatical equivalent; dropped.`,\n );\n }\n\n return { hero, image, notes };\n}\n","import type { EasyEmailProNode, EasyEmailProTextNode } from \"./types\";\n\n/** Escape `& < > \"` for text content and attribute values. */\nfunction escapeHtml(value: string): string {\n let out = \"\";\n for (let i = 0; i < value.length; i++) {\n const ch = value[i]!;\n if (ch === \"&\") out += \"&amp;\";\n else if (ch === \"<\") out += \"&lt;\";\n else if (ch === \">\") out += \"&gt;\";\n else if (ch === '\"') out += \"&quot;\";\n else out += ch;\n }\n return out;\n}\n\nfunction isTextNode(\n node: EasyEmailProNode | EasyEmailProTextNode,\n): node is EasyEmailProTextNode {\n return typeof (node as EasyEmailProTextNode).text === \"string\";\n}\n\n/**\n * Nesting (outer → inner): link → color/bgColor span → underline → strike →\n * em → strong. Matches the Task 4 brief / design §8.1 mark order.\n */\nfunction serialiseTextNode(node: EasyEmailProTextNode): string {\n let html = escapeHtml(node.text);\n\n if (node.bold) html = `<strong>${html}</strong>`;\n if (node.italic) html = `<em>${html}</em>`;\n if (node.strikethrough) html = `<s>${html}</s>`;\n if (node.underline) html = `<u>${html}</u>`;\n\n const styles: string[] = [];\n if (typeof node.color === \"string\" && node.color !== \"\") {\n styles.push(`color: ${escapeHtml(node.color)}`);\n }\n if (typeof node.bgColor === \"string\" && node.bgColor !== \"\") {\n styles.push(`background-color: ${escapeHtml(node.bgColor)}`);\n }\n if (styles.length > 0) {\n html = `<span style=\"${styles.join(\"; \")}\">${html}</span>`;\n }\n\n if (node.link) {\n const href = escapeHtml(node.link.href ?? \"\");\n const blank = node.link.blank === true ? ' target=\"_blank\"' : \"\";\n html = `<a href=\"${href}\"${blank}>${html}</a>`;\n }\n\n return html;\n}\n\n/** Easy Email Pro's `HTML_NODE_VOID_TAGS`: rendered `<tag />`, children ignored. */\nconst VOID_TAGS = new Set([\n \"img\",\n \"br\",\n \"hr\",\n \"area\",\n \"base\",\n \"col\",\n \"embed\",\n \"input\",\n \"link\",\n \"meta\",\n \"source\",\n]);\n\nconst TAG_NAME = /^[a-z][a-z0-9-]*$/;\nconst ATTRIBUTE_NAME = /^[a-z_:][a-z0-9_:.-]*$/i;\n\n/**\n * An inline `html-node` renders as `<tagName attrs>children</tagName>`. Only\n * non-empty string attributes are written, as Easy Email Pro does. A tag or\n * attribute name that could break out of the markup is dropped, the tag\n * falling back to `span`.\n */\nfunction serialiseHtmlNode(node: EasyEmailProNode): string {\n const rawTag = node.data?.[\"tagName\"];\n const lowered = typeof rawTag === \"string\" ? rawTag.toLowerCase() : \"\";\n const tagName = TAG_NAME.test(lowered) ? lowered : \"span\";\n\n let attrs = \"\";\n for (const [name, value] of Object.entries(node.attributes ?? {})) {\n if (typeof value !== \"string\" || !ATTRIBUTE_NAME.test(name)) continue;\n const trimmed = value.trim();\n if (trimmed === \"\") continue;\n attrs += ` ${name}=\"${escapeHtml(trimmed)}\"`;\n }\n\n if (VOID_TAGS.has(tagName)) return `<${tagName}${attrs} />`;\n return `<${tagName}${attrs}>${serialiseChildren(node.children)}</${tagName}>`;\n}\n\n/**\n * Easy Email Pro renders a `mergetag` as `{{ name }}`, the name being its\n * first text child and the marks on that child applying to the token.\n * `data.default` is not part of that output. A blank name has no variable to\n * keep.\n */\nfunction serialiseMergetag(node: EasyEmailProNode): string {\n const first = node.children?.[0];\n if (!first || !isTextNode(first)) return \"\";\n const name = first.text.trim();\n if (name === \"\") return \"\";\n return serialiseTextNode({ ...first, text: `{{ ${name} }}` });\n}\n\nfunction serialiseNode(node: EasyEmailProNode | EasyEmailProTextNode): string {\n if (node.type === \"line-break\") return \"<br>\";\n\n if (node.type === \"html-block-node\") {\n const element = node as EasyEmailProNode;\n const rawTag = element.data?.[\"tagName\"];\n const tagName =\n typeof rawTag === \"string\" && rawTag !== \"\" ? rawTag : \"div\";\n const inner = serialiseChildren(element.children);\n return `<${tagName}>${inner}</${tagName}>`;\n }\n\n if (node.type === \"html-node\") {\n return serialiseHtmlNode(node as EasyEmailProNode);\n }\n\n if (node.type === \"mergetag\")\n return serialiseMergetag(node as EasyEmailProNode);\n\n // Any other typed element has no inline rendering here and is dropped.\n if (typeof node.type === \"string\" && node.type !== \"\") return \"\";\n\n if (isTextNode(node)) return serialiseTextNode(node);\n\n return \"\";\n}\n\n/** Slate children → HTML for TitleBlock / ParagraphBlock content. */\nexport function serialiseChildren(\n children: Array<EasyEmailProNode | EasyEmailProTextNode> | undefined,\n): string {\n if (!children || children.length === 0) return \"\";\n let out = \"\";\n for (const child of children) {\n out += serialiseNode(child);\n }\n return out;\n}\n","import {\n createButtonBlock,\n createDividerBlock,\n createHtmlBlock,\n createImageBlock,\n createMenuBlock,\n createParagraphBlock,\n createSocialIconsBlock,\n createSpacerBlock,\n createTableBlock,\n createTitleBlock,\n createVideoBlock,\n findOpenTagEnd,\n generateId,\n} from \"@templatical/types\";\nimport type {\n Block,\n BlockStyles,\n BlockVisibility,\n ButtonBlock,\n DividerBlock,\n ImageBlock,\n HeadingLevel,\n MenuItemData,\n SocialIcon,\n SocialPlatform,\n TableCellData,\n TableRowData,\n} from \"@templatical/types\";\nimport {\n parseColor,\n parsePercent,\n parsePx,\n readPadding,\n} from \"./attribute-parser\";\nimport { isUnset, readAttr, type ResolveContext } from \"./normalize\";\nimport { serialiseChildren } from \"./rich-text\";\nimport type {\n ConversionStatus,\n EasyEmailProNode,\n EasyEmailProTextNode,\n ImportReportEntry,\n} from \"./types\";\n\nexport interface MapContext {\n resolve: ResolveContext;\n warnings: string[];\n /**\n * Width in px of the box the current node lays out in: the page, the inside\n * of a wrapper, band or hero, or a column's content box. Absent where the\n * converter cannot tell, and then no width is judged against it.\n */\n contentWidth?: number;\n}\n\nexport interface Converted {\n blocks: Block[];\n entries: ImportReportEntry[];\n}\n\nconst LEAF_TYPES = new Set([\n \"standard-paragraph\",\n \"standard-text\",\n \"standard-h1\",\n \"standard-h2\",\n \"standard-h3\",\n \"standard-h4\",\n \"standard-button\",\n \"standard-image\",\n \"standard-divider\",\n \"standard-spacer\",\n \"standard-navbar\",\n \"standard-social\",\n \"standard-table2\",\n \"marketing-countdown\",\n \"placeholder\",\n \"common-video\",\n \"raw\",\n]);\n\nconst SOCIAL_PLATFORMS = [\n \"facebook\",\n \"instagram\",\n \"twitter\",\n \"linkedin\",\n \"youtube\",\n \"tiktok\",\n \"pinterest\",\n \"whatsapp\",\n \"telegram\",\n \"github\",\n] as const satisfies ReadonlyArray<SocialPlatform>;\n\nconst ENTITIES: Record<string, string> = {\n \"&amp;\": \"&\",\n \"&lt;\": \"<\",\n \"&gt;\": \">\",\n \"&quot;\": '\"',\n \"&#39;\": \"'\",\n \"&apos;\": \"'\",\n \"&nbsp;\": \" \",\n};\n\n/**\n * Easy Email Pro writes `standard-table2-tr` / `standard-table2-td`; the plain\n * `tr` / `td` / `th` shape is read too.\n */\nconst TABLE_CELL_TYPES = new Set([\"standard-table2-td\", \"td\", \"th\"]);\n\nconst COUNTDOWN_NOTE =\n \"marketing-countdown GIF is the timer; Templatical countdown is Cloud-only\";\n\nexport function isLeafType(type: string | undefined): boolean {\n if (typeof type !== \"string\") return false;\n if (LEAF_TYPES.has(type)) return true;\n return headingLevelFromType(type) !== null;\n}\n\nexport function convertLeaf(\n node: EasyEmailProNode,\n map: MapContext,\n): Converted {\n const type = node.type;\n if (type === \"placeholder\") return empty();\n if (type === \"standard-paragraph\" || type === \"standard-text\") {\n return convertParagraph(node, map);\n }\n\n const heading = typeof type === \"string\" ? headingLevelFromType(type) : null;\n if (heading) return convertHeading(node, map, heading);\n\n switch (type) {\n case \"standard-button\":\n return convertButton(node, map);\n case \"standard-image\":\n return convertImage(node, map);\n case \"standard-divider\":\n return convertDivider(node, map);\n case \"standard-spacer\":\n return convertSpacer(node, map);\n case \"standard-navbar\":\n return convertNavbar(node, map);\n case \"standard-social\":\n return convertSocial(node, map);\n case \"standard-table2\":\n return convertTable(node, map);\n case \"marketing-countdown\":\n return convertCountdown(node, map);\n case \"common-video\":\n return convertVideo(node, map);\n case \"raw\":\n return convertRaw(node, map);\n default:\n return convertUnknown(node, map);\n }\n}\n\n/**\n * `standard-text` (the default text block) and `standard-paragraph` share one\n * shape and one MJML renderer, so both land here.\n */\nfunction convertParagraph(node: EasyEmailProNode, map: MapContext): Converted {\n return finish(\n createParagraphBlock({\n content: paragraphHtml(node, map),\n ...leafStyles(node, map),\n }),\n node,\n report(node.type ?? \"standard-paragraph\", \"paragraph\", \"converted\"),\n );\n}\n\n/**\n * ParagraphBlock has no color / fontSize / textAlign. Bake the cascaded\n * values into a wrapping `<p style>` (single wrapper, Unlayer/BeeFree class).\n */\nfunction paragraphHtml(node: EasyEmailProNode, map: MapContext): string {\n const html = serialiseChildren(node.children);\n const parts: string[] = [];\n const color = parseColor(readAttr(node, \"color\", map.resolve));\n if (color) parts.push(`color: ${escapeAttr(color)}`);\n const fontSize = setString(readAttr(node, \"font-size\", map.resolve));\n if (fontSize) parts.push(`font-size: ${escapeAttr(fontSize)}`);\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n if (align) parts.push(`text-align: ${align}`);\n if (parts.length === 0) return html;\n return `<p style=\"${parts.join(\"; \")}\">${html}</p>`;\n}\n\nfunction escapeAttr(value: string): string {\n let out = \"\";\n for (let i = 0; i < value.length; i++) {\n const ch = value[i];\n if (ch === \"&\") out += \"&amp;\";\n else if (ch === \"<\") out += \"&lt;\";\n else if (ch === \">\") out += \"&gt;\";\n else if (ch === '\"') out += \"&quot;\";\n else out += ch;\n }\n return out;\n}\n\nfunction convertHeading(\n node: EasyEmailProNode,\n map: MapContext,\n heading: { level: HeadingLevel; source: number },\n): Converted {\n const color = parseColor(readAttr(node, \"color\", map.resolve));\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n const clamped = heading.source > 4;\n return finish(\n createTitleBlock({\n content: serialiseChildren(node.children),\n level: heading.level,\n ...(color ? { color } : {}),\n ...(align ? { textAlign: align } : {}),\n ...leafStyles(node, map),\n }),\n node,\n clamped\n ? report(\n node.type ?? \"standard-h4\",\n \"title\",\n \"approximated\",\n `Heading level h${heading.source} clamped to 4 — Templatical titles support h1-h4.`,\n )\n : report(node.type ?? \"standard-h1\", \"title\", \"converted\"),\n );\n}\n\nfunction convertButton(node: EasyEmailProNode, map: MapContext): Converted {\n const fill = parseColor(readAttr(node, \"background-color\", map.resolve));\n const textColor = parseColor(readAttr(node, \"color\", map.resolve));\n const href = readAttr(node, \"href\", map.resolve);\n const width = buttonWidth(readAttr(node, \"width\", map.resolve));\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n const outlined =\n isBorderEnabled(readAttr(node, \"border-enabled\", map.resolve)) &&\n isUnset(readAttr(node, \"background-color\", map.resolve));\n\n const block: ButtonBlock = createButtonBlock({\n text: stripTags(serialiseChildren(node.children)),\n url: setString(href) ?? \"\",\n ...(fill ? { backgroundColor: fill } : {}),\n ...(textColor ? { textColor } : {}),\n ...(width !== undefined ? { width } : {}),\n ...(align ? { align } : {}),\n ...leafStyles(node, map),\n });\n // createButtonBlock defaults fill to #333333; an unset Pro fill with\n // border-enabled is an outlined button, which has no Templatical equivalent.\n if (outlined) block.backgroundColor = \"#ffffff\";\n\n return finish(\n block,\n node,\n outlined\n ? report(\n \"standard-button\",\n \"button\",\n \"approximated\",\n \"outlined button has no Templatical equivalent\",\n )\n : report(\"standard-button\", \"button\", \"converted\"),\n );\n}\n\nfunction convertImage(node: EasyEmailProNode, map: MapContext): Converted {\n const src = setString(readAttr(node, \"src\", map.resolve)) ?? \"\";\n const alt = setString(readAttr(node, \"alt\", map.resolve)) ?? \"\";\n const href = readAttr(node, \"href\", map.resolve);\n const linkUrl = setString(href);\n const radius = parsePx(readAttr(node, \"border-radius\", map.resolve));\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n const target = setString(readAttr(node, \"target\", map.resolve));\n const styles = leafStyles(node, map);\n const { left, right } = styles.styles.padding;\n const room =\n map.contentWidth === undefined\n ? undefined\n : map.contentWidth - left - right;\n const notes: string[] = [];\n const width = imageWidth(readAttr(node, \"width\", map.resolve), room, notes);\n\n return finish(\n createImageBlock({\n src,\n alt,\n width,\n ...(align ? { align } : {}),\n ...(radius !== undefined && radius > 0 ? { borderRadius: radius } : {}),\n ...(linkUrl ? { linkUrl } : {}),\n ...(linkUrl && target === \"_blank\" ? { linkOpenInNewTab: true } : {}),\n ...styles,\n }),\n node,\n notes.length > 0\n ? report(\"standard-image\", \"image\", \"approximated\", notes.join(\" \"))\n : report(\"standard-image\", \"image\", \"converted\"),\n );\n}\n\n/**\n * An image's `width` as `ImageBlock.width`. A missing, unreadable or `100%`\n * width is `\"full\"`, MJML's default. A px width stays px until it fills `room`,\n * the column less the image's own side padding, and then it is `\"full\"`. A\n * percentage under 100% becomes px of `room` and pushes a note, since a px\n * width keeps its size on a phone where a percentage shrinks with the column.\n */\nfunction imageWidth(\n value: unknown,\n room: number | undefined,\n notes: string[],\n): ImageBlock[\"width\"] {\n if (isUnset(value)) return \"full\";\n if (typeof value === \"string\" && value.trim().endsWith(\"%\")) {\n const percent = parsePercent(value);\n if (percent === null || percent <= 0 || percent >= 100) return \"full\";\n if (room === undefined) {\n notes.push(\n `Image width ${value.trim()} has no known column to resolve against; imported as full width.`,\n );\n return \"full\";\n }\n const px = Math.round((room * percent) / 100);\n if (px >= room) return \"full\";\n notes.push(\n `Image width ${value.trim()} imported as ${px}px, which keeps its size on a phone.`,\n );\n return px;\n }\n const px = parsePx(value);\n if (px === undefined || px <= 0) return \"full\";\n return room !== undefined && px >= room ? \"full\" : px;\n}\n\nfunction convertDivider(node: EasyEmailProNode, map: MapContext): Converted {\n const color = parseColor(readAttr(node, \"border-color\", map.resolve));\n const thickness = parsePx(readAttr(node, \"border-width\", map.resolve));\n const lineStyle = asLineStyle(readAttr(node, \"border-style\", map.resolve));\n const styles = leafStyles(node, map);\n const { left, right } = styles.styles.padding;\n const room =\n map.contentWidth === undefined\n ? undefined\n : map.contentWidth - left - right;\n return finish(\n createDividerBlock({\n ...(color ? { color } : {}),\n ...(thickness !== undefined ? { thickness } : {}),\n ...(lineStyle ? { lineStyle } : {}),\n width: dividerWidth(readAttr(node, \"width\", map.resolve), room),\n ...styles,\n }),\n node,\n report(\"standard-divider\", \"divider\", \"converted\"),\n );\n}\n\n/**\n * A missing or `100%` width is `\"full\"`. Any other percentage stays a share of\n * the column, clamped to 0-100 and rounded to two decimals so it stays a\n * `DividerPercentWidth`. A px width stays px until it fills `room`, the space\n * the column leaves the line once the divider's own padding is off, and then\n * it is `\"full\"`. An unreadable width falls back to `\"full\"`, MJML's default.\n */\nfunction dividerWidth(\n value: unknown,\n room: number | undefined,\n): DividerBlock[\"width\"] {\n if (isUnset(value)) return \"full\";\n if (typeof value === \"string\" && value.trim().endsWith(\"%\")) {\n const percent = parsePercent(value);\n if (percent === null) return \"full\";\n const clamped = Math.min(100, Math.max(0, percent));\n const rounded = Math.round(clamped * 100) / 100;\n return rounded >= 100 ? \"full\" : `${rounded}%`;\n }\n const px = parsePx(value);\n if (px === undefined) return \"full\";\n return room !== undefined && px >= room ? \"full\" : px;\n}\n\nfunction convertSpacer(node: EasyEmailProNode, map: MapContext): Converted {\n const height = parsePx(readAttr(node, \"height\", map.resolve));\n return finish(\n createSpacerBlock({\n ...(height !== undefined ? { height } : {}),\n ...leafStyles(node, map),\n }),\n node,\n report(\"standard-spacer\", \"spacer\", \"converted\"),\n );\n}\n\nfunction convertNavbar(node: EasyEmailProNode, map: MapContext): Converted {\n const items: MenuItemData[] = [];\n for (const child of node.children ?? []) {\n if (!isElement(child) || child.type !== \"standard-navbar-link\") continue;\n const href = readAttr(child, \"href\", map.resolve);\n const target = setString(readAttr(child, \"target\", map.resolve));\n const color = parseColor(readAttr(child, \"color\", map.resolve));\n const weight = setString(readAttr(child, \"font-weight\", map.resolve));\n const deco = setString(readAttr(child, \"text-decoration\", map.resolve));\n items.push({\n id: generateId(),\n text: stripTags(serialiseChildren(child.children)),\n url: setString(href) ?? \"\",\n openInNewTab: target === \"_blank\",\n bold: weight === \"bold\" || weight === \"700\",\n underline: deco !== undefined && deco.includes(\"underline\"),\n ...(color ? { color } : {}),\n });\n }\n if (items.length === 0) return empty();\n\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n return finish(\n createMenuBlock({\n items,\n ...(align ? { textAlign: align } : {}),\n ...leafStyles(node, map),\n }),\n node,\n report(\"standard-navbar\", \"menu\", \"converted\"),\n );\n}\n\nfunction convertSocial(node: EasyEmailProNode, map: MapContext): Converted {\n const icons: SocialIcon[] = [];\n let customSrc = false;\n for (const child of node.children ?? []) {\n if (!isElement(child) || child.type !== \"standard-social-element\") continue;\n const href = readAttr(child, \"href\", map.resolve);\n const src = readAttr(child, \"src\", map.resolve);\n if (typeof src === \"string\" && !isUnset(src)) customSrc = true;\n icons.push({\n id: generateId(),\n platform: inferPlatform(href, src),\n url: setString(href) ?? \"\",\n });\n }\n if (icons.length === 0) return empty();\n\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n return finish(\n createSocialIconsBlock({\n icons,\n ...(align ? { align } : {}),\n ...leafStyles(node, map),\n }),\n node,\n customSrc\n ? report(\n \"standard-social\",\n \"social\",\n \"approximated\",\n \"custom src was present; SocialIconsBlock has no custom PNG\",\n )\n : report(\"standard-social\", \"social\", \"converted\"),\n );\n}\n\nfunction convertTable(node: EasyEmailProNode, map: MapContext): Converted {\n const rows: TableRowData[] = [];\n let hasHeaderRow = false;\n let first = true;\n for (const row of collectRows(node)) {\n const cells: TableCellData[] = [];\n let rowHasTh = false;\n for (const cell of row.children ?? []) {\n if (!isElement(cell) || !TABLE_CELL_TYPES.has(cell.type ?? \"\")) continue;\n if (cell.type === \"th\") rowHasTh = true;\n cells.push({\n id: generateId(),\n content: serialiseChildren(cell.children),\n });\n }\n if (cells.length === 0) continue;\n if (first) {\n hasHeaderRow = rowHasTh;\n first = false;\n }\n rows.push({ id: generateId(), cells });\n }\n if (rows.length === 0) return empty();\n\n const align = parseAlign(readAttr(node, \"align\", map.resolve));\n const color = parseColor(readAttr(node, \"color\", map.resolve));\n return finish(\n createTableBlock({\n rows,\n hasHeaderRow,\n ...(align ? { textAlign: align } : {}),\n ...(color ? { color } : {}),\n ...leafStyles(node, map),\n }),\n node,\n report(\"standard-table2\", \"table\", \"converted\"),\n );\n}\n\nfunction convertCountdown(node: EasyEmailProNode, map: MapContext): Converted {\n const blocks: Block[] = [];\n const entries: ImportReportEntry[] = [];\n\n for (const child of node.children ?? []) {\n if (!isElement(child)) continue;\n const remapped = remapOverlay(child);\n if (!remapped) continue;\n const inner = convertLeaf(remapped, map);\n for (const block of inner.blocks) blocks.push(block);\n for (const entry of inner.entries) {\n entries.push({\n sourceTag: \"marketing-countdown\",\n templaticalBlockType: entry.templaticalBlockType,\n status: \"approximated\",\n note: entry.note ? `${entry.note} marketing-countdown` : COUNTDOWN_NOTE,\n });\n }\n }\n\n const src = readAttr(node, \"src\", map.resolve);\n if (typeof src === \"string\" && !isUnset(src)) {\n const image = createImageBlock({\n src,\n ...leafStyles(node, map),\n });\n const visibility = readVisibility(node);\n if (visibility) image.visibility = visibility;\n blocks.push(image);\n entries.push({\n sourceTag: \"marketing-countdown\",\n templaticalBlockType: \"image\",\n status: \"approximated\",\n note: COUNTDOWN_NOTE,\n });\n }\n\n return { blocks, entries };\n}\n\nfunction convertVideo(node: EasyEmailProNode, map: MapContext): Converted {\n const url = firstUrl(node, map);\n if (!url) return convertUnknown(node, map);\n return finish(\n createVideoBlock({\n url,\n ...leafStyles(node, map),\n }),\n node,\n report(\"common-video\", \"video\", \"converted\"),\n );\n}\n\n/** `raw` is `<mj-raw>{data.content}</mj-raw>`: the markup moves across as is. */\nfunction convertRaw(node: EasyEmailProNode, map: MapContext): Converted {\n const content = node.data?.[\"content\"];\n if (typeof content !== \"string\") return convertUnknown(node, map);\n return finish(\n createHtmlBlock({\n content,\n ...leafStyles(node, map),\n }),\n node,\n report(\"raw\", \"html\", \"converted\"),\n );\n}\n\nfunction convertUnknown(node: EasyEmailProNode, map: MapContext): Converted {\n const sourceTag = node.type ?? \"unknown\";\n return finish(\n createHtmlBlock({\n content: JSON.stringify(node),\n ...leafStyles(node, map),\n }),\n node,\n report(\n sourceTag,\n \"html\",\n \"html-fallback\",\n `Unknown Easy Email Pro type \"${sourceTag}\"; preserved as HTML.`,\n ),\n );\n}\n\nfunction remapOverlay(child: EasyEmailProNode): EasyEmailProNode | null {\n if (child.type === \"text\") {\n return { ...child, type: \"standard-paragraph\" };\n }\n if (child.type === \"standard-paragraph\" || child.type === \"standard-text\") {\n return child;\n }\n if (typeof child.type === \"string\" && headingLevelFromType(child.type)) {\n return child;\n }\n return null;\n}\n\nfunction collectRows(node: EasyEmailProNode): EasyEmailProNode[] {\n const rows: EasyEmailProNode[] = [];\n for (const child of node.children ?? []) {\n if (!isElement(child)) continue;\n if (isTableRow(child)) {\n rows.push(child);\n continue;\n }\n for (const inner of child.children ?? []) {\n if (isElement(inner) && isTableRow(inner)) rows.push(inner);\n }\n }\n return rows;\n}\n\nfunction isTableRow(node: EasyEmailProNode): boolean {\n return node.type === \"standard-table2-tr\" || node.type === \"tr\";\n}\n\nfunction firstUrl(node: EasyEmailProNode, map: MapContext): string | undefined {\n for (const key of [\"src\", \"href\", \"url\"] as const) {\n const value = readAttr(node, key, map.resolve);\n if (typeof value === \"string\" && !isUnset(value)) return value;\n }\n return undefined;\n}\n\nfunction inferPlatform(href: unknown, src: unknown): SocialPlatform {\n const host = hostname(typeof href === \"string\" ? href : \"\");\n for (const platform of SOCIAL_PLATFORMS) {\n if (host.includes(platform)) return platform;\n }\n const path = pathOf(typeof src === \"string\" ? src : \"\");\n for (const platform of SOCIAL_PLATFORMS) {\n if (path.includes(platform)) return platform;\n }\n return \"website\";\n}\n\nfunction hostname(href: string): string {\n const lower = href.toLowerCase();\n const scheme = lower.indexOf(\"://\");\n const rest = scheme === -1 ? lower : lower.slice(scheme + 3);\n const slash = rest.indexOf(\"/\");\n const hostport = slash === -1 ? rest : rest.slice(0, slash);\n const colon = hostport.indexOf(\":\");\n return colon === -1 ? hostport : hostport.slice(0, colon);\n}\n\nfunction pathOf(src: string): string {\n const lower = src.toLowerCase();\n const scheme = lower.indexOf(\"://\");\n const rest = scheme === -1 ? lower : lower.slice(scheme + 3);\n const slash = rest.indexOf(\"/\");\n return slash === -1 ? rest : rest.slice(slash);\n}\n\nfunction headingLevelFromType(\n type: string,\n): { level: HeadingLevel; source: number } | null {\n if (!type.startsWith(\"standard-h\")) return null;\n const raw = type.slice(\"standard-h\".length);\n if (raw.length === 0) return null;\n for (let i = 0; i < raw.length; i++) {\n const code = raw.charCodeAt(i);\n if (code < 48 || code > 57) return null;\n }\n const source = Number(raw);\n if (!Number.isFinite(source) || source < 1) return null;\n const level = (source > 4 ? 4 : source) as HeadingLevel;\n return { level, source };\n}\n\nfunction leafStyles(\n node: EasyEmailProNode,\n map: MapContext,\n): { styles: BlockStyles } {\n return {\n styles: {\n padding: readPadding((key) => readAttr(node, key, map.resolve)),\n },\n };\n}\n\nfunction finish(\n block: Block,\n node: EasyEmailProNode,\n entry: ImportReportEntry,\n): Converted {\n const visibility = readVisibility(node);\n if (visibility) block.visibility = visibility;\n return { blocks: [block], entries: [entry] };\n}\n\nfunction readVisibility(node: EasyEmailProNode): BlockVisibility | undefined {\n if (node.visible === \"desktop\") return { desktop: true, mobile: false };\n if (node.visible === \"mobile\") return { desktop: false, mobile: true };\n return undefined;\n}\n\nfunction report(\n sourceTag: string,\n templaticalBlockType: string,\n status: ConversionStatus,\n note?: string,\n): ImportReportEntry {\n return {\n sourceTag,\n templaticalBlockType,\n status,\n ...(note ? { note } : {}),\n };\n}\n\nfunction empty(): Converted {\n return { blocks: [], entries: [] };\n}\n\nfunction isElement(\n node: EasyEmailProNode | EasyEmailProTextNode,\n): node is EasyEmailProNode {\n return typeof node.type === \"string\" && node.type !== \"\";\n}\n\nfunction isBorderEnabled(value: unknown): boolean {\n return value === true || value === \"true\";\n}\n\nfunction buttonWidth(value: unknown): number | \"full\" | undefined {\n if (isUnset(value)) return undefined;\n if (typeof value === \"string\" && value.trim() === \"100%\") return \"full\";\n return parsePx(value);\n}\n\nfunction parseAlign(value: unknown): \"left\" | \"center\" | \"right\" | undefined {\n if (typeof value !== \"string\") return undefined;\n const align = value.trim().toLowerCase();\n if (align === \"left\" || align === \"center\" || align === \"right\") return align;\n return undefined;\n}\n\nfunction asLineStyle(\n value: unknown,\n): \"solid\" | \"dashed\" | \"dotted\" | undefined {\n if (typeof value !== \"string\") return undefined;\n const style = value.trim().toLowerCase();\n if (style === \"solid\" || style === \"dashed\" || style === \"dotted\") {\n return style;\n }\n return undefined;\n}\n\nfunction setString(value: unknown): string | undefined {\n if (typeof value !== \"string\" || isUnset(value)) return undefined;\n return value;\n}\n\n/** Button labels are plain text — strip tags the serialiser may have emitted. */\nfunction stripTags(html: string): string {\n if (html === \"\") return \"\";\n return decodeEntities(removeTags(html)).trim();\n}\n\nfunction removeTags(html: string): string {\n let out = \"\";\n let i = 0;\n while (i < html.length) {\n const open = html.indexOf(\"<\", i);\n if (open === -1) {\n out += html.slice(i);\n break;\n }\n out += html.slice(i, open);\n const tagEnd = findOpenTagEnd(html, open + 1);\n if (tagEnd === -1) {\n out += html.slice(open);\n break;\n }\n i = tagEnd + 1;\n }\n return out;\n}\n\nfunction decodeEntities(text: string): string {\n let out = \"\";\n let i = 0;\n while (i < text.length) {\n if (text[i] === \"&\") {\n const semi = text.indexOf(\";\", i + 1);\n if (semi !== -1 && semi - i <= 6) {\n const mapped = ENTITIES[text.slice(i, semi + 1)];\n if (mapped !== undefined) {\n out += mapped;\n i = semi + 1;\n continue;\n }\n }\n }\n out += text[i];\n i++;\n }\n return out;\n}\n","import type { ColumnLayout } from \"@templatical/types\";\n\nconst LAYOUT_SHAPES: Array<{ layout: ColumnLayout; percents: number[] }> = [\n { layout: \"1\", percents: [100] },\n { layout: \"2\", percents: [50, 50] },\n { layout: \"1-2\", percents: [33.33, 66.67] },\n { layout: \"2-1\", percents: [66.67, 33.33] },\n { layout: \"3\", percents: [33.33, 33.33, 33.34] },\n];\n\nconst WIDTH_TOLERANCE = 2;\n\nexport const COLUMN_COUNT: Record<ColumnLayout, number> = {\n \"1\": 1,\n \"2\": 2,\n \"3\": 3,\n \"2-1\": 2,\n \"1-2\": 2,\n};\n\nexport function columnPixels(\n layout: ColumnLayout,\n container: number,\n): number[] {\n switch (layout) {\n case \"2\":\n return [container / 2, container / 2];\n case \"3\":\n return [container / 3, container / 3, container / 3];\n case \"1-2\":\n return [container / 3, (container * 2) / 3];\n case \"2-1\":\n return [(container * 2) / 3, container / 3];\n default:\n return [container];\n }\n}\n\n/**\n * Resolve column widths to one of the five layouts `ColumnLayout` allows.\n *\n * `exact: false` means the caller reports `approximated` — Chamaileon permits\n * any column count at any width and this union permits five shapes, so this is\n * the importer's main irreducible loss.\n */\nexport function matchColumnLayout(percents: Array<number | null>): {\n layout: ColumnLayout;\n exact: boolean;\n} {\n const count = percents.length;\n if (count === 0) return { layout: \"1\", exact: true };\n\n // All-unset is \"distribute equally\", which is exactly what the n-column\n // layout means — not a missing value to approximate around.\n if (percents.every((p) => p === null)) {\n if (count === 1) return { layout: \"1\", exact: true };\n if (count === 2) return { layout: \"2\", exact: true };\n if (count === 3) return { layout: \"3\", exact: true };\n return { layout: \"3\", exact: false };\n }\n\n const known = percents.filter((p): p is number => p !== null);\n const unsetCount = count - known.length;\n const remainder =\n unsetCount === 0\n ? 0\n : Math.max(0, 100 - known.reduce((a, b) => a + b, 0)) / unsetCount;\n const resolved = percents.map((p) => p ?? remainder);\n\n const sameCount = LAYOUT_SHAPES.filter((s) => s.percents.length === count);\n\n for (const shape of sameCount) {\n if (\n shape.percents.every(\n (want, i) => Math.abs(want - resolved[i]) <= WIDTH_TOLERANCE,\n )\n ) {\n return { layout: shape.layout, exact: true };\n }\n }\n\n const candidates =\n sameCount.length > 0\n ? sameCount\n : LAYOUT_SHAPES.filter((s) => s.layout === \"3\");\n\n let best = candidates[0];\n let bestError = Infinity;\n for (const shape of candidates) {\n const error = shape.percents.reduce(\n (sum, want, i) => sum + Math.abs(want - (resolved[i] ?? 0)),\n 0,\n );\n if (error < bestError) {\n bestError = error;\n best = shape;\n }\n }\n\n return { layout: best.layout, exact: false };\n}\n\n/** Convert absolute px column widths to percents of `bodyWidth`. */\nexport function widthsToPercents(\n widthsPx: Array<number | undefined>,\n bodyWidth: number,\n): Array<number | null> {\n return widthsPx.map((w) => (w === undefined ? null : (w / bodyWidth) * 100));\n}\n","import { createSectionBlock } from \"@templatical/types\";\nimport type {\n Block,\n BlockVisibility,\n SectionBlock,\n SectionWrapper,\n} from \"@templatical/types\";\nimport {\n parseColor,\n parsePercent,\n parsePx,\n readMjmlBackgroundImage,\n readMjmlHero,\n readPadding,\n} from \"./attribute-parser\";\nimport { convertLeaf, type Converted, type MapContext } from \"./block-mapper\";\nimport { COLUMN_COUNT, columnPixels, matchColumnLayout } from \"./column-layout\";\nimport { isUnset, readAttr } from \"./normalize\";\nimport type {\n ConversionStatus,\n EasyEmailProNode,\n EasyEmailProTextNode,\n ImportReportEntry,\n} from \"./types\";\n\nexport function buildTopLevel(\n node: EasyEmailProNode,\n map: MapContext,\n): Converted {\n switch (node.type) {\n case \"standard-wrapper\":\n return buildWrapper(node, map);\n case \"standard-hero\":\n return buildHero(node, map);\n case \"standard-section\":\n return buildSection(node, map);\n default:\n return empty();\n }\n}\n\nfunction buildSection(node: EasyEmailProNode, map: MapContext): Converted {\n const plan = collectSlots(node);\n const rawWidths = plan.columns.map((column) =>\n readAttr(column, \"width\", map.resolve),\n );\n const { layout, exact } = matchColumnLayout(\n rawWidths.map((width) => parsePercent(width)),\n );\n const slots = COLUMN_COUNT[layout];\n const sectionWidth = insideWidth(map.contentWidth, node, map);\n const slotWidths =\n sectionWidth === undefined ? undefined : columnPixels(layout, sectionWidth);\n const leftover = convertFlow(\n plan.leftovers,\n withContentWidth(map, slotWidths?.[0]),\n );\n const children: Block[][] = Array.from({ length: slots }, () => []);\n if (leftover.blocks.length > 0) {\n children[0].push(...leftover.blocks);\n }\n\n const entries = leftover.entries;\n plan.columns.forEach((column, index) => {\n const slot = Math.min(index, slots - 1);\n const inner = convertFlow(\n column.children ?? [],\n withContentWidth(map, insideWidth(slotWidths?.[slot], column, map)),\n );\n children[slot].push(...inner.blocks);\n for (const entry of inner.entries) entries.push(entry);\n });\n\n const reasons: string[] = [];\n if (plan.mixed) {\n reasons.push(\n \"Section mixed columns and groups; flattened into the column flow.\",\n );\n }\n if (!exact) {\n if (plan.columns.length > slots) {\n reasons.push(\n `${plan.columns.length}-column layout has no exact Templatical equivalent; folded onto \"${layout}\".`,\n );\n } else {\n const shown = rawWidths\n .map((width) =>\n typeof width === \"string\" && !isUnset(width) ? width : \"auto\",\n )\n .join(\", \");\n reasons.push(\n `Column widths ${shown} have no exact Templatical layout; resolved to \"${layout}\".`,\n );\n }\n }\n\n const section = createSectionBlock();\n section.columns = layout;\n section.children = children;\n paintSection(section, node, map, {\n stackOnMobile: plan.grouped ? false : undefined,\n });\n const background = readMjmlBackgroundImage(\n (name) => readAttr(node, name, map.resolve),\n \"Section\",\n map.contentWidth,\n );\n if (background) {\n section.backgroundImage = background.image;\n reasons.push(...background.notes);\n }\n entries.unshift(\n sectionEntry(\n node,\n reasons.length > 0 ? \"approximated\" : \"converted\",\n reasons.length > 0 ? reasons.join(\" \") : undefined,\n ),\n );\n return { blocks: [section], entries };\n}\n\n/**\n * A `standard-hero` as a one-column section: its children walk into the one\n * column, and its mode, height and background map onto `hero` and\n * `backgroundImage` (`readMjmlHero`). Its fill follows `paintSection`; where\n * that finds none and the source leaves `background-color` out, it is\n * mj-hero's own white.\n */\nfunction buildHero(node: EasyEmailProNode, map: MapContext): Converted {\n const entries: ImportReportEntry[] = [];\n const inner = convertFlow(\n node.children ?? [],\n withContentWidth(map, insideWidth(map.contentWidth, node, map)),\n );\n for (const entry of inner.entries) entries.push(entry);\n\n const section = createSectionBlock();\n section.columns = \"1\";\n section.children = [inner.blocks];\n paintSection(section, node, map);\n // An explicit `transparent` stays unset because `isUnset` reads it as no\n // colour, so the hero paints nothing, as its MJML does. Only a source that\n // leaves `background-color` out takes mj-hero's white.\n const ownFill = readAttr(node, \"background-color\", map.resolve);\n const fillAbsent =\n ownFill === undefined ||\n ownFill === null ||\n (typeof ownFill === \"string\" && ownFill.trim() === \"\");\n if (!section.styles.backgroundColor && fillAbsent) {\n section.styles.backgroundColor = \"#ffffff\";\n }\n\n const read = readMjmlHero(\n (name) => readAttr(node, name, map.resolve),\n \"Hero\",\n map.contentWidth,\n );\n if (read.image) section.backgroundImage = read.image;\n if (read.hero) section.hero = read.hero;\n\n entries.unshift(\n sectionEntry(\n node,\n read.notes.length > 0 ? \"approximated\" : \"converted\",\n read.notes.length > 0 ? read.notes.join(\" \") : undefined,\n ),\n );\n return { blocks: [section], entries };\n}\n\nfunction buildWrapper(node: EasyEmailProNode, map: MapContext): Converted {\n const blocks: Block[] = [];\n const entries: ImportReportEntry[] = [];\n const childMap = withContentWidth(\n map,\n insideWidth(map.contentWidth, node, map),\n );\n for (const child of elements(node)) {\n if (child.type === \"placeholder\") continue;\n const inner = buildTopLevel(child, childMap);\n for (const block of inner.blocks) blocks.push(block);\n for (const entry of inner.entries) entries.push(entry);\n }\n\n if (!blocks.some(isSection)) {\n return {\n blocks: [],\n entries: [\n {\n sourceTag: \"standard-wrapper\",\n templaticalBlockType: null,\n status: \"skipped\",\n note: \"An empty standard-wrapper produces nothing.\",\n },\n ],\n };\n }\n\n applyWrapper(node, blocks, entries, map);\n return { blocks, entries };\n}\n\n/**\n * Paint `node`'s `mj-wrapper` band onto every section in `blocks`. A section\n * holds one band, so a band around several sections is copied onto each and\n * their `converted` entries become `approximated`. A band image value with no\n * exact keyword is noted on every section entry, or on one entry of the\n * band's own when its sections (bare leaves) have none.\n */\nexport function applyWrapper(\n node: EasyEmailProNode,\n blocks: Block[],\n entries: ImportReportEntry[],\n map: MapContext,\n): void {\n const sections = blocks.filter(isSection);\n if (sections.length === 0) return;\n\n const { wrapper, notes } = readWrapper(node, map);\n for (const section of sections) {\n section.wrapper = {\n ...wrapper,\n ...(wrapper.backgroundImage\n ? {\n backgroundImage: {\n ...wrapper.backgroundImage,\n position: { ...wrapper.backgroundImage.position },\n },\n }\n : {}),\n };\n }\n if (sections.length > 1) {\n const note = `${node.type ?? \"standard-wrapper\"} holding ${sections.length} sections was applied to each of them — Templatical has no multi-section band.`;\n for (const entry of entries) {\n if (entry.templaticalBlockType !== \"section\") continue;\n if (entry.status !== \"converted\") continue;\n entry.status = \"approximated\";\n entry.note = note;\n }\n }\n if (notes.length > 0) {\n const sectionEntries = entries.filter(\n (entry) => entry.templaticalBlockType === \"section\",\n );\n if (sectionEntries.length === 0) {\n entries.push({\n sourceTag: node.type ?? \"standard-wrapper\",\n templaticalBlockType: \"section\",\n status: \"approximated\",\n note: notes.join(\" \"),\n });\n }\n for (const entry of sectionEntries) {\n entry.status = \"approximated\";\n entry.note = [entry.note, ...notes].filter(Boolean).join(\" \");\n }\n }\n}\n\n/** `width` less `node`'s own left and right padding; unknown stays unknown. */\nexport function insideWidth(\n width: number | undefined,\n node: EasyEmailProNode,\n map: MapContext,\n): number | undefined {\n if (width === undefined) return undefined;\n const padding = readPadding((key) => readAttr(node, key, map.resolve));\n return Math.max(0, width - padding.left - padding.right);\n}\n\nexport function withContentWidth(\n map: MapContext,\n contentWidth: number | undefined,\n): MapContext {\n return { ...map, contentWidth };\n}\n\nfunction isSection(block: Block): block is SectionBlock {\n return block.type === \"section\";\n}\n\n/**\n * Direct columns become slots. A sole `standard-group` of columns becomes\n * those slots with `stackOnMobile: false`. Mixed group + columns flatten\n * into the slot list and are approximated.\n */\nfunction collectSlots(section: EasyEmailProNode): {\n columns: EasyEmailProNode[];\n leftovers: EasyEmailProNode[];\n grouped: boolean;\n mixed: boolean;\n} {\n const kids = structuralChildren(section);\n\n if (kids.every((kid) => kid.type === \"standard-column\")) {\n return { columns: kids, leftovers: [], grouped: false, mixed: false };\n }\n\n if (kids.length === 1 && kids[0].type === \"standard-group\") {\n const groupKids = structuralChildren(kids[0]);\n if (groupKids.every((kid) => kid.type === \"standard-column\")) {\n return {\n columns: groupKids,\n leftovers: [],\n grouped: true,\n mixed: false,\n };\n }\n }\n\n const columns: EasyEmailProNode[] = [];\n const leftovers: EasyEmailProNode[] = [];\n let grouped = false;\n for (const kid of kids) {\n if (kid.type === \"standard-column\") {\n columns.push(kid);\n continue;\n }\n if (kid.type === \"standard-group\") {\n grouped = true;\n for (const inner of structuralChildren(kid)) {\n if (inner.type === \"standard-column\") columns.push(inner);\n else leftovers.push(inner);\n }\n continue;\n }\n leftovers.push(kid);\n }\n return { columns, leftovers, grouped, mixed: true };\n}\n\nfunction convertFlow(\n nodes: Array<EasyEmailProNode | EasyEmailProTextNode> | undefined,\n map: MapContext,\n): Converted {\n const blocks: Block[] = [];\n const entries: ImportReportEntry[] = [];\n for (const child of nodes ?? []) {\n if (!isElement(child)) continue;\n if (child.type === \"placeholder\") continue;\n if (child.type === \"standard-group\") {\n const innerColumns = structuralChildren(child).filter(\n (node) => node.type === \"standard-column\",\n );\n entries.push({\n sourceTag: \"standard-group\",\n templaticalBlockType: null,\n status: \"approximated\",\n note: `nested group flattened (${innerColumns.length} columns)`,\n });\n for (const column of innerColumns) {\n const inner = convertFlow(column.children, map);\n for (const block of inner.blocks) blocks.push(block);\n for (const entry of inner.entries) entries.push(entry);\n }\n continue;\n }\n if (child.type === \"standard-column\") {\n const inner = convertFlow(child.children, map);\n for (const block of inner.blocks) blocks.push(block);\n for (const entry of inner.entries) entries.push(entry);\n continue;\n }\n const converted = convertLeaf(child, map);\n for (const block of converted.blocks) blocks.push(block);\n for (const entry of converted.entries) entries.push(entry);\n }\n return { blocks, entries };\n}\n\n/** `createSectionBlock()` first, then mutate fill — never a partial `styles`. */\nfunction paintSection(\n section: SectionBlock,\n node: EasyEmailProNode,\n map: MapContext,\n extras?: { stackOnMobile?: boolean },\n): void {\n section.styles.padding = readPadding((key) =>\n readAttr(node, key, map.resolve),\n );\n const fill = sectionFill(node, map);\n if (fill) section.styles.backgroundColor = fill;\n const radius = parsePx(readAttr(node, \"border-radius\", map.resolve));\n if (radius !== undefined && radius > 0) section.borderRadius = radius;\n if (extras?.stackOnMobile === false) section.stackOnMobile = false;\n const visibility = readVisibility(node);\n if (visibility) section.visibility = visibility;\n}\n\nfunction sectionFill(\n node: EasyEmailProNode,\n map: MapContext,\n): string | undefined {\n const own = parseColor(readAttr(node, \"background-color\", map.resolve));\n if (own) return own;\n return parseColor(\n readAttr(map.resolve.page, \"content-background-color\", map.resolve),\n );\n}\n\nfunction readWrapper(\n node: EasyEmailProNode,\n map: MapContext,\n): { wrapper: SectionWrapper; notes: string[] } {\n const backgroundColor = parseColor(\n readAttr(node, \"background-color\", map.resolve),\n );\n const padding = readPadding((key) => readAttr(node, key, map.resolve));\n const radius = parsePx(readAttr(node, \"border-radius\", map.resolve));\n const background = readMjmlBackgroundImage(\n (name) => readAttr(node, name, map.resolve),\n \"Wrapper\",\n map.contentWidth,\n );\n return {\n wrapper: {\n ...(backgroundColor ? { backgroundColor } : {}),\n padding,\n ...(radius !== undefined && radius > 0 ? { borderRadius: radius } : {}),\n ...(background ? { backgroundImage: background.image } : {}),\n },\n notes: background?.notes ?? [],\n };\n}\n\nfunction sectionEntry(\n node: EasyEmailProNode,\n status: ConversionStatus,\n note?: string,\n): ImportReportEntry {\n return {\n sourceTag: node.type ?? \"standard-section\",\n templaticalBlockType: \"section\",\n status,\n ...(note ? { note } : {}),\n };\n}\n\nfunction readVisibility(node: EasyEmailProNode): BlockVisibility | undefined {\n if (node.visible === \"desktop\") return { desktop: true, mobile: false };\n if (node.visible === \"mobile\") return { desktop: false, mobile: true };\n return undefined;\n}\n\nfunction structuralChildren(node: EasyEmailProNode): EasyEmailProNode[] {\n return elements(node).filter((child) => child.type !== \"placeholder\");\n}\n\nfunction elements(node: EasyEmailProNode): EasyEmailProNode[] {\n const out: EasyEmailProNode[] = [];\n for (const child of node.children ?? []) {\n if (isElement(child)) out.push(child);\n }\n return out;\n}\n\nfunction isElement(\n node: EasyEmailProNode | EasyEmailProTextNode,\n): node is EasyEmailProNode {\n return typeof node.type === \"string\" && node.type !== \"\";\n}\n\nfunction empty(): Converted {\n return { blocks: [], entries: [] };\n}\n","import {\n canonicalFontStack,\n createDefaultTemplateContent,\n createSectionBlock,\n DEFAULT_TEMPLATE_DEFAULTS,\n} from \"@templatical/types\";\nimport type {\n Block,\n TemplateContent,\n TemplateSettings,\n} from \"@templatical/types\";\nimport { parseColor, parsePx } from \"./attribute-parser\";\nimport { convertLeaf, isLeafType, type MapContext } from \"./block-mapper\";\nimport {\n contextFromPage,\n isUnset,\n readAttr,\n unwrapDocument,\n withWidgetInput,\n} from \"./normalize\";\nimport {\n applyWrapper,\n buildTopLevel,\n insideWidth,\n withContentWidth,\n} from \"./section-builder\";\nimport type {\n EasyEmailProDocument,\n EasyEmailProNode,\n EasyEmailProPage,\n EasyEmailProTextNode,\n ImportReportEntry,\n ImportResult,\n} from \"./types\";\n\nconst INVALID_MESSAGE =\n \"Invalid Easy Email Pro template: expected a page JSON object (EmailTemplate { subject, content } or the page element).\";\nconst OSS_MESSAGE =\n \"Invalid Easy Email Pro template: this looks like open-source Easy Email JSON, not Easy Email Pro (expected standard-* children).\";\nconst EMPTY_WARNING =\n \"No convertible content was found in the Easy Email Pro page. Check that page.children holds at least one standard-section.\";\nconst MOBILE_WARNING =\n \"mobileAttributes were dropped; Templatical has no per-viewport padding.\";\n\nfunction varWarning(resolved: number, unresolved: number): string {\n return `Resolved ${resolved} $var() values, ${unresolved} left unresolved.`;\n}\n\nconst OSS_CHILD_TYPES = new Set([\n \"section\",\n \"column\",\n \"text\",\n \"button\",\n \"image\",\n \"wrapper\",\n \"hero\",\n \"navbar\",\n \"social\",\n]);\n\nconst STRUCTURE_TYPES = new Set([\n \"standard-section\",\n \"standard-wrapper\",\n \"standard-hero\",\n]);\n\nconst WIDGET_TYPES = new Set([\"section_widget\", \"wrapper_widget\"]);\n\n/**\n * Header and footer bands. Easy Email Pro renders each as an `mj-wrapper`\n * carrying the node's own attributes around `data.content`, whose items are\n * page children.\n */\nconst PAGE_BAND_TYPES = new Set([\"page-header\", \"page-footer\"]);\n\n/**\n * `DEFAULT_TEMPLATE_DEFAULTS` is typed `Partial<TemplateSettings>` so a\n * consumer can override any subset, but its own literal always sets the six\n * required fields. Narrowing once here is what lets each fallback come out as\n * `number`/`string`/`boolean` rather than `| undefined`.\n */\nconst REQUIRED_DEFAULTS = DEFAULT_TEMPLATE_DEFAULTS as Required<\n Pick<\n TemplateSettings,\n | \"width\"\n | \"backgroundColor\"\n | \"textColor\"\n | \"linkUnderline\"\n | \"fontFamily\"\n | \"locale\"\n >\n>;\n\n/**\n * Convert an Easy Email Pro page (or EmailTemplate envelope) into a\n * Templatical template. Accepts a bare `page` element, an\n * `EmailTemplate { subject, content }` envelope, or a JSON string of either.\n */\nexport function convertEasyEmailProTemplate(\n doc: EasyEmailProDocument | EasyEmailProPage | string,\n): ImportResult {\n const root: unknown = typeof doc === \"string\" ? safeParse(doc) : doc;\n\n if (typeof root !== \"object\" || root === null || Array.isArray(root)) {\n throw new Error(INVALID_MESSAGE);\n }\n\n const unwrapped = unwrapDocument(root);\n if (unwrapped.page.type !== \"page\") {\n throw new Error(INVALID_MESSAGE);\n }\n const page = unwrapped.page as EasyEmailProPage;\n const subject = unwrapped.subject;\n assertNotOss(page);\n\n const warnings: string[] = [];\n const entries: ImportReportEntry[] = [];\n const blocks: Block[] = [];\n const resolve = contextFromPage(page);\n const data = isPlainObject(page.data) ? page.data : {};\n const settings = readSettings(page, data, resolve);\n const map: MapContext = { resolve, warnings, contentWidth: settings.width };\n\n const subjectRaw = typeof subject === \"string\" ? subject.trim() : \"\";\n if (subjectRaw) {\n warnings.push(\n `Document subject \"${subject}\" has no TemplateSettings field and was dropped.`,\n );\n }\n if (Array.isArray(data.fonts) && data.fonts.length > 0) {\n warnings.push(\n \"Dropped fonts[] — Templatical templates have no document-level font table.\",\n );\n }\n if (isNonEmptyHeadStyles(data.headStyles)) {\n warnings.push(\n \"Dropped headStyles — Templatical templates have no document-level head-style table.\",\n );\n }\n if (\n isPlainObject(data.classAttributes) &&\n Object.keys(data.classAttributes).length > 0\n ) {\n warnings.push(\n \"Dropped classAttributes — class-based MJML attribute cascade is not applied.\",\n );\n }\n\n for (const child of page.children ?? []) {\n if (!isElement(child)) continue;\n walkNode(child, map, entries, blocks);\n }\n\n if (hasMobileAttributes(page)) {\n warnings.push(MOBILE_WARNING);\n }\n\n if (resolve.stats.resolved > 0 || resolve.stats.unresolved > 0) {\n warnings.push(varWarning(resolve.stats.resolved, resolve.stats.unresolved));\n }\n\n if (blocks.length === 0) {\n warnings.push(EMPTY_WARNING);\n }\n\n const defaults = createDefaultTemplateContent();\n const content: TemplateContent = {\n ...defaults,\n blocks,\n settings: {\n ...defaults.settings,\n ...settings,\n },\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 return { content, report: { entries, warnings, summary } };\n}\n\nfunction readSettings(\n page: EasyEmailProPage,\n data: Record<string, unknown>,\n resolve: MapContext[\"resolve\"],\n): TemplateSettings {\n const width =\n parsePx(readAttr(page, \"width\", resolve)) ?? REQUIRED_DEFAULTS.width;\n // Page `background-color` is the viewport band. `content-background-color`\n // is the section fill fallback (section-builder), never a settings field.\n const backgroundColor =\n parseColor(readAttr(page, \"background-color\", resolve)) ??\n REQUIRED_DEFAULTS.backgroundColor;\n const fontFamilyRaw = readAttr(page, \"font-family\", resolve);\n const fontFamily =\n (typeof fontFamilyRaw === \"string\" && !isUnset(fontFamilyRaw)\n ? canonicalFontStack(fontFamilyRaw)\n : \"\") || REQUIRED_DEFAULTS.fontFamily;\n const textColor =\n parseColor(readAttr(page, \"color\", resolve)) ?? REQUIRED_DEFAULTS.textColor;\n const linkColor = parseColor(readAttr(page, \"link-color\", resolve));\n const deco = readAttr(page, \"link-text-decoration\", resolve);\n const linkUnderline =\n deco === \"underline\"\n ? true\n : deco === \"none\"\n ? false\n : REQUIRED_DEFAULTS.linkUnderline;\n const preheaderRaw =\n typeof data.preheader === \"string\" ? data.preheader.trim() : \"\";\n\n return {\n width,\n backgroundColor,\n textColor,\n fontFamily,\n linkUnderline,\n locale: REQUIRED_DEFAULTS.locale,\n ...(linkColor ? { linkColor } : {}),\n ...(preheaderRaw ? { preheaderText: preheaderRaw } : {}),\n };\n}\n\nfunction walkNode(\n node: EasyEmailProNode,\n map: MapContext,\n entries: ImportReportEntry[],\n blocks: Block[],\n): void {\n if (node.type === \"placeholder\") return;\n\n const logic = node.logic;\n const logicOn = hasLogic(logic);\n if (logicOn && !hasTypedContent(node)) {\n entries.push({\n sourceTag: node.type ?? \"logic\",\n templaticalBlockType: null,\n status: \"skipped\",\n note: `Skipped empty logic (${logicExpression(logic)})`,\n });\n return;\n }\n\n if (typeof node.type === \"string\" && WIDGET_TYPES.has(node.type)) {\n const from = entries.length;\n const data = isPlainObject(node.data) ? node.data : {};\n const input = isPlainObject(data.input) ? data.input : undefined;\n const inner: MapContext = {\n ...map,\n resolve: withWidgetInput(map.resolve, input),\n };\n for (const child of node.children ?? []) {\n if (!isElement(child)) continue;\n walkNode(child, inner, entries, blocks);\n }\n markApproximated(\n entries,\n from,\n `${node.type} flattened; $var resolved from data.input`,\n {\n sourceTag: node.type,\n },\n );\n if (logicOn) {\n markApproximated(entries, from, `logic ${logicExpression(logic)}`);\n }\n return;\n }\n\n const from = entries.length;\n if (typeof node.type === \"string\" && STRUCTURE_TYPES.has(node.type)) {\n const converted = buildTopLevel(node, map);\n for (const block of converted.blocks) blocks.push(block);\n for (const entry of converted.entries) entries.push(entry);\n } else if (isPageBand(node)) {\n walkBand(node, map, entries, blocks);\n } else {\n const converted = convertLeaf(node, map);\n for (const entry of converted.entries) entries.push(entry);\n if (converted.blocks.length > 0) {\n if (isLeafType(node.type)) {\n blocks.push(wrapInSection(converted.blocks));\n } else {\n blocks.push(...converted.blocks);\n }\n }\n }\n\n if (logicOn) {\n markApproximated(entries, from, `logic ${logicExpression(logic)}`);\n }\n}\n\n/**\n * A band's content walks as page children, so sections, wrappers, widgets and\n * bare leaves all convert as they would at the top. The band's own paint then\n * lands on the resulting sections, the way a `standard-wrapper`'s does.\n */\nfunction walkBand(\n node: PageBand,\n map: MapContext,\n entries: ImportReportEntry[],\n blocks: Block[],\n): void {\n const inner = withContentWidth(map, insideWidth(map.contentWidth, node, map));\n const bandBlocks: Block[] = [];\n const bandEntries: ImportReportEntry[] = [];\n for (const child of bandContent(node)) {\n walkNode(child, inner, bandEntries, bandBlocks);\n }\n if (bandBlocks.length === 0 && bandEntries.length === 0) {\n entries.push({\n sourceTag: node.type,\n templaticalBlockType: null,\n status: \"skipped\",\n note: `An empty ${node.type} produces nothing.`,\n });\n return;\n }\n applyWrapper(node, bandBlocks, bandEntries, map);\n for (const block of bandBlocks) blocks.push(block);\n for (const entry of bandEntries) entries.push(entry);\n}\n\ntype PageBand = EasyEmailProNode & { type: string };\n\nfunction isPageBand(node: EasyEmailProNode): node is PageBand {\n return typeof node.type === \"string\" && PAGE_BAND_TYPES.has(node.type);\n}\n\nfunction bandContent(node: EasyEmailProNode): EasyEmailProNode[] {\n const content = isPlainObject(node.data) ? node.data.content : undefined;\n if (!Array.isArray(content)) return [];\n return content.filter(\n (child): child is EasyEmailProNode =>\n isPlainObject(child) && isElement(child as EasyEmailProNode),\n );\n}\n\nfunction wrapInSection(blocks: Block[]): Block {\n const section = createSectionBlock();\n section.columns = \"1\";\n section.children = [blocks];\n return section;\n}\n\nfunction markApproximated(\n entries: ImportReportEntry[],\n from: number,\n extra: string,\n rewrite?: { sourceTag: string },\n): void {\n for (let i = from; i < entries.length; i++) {\n const entry = entries[i];\n if (rewrite) entry.sourceTag = rewrite.sourceTag;\n if (entry.status === \"converted\") entry.status = \"approximated\";\n entry.note = entry.note ? `${entry.note} ${extra}` : extra;\n }\n}\n\nfunction hasLogic(\n logic: EasyEmailProNode[\"logic\"],\n): logic is NonNullable<EasyEmailProNode[\"logic\"]> {\n if (logic == null || typeof logic !== \"object\") return false;\n return logic.condition != null || logic.iteration != null;\n}\n\nfunction logicExpression(\n logic: NonNullable<EasyEmailProNode[\"logic\"]>,\n): string {\n const parts: string[] = [];\n if (logic.condition != null) {\n parts.push(\n typeof logic.condition === \"string\"\n ? logic.condition\n : JSON.stringify(logic.condition),\n );\n }\n if (logic.iteration != null) {\n const iteration = logic.iteration;\n if (typeof iteration === \"string\") {\n parts.push(iteration);\n } else if (\n isPlainObject(iteration) &&\n typeof iteration.dataSource === \"string\"\n ) {\n parts.push(iteration.dataSource);\n } else {\n parts.push(JSON.stringify(iteration));\n }\n }\n return parts.join(\" \");\n}\n\nfunction hasTypedContent(node: EasyEmailProNode): boolean {\n const kids = isPageBand(node) ? bandContent(node) : (node.children ?? []);\n for (const child of kids) {\n if (!isElement(child)) continue;\n if (child.type === \"placeholder\") continue;\n return true;\n }\n return false;\n}\n\nfunction hasMobileAttributes(node: unknown): boolean {\n if (!isPlainObject(node)) return false;\n const mobile = node.mobileAttributes;\n if (isPlainObject(mobile) && Object.keys(mobile).length > 0) return true;\n const band = isPageBand(node as EasyEmailProNode)\n ? bandContent(node as EasyEmailProNode)\n : [];\n const children = Array.isArray(node.children) ? node.children : [];\n for (const child of [...children, ...band]) {\n if (hasMobileAttributes(child)) return true;\n }\n return false;\n}\n\nfunction assertNotOss(page: EasyEmailProPage): void {\n const children = page.children ?? [];\n for (const child of children) {\n if (!child || typeof child !== \"object\") continue;\n const type = (child as EasyEmailProNode).type;\n if (typeof type !== \"string\") continue;\n if (OSS_CHILD_TYPES.has(type)) {\n throw new Error(OSS_MESSAGE);\n }\n break;\n }\n}\n\nfunction isElement(\n node: EasyEmailProNode | EasyEmailProTextNode,\n): node is EasyEmailProNode {\n return typeof node.type === \"string\" && node.type !== \"\";\n}\n\nfunction isNonEmptyHeadStyles(value: unknown): boolean {\n if (Array.isArray(value)) return value.length > 0;\n return isPlainObject(value) && Object.keys(value).length > 0;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction safeParse(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n throw new Error(INVALID_MESSAGE);\n }\n}\n"],"mappings":";;AAMA,MAAM,aAAa;;AAGnB,MAAa,mBAA2C;CACtD,sBAAsB;CACtB,iBAAiB;CACjB,eAAe;CACf,eAAe;CACf,eAAe;CACf,eAAe;CACf,mBAAmB;CACnB,kBAAkB;CAClB,mBAAmB;CACnB,wBAAwB;CACxB,mBAAmB;CACnB,2BAA2B;CAC3B,mBAAmB;CACnB,oBAAoB;CACpB,iBAAiB;CACjB,oBAAoB;CACpB,oBAAoB;CACpB,mBAAmB;CACnB,kBAAkB;AACpB;;;;;;AA2BA,SAAgB,QAAQ,OAAyB;CAC/C,IAAI,UAAU,QAAQ,UAAU,KAAA,GAAW,OAAO;CAClD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,MAAM,UAAU,MAAM,KAAK;CAC3B,OACE,YAAY,MACZ,YAAY,WACZ,QAAQ,YAAY,MAAM,iBAC1B,QAAQ,SAAS,UAAU;AAE/B;;AAGA,SAAgB,mBACd,WACwB;CACxB,MAAM,MAA8B,CAAC;CACrC,IAAI,CAAC,WAAW,OAAO;CACvB,KAAK,MAAM,SAAS,WAAW;EAC7B,IAAI,OAAO,MAAM,SAAS,YAAY,MAAM,SAAS,IAAI;EACzD,IAAI,OAAO,MAAM,UAAU,UAAU;EACrC,IAAI,MAAM,QAAQ,MAAM;CAC1B;CACA,OAAO;AACT;;;;;AAMA,SAAgB,eACd,OACA,WACyD;CACzD,IAAI,MAAM;CACV,IAAI,IAAI;CACR,IAAI,WAAW;CACf,IAAI,aAAa;CAEjB,OAAO,IAAI,MAAM,QAAQ;EACvB,MAAM,QAAQ,MAAM,QAAQ,YAAY,CAAC;EACzC,IAAI,UAAU,IAAI;GAChB,OAAO,MAAM,MAAM,CAAC;GACpB;EACF;EACA,OAAO,MAAM,MAAM,GAAG,KAAK;EAC3B,MAAM,YAAY,QAAQ;EAC1B,MAAM,UAAU,kBAAkB,OAAO,SAAS;EAClD,IAAI,YAAY,IAAI;GAElB,OAAO,MAAM,MAAM,KAAK;GACxB,cAAc;GACd;EACF;EACA,MAAM,OAAO,MAAM,MAAM,WAAW,OAAO;EAC3C,IAAI,OAAO,UAAU,eAAe,KAAK,WAAW,IAAI,GAAG;GACzD,OAAO,UAAU;GACjB,YAAY;EACd,OAAO;GACL,OAAO,MAAM,MAAM,OAAO,UAAU,CAAC;GACrC,cAAc;EAChB;EACA,IAAI,UAAU;CAChB;CAEA,OAAO;EAAE,OAAO;EAAK;EAAU;CAAW;AAC5C;;AAGA,SAAS,kBAAkB,OAAe,SAAyB;CACjE,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,SAAS,IAAI,MAAM,QAAQ,KAAK;EAC3C,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO,KAAK,SAAS;OACpB,IAAI,OAAO,KAAK;GACnB,SAAS;GACT,IAAI,UAAU,GAAG,OAAO;EAC1B;CACF;CACA,OAAO;AACT;AAEA,SAAgB,gBAAgB,MAAwC;CACtE,MAAM,OAAOA,gBAAc,KAAK,IAAI,IAAI,KAAK,OAAO,CAAC;CACrD,OAAO;EACL,WAAW,mBACT,MAAM,QAAQ,KAAK,SAAS,IACvB,KAAK,YACN,KAAA,CACN;EACA,iBAAiB,gBAAgB,KAAK,eAAe;EACrD,oBAAoB,gBAAgB,KAAK,kBAAkB;EAC3D,kBAAkB,UAAU,KAAK,gBAAgB;EACjD;EACA,OAAO;GAAE,UAAU;GAAG,YAAY;EAAE;EACpC,2BAAW,IAAI,QAAQ;CACzB;AACF;;AAGA,SAAgB,gBACd,KACA,OACgB;CAChB,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,YAAY,EAAE,GAAG,IAAI,UAAU;CACrC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,IAAI,OAAO,UAAU,UAAU,UAAU,OAAO;CAGlD,OAAO;EAAE,GAAG;EAAK;EAAW,2BAAW,IAAI,QAAQ;CAAE;AACvD;;;;;;AAOA,SAAgB,SACd,MACA,KACA,KACS;CACT,IAAI,SAAS,IAAI,UAAU,IAAI,IAAI;CACnC,IAAI,QAAQ,IAAI,GAAG,GAAG,OAAO,OAAO,IAAI,GAAG;CAE3C,MAAM,MAAM,WAAW,MAAM,KAAK,GAAG;CACrC,IAAI,QAAiB;CACrB,IAAI,OAAO,QAAQ,UAAU;EAC3B,MAAM,SAAS,eAAe,KAAK,IAAI,SAAS;EAChD,IAAI,MAAM,YAAY,OAAO;EAC7B,IAAI,MAAM,cAAc,OAAO;EAC/B,QAAQ,OAAO;CACjB;CAEA,IAAI,CAAC,QAAQ;EACX,yBAAS,IAAI,IAAI;EACjB,IAAI,UAAU,IAAI,MAAM,MAAM;CAChC;CACA,OAAO,IAAI,KAAK,KAAK;CACrB,OAAO;AACT;AAEA,SAAS,WACP,MACA,KACA,KACS;CACT,MAAM,cAAc,KAAK,aAAa;CACtC,IAAI,gBAAgB,KAAA,GAAW,OAAO;CAEtC,IAAI,OAAO,KAAK,SAAS,UAAU;EACjC,MAAM,YAAY,IAAI,gBAAgB,KAAK,KAAK,GAAG;EACnD,IAAI,cAAc,KAAA,GAAW,OAAO;EAEpC,MAAM,WAAW,iBAAiB,KAAK;EACvC,IAAI,UAAU;GACZ,MAAM,eAAe,IAAI,mBAAmB,SAAS,GAAG;GACxD,IAAI,iBAAiB,KAAA,GAAW,OAAO;EACzC;CACF;CAEA,OAAO,IAAI,iBAAiB;AAC9B;;;;;;AAOA,SAAgB,eAAe,MAG7B;CACA,IAAI,CAACA,gBAAc,IAAI,GACrB,OAAO,EAAE,MAAM,CAAC,EAAE;CAGpB,IAAI,KAAK,SAAS,QAChB,OAAO,EAAE,MAAM,KAAyB;CAG1C,MAAM,MAAM;CACZ,MAAM,OAAOA,gBAAc,IAAI,OAAO,IACjC,IAAI,UACJ;CACL,MAAM,UAAU,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU,KAAA;CAChE,OAAO,YAAY,KAAA,IAAY,EAAE,KAAK,IAAI;EAAE;EAAM;CAAQ;AAC5D;AAEA,SAASA,gBAAc,OAAkD;CACvE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,UAAU,OAAyC;CAC1D,OAAOA,gBAAc,KAAK,IAAI,QAAQ,CAAC;AACzC;AAEA,SAAS,gBACP,OACyC;CACzC,IAAI,CAACA,gBAAc,KAAK,GAAG,OAAO,CAAC;CACnC,MAAM,MAA+C,CAAC;CACtD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,IAAIA,gBAAc,KAAK,GAAG,IAAI,OAAO;CAEvC,OAAO;AACT;;;;AC7PA,SAAgB,QAAQ,OAAoC;CAC1D,IAAI,QAAQ,KAAK,GAAG,OAAO,KAAA;CAC3B,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC,KAAK;CAC7B,IAAI,IAAI,YAAY,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC,QAAQ;CACrE,MAAM,IAAI,OAAO,GAAG;CACpB,OAAO,OAAO,MAAM,CAAC,IAAI,KAAA,IAAY;AACvC;;;;;AAMA,SAAgB,aAAa,OAA+B;CAC1D,IAAI,QAAQ,KAAK,GAAG,OAAO;CAC3B,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC,KAAK;CAC7B,IAAI,IAAI,SAAS,GAAG,GAAG,MAAM,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC,QAAQ;CACtD,MAAM,IAAI,OAAO,GAAG;CACpB,OAAO,OAAO,MAAM,CAAC,IAAI,OAAO;AAClC;;AAGA,SAAgB,WAAW,OAAoC;CAC7D,IAAI,QAAQ,KAAK,GAAG,OAAO,KAAA;CAC3B,IAAI,OAAO,UAAU,UAAU,OAAO,KAAA;CACtC,OAAO;AACT;;AAGA,SAAgB,YAAY,MAK1B;CACA,MAAM,QAAQ,QAAgB,QAAQ,KAAK,GAAG,CAAC,KAAK;CACpD,OAAO;EACL,KAAK,KAAK,aAAa;EACvB,OAAO,KAAK,eAAe;EAC3B,QAAQ,KAAK,gBAAgB;EAC7B,MAAM,KAAK,cAAc;CAC3B;AACF;AAQA,MAAM,SAAS;CAAC;CAAQ;CAAU;AAAO;AACzC,MAAM,SAAS;CAAC;CAAO;CAAU;AAAQ;AACzC,MAAM,UAAU;AAChB,MAAM,SAAS;;AAGf,MAAM,2BAA2B;CAC/B,MAAM;CACN,GAAG;CACH,GAAG;CACH,QAAQ;AACV;;;;;;AAOA,SAAS,sBACP,KACA,UAC0C;CAC1C,MAAM,QAAQ,IAAI,YAAY,CAAC,CAAC,MAAM,KAAK;CAC3C,MAAM,CAAC,SAAS;CAChB,IAAI,MAAM,WAAW,MAAM,UAAU,WAAW,UAAU,YACxD,OAAO;EAAE,MAAM;EAAO,OAAO;CAAK;CAEpC,IAAI,MAAM,OAAO,SAAS,SAAS,MAAM,GACvC,OAAO;EAAE,MAAM;EAAQ,OAAO;CAAK;CAErC,MAAM,KAAK,4BAA4B,KAAK,KAAK;CAIjD,OAAO;EAAE,MAFP,MAAM,SAAS,MAAM,KACpB,OAAO,QAAQ,aAAa,KAAA,KAAa,OAAO,GAAG,EAAE,KAAK,WACtC,UAAU;EAAQ,OAAO;CAAM;AACxD;;;;;;;;AASA,SAAS,wBAAwB,KAI/B;CACA,MAAM,QAAQ,IAAI,YAAY,CAAC,CAAC,MAAM,KAAK;CAC3C,IAAI,MAAM,WAAW,GAAG;EACtB,MAAM,CAAC,QAAQ;EACf,OAAO,SAAS,SAAS,SAAS,WAC9B;GAAE,GAAG;GAAU,GAAG;GAAM,OAAO;EAAK,IACpC;GAAE,GAAG;GAAM,GAAG;GAAU,OAAO;EAAK;CAC1C;CACA,IAAI,MAAM,WAAW,GAAG;EACtB,MAAM,CAAC,GAAG,KAAK;EAKf,OAHE,MAAM,SACN,MAAM,YACL,MAAM,aAAa,MAAM,UAAU,MAAM,WAC5B;GAAE,GAAG;GAAG,GAAG;GAAG,OAAO;EAAK,IAAI;GAAE,GAAG;GAAG,GAAG;GAAG,OAAO;EAAK;CAC1E;CACA,OAAO;EACL,GAAG,MAAM,MAAM,SAAS,SAAS,UAAU,SAAS,OAAO,KAAK;EAChE,GAAG,MAAM,MAAM,SAAS,SAAS,SAAS,SAAS,QAAQ,KAAK;EAChE,OAAO;CACT;AACF;;;;;;AAOA,SAAS,oBACP,OACA,MACqC;CACrC,MAAM,UAAU,KAAK,MAAM,UAAU,UAAU,KAAK;CACpD,IAAI,SAAS,OAAO;EAAE,OAAO;EAAS,OAAO;CAAK;CAClD,MAAM,UAAU,QAAQ,KAAK,KAAK;CAClC,IAAI,SAAS;EACX,MAAM,IAAI,OAAO,QAAQ,EAAE;EAC3B,OAAO;GACL,OAAO,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK;GAClD,OAAO,MAAM,KAAK,MAAM,MAAM,MAAM;EACtC;CACF;CACA,IAAI,OAAO,KAAK,KAAK,GACnB,OAAO;EAAE,OAAO,KAAK;EAAI,OAAO,WAAW,KAAK,MAAM;CAAE;CAE1D,OAAO;AACT;;;;;AAMA,SAAS,qBAAqB,KAG5B;CACA,MAAM,QAAQ,IAAI,YAAY,CAAC,CAAC,MAAM,KAAK;CAC3C,IAAI,MAAM,OAAO,SAAS,SAAS,WAAW,GAC5C,OAAO;EAAE,QAAQ;EAAO,OAAO;CAAK;CAEtC,OAAO;EAAE,QAAQ;EAAM,OAAO,MAAM,OAAO,SAAS,SAAS,QAAQ;CAAE;AACzE;;;;;;;;;;AAWA,SAAgB,wBACd,MACA,OACA,UAC4B;CAC5B,MAAM,SAAS,SAAqC;EAClD,MAAM,MAAM,KAAK,IAAI;EACrB,OAAO,QAAQ,GAAG,IAAI,KAAA,IAAY,OAAO,GAAG,CAAC,CAAC,KAAK;CACrD;CAEA,MAAM,MAAM,MAAM,gBAAgB,KAAK;CACvC,IAAI,CAAC,KAAK,OAAO;CAEjB,MAAM,QAAkB,CAAC;CACzB,MAAM,SAAS,MAAc,KAAa,UAAwB;EAChE,MAAM,KACJ,GAAG,MAAM,GAAG,KAAK,IAAI,IAAI,sDAAsD,MAAM,GACvF;CACF;CAEA,IAAI,OAAuB,yBAAyB;CACpD,MAAM,UAAU,MAAM,iBAAiB;CACvC,IAAI,SAAS;EACX,MAAM,SAAS,sBAAsB,SAAS,QAAQ;EACtD,OAAO,OAAO;EACd,IAAI,CAAC,OAAO,OAAO,MAAM,mBAAmB,SAAS,IAAI;CAC3D;CAEA,IAAI,IAAyB,yBAAyB;CACtD,IAAI,IAAyB,yBAAyB;CACtD,IAAI,SAAS;CACb,IAAI,SAAS;CACb,MAAM,cAAc,MAAM,qBAAqB;CAC/C,IAAI,aAAa;EACf,MAAM,QAAQ,wBAAwB,WAAW;EACjD,MAAM,QAAQ,oBAAoB,MAAM,GAAG,MAAM;EACjD,MAAM,QAAQ,oBAAoB,MAAM,GAAG,MAAM;EACjD,IAAI,OAAO,SAAS;EACpB,IAAI,OAAO,SAAS;EACpB,SAAS,CAAC,MAAM,SAAS,CAAC,OAAO;EACjC,SAAS,CAAC,MAAM,SAAS,CAAC,OAAO;CACnC;CAGA,MAAM,OAAO,MAAM,uBAAuB;CAC1C,MAAM,YAAY,OACd,oBAAoB,KAAK,YAAY,GAAG,MAAM,IAC9C;CACJ,IAAI,WAAW;EACb,IAAI,UAAU;EACd,SAAS;CACX;CACA,MAAM,OAAO,MAAM,uBAAuB;CAC1C,MAAM,YAAY,OACd,oBAAoB,KAAK,YAAY,GAAG,MAAM,IAC9C;CACJ,IAAI,WAAW;EACb,IAAI,UAAU;EACd,SAAS;CACX;CACA,IAAI,gBAAgB,UAAU,SAC5B,MAAM,uBAAuB,aAAa,GAAG,EAAE,GAAG,GAAG;CAEvD,IAAI,QAAQ,CAAC,WAAW,OAAO,MAAM,yBAAyB,MAAM,CAAC;CACrE,IAAI,QAAQ,CAAC,WAAW,OAAO,MAAM,yBAAyB,MAAM,CAAC;CAErE,IAAI,SAAkB,yBAAyB;CAC/C,MAAM,YAAY,MAAM,mBAAmB;CAC3C,IAAI,WAAW;EACb,MAAM,SAAS,qBAAqB,SAAS;EAC7C,SAAS,OAAO;EAChB,IAAI,CAAC,OAAO,OACV,MAAM,qBAAqB,WAAW,SAAS,WAAW,WAAW;CAEzE;CAEA,OAAO;EAAE,OAAO;GAAE;GAAK;GAAM,UAAU;IAAE;IAAG;GAAE;GAAG;EAAO;EAAG;CAAM;AACnE;AAUA,MAAM,cAAc;CAAC;CAAO;CAAU;AAAQ;AAE9C,MAAM,0BAA0B;CAC9B;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;;;;;AAaA,SAAgB,aACd,MACA,OACA,UACU;CACV,MAAM,SAAS,SAAqC;EAClD,MAAM,MAAM,KAAK,IAAI;EACrB,OAAO,QAAQ,GAAG,IAAI,KAAA,IAAY,OAAO,GAAG,CAAC,CAAC,KAAK;CACrD;CACA,MAAM,QAAkB,CAAC;CAEzB,MAAM,aAAa,yBAChB,SAAS;EACR,IAAI,SAAS,mBAAmB,OAAO;EACvC,IAAI,SAAS,qBAAqB,OAAO;EACzC,IAAI,SAAS,uBACX,OAAO,MAAM,IAAI,KAAK;EAExB,IACE,SAAS,2BACT,SAAS,yBAET;EAEF,OAAO,KAAK,IAAI;CAClB,GACA,OACA,QACF;CACA,IAAI,YAAY,MAAM,KAAK,GAAG,WAAW,KAAK;CAE9C,MAAM,QAAQ,QAAQ,MAAM,kBAAkB,CAAC;CAC/C,MAAM,SAAS,QAAQ,MAAM,mBAAmB,CAAC;CACjD,MAAM,QACJ,UAAU,KAAA,KAAa,WAAW,KAAA,KAAa,QAAQ,KAAK,SAAS;CACvE,MAAM,QAAQ,aACV;EACE,GAAG,WAAW;EACd,GAAI,QAAQ;GAAE,cAAc;GAAO,eAAe;EAAO,IAAI,CAAC;CAChE,IACA;CAEJ,MAAM,WAAW,MAAM,gBAAgB;CACvC,MAAM,gBACJ,YAAY,MAAM,UAAU,UAAU,UAAU,YAAY,CAAC,KAAK;CACpE,IAAI,YAAY,kBAAkB,SAAS,YAAY,GACrD,MAAM,KACJ,GAAG,MAAM,mBAAmB,SAAS,oDACvC;CAGF,MAAM,UAAU,MAAM,MAAM;CAC5B,MAAM,OAAO,UAAU,QAAQ,YAAY,IAAI;CAC/C,IAAI,OAA2B;CAC/B,IAAI,SAAS,gBAAgB;EAC3B,OAAO;GAAE,QAAQ;GAAS;EAAc;EACxC,IAAI,CAAC,OACH,MAAM,KACJ,GAAG,MAAM,gKACX;CAEJ,OAAO;EACL,IAAI,SAAS,gBACX,MAAM,KACJ,GAAG,MAAM,SAAS,QAAQ,6DAC5B;EAEF,MAAM,QAAQ,QAAQ,MAAM,QAAQ,CAAC;EACrC,IAAI,UAAU,KAAA,KAAa,QAAQ,GACjC,OAAO;GAAE,QAAQ,KAAK,MAAM,KAAK;GAAG;EAAc;CAEtD;CAEA,IAAI,QAAQ,CAAC,OACX,MAAM,KACJ,GAAG,MAAM,4FACX;CAGF,KAAK,MAAM,QAAQ,yBAAyB;EAC1C,MAAM,MAAM,MAAM,IAAI;EACtB,IAAI,QAAQ,KAAA,GAAW;EACvB,MAAM,KACJ,GAAG,MAAM,GAAG,KAAK,IAAI,IAAI,0CAC3B;CACF;CAEA,OAAO;EAAE;EAAM;EAAO;CAAM;AAC9B;;;;ACrXA,SAAS,WAAW,OAAuB;CACzC,IAAI,MAAM;CACV,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO,KAAK,OAAO;OAClB,IAAI,OAAO,KAAK,OAAO;OACvB,IAAI,OAAO,KAAK,OAAO;OACvB,IAAI,OAAO,MAAK,OAAO;OACvB,OAAO;CACd;CACA,OAAO;AACT;AAEA,SAAS,WACP,MAC8B;CAC9B,OAAO,OAAQ,KAA8B,SAAS;AACxD;;;;;AAMA,SAAS,kBAAkB,MAAoC;CAC7D,IAAI,OAAO,WAAW,KAAK,IAAI;CAE/B,IAAI,KAAK,MAAM,OAAO,WAAW,KAAK;CACtC,IAAI,KAAK,QAAQ,OAAO,OAAO,KAAK;CACpC,IAAI,KAAK,eAAe,OAAO,MAAM,KAAK;CAC1C,IAAI,KAAK,WAAW,OAAO,MAAM,KAAK;CAEtC,MAAM,SAAmB,CAAC;CAC1B,IAAI,OAAO,KAAK,UAAU,YAAY,KAAK,UAAU,IACnD,OAAO,KAAK,UAAU,WAAW,KAAK,KAAK,GAAG;CAEhD,IAAI,OAAO,KAAK,YAAY,YAAY,KAAK,YAAY,IACvD,OAAO,KAAK,qBAAqB,WAAW,KAAK,OAAO,GAAG;CAE7D,IAAI,OAAO,SAAS,GAClB,OAAO,gBAAgB,OAAO,KAAK,IAAI,EAAE,IAAI,KAAK;CAGpD,IAAI,KAAK,MAGP,OAAO,YAFM,WAAW,KAAK,KAAK,QAAQ,EAEpB,EAAE,GADV,KAAK,KAAK,UAAU,OAAO,uBAAqB,GAC7B,GAAG,KAAK;CAG3C,OAAO;AACT;;AAGA,MAAM,4BAAY,IAAI,IAAI;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,WAAW;AACjB,MAAM,iBAAiB;;;;;;;AAQvB,SAAS,kBAAkB,MAAgC;CACzD,MAAM,SAAS,KAAK,OAAO;CAC3B,MAAM,UAAU,OAAO,WAAW,WAAW,OAAO,YAAY,IAAI;CACpE,MAAM,UAAU,SAAS,KAAK,OAAO,IAAI,UAAU;CAEnD,IAAI,QAAQ;CACZ,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,cAAc,CAAC,CAAC,GAAG;EACjE,IAAI,OAAO,UAAU,YAAY,CAAC,eAAe,KAAK,IAAI,GAAG;EAC7D,MAAM,UAAU,MAAM,KAAK;EAC3B,IAAI,YAAY,IAAI;EACpB,SAAS,IAAI,KAAK,IAAI,WAAW,OAAO,EAAE;CAC5C;CAEA,IAAI,UAAU,IAAI,OAAO,GAAG,OAAO,IAAI,UAAU,MAAM;CACvD,OAAO,IAAI,UAAU,MAAM,GAAG,kBAAkB,KAAK,QAAQ,EAAE,IAAI,QAAQ;AAC7E;;;;;;;AAQA,SAAS,kBAAkB,MAAgC;CACzD,MAAM,QAAQ,KAAK,WAAW;CAC9B,IAAI,CAAC,SAAS,CAAC,WAAW,KAAK,GAAG,OAAO;CACzC,MAAM,OAAO,MAAM,KAAK,KAAK;CAC7B,IAAI,SAAS,IAAI,OAAO;CACxB,OAAO,kBAAkB;EAAE,GAAG;EAAO,MAAM,MAAM,KAAK;CAAK,CAAC;AAC9D;AAEA,SAAS,cAAc,MAAuD;CAC5E,IAAI,KAAK,SAAS,cAAc,OAAO;CAEvC,IAAI,KAAK,SAAS,mBAAmB;EACnC,MAAM,UAAU;EAChB,MAAM,SAAS,QAAQ,OAAO;EAC9B,MAAM,UACJ,OAAO,WAAW,YAAY,WAAW,KAAK,SAAS;EAEzD,OAAO,IAAI,QAAQ,GADL,kBAAkB,QAAQ,QACd,EAAE,IAAI,QAAQ;CAC1C;CAEA,IAAI,KAAK,SAAS,aAChB,OAAO,kBAAkB,IAAwB;CAGnD,IAAI,KAAK,SAAS,YAChB,OAAO,kBAAkB,IAAwB;CAGnD,IAAI,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS,IAAI,OAAO;CAE9D,IAAI,WAAW,IAAI,GAAG,OAAO,kBAAkB,IAAI;CAEnD,OAAO;AACT;;AAGA,SAAgB,kBACd,UACQ;CACR,IAAI,CAAC,YAAY,SAAS,WAAW,GAAG,OAAO;CAC/C,IAAI,MAAM;CACV,KAAK,MAAM,SAAS,UAClB,OAAO,cAAc,KAAK;CAE5B,OAAO;AACT;;;ACtFA,MAAM,6BAAa,IAAI,IAAI;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,mBAAmB;CACvB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,WAAmC;CACvC,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;AACZ;;;;;AAMA,MAAM,mCAAmB,IAAI,IAAI;CAAC;CAAsB;CAAM;AAAI,CAAC;AAEnE,MAAM,iBACJ;AAEF,SAAgB,WAAW,MAAmC;CAC5D,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,IAAI,WAAW,IAAI,IAAI,GAAG,OAAO;CACjC,OAAO,qBAAqB,IAAI,MAAM;AACxC;AAEA,SAAgB,YACd,MACA,KACW;CACX,MAAM,OAAO,KAAK;CAClB,IAAI,SAAS,eAAe,OAAOC,QAAM;CACzC,IAAI,SAAS,wBAAwB,SAAS,iBAC5C,OAAO,iBAAiB,MAAM,GAAG;CAGnC,MAAM,UAAU,OAAO,SAAS,WAAW,qBAAqB,IAAI,IAAI;CACxE,IAAI,SAAS,OAAO,eAAe,MAAM,KAAK,OAAO;CAErD,QAAQ,MAAR;EACE,KAAK,mBACH,OAAO,cAAc,MAAM,GAAG;EAChC,KAAK,kBACH,OAAO,aAAa,MAAM,GAAG;EAC/B,KAAK,oBACH,OAAO,eAAe,MAAM,GAAG;EACjC,KAAK,mBACH,OAAO,cAAc,MAAM,GAAG;EAChC,KAAK,mBACH,OAAO,cAAc,MAAM,GAAG;EAChC,KAAK,mBACH,OAAO,cAAc,MAAM,GAAG;EAChC,KAAK,mBACH,OAAO,aAAa,MAAM,GAAG;EAC/B,KAAK,uBACH,OAAO,iBAAiB,MAAM,GAAG;EACnC,KAAK,gBACH,OAAO,aAAa,MAAM,GAAG;EAC/B,KAAK,OACH,OAAO,WAAW,MAAM,GAAG;EAC7B,SACE,OAAO,eAAe,MAAM,GAAG;CACnC;AACF;;;;;AAMA,SAAS,iBAAiB,MAAwB,KAA4B;CAC5E,OAAO,OACL,qBAAqB;EACnB,SAAS,cAAc,MAAM,GAAG;EAChC,GAAG,WAAW,MAAM,GAAG;CACzB,CAAC,GACD,MACA,OAAO,KAAK,QAAQ,sBAAsB,aAAa,WAAW,CACpE;AACF;;;;;AAMA,SAAS,cAAc,MAAwB,KAAyB;CACtE,MAAM,OAAO,kBAAkB,KAAK,QAAQ;CAC5C,MAAM,QAAkB,CAAC;CACzB,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC7D,IAAI,OAAO,MAAM,KAAK,UAAU,WAAW,KAAK,GAAG;CACnD,MAAM,WAAW,UAAU,SAAS,MAAM,aAAa,IAAI,OAAO,CAAC;CACnE,IAAI,UAAU,MAAM,KAAK,cAAc,WAAW,QAAQ,GAAG;CAC7D,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC7D,IAAI,OAAO,MAAM,KAAK,eAAe,OAAO;CAC5C,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,OAAO,aAAa,MAAM,KAAK,IAAI,EAAE,IAAI,KAAK;AAChD;AAEA,SAAS,WAAW,OAAuB;CACzC,IAAI,MAAM;CACV,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO,KAAK,OAAO;OAClB,IAAI,OAAO,KAAK,OAAO;OACvB,IAAI,OAAO,KAAK,OAAO;OACvB,IAAI,OAAO,MAAK,OAAO;OACvB,OAAO;CACd;CACA,OAAO;AACT;AAEA,SAAS,eACP,MACA,KACA,SACW;CACX,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC7D,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC7D,MAAM,UAAU,QAAQ,SAAS;CACjC,OAAO,OACL,iBAAiB;EACf,SAAS,kBAAkB,KAAK,QAAQ;EACxC,OAAO,QAAQ;EACf,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,GAAI,QAAQ,EAAE,WAAW,MAAM,IAAI,CAAC;EACpC,GAAG,WAAW,MAAM,GAAG;CACzB,CAAC,GACD,MACA,UACI,OACE,KAAK,QAAQ,eACb,SACA,gBACA,kBAAkB,QAAQ,OAAO,kDACnC,IACA,OAAO,KAAK,QAAQ,eAAe,SAAS,WAAW,CAC7D;AACF;AAEA,SAAS,cAAc,MAAwB,KAA4B;CACzE,MAAM,OAAO,WAAW,SAAS,MAAM,oBAAoB,IAAI,OAAO,CAAC;CACvE,MAAM,YAAY,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CACjE,MAAM,OAAO,SAAS,MAAM,QAAQ,IAAI,OAAO;CAC/C,MAAM,QAAQ,YAAY,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC9D,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC7D,MAAM,WACJ,gBAAgB,SAAS,MAAM,kBAAkB,IAAI,OAAO,CAAC,KAC7D,QAAQ,SAAS,MAAM,oBAAoB,IAAI,OAAO,CAAC;CAEzD,MAAM,QAAqB,kBAAkB;EAC3C,MAAM,UAAU,kBAAkB,KAAK,QAAQ,CAAC;EAChD,KAAK,UAAU,IAAI,KAAK;EACxB,GAAI,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;EACxC,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EACjC,GAAI,UAAU,KAAA,IAAY,EAAE,MAAM,IAAI,CAAC;EACvC,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,GAAG,WAAW,MAAM,GAAG;CACzB,CAAC;CAGD,IAAI,UAAU,MAAM,kBAAkB;CAEtC,OAAO,OACL,OACA,MACA,WACI,OACE,mBACA,UACA,gBACA,+CACF,IACA,OAAO,mBAAmB,UAAU,WAAW,CACrD;AACF;AAEA,SAAS,aAAa,MAAwB,KAA4B;CACxE,MAAM,MAAM,UAAU,SAAS,MAAM,OAAO,IAAI,OAAO,CAAC,KAAK;CAC7D,MAAM,MAAM,UAAU,SAAS,MAAM,OAAO,IAAI,OAAO,CAAC,KAAK;CAE7D,MAAM,UAAU,UADH,SAAS,MAAM,QAAQ,IAAI,OACX,CAAC;CAC9B,MAAM,SAAS,QAAQ,SAAS,MAAM,iBAAiB,IAAI,OAAO,CAAC;CACnE,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC7D,MAAM,SAAS,UAAU,SAAS,MAAM,UAAU,IAAI,OAAO,CAAC;CAC9D,MAAM,SAAS,WAAW,MAAM,GAAG;CACnC,MAAM,EAAE,MAAM,UAAU,OAAO,OAAO;CACtC,MAAM,OACJ,IAAI,iBAAiB,KAAA,IACjB,KAAA,IACA,IAAI,eAAe,OAAO;CAChC,MAAM,QAAkB,CAAC;CACzB,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,GAAG,MAAM,KAAK;CAE1E,OAAO,OACL,iBAAiB;EACf;EACA;EACA;EACA,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,GAAI,WAAW,KAAA,KAAa,SAAS,IAAI,EAAE,cAAc,OAAO,IAAI,CAAC;EACrE,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B,GAAI,WAAW,WAAW,WAAW,EAAE,kBAAkB,KAAK,IAAI,CAAC;EACnE,GAAG;CACL,CAAC,GACD,MACA,MAAM,SAAS,IACX,OAAO,kBAAkB,SAAS,gBAAgB,MAAM,KAAK,GAAG,CAAC,IACjE,OAAO,kBAAkB,SAAS,WAAW,CACnD;AACF;;;;;;;;AASA,SAAS,WACP,OACA,MACA,OACqB;CACrB,IAAI,QAAQ,KAAK,GAAG,OAAO;CAC3B,IAAI,OAAO,UAAU,YAAY,MAAM,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG;EAC3D,MAAM,UAAU,aAAa,KAAK;EAClC,IAAI,YAAY,QAAQ,WAAW,KAAK,WAAW,KAAK,OAAO;EAC/D,IAAI,SAAS,KAAA,GAAW;GACtB,MAAM,KACJ,eAAe,MAAM,KAAK,EAAE,iEAC9B;GACA,OAAO;EACT;EACA,MAAM,KAAK,KAAK,MAAO,OAAO,UAAW,GAAG;EAC5C,IAAI,MAAM,MAAM,OAAO;EACvB,MAAM,KACJ,eAAe,MAAM,KAAK,EAAE,eAAe,GAAG,qCAChD;EACA,OAAO;CACT;CACA,MAAM,KAAK,QAAQ,KAAK;CACxB,IAAI,OAAO,KAAA,KAAa,MAAM,GAAG,OAAO;CACxC,OAAO,SAAS,KAAA,KAAa,MAAM,OAAO,SAAS;AACrD;AAEA,SAAS,eAAe,MAAwB,KAA4B;CAC1E,MAAM,QAAQ,WAAW,SAAS,MAAM,gBAAgB,IAAI,OAAO,CAAC;CACpE,MAAM,YAAY,QAAQ,SAAS,MAAM,gBAAgB,IAAI,OAAO,CAAC;CACrE,MAAM,YAAY,YAAY,SAAS,MAAM,gBAAgB,IAAI,OAAO,CAAC;CACzE,MAAM,SAAS,WAAW,MAAM,GAAG;CACnC,MAAM,EAAE,MAAM,UAAU,OAAO,OAAO;CACtC,MAAM,OACJ,IAAI,iBAAiB,KAAA,IACjB,KAAA,IACA,IAAI,eAAe,OAAO;CAChC,OAAO,OACL,mBAAmB;EACjB,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,GAAI,cAAc,KAAA,IAAY,EAAE,UAAU,IAAI,CAAC;EAC/C,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EACjC,OAAO,aAAa,SAAS,MAAM,SAAS,IAAI,OAAO,GAAG,IAAI;EAC9D,GAAG;CACL,CAAC,GACD,MACA,OAAO,oBAAoB,WAAW,WAAW,CACnD;AACF;;;;;;;;AASA,SAAS,aACP,OACA,MACuB;CACvB,IAAI,QAAQ,KAAK,GAAG,OAAO;CAC3B,IAAI,OAAO,UAAU,YAAY,MAAM,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG;EAC3D,MAAM,UAAU,aAAa,KAAK;EAClC,IAAI,YAAY,MAAM,OAAO;EAE7B,MAAM,UAAU,KAAK,MADL,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,OAAO,CAChB,IAAI,GAAG,IAAI;EAC5C,OAAO,WAAW,MAAM,SAAS,GAAG,QAAQ;CAC9C;CACA,MAAM,KAAK,QAAQ,KAAK;CACxB,IAAI,OAAO,KAAA,GAAW,OAAO;CAC7B,OAAO,SAAS,KAAA,KAAa,MAAM,OAAO,SAAS;AACrD;AAEA,SAAS,cAAc,MAAwB,KAA4B;CACzE,MAAM,SAAS,QAAQ,SAAS,MAAM,UAAU,IAAI,OAAO,CAAC;CAC5D,OAAO,OACL,kBAAkB;EAChB,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;EACzC,GAAG,WAAW,MAAM,GAAG;CACzB,CAAC,GACD,MACA,OAAO,mBAAmB,UAAU,WAAW,CACjD;AACF;AAEA,SAAS,cAAc,MAAwB,KAA4B;CACzE,MAAM,QAAwB,CAAC;CAC/B,KAAK,MAAM,SAAS,KAAK,YAAY,CAAC,GAAG;EACvC,IAAI,CAACC,YAAU,KAAK,KAAK,MAAM,SAAS,wBAAwB;EAChE,MAAM,OAAO,SAAS,OAAO,QAAQ,IAAI,OAAO;EAChD,MAAM,SAAS,UAAU,SAAS,OAAO,UAAU,IAAI,OAAO,CAAC;EAC/D,MAAM,QAAQ,WAAW,SAAS,OAAO,SAAS,IAAI,OAAO,CAAC;EAC9D,MAAM,SAAS,UAAU,SAAS,OAAO,eAAe,IAAI,OAAO,CAAC;EACpE,MAAM,OAAO,UAAU,SAAS,OAAO,mBAAmB,IAAI,OAAO,CAAC;EACtE,MAAM,KAAK;GACT,IAAI,WAAW;GACf,MAAM,UAAU,kBAAkB,MAAM,QAAQ,CAAC;GACjD,KAAK,UAAU,IAAI,KAAK;GACxB,cAAc,WAAW;GACzB,MAAM,WAAW,UAAU,WAAW;GACtC,WAAW,SAAS,KAAA,KAAa,KAAK,SAAS,WAAW;GAC1D,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EAC3B,CAAC;CACH;CACA,IAAI,MAAM,WAAW,GAAG,OAAOD,QAAM;CAErC,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC7D,OAAO,OACL,gBAAgB;EACd;EACA,GAAI,QAAQ,EAAE,WAAW,MAAM,IAAI,CAAC;EACpC,GAAG,WAAW,MAAM,GAAG;CACzB,CAAC,GACD,MACA,OAAO,mBAAmB,QAAQ,WAAW,CAC/C;AACF;AAEA,SAAS,cAAc,MAAwB,KAA4B;CACzE,MAAM,QAAsB,CAAC;CAC7B,IAAI,YAAY;CAChB,KAAK,MAAM,SAAS,KAAK,YAAY,CAAC,GAAG;EACvC,IAAI,CAACC,YAAU,KAAK,KAAK,MAAM,SAAS,2BAA2B;EACnE,MAAM,OAAO,SAAS,OAAO,QAAQ,IAAI,OAAO;EAChD,MAAM,MAAM,SAAS,OAAO,OAAO,IAAI,OAAO;EAC9C,IAAI,OAAO,QAAQ,YAAY,CAAC,QAAQ,GAAG,GAAG,YAAY;EAC1D,MAAM,KAAK;GACT,IAAI,WAAW;GACf,UAAU,cAAc,MAAM,GAAG;GACjC,KAAK,UAAU,IAAI,KAAK;EAC1B,CAAC;CACH;CACA,IAAI,MAAM,WAAW,GAAG,OAAOD,QAAM;CAErC,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC7D,OAAO,OACL,uBAAuB;EACrB;EACA,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,GAAG,WAAW,MAAM,GAAG;CACzB,CAAC,GACD,MACA,YACI,OACE,mBACA,UACA,gBACA,4DACF,IACA,OAAO,mBAAmB,UAAU,WAAW,CACrD;AACF;AAEA,SAAS,aAAa,MAAwB,KAA4B;CACxE,MAAM,OAAuB,CAAC;CAC9B,IAAI,eAAe;CACnB,IAAI,QAAQ;CACZ,KAAK,MAAM,OAAO,YAAY,IAAI,GAAG;EACnC,MAAM,QAAyB,CAAC;EAChC,IAAI,WAAW;EACf,KAAK,MAAM,QAAQ,IAAI,YAAY,CAAC,GAAG;GACrC,IAAI,CAACC,YAAU,IAAI,KAAK,CAAC,iBAAiB,IAAI,KAAK,QAAQ,EAAE,GAAG;GAChE,IAAI,KAAK,SAAS,MAAM,WAAW;GACnC,MAAM,KAAK;IACT,IAAI,WAAW;IACf,SAAS,kBAAkB,KAAK,QAAQ;GAC1C,CAAC;EACH;EACA,IAAI,MAAM,WAAW,GAAG;EACxB,IAAI,OAAO;GACT,eAAe;GACf,QAAQ;EACV;EACA,KAAK,KAAK;GAAE,IAAI,WAAW;GAAG;EAAM,CAAC;CACvC;CACA,IAAI,KAAK,WAAW,GAAG,OAAOD,QAAM;CAEpC,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC7D,MAAM,QAAQ,WAAW,SAAS,MAAM,SAAS,IAAI,OAAO,CAAC;CAC7D,OAAO,OACL,iBAAiB;EACf;EACA;EACA,GAAI,QAAQ,EAAE,WAAW,MAAM,IAAI,CAAC;EACpC,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,GAAG,WAAW,MAAM,GAAG;CACzB,CAAC,GACD,MACA,OAAO,mBAAmB,SAAS,WAAW,CAChD;AACF;AAEA,SAAS,iBAAiB,MAAwB,KAA4B;CAC5E,MAAM,SAAkB,CAAC;CACzB,MAAM,UAA+B,CAAC;CAEtC,KAAK,MAAM,SAAS,KAAK,YAAY,CAAC,GAAG;EACvC,IAAI,CAACC,YAAU,KAAK,GAAG;EACvB,MAAM,WAAW,aAAa,KAAK;EACnC,IAAI,CAAC,UAAU;EACf,MAAM,QAAQ,YAAY,UAAU,GAAG;EACvC,KAAK,MAAM,SAAS,MAAM,QAAQ,OAAO,KAAK,KAAK;EACnD,KAAK,MAAM,SAAS,MAAM,SACxB,QAAQ,KAAK;GACX,WAAW;GACX,sBAAsB,MAAM;GAC5B,QAAQ;GACR,MAAM,MAAM,OAAO,GAAG,MAAM,KAAK,wBAAwB;EAC3D,CAAC;CAEL;CAEA,MAAM,MAAM,SAAS,MAAM,OAAO,IAAI,OAAO;CAC7C,IAAI,OAAO,QAAQ,YAAY,CAAC,QAAQ,GAAG,GAAG;EAC5C,MAAM,QAAQ,iBAAiB;GAC7B;GACA,GAAG,WAAW,MAAM,GAAG;EACzB,CAAC;EACD,MAAM,aAAaC,iBAAe,IAAI;EACtC,IAAI,YAAY,MAAM,aAAa;EACnC,OAAO,KAAK,KAAK;EACjB,QAAQ,KAAK;GACX,WAAW;GACX,sBAAsB;GACtB,QAAQ;GACR,MAAM;EACR,CAAC;CACH;CAEA,OAAO;EAAE;EAAQ;CAAQ;AAC3B;AAEA,SAAS,aAAa,MAAwB,KAA4B;CACxE,MAAM,MAAM,SAAS,MAAM,GAAG;CAC9B,IAAI,CAAC,KAAK,OAAO,eAAe,MAAM,GAAG;CACzC,OAAO,OACL,iBAAiB;EACf;EACA,GAAG,WAAW,MAAM,GAAG;CACzB,CAAC,GACD,MACA,OAAO,gBAAgB,SAAS,WAAW,CAC7C;AACF;;AAGA,SAAS,WAAW,MAAwB,KAA4B;CACtE,MAAM,UAAU,KAAK,OAAO;CAC5B,IAAI,OAAO,YAAY,UAAU,OAAO,eAAe,MAAM,GAAG;CAChE,OAAO,OACL,gBAAgB;EACd;EACA,GAAG,WAAW,MAAM,GAAG;CACzB,CAAC,GACD,MACA,OAAO,OAAO,QAAQ,WAAW,CACnC;AACF;AAEA,SAAS,eAAe,MAAwB,KAA4B;CAC1E,MAAM,YAAY,KAAK,QAAQ;CAC/B,OAAO,OACL,gBAAgB;EACd,SAAS,KAAK,UAAU,IAAI;EAC5B,GAAG,WAAW,MAAM,GAAG;CACzB,CAAC,GACD,MACA,OACE,WACA,QACA,iBACA,gCAAgC,UAAU,sBAC5C,CACF;AACF;AAEA,SAAS,aAAa,OAAkD;CACtE,IAAI,MAAM,SAAS,QACjB,OAAO;EAAE,GAAG;EAAO,MAAM;CAAqB;CAEhD,IAAI,MAAM,SAAS,wBAAwB,MAAM,SAAS,iBACxD,OAAO;CAET,IAAI,OAAO,MAAM,SAAS,YAAY,qBAAqB,MAAM,IAAI,GACnE,OAAO;CAET,OAAO;AACT;AAEA,SAAS,YAAY,MAA4C;CAC/D,MAAM,OAA2B,CAAC;CAClC,KAAK,MAAM,SAAS,KAAK,YAAY,CAAC,GAAG;EACvC,IAAI,CAACD,YAAU,KAAK,GAAG;EACvB,IAAI,WAAW,KAAK,GAAG;GACrB,KAAK,KAAK,KAAK;GACf;EACF;EACA,KAAK,MAAM,SAAS,MAAM,YAAY,CAAC,GACrC,IAAIA,YAAU,KAAK,KAAK,WAAW,KAAK,GAAG,KAAK,KAAK,KAAK;CAE9D;CACA,OAAO;AACT;AAEA,SAAS,WAAW,MAAiC;CACnD,OAAO,KAAK,SAAS,wBAAwB,KAAK,SAAS;AAC7D;AAEA,SAAS,SAAS,MAAwB,KAAqC;CAC7E,KAAK,MAAM,OAAO;EAAC;EAAO;EAAQ;CAAK,GAAY;EACjD,MAAM,QAAQ,SAAS,MAAM,KAAK,IAAI,OAAO;EAC7C,IAAI,OAAO,UAAU,YAAY,CAAC,QAAQ,KAAK,GAAG,OAAO;CAC3D;AAEF;AAEA,SAAS,cAAc,MAAe,KAA8B;CAClE,MAAM,OAAO,SAAS,OAAO,SAAS,WAAW,OAAO,EAAE;CAC1D,KAAK,MAAM,YAAY,kBACrB,IAAI,KAAK,SAAS,QAAQ,GAAG,OAAO;CAEtC,MAAM,OAAO,OAAO,OAAO,QAAQ,WAAW,MAAM,EAAE;CACtD,KAAK,MAAM,YAAY,kBACrB,IAAI,KAAK,SAAS,QAAQ,GAAG,OAAO;CAEtC,OAAO;AACT;AAEA,SAAS,SAAS,MAAsB;CACtC,MAAM,QAAQ,KAAK,YAAY;CAC/B,MAAM,SAAS,MAAM,QAAQ,KAAK;CAClC,MAAM,OAAO,WAAW,KAAK,QAAQ,MAAM,MAAM,SAAS,CAAC;CAC3D,MAAM,QAAQ,KAAK,QAAQ,GAAG;CAC9B,MAAM,WAAW,UAAU,KAAK,OAAO,KAAK,MAAM,GAAG,KAAK;CAC1D,MAAM,QAAQ,SAAS,QAAQ,GAAG;CAClC,OAAO,UAAU,KAAK,WAAW,SAAS,MAAM,GAAG,KAAK;AAC1D;AAEA,SAAS,OAAO,KAAqB;CACnC,MAAM,QAAQ,IAAI,YAAY;CAC9B,MAAM,SAAS,MAAM,QAAQ,KAAK;CAClC,MAAM,OAAO,WAAW,KAAK,QAAQ,MAAM,MAAM,SAAS,CAAC;CAC3D,MAAM,QAAQ,KAAK,QAAQ,GAAG;CAC9B,OAAO,UAAU,KAAK,OAAO,KAAK,MAAM,KAAK;AAC/C;AAEA,SAAS,qBACP,MACgD;CAChD,IAAI,CAAC,KAAK,WAAW,YAAY,GAAG,OAAO;CAC3C,MAAM,MAAM,KAAK,MAAM,EAAmB;CAC1C,IAAI,IAAI,WAAW,GAAG,OAAO;CAC7B,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACnC,MAAM,OAAO,IAAI,WAAW,CAAC;EAC7B,IAAI,OAAO,MAAM,OAAO,IAAI,OAAO;CACrC;CACA,MAAM,SAAS,OAAO,GAAG;CACzB,IAAI,CAAC,OAAO,SAAS,MAAM,KAAK,SAAS,GAAG,OAAO;CAEnD,OAAO;EAAE,OADM,SAAS,IAAI,IAAI;EAChB;CAAO;AACzB;AAEA,SAAS,WACP,MACA,KACyB;CACzB,OAAO,EACL,QAAQ,EACN,SAAS,aAAa,QAAQ,SAAS,MAAM,KAAK,IAAI,OAAO,CAAC,EAChE,EACF;AACF;AAEA,SAAS,OACP,OACA,MACA,OACW;CACX,MAAM,aAAaC,iBAAe,IAAI;CACtC,IAAI,YAAY,MAAM,aAAa;CACnC,OAAO;EAAE,QAAQ,CAAC,KAAK;EAAG,SAAS,CAAC,KAAK;CAAE;AAC7C;AAEA,SAASA,iBAAe,MAAqD;CAC3E,IAAI,KAAK,YAAY,WAAW,OAAO;EAAE,SAAS;EAAM,QAAQ;CAAM;CACtE,IAAI,KAAK,YAAY,UAAU,OAAO;EAAE,SAAS;EAAO,QAAQ;CAAK;AAEvE;AAEA,SAAS,OACP,WACA,sBACA,QACA,MACmB;CACnB,OAAO;EACL;EACA;EACA;EACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;CACzB;AACF;AAEA,SAASF,UAAmB;CAC1B,OAAO;EAAE,QAAQ,CAAC;EAAG,SAAS,CAAC;CAAE;AACnC;AAEA,SAASC,YACP,MAC0B;CAC1B,OAAO,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS;AACxD;AAEA,SAAS,gBAAgB,OAAyB;CAChD,OAAO,UAAU,QAAQ,UAAU;AACrC;AAEA,SAAS,YAAY,OAA6C;CAChE,IAAI,QAAQ,KAAK,GAAG,OAAO,KAAA;CAC3B,IAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,QAAQ,OAAO;CACjE,OAAO,QAAQ,KAAK;AACtB;AAEA,SAAS,WAAW,OAAyD;CAC3E,IAAI,OAAO,UAAU,UAAU,OAAO,KAAA;CACtC,MAAM,QAAQ,MAAM,KAAK,CAAC,CAAC,YAAY;CACvC,IAAI,UAAU,UAAU,UAAU,YAAY,UAAU,SAAS,OAAO;AAE1E;AAEA,SAAS,YACP,OAC2C;CAC3C,IAAI,OAAO,UAAU,UAAU,OAAO,KAAA;CACtC,MAAM,QAAQ,MAAM,KAAK,CAAC,CAAC,YAAY;CACvC,IAAI,UAAU,WAAW,UAAU,YAAY,UAAU,UACvD,OAAO;AAGX;AAEA,SAAS,UAAU,OAAoC;CACrD,IAAI,OAAO,UAAU,YAAY,QAAQ,KAAK,GAAG,OAAO,KAAA;CACxD,OAAO;AACT;;AAGA,SAAS,UAAU,MAAsB;CACvC,IAAI,SAAS,IAAI,OAAO;CACxB,OAAO,eAAe,WAAW,IAAI,CAAC,CAAC,CAAC,KAAK;AAC/C;AAEA,SAAS,WAAW,MAAsB;CACxC,IAAI,MAAM;CACV,IAAI,IAAI;CACR,OAAO,IAAI,KAAK,QAAQ;EACtB,MAAM,OAAO,KAAK,QAAQ,KAAK,CAAC;EAChC,IAAI,SAAS,IAAI;GACf,OAAO,KAAK,MAAM,CAAC;GACnB;EACF;EACA,OAAO,KAAK,MAAM,GAAG,IAAI;EACzB,MAAM,SAAS,eAAe,MAAM,OAAO,CAAC;EAC5C,IAAI,WAAW,IAAI;GACjB,OAAO,KAAK,MAAM,IAAI;GACtB;EACF;EACA,IAAI,SAAS;CACf;CACA,OAAO;AACT;AAEA,SAAS,eAAe,MAAsB;CAC5C,IAAI,MAAM;CACV,IAAI,IAAI;CACR,OAAO,IAAI,KAAK,QAAQ;EACtB,IAAI,KAAK,OAAO,KAAK;GACnB,MAAM,OAAO,KAAK,QAAQ,KAAK,IAAI,CAAC;GACpC,IAAI,SAAS,MAAM,OAAO,KAAK,GAAG;IAChC,MAAM,SAAS,SAAS,KAAK,MAAM,GAAG,OAAO,CAAC;IAC9C,IAAI,WAAW,KAAA,GAAW;KACxB,OAAO;KACP,IAAI,OAAO;KACX;IACF;GACF;EACF;EACA,OAAO,KAAK;EACZ;CACF;CACA,OAAO;AACT;;;AC/xBA,MAAM,gBAAqE;CACzE;EAAE,QAAQ;EAAK,UAAU,CAAC,GAAG;CAAE;CAC/B;EAAE,QAAQ;EAAK,UAAU,CAAC,IAAI,EAAE;CAAE;CAClC;EAAE,QAAQ;EAAO,UAAU,CAAC,OAAO,KAAK;CAAE;CAC1C;EAAE,QAAQ;EAAO,UAAU,CAAC,OAAO,KAAK;CAAE;CAC1C;EAAE,QAAQ;EAAK,UAAU;GAAC;GAAO;GAAO;EAAK;CAAE;AACjD;AAEA,MAAM,kBAAkB;AAExB,MAAa,eAA6C;CACxD,KAAK;CACL,KAAK;CACL,KAAK;CACL,OAAO;CACP,OAAO;AACT;AAEA,SAAgB,aACd,QACA,WACU;CACV,QAAQ,QAAR;EACE,KAAK,KACH,OAAO,CAAC,YAAY,GAAG,YAAY,CAAC;EACtC,KAAK,KACH,OAAO;GAAC,YAAY;GAAG,YAAY;GAAG,YAAY;EAAC;EACrD,KAAK,OACH,OAAO,CAAC,YAAY,GAAI,YAAY,IAAK,CAAC;EAC5C,KAAK,OACH,OAAO,CAAE,YAAY,IAAK,GAAG,YAAY,CAAC;EAC5C,SACE,OAAO,CAAC,SAAS;CACrB;AACF;;;;;;;;AASA,SAAgB,kBAAkB,UAGhC;CACA,MAAM,QAAQ,SAAS;CACvB,IAAI,UAAU,GAAG,OAAO;EAAE,QAAQ;EAAK,OAAO;CAAK;CAInD,IAAI,SAAS,OAAO,MAAM,MAAM,IAAI,GAAG;EACrC,IAAI,UAAU,GAAG,OAAO;GAAE,QAAQ;GAAK,OAAO;EAAK;EACnD,IAAI,UAAU,GAAG,OAAO;GAAE,QAAQ;GAAK,OAAO;EAAK;EACnD,IAAI,UAAU,GAAG,OAAO;GAAE,QAAQ;GAAK,OAAO;EAAK;EACnD,OAAO;GAAE,QAAQ;GAAK,OAAO;EAAM;CACrC;CAEA,MAAM,QAAQ,SAAS,QAAQ,MAAmB,MAAM,IAAI;CAC5D,MAAM,aAAa,QAAQ,MAAM;CACjC,MAAM,YACJ,eAAe,IACX,IACA,KAAK,IAAI,GAAG,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI;CAC5D,MAAM,WAAW,SAAS,KAAK,MAAM,KAAK,SAAS;CAEnD,MAAM,YAAY,cAAc,QAAQ,MAAM,EAAE,SAAS,WAAW,KAAK;CAEzE,KAAK,MAAM,SAAS,WAClB,IACE,MAAM,SAAS,OACZ,MAAM,MAAM,KAAK,IAAI,OAAO,SAAS,EAAE,KAAK,eAC/C,GAEA,OAAO;EAAE,QAAQ,MAAM;EAAQ,OAAO;CAAK;CAI/C,MAAM,aACJ,UAAU,SAAS,IACf,YACA,cAAc,QAAQ,MAAM,EAAE,WAAW,GAAG;CAElD,IAAI,OAAO,WAAW;CACtB,IAAI,YAAY;CAChB,KAAK,MAAM,SAAS,YAAY;EAC9B,MAAM,QAAQ,MAAM,SAAS,QAC1B,KAAK,MAAM,MAAM,MAAM,KAAK,IAAI,QAAQ,SAAS,MAAM,EAAE,GAC1D,CACF;EACA,IAAI,QAAQ,WAAW;GACrB,YAAY;GACZ,OAAO;EACT;CACF;CAEA,OAAO;EAAE,QAAQ,KAAK;EAAQ,OAAO;CAAM;AAC7C;;;AC3EA,SAAgB,cACd,MACA,KACW;CACX,QAAQ,KAAK,MAAb;EACE,KAAK,oBACH,OAAO,aAAa,MAAM,GAAG;EAC/B,KAAK,iBACH,OAAO,UAAU,MAAM,GAAG;EAC5B,KAAK,oBACH,OAAO,aAAa,MAAM,GAAG;EAC/B,SACE,OAAO,MAAM;CACjB;AACF;AAEA,SAAS,aAAa,MAAwB,KAA4B;CACxE,MAAM,OAAO,aAAa,IAAI;CAC9B,MAAM,YAAY,KAAK,QAAQ,KAAK,WAClC,SAAS,QAAQ,SAAS,IAAI,OAAO,CACvC;CACA,MAAM,EAAE,QAAQ,UAAU,kBACxB,UAAU,KAAK,UAAU,aAAa,KAAK,CAAC,CAC9C;CACA,MAAM,QAAQ,aAAa;CAC3B,MAAM,eAAe,YAAY,IAAI,cAAc,MAAM,GAAG;CAC5D,MAAM,aACJ,iBAAiB,KAAA,IAAY,KAAA,IAAY,aAAa,QAAQ,YAAY;CAC5E,MAAM,WAAW,YACf,KAAK,WACL,iBAAiB,KAAK,aAAa,EAAE,CACvC;CACA,MAAM,WAAsB,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS,CAAC,CAAC;CAClE,IAAI,SAAS,OAAO,SAAS,GAC3B,SAAS,EAAE,CAAC,KAAK,GAAG,SAAS,MAAM;CAGrC,MAAM,UAAU,SAAS;CACzB,KAAK,QAAQ,SAAS,QAAQ,UAAU;EACtC,MAAM,OAAO,KAAK,IAAI,OAAO,QAAQ,CAAC;EACtC,MAAM,QAAQ,YACZ,OAAO,YAAY,CAAC,GACpB,iBAAiB,KAAK,YAAY,aAAa,OAAO,QAAQ,GAAG,CAAC,CACpE;EACA,SAAS,KAAK,CAAC,KAAK,GAAG,MAAM,MAAM;EACnC,KAAK,MAAM,SAAS,MAAM,SAAS,QAAQ,KAAK,KAAK;CACvD,CAAC;CAED,MAAM,UAAoB,CAAC;CAC3B,IAAI,KAAK,OACP,QAAQ,KACN,mEACF;CAEF,IAAI,CAAC,OAAO;EACV,IAAI,KAAK,QAAQ,SAAS,OACxB,QAAQ,KACN,GAAG,KAAK,QAAQ,OAAO,mEAAmE,OAAO,GACnG;OACK;GACL,MAAM,QAAQ,UACX,KAAK,UACJ,OAAO,UAAU,YAAY,CAAC,QAAQ,KAAK,IAAI,QAAQ,MACzD,CAAC,CACA,KAAK,IAAI;GACZ,QAAQ,KACN,iBAAiB,MAAM,kDAAkD,OAAO,GAClF;EACF;CACF;CAEA,MAAM,UAAU,mBAAmB;CACnC,QAAQ,UAAU;CAClB,QAAQ,WAAW;CACnB,aAAa,SAAS,MAAM,KAAK,EAC/B,eAAe,KAAK,UAAU,QAAQ,KAAA,EACxC,CAAC;CACD,MAAM,aAAa,yBAChB,SAAS,SAAS,MAAM,MAAM,IAAI,OAAO,GAC1C,WACA,IAAI,YACN;CACA,IAAI,YAAY;EACd,QAAQ,kBAAkB,WAAW;EACrC,QAAQ,KAAK,GAAG,WAAW,KAAK;CAClC;CACA,QAAQ,QACN,aACE,MACA,QAAQ,SAAS,IAAI,iBAAiB,aACtC,QAAQ,SAAS,IAAI,QAAQ,KAAK,GAAG,IAAI,KAAA,CAC3C,CACF;CACA,OAAO;EAAE,QAAQ,CAAC,OAAO;EAAG;CAAQ;AACtC;;;;;;;;AASA,SAAS,UAAU,MAAwB,KAA4B;CACrE,MAAM,UAA+B,CAAC;CACtC,MAAM,QAAQ,YACZ,KAAK,YAAY,CAAC,GAClB,iBAAiB,KAAK,YAAY,IAAI,cAAc,MAAM,GAAG,CAAC,CAChE;CACA,KAAK,MAAM,SAAS,MAAM,SAAS,QAAQ,KAAK,KAAK;CAErD,MAAM,UAAU,mBAAmB;CACnC,QAAQ,UAAU;CAClB,QAAQ,WAAW,CAAC,MAAM,MAAM;CAChC,aAAa,SAAS,MAAM,GAAG;CAI/B,MAAM,UAAU,SAAS,MAAM,oBAAoB,IAAI,OAAO;CAC9D,MAAM,aACJ,YAAY,KAAA,KACZ,YAAY,QACX,OAAO,YAAY,YAAY,QAAQ,KAAK,MAAM;CACrD,IAAI,CAAC,QAAQ,OAAO,mBAAmB,YACrC,QAAQ,OAAO,kBAAkB;CAGnC,MAAM,OAAO,cACV,SAAS,SAAS,MAAM,MAAM,IAAI,OAAO,GAC1C,QACA,IAAI,YACN;CACA,IAAI,KAAK,OAAO,QAAQ,kBAAkB,KAAK;CAC/C,IAAI,KAAK,MAAM,QAAQ,OAAO,KAAK;CAEnC,QAAQ,QACN,aACE,MACA,KAAK,MAAM,SAAS,IAAI,iBAAiB,aACzC,KAAK,MAAM,SAAS,IAAI,KAAK,MAAM,KAAK,GAAG,IAAI,KAAA,CACjD,CACF;CACA,OAAO;EAAE,QAAQ,CAAC,OAAO;EAAG;CAAQ;AACtC;AAEA,SAAS,aAAa,MAAwB,KAA4B;CACxE,MAAM,SAAkB,CAAC;CACzB,MAAM,UAA+B,CAAC;CACtC,MAAM,WAAW,iBACf,KACA,YAAY,IAAI,cAAc,MAAM,GAAG,CACzC;CACA,KAAK,MAAM,SAAS,SAAS,IAAI,GAAG;EAClC,IAAI,MAAM,SAAS,eAAe;EAClC,MAAM,QAAQ,cAAc,OAAO,QAAQ;EAC3C,KAAK,MAAM,SAAS,MAAM,QAAQ,OAAO,KAAK,KAAK;EACnD,KAAK,MAAM,SAAS,MAAM,SAAS,QAAQ,KAAK,KAAK;CACvD;CAEA,IAAI,CAAC,OAAO,KAAK,SAAS,GACxB,OAAO;EACL,QAAQ,CAAC;EACT,SAAS,CACP;GACE,WAAW;GACX,sBAAsB;GACtB,QAAQ;GACR,MAAM;EACR,CACF;CACF;CAGF,aAAa,MAAM,QAAQ,SAAS,GAAG;CACvC,OAAO;EAAE;EAAQ;CAAQ;AAC3B;;;;;;;;AASA,SAAgB,aACd,MACA,QACA,SACA,KACM;CACN,MAAM,WAAW,OAAO,OAAO,SAAS;CACxC,IAAI,SAAS,WAAW,GAAG;CAE3B,MAAM,EAAE,SAAS,UAAU,YAAY,MAAM,GAAG;CAChD,KAAK,MAAM,WAAW,UACpB,QAAQ,UAAU;EAChB,GAAG;EACH,GAAI,QAAQ,kBACR,EACE,iBAAiB;GACf,GAAG,QAAQ;GACX,UAAU,EAAE,GAAG,QAAQ,gBAAgB,SAAS;EAClD,EACF,IACA,CAAC;CACP;CAEF,IAAI,SAAS,SAAS,GAAG;EACvB,MAAM,OAAO,GAAG,KAAK,QAAQ,mBAAmB,WAAW,SAAS,OAAO;EAC3E,KAAK,MAAM,SAAS,SAAS;GAC3B,IAAI,MAAM,yBAAyB,WAAW;GAC9C,IAAI,MAAM,WAAW,aAAa;GAClC,MAAM,SAAS;GACf,MAAM,OAAO;EACf;CACF;CACA,IAAI,MAAM,SAAS,GAAG;EACpB,MAAM,iBAAiB,QAAQ,QAC5B,UAAU,MAAM,yBAAyB,SAC5C;EACA,IAAI,eAAe,WAAW,GAC5B,QAAQ,KAAK;GACX,WAAW,KAAK,QAAQ;GACxB,sBAAsB;GACtB,QAAQ;GACR,MAAM,MAAM,KAAK,GAAG;EACtB,CAAC;EAEH,KAAK,MAAM,SAAS,gBAAgB;GAClC,MAAM,SAAS;GACf,MAAM,OAAO,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EAC9D;CACF;AACF;;AAGA,SAAgB,YACd,OACA,MACA,KACoB;CACpB,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;CAChC,MAAM,UAAU,aAAa,QAAQ,SAAS,MAAM,KAAK,IAAI,OAAO,CAAC;CACrE,OAAO,KAAK,IAAI,GAAG,QAAQ,QAAQ,OAAO,QAAQ,KAAK;AACzD;AAEA,SAAgB,iBACd,KACA,cACY;CACZ,OAAO;EAAE,GAAG;EAAK;CAAa;AAChC;AAEA,SAAS,UAAU,OAAqC;CACtD,OAAO,MAAM,SAAS;AACxB;;;;;;AAOA,SAAS,aAAa,SAKpB;CACA,MAAM,OAAO,mBAAmB,OAAO;CAEvC,IAAI,KAAK,OAAO,QAAQ,IAAI,SAAS,iBAAiB,GACpD,OAAO;EAAE,SAAS;EAAM,WAAW,CAAC;EAAG,SAAS;EAAO,OAAO;CAAM;CAGtE,IAAI,KAAK,WAAW,KAAK,KAAK,EAAE,CAAC,SAAS,kBAAkB;EAC1D,MAAM,YAAY,mBAAmB,KAAK,EAAE;EAC5C,IAAI,UAAU,OAAO,QAAQ,IAAI,SAAS,iBAAiB,GACzD,OAAO;GACL,SAAS;GACT,WAAW,CAAC;GACZ,SAAS;GACT,OAAO;EACT;CAEJ;CAEA,MAAM,UAA8B,CAAC;CACrC,MAAM,YAAgC,CAAC;CACvC,IAAI,UAAU;CACd,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,IAAI,SAAS,mBAAmB;GAClC,QAAQ,KAAK,GAAG;GAChB;EACF;EACA,IAAI,IAAI,SAAS,kBAAkB;GACjC,UAAU;GACV,KAAK,MAAM,SAAS,mBAAmB,GAAG,GACxC,IAAI,MAAM,SAAS,mBAAmB,QAAQ,KAAK,KAAK;QACnD,UAAU,KAAK,KAAK;GAE3B;EACF;EACA,UAAU,KAAK,GAAG;CACpB;CACA,OAAO;EAAE;EAAS;EAAW;EAAS,OAAO;CAAK;AACpD;AAEA,SAAS,YACP,OACA,KACW;CACX,MAAM,SAAkB,CAAC;CACzB,MAAM,UAA+B,CAAC;CACtC,KAAK,MAAM,SAAS,SAAS,CAAC,GAAG;EAC/B,IAAI,CAACE,YAAU,KAAK,GAAG;EACvB,IAAI,MAAM,SAAS,eAAe;EAClC,IAAI,MAAM,SAAS,kBAAkB;GACnC,MAAM,eAAe,mBAAmB,KAAK,CAAC,CAAC,QAC5C,SAAS,KAAK,SAAS,iBAC1B;GACA,QAAQ,KAAK;IACX,WAAW;IACX,sBAAsB;IACtB,QAAQ;IACR,MAAM,2BAA2B,aAAa,OAAO;GACvD,CAAC;GACD,KAAK,MAAM,UAAU,cAAc;IACjC,MAAM,QAAQ,YAAY,OAAO,UAAU,GAAG;IAC9C,KAAK,MAAM,SAAS,MAAM,QAAQ,OAAO,KAAK,KAAK;IACnD,KAAK,MAAM,SAAS,MAAM,SAAS,QAAQ,KAAK,KAAK;GACvD;GACA;EACF;EACA,IAAI,MAAM,SAAS,mBAAmB;GACpC,MAAM,QAAQ,YAAY,MAAM,UAAU,GAAG;GAC7C,KAAK,MAAM,SAAS,MAAM,QAAQ,OAAO,KAAK,KAAK;GACnD,KAAK,MAAM,SAAS,MAAM,SAAS,QAAQ,KAAK,KAAK;GACrD;EACF;EACA,MAAM,YAAY,YAAY,OAAO,GAAG;EACxC,KAAK,MAAM,SAAS,UAAU,QAAQ,OAAO,KAAK,KAAK;EACvD,KAAK,MAAM,SAAS,UAAU,SAAS,QAAQ,KAAK,KAAK;CAC3D;CACA,OAAO;EAAE;EAAQ;CAAQ;AAC3B;;AAGA,SAAS,aACP,SACA,MACA,KACA,QACM;CACN,QAAQ,OAAO,UAAU,aAAa,QACpC,SAAS,MAAM,KAAK,IAAI,OAAO,CACjC;CACA,MAAM,OAAO,YAAY,MAAM,GAAG;CAClC,IAAI,MAAM,QAAQ,OAAO,kBAAkB;CAC3C,MAAM,SAAS,QAAQ,SAAS,MAAM,iBAAiB,IAAI,OAAO,CAAC;CACnE,IAAI,WAAW,KAAA,KAAa,SAAS,GAAG,QAAQ,eAAe;CAC/D,IAAI,QAAQ,kBAAkB,OAAO,QAAQ,gBAAgB;CAC7D,MAAM,aAAa,eAAe,IAAI;CACtC,IAAI,YAAY,QAAQ,aAAa;AACvC;AAEA,SAAS,YACP,MACA,KACoB;CACpB,MAAM,MAAM,WAAW,SAAS,MAAM,oBAAoB,IAAI,OAAO,CAAC;CACtE,IAAI,KAAK,OAAO;CAChB,OAAO,WACL,SAAS,IAAI,QAAQ,MAAM,4BAA4B,IAAI,OAAO,CACpE;AACF;AAEA,SAAS,YACP,MACA,KAC8C;CAC9C,MAAM,kBAAkB,WACtB,SAAS,MAAM,oBAAoB,IAAI,OAAO,CAChD;CACA,MAAM,UAAU,aAAa,QAAQ,SAAS,MAAM,KAAK,IAAI,OAAO,CAAC;CACrE,MAAM,SAAS,QAAQ,SAAS,MAAM,iBAAiB,IAAI,OAAO,CAAC;CACnE,MAAM,aAAa,yBAChB,SAAS,SAAS,MAAM,MAAM,IAAI,OAAO,GAC1C,WACA,IAAI,YACN;CACA,OAAO;EACL,SAAS;GACP,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;GAC7C;GACA,GAAI,WAAW,KAAA,KAAa,SAAS,IAAI,EAAE,cAAc,OAAO,IAAI,CAAC;GACrE,GAAI,aAAa,EAAE,iBAAiB,WAAW,MAAM,IAAI,CAAC;EAC5D;EACA,OAAO,YAAY,SAAS,CAAC;CAC/B;AACF;AAEA,SAAS,aACP,MACA,QACA,MACmB;CACnB,OAAO;EACL,WAAW,KAAK,QAAQ;EACxB,sBAAsB;EACtB;EACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;CACzB;AACF;AAEA,SAAS,eAAe,MAAqD;CAC3E,IAAI,KAAK,YAAY,WAAW,OAAO;EAAE,SAAS;EAAM,QAAQ;CAAM;CACtE,IAAI,KAAK,YAAY,UAAU,OAAO;EAAE,SAAS;EAAO,QAAQ;CAAK;AAEvE;AAEA,SAAS,mBAAmB,MAA4C;CACtE,OAAO,SAAS,IAAI,CAAC,CAAC,QAAQ,UAAU,MAAM,SAAS,aAAa;AACtE;AAEA,SAAS,SAAS,MAA4C;CAC5D,MAAM,MAA0B,CAAC;CACjC,KAAK,MAAM,SAAS,KAAK,YAAY,CAAC,GACpC,IAAIA,YAAU,KAAK,GAAG,IAAI,KAAK,KAAK;CAEtC,OAAO;AACT;AAEA,SAASA,YACP,MAC0B;CAC1B,OAAO,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS;AACxD;AAEA,SAAS,QAAmB;CAC1B,OAAO;EAAE,QAAQ,CAAC;EAAG,SAAS,CAAC;CAAE;AACnC;;;AC9aA,MAAM,kBACJ;AACF,MAAM,cACJ;AACF,MAAM,gBACJ;AACF,MAAM,iBACJ;AAEF,SAAS,WAAW,UAAkB,YAA4B;CAChE,OAAO,YAAY,SAAS,kBAAkB,WAAW;AAC3D;AAEA,MAAM,kCAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,kCAAkB,IAAI,IAAI;CAC9B;CACA;CACA;AACF,CAAC;AAED,MAAM,+BAAe,IAAI,IAAI,CAAC,kBAAkB,gBAAgB,CAAC;;;;;;AAOjE,MAAM,kCAAkB,IAAI,IAAI,CAAC,eAAe,aAAa,CAAC;;;;;;;AAQ9D,MAAM,oBAAoB;;;;;;AAiB1B,SAAgB,4BACd,KACc;CACd,MAAM,OAAgB,OAAO,QAAQ,WAAW,UAAU,GAAG,IAAI;CAEjE,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,GACjE,MAAM,IAAI,MAAM,eAAe;CAGjC,MAAM,YAAY,eAAe,IAAI;CACrC,IAAI,UAAU,KAAK,SAAS,QAC1B,MAAM,IAAI,MAAM,eAAe;CAEjC,MAAM,OAAO,UAAU;CACvB,MAAM,UAAU,UAAU;CAC1B,aAAa,IAAI;CAEjB,MAAM,WAAqB,CAAC;CAC5B,MAAM,UAA+B,CAAC;CACtC,MAAM,SAAkB,CAAC;CACzB,MAAM,UAAU,gBAAgB,IAAI;CACpC,MAAM,OAAO,cAAc,KAAK,IAAI,IAAI,KAAK,OAAO,CAAC;CACrD,MAAM,WAAW,aAAa,MAAM,MAAM,OAAO;CACjD,MAAM,MAAkB;EAAE;EAAS;EAAU,cAAc,SAAS;CAAM;CAG1E,IADmB,OAAO,YAAY,WAAW,QAAQ,KAAK,IAAI,IAEhE,SAAS,KACP,qBAAqB,QAAQ,iDAC/B;CAEF,IAAI,MAAM,QAAQ,KAAK,KAAK,KAAK,KAAK,MAAM,SAAS,GACnD,SAAS,KACP,4EACF;CAEF,IAAI,qBAAqB,KAAK,UAAU,GACtC,SAAS,KACP,qFACF;CAEF,IACE,cAAc,KAAK,eAAe,KAClC,OAAO,KAAK,KAAK,eAAe,CAAC,CAAC,SAAS,GAE3C,SAAS,KACP,8EACF;CAGF,KAAK,MAAM,SAAS,KAAK,YAAY,CAAC,GAAG;EACvC,IAAI,CAAC,UAAU,KAAK,GAAG;EACvB,SAAS,OAAO,KAAK,SAAS,MAAM;CACtC;CAEA,IAAI,oBAAoB,IAAI,GAC1B,SAAS,KAAK,cAAc;CAG9B,IAAI,QAAQ,MAAM,WAAW,KAAK,QAAQ,MAAM,aAAa,GAC3D,SAAS,KAAK,WAAW,QAAQ,MAAM,UAAU,QAAQ,MAAM,UAAU,CAAC;CAG5E,IAAI,OAAO,WAAW,GACpB,SAAS,KAAK,aAAa;CAG7B,MAAM,WAAW,6BAA6B;CAkB9C,OAAO;EAAE,SAAA;GAhBP,GAAG;GACH;GACA,UAAU;IACR,GAAG,SAAS;IACZ,GAAG;GACL;EAWa;EAAG,QAAQ;GAAE;GAAS;GAAU,SAAA;IAP7C,OAAO,QAAQ;IACf,WAAW,QAAQ,QAAQ,MAAM,EAAE,WAAW,WAAW,CAAC,CAAC;IAC3D,cAAc,QAAQ,QAAQ,MAAM,EAAE,WAAW,cAAc,CAAC,CAAC;IACjE,cAAc,QAAQ,QAAQ,MAAM,EAAE,WAAW,eAAe,CAAC,CAAC;IAClE,SAAS,QAAQ,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC,CAAC;GAGJ;EAAE;CAAE;AAC3D;AAEA,SAAS,aACP,MACA,MACA,SACkB;CAClB,MAAM,QACJ,QAAQ,SAAS,MAAM,SAAS,OAAO,CAAC,KAAK,kBAAkB;CAGjE,MAAM,kBACJ,WAAW,SAAS,MAAM,oBAAoB,OAAO,CAAC,KACtD,kBAAkB;CACpB,MAAM,gBAAgB,SAAS,MAAM,eAAe,OAAO;CAC3D,MAAM,cACH,OAAO,kBAAkB,YAAY,CAAC,QAAQ,aAAa,IACxD,mBAAmB,aAAa,IAChC,OAAO,kBAAkB;CAC/B,MAAM,YACJ,WAAW,SAAS,MAAM,SAAS,OAAO,CAAC,KAAK,kBAAkB;CACpE,MAAM,YAAY,WAAW,SAAS,MAAM,cAAc,OAAO,CAAC;CAClE,MAAM,OAAO,SAAS,MAAM,wBAAwB,OAAO;CAC3D,MAAM,gBACJ,SAAS,cACL,OACA,SAAS,SACP,QACA,kBAAkB;CAC1B,MAAM,eACJ,OAAO,KAAK,cAAc,WAAW,KAAK,UAAU,KAAK,IAAI;CAE/D,OAAO;EACL;EACA;EACA;EACA;EACA;EACA,QAAQ,kBAAkB;EAC1B,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EACjC,GAAI,eAAe,EAAE,eAAe,aAAa,IAAI,CAAC;CACxD;AACF;AAEA,SAAS,SACP,MACA,KACA,SACA,QACM;CACN,IAAI,KAAK,SAAS,eAAe;CAEjC,MAAM,QAAQ,KAAK;CACnB,MAAM,UAAU,SAAS,KAAK;CAC9B,IAAI,WAAW,CAAC,gBAAgB,IAAI,GAAG;EACrC,QAAQ,KAAK;GACX,WAAW,KAAK,QAAQ;GACxB,sBAAsB;GACtB,QAAQ;GACR,MAAM,wBAAwB,gBAAgB,KAAK,EAAE;EACvD,CAAC;EACD;CACF;CAEA,IAAI,OAAO,KAAK,SAAS,YAAY,aAAa,IAAI,KAAK,IAAI,GAAG;EAChE,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,cAAc,KAAK,IAAI,IAAI,KAAK,OAAO,CAAC;EACrD,MAAM,QAAQ,cAAc,KAAK,KAAK,IAAI,KAAK,QAAQ,KAAA;EACvD,MAAM,QAAoB;GACxB,GAAG;GACH,SAAS,gBAAgB,IAAI,SAAS,KAAK;EAC7C;EACA,KAAK,MAAM,SAAS,KAAK,YAAY,CAAC,GAAG;GACvC,IAAI,CAAC,UAAU,KAAK,GAAG;GACvB,SAAS,OAAO,OAAO,SAAS,MAAM;EACxC;EACA,iBACE,SACA,MACA,GAAG,KAAK,KAAK,4CACb,EACE,WAAW,KAAK,KAClB,CACF;EACA,IAAI,SACF,iBAAiB,SAAS,MAAM,SAAS,gBAAgB,KAAK,GAAG;EAEnE;CACF;CAEA,MAAM,OAAO,QAAQ;CACrB,IAAI,OAAO,KAAK,SAAS,YAAY,gBAAgB,IAAI,KAAK,IAAI,GAAG;EACnE,MAAM,YAAY,cAAc,MAAM,GAAG;EACzC,KAAK,MAAM,SAAS,UAAU,QAAQ,OAAO,KAAK,KAAK;EACvD,KAAK,MAAM,SAAS,UAAU,SAAS,QAAQ,KAAK,KAAK;CAC3D,OAAO,IAAI,WAAW,IAAI,GACxB,SAAS,MAAM,KAAK,SAAS,MAAM;MAC9B;EACL,MAAM,YAAY,YAAY,MAAM,GAAG;EACvC,KAAK,MAAM,SAAS,UAAU,SAAS,QAAQ,KAAK,KAAK;EACzD,IAAI,UAAU,OAAO,SAAS,GAAG;GAC/B,IAAI,WAAW,KAAK,IAAI,GACtB,OAAO,KAAK,cAAc,UAAU,MAAM,CAAC;QAE3C,OAAO,KAAK,GAAG,UAAU,MAAM;EAEnC;CACF;CAEA,IAAI,SACF,iBAAiB,SAAS,MAAM,SAAS,gBAAgB,KAAK,GAAG;AAErE;;;;;;AAOA,SAAS,SACP,MACA,KACA,SACA,QACM;CACN,MAAM,QAAQ,iBAAiB,KAAK,YAAY,IAAI,cAAc,MAAM,GAAG,CAAC;CAC5E,MAAM,aAAsB,CAAC;CAC7B,MAAM,cAAmC,CAAC;CAC1C,KAAK,MAAM,SAAS,YAAY,IAAI,GAClC,SAAS,OAAO,OAAO,aAAa,UAAU;CAEhD,IAAI,WAAW,WAAW,KAAK,YAAY,WAAW,GAAG;EACvD,QAAQ,KAAK;GACX,WAAW,KAAK;GAChB,sBAAsB;GACtB,QAAQ;GACR,MAAM,YAAY,KAAK,KAAK;EAC9B,CAAC;EACD;CACF;CACA,aAAa,MAAM,YAAY,aAAa,GAAG;CAC/C,KAAK,MAAM,SAAS,YAAY,OAAO,KAAK,KAAK;CACjD,KAAK,MAAM,SAAS,aAAa,QAAQ,KAAK,KAAK;AACrD;AAIA,SAAS,WAAW,MAA0C;CAC5D,OAAO,OAAO,KAAK,SAAS,YAAY,gBAAgB,IAAI,KAAK,IAAI;AACvE;AAEA,SAAS,YAAY,MAA4C;CAC/D,MAAM,UAAU,cAAc,KAAK,IAAI,IAAI,KAAK,KAAK,UAAU,KAAA;CAC/D,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG,OAAO,CAAC;CACrC,OAAO,QAAQ,QACZ,UACC,cAAc,KAAK,KAAK,UAAU,KAAyB,CAC/D;AACF;AAEA,SAAS,cAAc,QAAwB;CAC7C,MAAM,UAAU,mBAAmB;CACnC,QAAQ,UAAU;CAClB,QAAQ,WAAW,CAAC,MAAM;CAC1B,OAAO;AACT;AAEA,SAAS,iBACP,SACA,MACA,OACA,SACM;CACN,KAAK,IAAI,IAAI,MAAM,IAAI,QAAQ,QAAQ,KAAK;EAC1C,MAAM,QAAQ,QAAQ;EACtB,IAAI,SAAS,MAAM,YAAY,QAAQ;EACvC,IAAI,MAAM,WAAW,aAAa,MAAM,SAAS;EACjD,MAAM,OAAO,MAAM,OAAO,GAAG,MAAM,KAAK,GAAG,UAAU;CACvD;AACF;AAEA,SAAS,SACP,OACiD;CACjD,IAAI,SAAS,QAAQ,OAAO,UAAU,UAAU,OAAO;CACvD,OAAO,MAAM,aAAa,QAAQ,MAAM,aAAa;AACvD;AAEA,SAAS,gBACP,OACQ;CACR,MAAM,QAAkB,CAAC;CACzB,IAAI,MAAM,aAAa,MACrB,MAAM,KACJ,OAAO,MAAM,cAAc,WACvB,MAAM,YACN,KAAK,UAAU,MAAM,SAAS,CACpC;CAEF,IAAI,MAAM,aAAa,MAAM;EAC3B,MAAM,YAAY,MAAM;EACxB,IAAI,OAAO,cAAc,UACvB,MAAM,KAAK,SAAS;OACf,IACL,cAAc,SAAS,KACvB,OAAO,UAAU,eAAe,UAEhC,MAAM,KAAK,UAAU,UAAU;OAE/B,MAAM,KAAK,KAAK,UAAU,SAAS,CAAC;CAExC;CACA,OAAO,MAAM,KAAK,GAAG;AACvB;AAEA,SAAS,gBAAgB,MAAiC;CACxD,MAAM,OAAO,WAAW,IAAI,IAAI,YAAY,IAAI,IAAK,KAAK,YAAY,CAAC;CACvE,KAAK,MAAM,SAAS,MAAM;EACxB,IAAI,CAAC,UAAU,KAAK,GAAG;EACvB,IAAI,MAAM,SAAS,eAAe;EAClC,OAAO;CACT;CACA,OAAO;AACT;AAEA,SAAS,oBAAoB,MAAwB;CACnD,IAAI,CAAC,cAAc,IAAI,GAAG,OAAO;CACjC,MAAM,SAAS,KAAK;CACpB,IAAI,cAAc,MAAM,KAAK,OAAO,KAAK,MAAM,CAAC,CAAC,SAAS,GAAG,OAAO;CACpE,MAAM,OAAO,WAAW,IAAwB,IAC5C,YAAY,IAAwB,IACpC,CAAC;CACL,MAAM,WAAW,MAAM,QAAQ,KAAK,QAAQ,IAAI,KAAK,WAAW,CAAC;CACjE,KAAK,MAAM,SAAS,CAAC,GAAG,UAAU,GAAG,IAAI,GACvC,IAAI,oBAAoB,KAAK,GAAG,OAAO;CAEzC,OAAO;AACT;AAEA,SAAS,aAAa,MAA8B;CAClD,MAAM,WAAW,KAAK,YAAY,CAAC;CACnC,KAAK,MAAM,SAAS,UAAU;EAC5B,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU;EACzC,MAAM,OAAQ,MAA2B;EACzC,IAAI,OAAO,SAAS,UAAU;EAC9B,IAAI,gBAAgB,IAAI,IAAI,GAC1B,MAAM,IAAI,MAAM,WAAW;EAE7B;CACF;AACF;AAEA,SAAS,UACP,MAC0B;CAC1B,OAAO,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS;AACxD;AAEA,SAAS,qBAAqB,OAAyB;CACrD,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO,MAAM,SAAS;CAChD,OAAO,cAAc,KAAK,KAAK,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS;AAC7D;AAEA,SAAS,cAAc,OAAkD;CACvE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,UAAU,KAAsB;CACvC,IAAI;EACF,OAAO,KAAK,MAAM,GAAG;CACvB,QAAQ;EACN,MAAM,IAAI,MAAM,eAAe;CACjC;AACF"}
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@templatical/import-easy-email-pro",
3
3
  "description": "Convert Easy Email Pro email templates to Templatical format",
4
- "version": "0.46.0",
4
+ "version": "0.48.0",
5
5
  "bugs": "https://github.com/templatical/sdk/issues",
6
6
  "dependencies": {
7
- "@templatical/types": "0.46.0"
7
+ "@templatical/types": "0.48.0"
8
8
  },
9
9
  "devDependencies": {
10
10
  "@types/node": "^25.9.9",
11
11
  "typescript": "^6.0.3",
12
- "vitest": "^5.0.3"
12
+ "vitest": "^5.0.4"
13
13
  },
14
14
  "exports": {
15
15
  ".": {