docgen-utils 1.0.20 → 1.0.22

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.
Files changed (33) hide show
  1. package/README.md +2 -0
  2. package/dist/bundle.js +24203 -23922
  3. package/dist/bundle.min.js +251 -251
  4. package/dist/cli.js +501 -153
  5. package/dist/packages/cli/commands/export-docs.d.ts.map +1 -1
  6. package/dist/packages/cli/commands/export-docs.js +160 -11
  7. package/dist/packages/cli/commands/export-docs.js.map +1 -1
  8. package/dist/packages/docs/common.d.ts +31 -2
  9. package/dist/packages/docs/common.d.ts.map +1 -1
  10. package/dist/packages/docs/common.js +40 -0
  11. package/dist/packages/docs/common.js.map +1 -1
  12. package/dist/packages/docs/convert.d.ts.map +1 -1
  13. package/dist/packages/docs/convert.js +91 -21
  14. package/dist/packages/docs/convert.js.map +1 -1
  15. package/dist/packages/docs/create-document.d.ts.map +1 -1
  16. package/dist/packages/docs/create-document.js +8 -2
  17. package/dist/packages/docs/create-document.js.map +1 -1
  18. package/dist/packages/docs/import-docx.d.ts.map +1 -1
  19. package/dist/packages/docs/import-docx.js +2 -1
  20. package/dist/packages/docs/import-docx.js.map +1 -1
  21. package/dist/packages/docs/parse-css.d.ts.map +1 -1
  22. package/dist/packages/docs/parse-css.js +10 -3
  23. package/dist/packages/docs/parse-css.js.map +1 -1
  24. package/dist/packages/docs/parse.d.ts.map +1 -1
  25. package/dist/packages/docs/parse.js +233 -123
  26. package/dist/packages/docs/parse.js.map +1 -1
  27. package/dist/packages/slides/import-pptx.d.ts.map +1 -1
  28. package/dist/packages/slides/import-pptx.js +73 -2
  29. package/dist/packages/slides/import-pptx.js.map +1 -1
  30. package/dist/packages/slides/parse.d.ts.map +1 -1
  31. package/dist/packages/slides/parse.js +68 -2
  32. package/dist/packages/slides/parse.js.map +1 -1
  33. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -43617,11 +43617,18 @@ async function loadZipSafely(arrayBuffer) {
43617
43617
  }
43618
43618
 
43619
43619
  // node_modules/rtf.js/index.js
43620
+ var rtf_exports = {};
43621
+ __export(rtf_exports, {
43622
+ EMFJS: () => EMFJS,
43623
+ RTFJS: () => RTFJS,
43624
+ WMFJS: () => WMFJS
43625
+ });
43620
43626
  var RTFJS = __toESM(require_RTFJS_bundle());
43621
43627
  var EMFJS = __toESM(require_EMFJS_bundle());
43622
43628
  var WMFJS = __toESM(require_WMFJS_bundle());
43623
43629
 
43624
43630
  // packages/docs/import-docx.ts
43631
+ var { EMFJS: EMFJS2 } = rtf_exports;
43625
43632
  var TWIPS_PER_PX = 1440 / 96;
43626
43633
  var EMU_PER_PX = 914400 / 96;
43627
43634
  var HALF_POINTS_TO_PT = 0.5;
@@ -43872,7 +43879,7 @@ async function convertEmfToSvg(buffer2) {
43872
43879
  console.log = () => {
43873
43880
  };
43874
43881
  try {
43875
- const renderer = new EMFJS.Renderer(buffer2);
43882
+ const renderer = new EMFJS2.Renderer(buffer2);
43876
43883
  const svg = renderer.render({
43877
43884
  width: boundsWidth + "px",
43878
43885
  height: boundsHeight + "px",
@@ -46414,6 +46421,34 @@ function parseDecorativeShapes(spTree, scale, themeColors, imageMap, themeFonts)
46414
46421
  }
46415
46422
  function parseGroupShape(grpSp, scale, themeColors, imageMap, themeFonts) {
46416
46423
  const elements = [];
46424
+ const grpSpPr = findChild2(grpSp, "grpSpPr");
46425
+ const xfrm = grpSpPr ? findChild2(grpSpPr, "xfrm") : null;
46426
+ const grpOff = xfrm ? findChild2(xfrm, "off") : null;
46427
+ const grpExt = xfrm ? findChild2(xfrm, "ext") : null;
46428
+ const chOff = xfrm ? findChild2(xfrm, "chOff") : null;
46429
+ const chExt = xfrm ? findChild2(xfrm, "chExt") : null;
46430
+ const hasTransform = !!(grpOff && grpExt && chOff && chExt);
46431
+ const grpOffX = parseInt(grpOff?.getAttribute("x") ?? "0", 10);
46432
+ const grpOffY = parseInt(grpOff?.getAttribute("y") ?? "0", 10);
46433
+ const grpExtCx = parseInt(grpExt?.getAttribute("cx") ?? "0", 10);
46434
+ const grpExtCy = parseInt(grpExt?.getAttribute("cy") ?? "0", 10);
46435
+ const chOffX = parseInt(chOff?.getAttribute("x") ?? "0", 10);
46436
+ const chOffY = parseInt(chOff?.getAttribute("y") ?? "0", 10);
46437
+ const chExtCx = parseInt(chExt?.getAttribute("cx") ?? "1", 10);
46438
+ const chExtCy = parseInt(chExt?.getAttribute("cy") ?? "1", 10);
46439
+ const scaleX = grpExtCx / chExtCx;
46440
+ const scaleY = grpExtCy / chExtCy;
46441
+ function remapCoords(el) {
46442
+ if (!hasTransform) return;
46443
+ const childXEmu = el.x / scale * EMU_PER_PX2;
46444
+ const childYEmu = el.y / scale * EMU_PER_PX2;
46445
+ const childWEmu = el.w / scale * EMU_PER_PX2;
46446
+ const childHEmu = el.h / scale * EMU_PER_PX2;
46447
+ el.x = Math.round(emuToPx2(grpOffX + (childXEmu - chOffX) * scaleX) * scale);
46448
+ el.y = Math.round(emuToPx2(grpOffY + (childYEmu - chOffY) * scaleY) * scale);
46449
+ el.w = Math.round(emuToPx2(childWEmu * scaleX) * scale);
46450
+ el.h = Math.round(emuToPx2(childHEmu * scaleY) * scale);
46451
+ }
46417
46452
  for (let i = 0; i < grpSp.children.length; i++) {
46418
46453
  const child = grpSp.children[i];
46419
46454
  if (child.localName === "sp") {
@@ -46431,16 +46466,23 @@ function parseGroupShape(grpSp, scale, themeColors, imageMap, themeFonts) {
46431
46466
  const shape2 = parseShape(child, scale, themeColors, themeFonts);
46432
46467
  if (shape2) {
46433
46468
  shape2.clipPath = clipPath;
46469
+ remapCoords(shape2);
46434
46470
  elements.push({ kind: "shape", data: shape2 });
46435
46471
  }
46436
46472
  continue;
46437
46473
  }
46438
46474
  }
46439
46475
  const shape = parseShape(child, scale, themeColors, themeFonts);
46440
- if (shape) elements.push({ kind: "shape", data: shape });
46476
+ if (shape) {
46477
+ remapCoords(shape);
46478
+ elements.push({ kind: "shape", data: shape });
46479
+ }
46441
46480
  } else if (child.localName === "pic") {
46442
46481
  const img = parsePicture(child, scale, imageMap);
46443
- if (img) elements.push({ kind: "image", data: img });
46482
+ if (img) {
46483
+ remapCoords(img);
46484
+ elements.push({ kind: "image", data: img });
46485
+ }
46444
46486
  } else if (child.localName === "grpSp") {
46445
46487
  const nested = parseGroupShape(child, scale, themeColors, imageMap, themeFonts);
46446
46488
  elements.push(...nested);
@@ -46616,6 +46658,27 @@ function parseShape(sp, scale, themeColors, themeFonts) {
46616
46658
  }
46617
46659
  }
46618
46660
  }
46661
+ const effectLst = findChild2(spPr, "effectLst");
46662
+ if (effectLst) {
46663
+ const outerShdw = findChild2(effectLst, "outerShdw");
46664
+ if (outerShdw) {
46665
+ const blurRad = parseInt(outerShdw.getAttribute("blurRad") ?? "0", 10);
46666
+ const blurPx = Math.round(emuToPx2(blurRad) * scale);
46667
+ let shadowColor = "rgba(0,0,0,0.3)";
46668
+ const prstClr = findChild2(outerShdw, "prstClr");
46669
+ const srgbClr = findChild2(outerShdw, "srgbClr");
46670
+ if (prstClr || srgbClr) {
46671
+ const colorEl = prstClr ?? srgbClr;
46672
+ const alphaEl = colorEl ? findChild2(colorEl, "alpha") : null;
46673
+ const alphaVal = alphaEl ? parseInt(alphaEl.getAttribute("val") ?? "100000", 10) / 1e5 : 1;
46674
+ const baseColor = prstClr?.getAttribute("val") === "black" ? "0,0,0" : prstClr?.getAttribute("val") === "white" ? "255,255,255" : "0,0,0";
46675
+ shadowColor = `rgba(${baseColor},${alphaVal})`;
46676
+ }
46677
+ if (blurPx > 0) {
46678
+ shape.boxShadow = `0 0 ${blurPx}px ${shadowColor}`;
46679
+ }
46680
+ }
46681
+ }
46619
46682
  const txBody = findChild2(sp, "txBody");
46620
46683
  if (txBody) {
46621
46684
  const bodyPr = findChild2(txBody, "bodyPr");
@@ -47764,6 +47827,9 @@ function renderSlideHtml(elements, bgColor, contentOffsetX = 0) {
47764
47827
  styles.push(`border:${shape.borderWidth}px ${borderStyle} ${shape.borderColor}`);
47765
47828
  styles.push("box-sizing:border-box");
47766
47829
  }
47830
+ if (shape.boxShadow) {
47831
+ styles.push(`box-shadow:${shape.boxShadow}`);
47832
+ }
47767
47833
  if (shape.padding) {
47768
47834
  styles.push(
47769
47835
  `padding:${shape.padding.top}px ${shape.padding.right}px ${shape.padding.bottom}px ${shape.padding.left}px`
@@ -48153,6 +48219,9 @@ async function importPptx(arrayBuffer) {
48153
48219
  } else if (child.localName === "pic") {
48154
48220
  const img = parsePicture(child, scale, imageMap);
48155
48221
  if (img) elements.push({ kind: "image", data: img });
48222
+ } else if (child.localName === "grpSp") {
48223
+ const grpElements = parseGroupShape(child, scale, themeColors, imageMap, themeFonts);
48224
+ elements.push(...grpElements);
48156
48225
  } else if (child.localName === "graphicFrame") {
48157
48226
  const table = parseTable2(child, scale, themeColors, themeFonts, tableStyleMap);
48158
48227
  if (table) {
@@ -68753,6 +68822,28 @@ var UTF16LE = new Uint8Array([255, 254]);
68753
68822
  var UTF16BE = new Uint8Array([254, 255]);
68754
68823
 
68755
68824
  // packages/docs/common.ts
68825
+ function isStyledTableCell(cell) {
68826
+ if (typeof cell !== "object" || Array.isArray(cell)) return false;
68827
+ if (!("content" in cell)) return false;
68828
+ const styledCell = cell;
68829
+ const content = styledCell.content;
68830
+ if (typeof content === "string") return true;
68831
+ if (Array.isArray(content) && content.length > 0) {
68832
+ const first = content[0];
68833
+ if (typeof first === "object" && first !== null && "type" in first) {
68834
+ return false;
68835
+ }
68836
+ }
68837
+ return true;
68838
+ }
68839
+ function isComplexTableCell(cell) {
68840
+ if (typeof cell !== "object" || Array.isArray(cell)) return false;
68841
+ if (!("content" in cell)) return false;
68842
+ const content = cell.content;
68843
+ if (!Array.isArray(content) || content.length === 0) return false;
68844
+ const first = content[0];
68845
+ return typeof first === "object" && first !== null && "type" in first;
68846
+ }
68756
68847
  var HEADING_LEVEL_MAP = {
68757
68848
  1: HeadingLevel.HEADING_1,
68758
68849
  2: HeadingLevel.HEADING_2,
@@ -70025,7 +70116,7 @@ function getElementStyles(element, cssContext, parentElement2) {
70025
70116
  }
70026
70117
  }
70027
70118
  }
70028
- if (!parentElement2) {
70119
+ {
70029
70120
  const fillIn = (source) => {
70030
70121
  for (const [key2, value] of Object.entries(source)) {
70031
70122
  if (value !== void 0 && result[key2] === void 0) {
@@ -71545,7 +71636,73 @@ function detectTimeline(element, cssContext) {
71545
71636
  }
71546
71637
 
71547
71638
  // packages/docs/parse.ts
71548
- function parseContainerContent(element, cssContext, inheritedColor) {
71639
+ function getDirectRows(tableEl) {
71640
+ const result = [];
71641
+ for (const child of tableEl.children) {
71642
+ const childTag = child.tagName.toLowerCase();
71643
+ if (childTag === "tr") {
71644
+ result.push(child);
71645
+ } else if (childTag === "thead" || childTag === "tbody" || childTag === "tfoot") {
71646
+ for (const grandchild of child.children) {
71647
+ if (grandchild.tagName.toLowerCase() === "tr") {
71648
+ result.push(grandchild);
71649
+ }
71650
+ }
71651
+ }
71652
+ }
71653
+ return result;
71654
+ }
71655
+ function getDirectCells(rowEl) {
71656
+ const result = [];
71657
+ for (const child of rowEl.children) {
71658
+ const childTag = child.tagName.toLowerCase();
71659
+ if (childTag === "td" || childTag === "th") {
71660
+ result.push(child);
71661
+ }
71662
+ }
71663
+ return result;
71664
+ }
71665
+ function cellHasNestedTable(cellEl) {
71666
+ return cellEl.querySelector("table") !== null;
71667
+ }
71668
+ function isLayoutTable(tableEl, cssContext) {
71669
+ const styles = getElementStyles(tableEl, cssContext);
71670
+ const inlineStyle = tableEl.getAttribute("style") || "";
71671
+ if (inlineStyle.includes("border: none") || inlineStyle.includes("border:none")) {
71672
+ return true;
71673
+ }
71674
+ if (styles.border && styles.border.includes("none")) {
71675
+ return true;
71676
+ }
71677
+ return false;
71678
+ }
71679
+ function createParsedImageElement(imageEl, imageKey) {
71680
+ const src = imageEl.getAttribute("src")?.trim();
71681
+ if (!src) {
71682
+ return null;
71683
+ }
71684
+ const alt = imageEl.getAttribute("alt") || void 0;
71685
+ let width;
71686
+ let height;
71687
+ const widthAttr = imageEl.getAttribute("width");
71688
+ const heightAttr = imageEl.getAttribute("height");
71689
+ if (widthAttr && !widthAttr.includes("%")) {
71690
+ width = parseInt(widthAttr, 10) || void 0;
71691
+ }
71692
+ if (heightAttr && !heightAttr.includes("%")) {
71693
+ height = parseInt(heightAttr, 10) || void 0;
71694
+ }
71695
+ let caption;
71696
+ const parentFigure = imageEl.closest("figure");
71697
+ if (parentFigure) {
71698
+ const figcaption = parentFigure.querySelector("figcaption");
71699
+ if (figcaption) {
71700
+ caption = getTextContent(figcaption).trim() || void 0;
71701
+ }
71702
+ }
71703
+ return { type: "image", imageKey, src, alt, width, height, caption };
71704
+ }
71705
+ function parseContainerContent(element, cssContext, nextImageKey, inheritedColor) {
71549
71706
  const innerElements = [];
71550
71707
  function processInnerNode(node, color) {
71551
71708
  if (node.nodeType === Node.TEXT_NODE) {
@@ -71628,18 +71785,48 @@ function parseContainerContent(element, cssContext, inheritedColor) {
71628
71785
  }
71629
71786
  if (tagName19 === "table") {
71630
71787
  const rows = [];
71631
- for (const tr of el.querySelectorAll("tr")) {
71788
+ const directRows = getDirectRows(el);
71789
+ for (const tr of directRows) {
71632
71790
  const cells = [];
71633
- for (const cell of tr.querySelectorAll("td, th")) {
71791
+ const directCells = getDirectCells(tr);
71792
+ for (const cell of directCells) {
71793
+ let cellBackgroundColor;
71794
+ const cellStyles = getElementStyles(cell, cssContext, tr);
71795
+ if (cellStyles.backgroundColor) {
71796
+ const hexBg = extractHexColor(cellStyles.backgroundColor);
71797
+ if (hexBg) cellBackgroundColor = hexBg;
71798
+ }
71799
+ if (!cellBackgroundColor) {
71800
+ const inlineStyle = cell.getAttribute("style") || "";
71801
+ if (inlineStyle) {
71802
+ const bgMatch = inlineStyle.match(/background(?:-color)?\s*:\s*([^;]+)/i);
71803
+ if (bgMatch) {
71804
+ const hexBg = extractHexColor(bgMatch[1]);
71805
+ if (hexBg) cellBackgroundColor = hexBg;
71806
+ }
71807
+ }
71808
+ }
71634
71809
  const runs = extractInlineRuns(cell, cssContext);
71635
- if (runs.length > 0) {
71636
- if (hasInlineFormatting(runs)) {
71637
- cells.push(runs);
71810
+ if (cellBackgroundColor) {
71811
+ if (runs.length > 0) {
71812
+ if (hasInlineFormatting(runs)) {
71813
+ cells.push({ content: runs, backgroundColor: cellBackgroundColor });
71814
+ } else {
71815
+ cells.push({ content: runs.map((r) => r.text).join(""), backgroundColor: cellBackgroundColor });
71816
+ }
71638
71817
  } else {
71639
- cells.push(runs.map((r) => r.text).join(""));
71818
+ cells.push({ content: "", backgroundColor: cellBackgroundColor });
71640
71819
  }
71641
71820
  } else {
71642
- cells.push("");
71821
+ if (runs.length > 0) {
71822
+ if (hasInlineFormatting(runs)) {
71823
+ cells.push(runs);
71824
+ } else {
71825
+ cells.push(runs.map((r) => r.text).join(""));
71826
+ }
71827
+ } else {
71828
+ cells.push("");
71829
+ }
71643
71830
  }
71644
71831
  }
71645
71832
  if (cells.length > 0) {
@@ -71728,7 +71915,7 @@ function parseContainerContent(element, cssContext, inheritedColor) {
71728
71915
  }
71729
71916
  return innerElements;
71730
71917
  }
71731
- function parseBlockquoteContent(element, cssContext) {
71918
+ function parseBlockquoteContent(element, cssContext, nextImageKey) {
71732
71919
  const innerElements = [];
71733
71920
  const blockquoteStyles = getElementStyles(element, cssContext);
71734
71921
  const blockquoteIsItalic = blockquoteStyles.fontStyle === "italic";
@@ -71842,7 +72029,7 @@ function parseBlockquoteContent(element, cssContext) {
71842
72029
  }
71843
72030
  const nestedBorderHex = extractBorderColorFromStyle(styles);
71844
72031
  if (nestedBgColor || nestedBorderHex) {
71845
- const nestedContent = parseBlockquoteContent(el, cssContext);
72032
+ const nestedContent = parseBlockquoteContent(el, cssContext, nextImageKey);
71846
72033
  if (nestedContent.length > 0) {
71847
72034
  let nestedBorderStyle;
71848
72035
  if (styles.borderLeft && !styles.border) {
@@ -71895,28 +72082,9 @@ function parseBlockquoteContent(element, cssContext) {
71895
72082
  }
71896
72083
  }
71897
72084
  if (tagName19 === "img") {
71898
- const src = el.getAttribute("src")?.trim();
71899
- if (src) {
71900
- const alt = el.getAttribute("alt") || void 0;
71901
- let width;
71902
- let height;
71903
- const widthAttr = el.getAttribute("width");
71904
- const heightAttr = el.getAttribute("height");
71905
- if (widthAttr && !widthAttr.includes("%")) {
71906
- width = parseInt(widthAttr, 10) || void 0;
71907
- }
71908
- if (heightAttr && !heightAttr.includes("%")) {
71909
- height = parseInt(heightAttr, 10) || void 0;
71910
- }
71911
- let caption;
71912
- const parentFigure = el.closest("figure");
71913
- if (parentFigure) {
71914
- const figcaption = parentFigure.querySelector("figcaption");
71915
- if (figcaption) {
71916
- caption = getTextContent(figcaption).trim() || void 0;
71917
- }
71918
- }
71919
- innerElements.push({ type: "image", src, alt, width, height, caption });
72085
+ const imageElement = createParsedImageElement(el, nextImageKey());
72086
+ if (imageElement) {
72087
+ innerElements.push(imageElement);
71920
72088
  }
71921
72089
  return;
71922
72090
  }
@@ -72087,6 +72255,8 @@ function parseHtmlContent(html) {
72087
72255
  const elements = [];
72088
72256
  const cssContext = parseCssContext(doc);
72089
72257
  const processedSvgs = /* @__PURE__ */ new Set();
72258
+ let imageIndex = 0;
72259
+ const nextImageKey = () => `image-${imageIndex++}`;
72090
72260
  const { body } = doc;
72091
72261
  function processNode(node, inheritedAlignment, inheritedColor) {
72092
72262
  if (node.nodeType === Node.TEXT_NODE) {
@@ -72223,7 +72393,7 @@ function parseHtmlContent(html) {
72223
72393
  return;
72224
72394
  }
72225
72395
  if (tagName19 === "p" && isBlockquoteOrCallout(element, cssContext)) {
72226
- const content = parseBlockquoteContent(element, cssContext);
72396
+ const content = parseBlockquoteContent(element, cssContext, nextImageKey);
72227
72397
  if (content.length > 0) {
72228
72398
  const elementStyles = getElementStyles(element, cssContext);
72229
72399
  let borderColor;
@@ -72412,18 +72582,62 @@ function parseHtmlContent(html) {
72412
72582
  }
72413
72583
  if (tagName19 === "table") {
72414
72584
  const rows = [];
72415
- for (const tr of element.querySelectorAll("tr")) {
72585
+ const directRows = getDirectRows(element);
72586
+ for (const tr of directRows) {
72416
72587
  const cells = [];
72417
- for (const cell of tr.querySelectorAll("td, th")) {
72418
- const runs = extractInlineRuns(cell, cssContext);
72419
- if (runs.length > 0) {
72420
- if (hasInlineFormatting(runs)) {
72421
- cells.push(runs);
72588
+ const directCells = getDirectCells(tr);
72589
+ for (const cell of directCells) {
72590
+ if (cellHasNestedTable(cell)) {
72591
+ const nestedContent = parseContainerContent(cell, cssContext, nextImageKey);
72592
+ if (nestedContent.length > 0) {
72593
+ cells.push({ content: nestedContent });
72422
72594
  } else {
72423
- cells.push(runs.map((r) => r.text).join(""));
72595
+ cells.push("");
72424
72596
  }
72425
72597
  } else {
72426
- cells.push("");
72598
+ let cellBackgroundColor;
72599
+ const cellStylesWithRowParent = getElementStyles(cell, cssContext, tr);
72600
+ if (cellStylesWithRowParent.backgroundColor) {
72601
+ const hexBg = extractHexColor(cellStylesWithRowParent.backgroundColor);
72602
+ if (hexBg) cellBackgroundColor = hexBg;
72603
+ }
72604
+ if (!cellBackgroundColor) {
72605
+ const cellStylesWithTableParent = getElementStyles(cell, cssContext, element);
72606
+ if (cellStylesWithTableParent.backgroundColor) {
72607
+ const hexBg = extractHexColor(cellStylesWithTableParent.backgroundColor);
72608
+ if (hexBg) cellBackgroundColor = hexBg;
72609
+ }
72610
+ }
72611
+ const inlineStyle = cell.getAttribute("style") || "";
72612
+ if (inlineStyle && !cellBackgroundColor) {
72613
+ const bgMatch = inlineStyle.match(/background(?:-color)?\s*:\s*([^;]+)/i);
72614
+ if (bgMatch) {
72615
+ const hexBg = extractHexColor(bgMatch[1]);
72616
+ if (hexBg) cellBackgroundColor = hexBg;
72617
+ }
72618
+ }
72619
+ const runs = extractInlineRuns(cell, cssContext);
72620
+ if (cellBackgroundColor) {
72621
+ if (runs.length > 0) {
72622
+ if (hasInlineFormatting(runs)) {
72623
+ cells.push({ content: runs, backgroundColor: cellBackgroundColor });
72624
+ } else {
72625
+ cells.push({ content: runs.map((r) => r.text).join(""), backgroundColor: cellBackgroundColor });
72626
+ }
72627
+ } else {
72628
+ cells.push({ content: "", backgroundColor: cellBackgroundColor });
72629
+ }
72630
+ } else {
72631
+ if (runs.length > 0) {
72632
+ if (hasInlineFormatting(runs)) {
72633
+ cells.push(runs);
72634
+ } else {
72635
+ cells.push(runs.map((r) => r.text).join(""));
72636
+ }
72637
+ } else {
72638
+ cells.push("");
72639
+ }
72640
+ }
72427
72641
  }
72428
72642
  }
72429
72643
  if (cells.length > 0) {
@@ -72559,7 +72773,8 @@ function parseHtmlContent(html) {
72559
72773
  }
72560
72774
  }
72561
72775
  }
72562
- elements.push({ type: "table", rows, cellPadding, headerBackgroundColor, headerTextColor, evenRowBackgroundColor, hasHeader: hasExplicitHeader ? true : void 0, horizontalBordersOnly: horizontalBordersOnly || void 0, columnWidths: calculateColumnWidths(rows, element) });
72776
+ const noBorders = isLayoutTable(element, cssContext);
72777
+ elements.push({ type: "table", rows, cellPadding, headerBackgroundColor, headerTextColor, evenRowBackgroundColor, hasHeader: hasExplicitHeader ? true : void 0, horizontalBordersOnly: horizontalBordersOnly || void 0, noBorders: noBorders || void 0, columnWidths: calculateColumnWidths(rows, element) });
72563
72778
  }
72564
72779
  return;
72565
72780
  }
@@ -72600,8 +72815,8 @@ function parseHtmlContent(html) {
72600
72815
  const sidebarStyles = getElementStyles(sidebarEl, cssContext);
72601
72816
  const sidebarBgColor = sidebarStyles.backgroundColor ? extractHexColor(sidebarStyles.backgroundColor) : void 0;
72602
72817
  const sidebarTextColor = sidebarStyles.color ? extractHexColor(sidebarStyles.color) : void 0;
72603
- const sidebarContent = parseContainerContent(sidebarEl, cssContext, sidebarTextColor);
72604
- const mainContent = parseContainerContent(mainEl, cssContext);
72818
+ const sidebarContent = parseContainerContent(sidebarEl, cssContext, nextImageKey, sidebarTextColor);
72819
+ const mainContent = parseContainerContent(mainEl, cssContext, nextImageKey);
72605
72820
  if (sidebarContent.length > 0 || mainContent.length > 0) {
72606
72821
  elements.push({
72607
72822
  type: "two-column-layout",
@@ -72665,7 +72880,7 @@ function parseHtmlContent(html) {
72665
72880
  }
72666
72881
  const columnContents = [];
72667
72882
  for (const col of gridColumns) {
72668
- const colContent = parseContainerContent(col, cssContext);
72883
+ const colContent = parseContainerContent(col, cssContext, nextImageKey);
72669
72884
  columnContents.push(colContent);
72670
72885
  }
72671
72886
  const hasContent = columnContents.some((c) => c.length > 0);
@@ -73030,56 +73245,18 @@ function parseHtmlContent(html) {
73030
73245
  return;
73031
73246
  }
73032
73247
  if (tagName19 === "img") {
73033
- const src = element.getAttribute("src")?.trim();
73034
- if (src) {
73035
- const alt = element.getAttribute("alt") || void 0;
73036
- let width;
73037
- let height;
73038
- const widthAttr = element.getAttribute("width");
73039
- const heightAttr = element.getAttribute("height");
73040
- if (widthAttr && !widthAttr.includes("%")) {
73041
- width = parseInt(widthAttr, 10) || void 0;
73042
- }
73043
- if (heightAttr && !heightAttr.includes("%")) {
73044
- height = parseInt(heightAttr, 10) || void 0;
73045
- }
73046
- let caption;
73047
- const parentFigure = element.closest("figure");
73048
- if (parentFigure) {
73049
- const figcaption = parentFigure.querySelector("figcaption");
73050
- if (figcaption) {
73051
- caption = getTextContent(figcaption).trim() || void 0;
73052
- }
73053
- }
73054
- elements.push({ type: "image", src, alt, width, height, caption });
73248
+ const imageElement = createParsedImageElement(element, nextImageKey());
73249
+ if (imageElement) {
73250
+ elements.push(imageElement);
73055
73251
  }
73056
73252
  return;
73057
73253
  }
73058
73254
  if (tagName19 === "picture") {
73059
73255
  const imgEl = element.querySelector("img");
73060
73256
  if (imgEl) {
73061
- const src = imgEl.getAttribute("src")?.trim();
73062
- if (src) {
73063
- const alt = imgEl.getAttribute("alt") || void 0;
73064
- let width;
73065
- let height;
73066
- const widthAttr = imgEl.getAttribute("width");
73067
- const heightAttr = imgEl.getAttribute("height");
73068
- if (widthAttr && !widthAttr.includes("%")) {
73069
- width = parseInt(widthAttr, 10) || void 0;
73070
- }
73071
- if (heightAttr && !heightAttr.includes("%")) {
73072
- height = parseInt(heightAttr, 10) || void 0;
73073
- }
73074
- let caption;
73075
- const parentFigure = element.closest("figure");
73076
- if (parentFigure) {
73077
- const figcaption = parentFigure.querySelector("figcaption");
73078
- if (figcaption) {
73079
- caption = getTextContent(figcaption).trim() || void 0;
73080
- }
73081
- }
73082
- elements.push({ type: "image", src, alt, width, height, caption });
73257
+ const imageElement = createParsedImageElement(imgEl, nextImageKey());
73258
+ if (imageElement) {
73259
+ elements.push(imageElement);
73083
73260
  }
73084
73261
  }
73085
73262
  return;
@@ -73087,25 +73264,9 @@ function parseHtmlContent(html) {
73087
73264
  if (tagName19 === "figure") {
73088
73265
  const imgEl = element.querySelector("img") || element.querySelector("picture img");
73089
73266
  if (imgEl) {
73090
- const src = imgEl.getAttribute("src")?.trim();
73091
- if (src) {
73092
- const alt = imgEl.getAttribute("alt") || void 0;
73093
- let width;
73094
- let height;
73095
- const widthAttr = imgEl.getAttribute("width");
73096
- const heightAttr = imgEl.getAttribute("height");
73097
- if (widthAttr && !widthAttr.includes("%")) {
73098
- width = parseInt(widthAttr, 10) || void 0;
73099
- }
73100
- if (heightAttr && !heightAttr.includes("%")) {
73101
- height = parseInt(heightAttr, 10) || void 0;
73102
- }
73103
- let caption;
73104
- const figcaption = element.querySelector("figcaption");
73105
- if (figcaption) {
73106
- caption = getTextContent(figcaption).trim() || void 0;
73107
- }
73108
- elements.push({ type: "image", src, alt, width, height, caption });
73267
+ const imageElement = createParsedImageElement(imgEl, nextImageKey());
73268
+ if (imageElement) {
73269
+ elements.push(imageElement);
73109
73270
  return;
73110
73271
  }
73111
73272
  }
@@ -73117,7 +73278,7 @@ function parseHtmlContent(html) {
73117
73278
  return;
73118
73279
  }
73119
73280
  if (isBlockquoteOrCallout(element, cssContext)) {
73120
- const content = parseBlockquoteContent(element, cssContext);
73281
+ const content = parseBlockquoteContent(element, cssContext, nextImageKey);
73121
73282
  if (content.length > 0) {
73122
73283
  const elementStyles = getElementStyles(element, cssContext);
73123
73284
  let borderColor;
@@ -73695,35 +73856,83 @@ function createTableRow(cells, isHeaderRow, columnCount, cellPadding, headerBack
73695
73856
  tableHeader: isHeaderRow,
73696
73857
  children: cells.map(
73697
73858
  (cell, cellIndex) => {
73698
- const textRuns = typeof cell === "string" ? [new TextRun({
73699
- text: cell,
73700
- bold: isHeaderRow,
73701
- color: isHeaderRow && headerTextColor ? headerTextColor : void 0
73702
- })] : cell.map((run) => new TextRun({
73703
- text: run.text,
73704
- bold: isHeaderRow || run.bold,
73705
- italics: run.italic,
73706
- // Use header text color for header rows, otherwise use run's color
73707
- color: isHeaderRow && headerTextColor ? headerTextColor : run.color,
73708
- size: run.size,
73709
- font: run.fontFamily ? mapToOfficeFont(run.fontFamily) : void 0,
73710
- superScript: run.superscript,
73711
- subScript: run.subscript,
73712
- strike: run.strike,
73713
- characterSpacing: run.letterSpacing,
73714
- underline: run.underline ? {
73715
- type: getUnderlineType(run.underline.type),
73716
- color: run.underline.color
73717
- } : void 0,
73718
- // Preserve inline background colors for badge/pill styling in table cells
73719
- shading: run.backgroundColor ? {
73720
- type: ShadingType.CLEAR,
73721
- fill: run.backgroundColor,
73722
- color: "auto"
73723
- } : void 0
73724
- }));
73859
+ let cellContent;
73860
+ let cellBackgroundColor;
73861
+ if (isComplexTableCell(cell)) {
73862
+ cellContent = [];
73863
+ for (const nestedElement of cell.content) {
73864
+ cellContent.push(...convertElementToDocx(nestedElement));
73865
+ }
73866
+ if (cellContent.length === 0) {
73867
+ cellContent = [new Paragraph({ children: [] })];
73868
+ }
73869
+ } else if (isStyledTableCell(cell)) {
73870
+ cellBackgroundColor = cell.backgroundColor;
73871
+ const content = cell.content;
73872
+ const textRuns = typeof content === "string" ? [new TextRun({
73873
+ text: content,
73874
+ bold: isHeaderRow,
73875
+ color: isHeaderRow && headerTextColor ? headerTextColor : void 0
73876
+ })] : content.map((run) => new TextRun({
73877
+ text: run.text,
73878
+ bold: isHeaderRow || run.bold,
73879
+ italics: run.italic,
73880
+ color: isHeaderRow && headerTextColor ? headerTextColor : run.color,
73881
+ size: run.size,
73882
+ font: run.fontFamily ? mapToOfficeFont(run.fontFamily) : void 0,
73883
+ superScript: run.superscript,
73884
+ subScript: run.subscript,
73885
+ strike: run.strike,
73886
+ characterSpacing: run.letterSpacing,
73887
+ underline: run.underline ? {
73888
+ type: getUnderlineType(run.underline.type),
73889
+ color: run.underline.color
73890
+ } : void 0
73891
+ // Note: Don't apply run-level backgroundColor here - cell background handles it
73892
+ }));
73893
+ cellContent = [new Paragraph({ children: textRuns })];
73894
+ } else if (typeof cell === "string") {
73895
+ const textRuns = [new TextRun({
73896
+ text: cell,
73897
+ bold: isHeaderRow,
73898
+ color: isHeaderRow && headerTextColor ? headerTextColor : void 0
73899
+ })];
73900
+ cellContent = [new Paragraph({ children: textRuns })];
73901
+ } else if (Array.isArray(cell)) {
73902
+ const textRuns = cell.map((run) => new TextRun({
73903
+ text: run.text,
73904
+ bold: isHeaderRow || run.bold,
73905
+ italics: run.italic,
73906
+ color: isHeaderRow && headerTextColor ? headerTextColor : run.color,
73907
+ size: run.size,
73908
+ font: run.fontFamily ? mapToOfficeFont(run.fontFamily) : void 0,
73909
+ superScript: run.superscript,
73910
+ subScript: run.subscript,
73911
+ strike: run.strike,
73912
+ characterSpacing: run.letterSpacing,
73913
+ underline: run.underline ? {
73914
+ type: getUnderlineType(run.underline.type),
73915
+ color: run.underline.color
73916
+ } : void 0,
73917
+ // Preserve inline background colors for badge/pill styling in table cells
73918
+ shading: run.backgroundColor ? {
73919
+ type: ShadingType.CLEAR,
73920
+ fill: run.backgroundColor,
73921
+ color: "auto"
73922
+ } : void 0
73923
+ }));
73924
+ cellContent = [new Paragraph({ children: textRuns })];
73925
+ } else {
73926
+ cellContent = [new Paragraph({ children: [] })];
73927
+ }
73725
73928
  let shading;
73726
- if (isHeaderRow && headerBackgroundColor) {
73929
+ if (cellBackgroundColor) {
73930
+ shading = {
73931
+ type: ShadingType.CLEAR,
73932
+ color: "auto",
73933
+ fill: cellBackgroundColor
73934
+ };
73935
+ } else if (isHeaderRow && headerBackgroundColor) {
73727
73936
  shading = {
73728
73937
  type: ShadingType.CLEAR,
73729
73938
  color: "auto",
@@ -73741,11 +73950,7 @@ function createTableRow(cells, isHeaderRow, columnCount, cellPadding, headerBack
73741
73950
  const needsSpan = isLastCell && remainingColumns > 0;
73742
73951
  const cellColumnSpan = needsSpan ? remainingColumns + 1 : void 0;
73743
73952
  return new TableCell({
73744
- children: [
73745
- new Paragraph({
73746
- children: textRuns
73747
- })
73748
- ],
73953
+ children: cellContent,
73749
73954
  width: {
73750
73955
  size: columnWidths?.[cellIndex] ?? 100 / columnCount,
73751
73956
  type: WidthType.PERCENTAGE
@@ -74074,6 +74279,15 @@ function convertElementToDocx(element) {
74074
74279
  const cell = row[cellIndex];
74075
74280
  if (typeof cell === "string") {
74076
74281
  children.push(new TextRun({ text: cell }));
74282
+ } else if (isStyledTableCell(cell)) {
74283
+ const content = cell.content;
74284
+ if (typeof content === "string") {
74285
+ children.push(new TextRun({ text: content }));
74286
+ } else {
74287
+ children.push(...inlineRunsToTextRuns(content));
74288
+ }
74289
+ } else if (isComplexTableCell(cell)) {
74290
+ continue;
74077
74291
  } else {
74078
74292
  children.push(...inlineRunsToTextRuns(cell));
74079
74293
  }
@@ -74520,8 +74734,14 @@ function createDocxDocument(html, options = {}) {
74520
74734
  if (imageMap && imageMap.size > 0) {
74521
74735
  let populateImageData2 = function(elements) {
74522
74736
  for (const element of elements) {
74523
- if (element.type === "image" && !element.imageData && imageMap.has(element.src)) {
74524
- element.imageData = imageMap.get(element.src);
74737
+ if (element.type === "image" && !element.imageData) {
74738
+ const lookupKeys = [element.imageKey, element.src].filter((key2) => Boolean(key2));
74739
+ for (const lookupKey of lookupKeys) {
74740
+ if (imageMap.has(lookupKey)) {
74741
+ element.imageData = imageMap.get(lookupKey);
74742
+ break;
74743
+ }
74744
+ }
74525
74745
  }
74526
74746
  if (element.type === "blockquote" && element.content) {
74527
74747
  populateImageData2(element.content);
@@ -74888,6 +75108,50 @@ function parseImageDimensions(data) {
74888
75108
  }
74889
75109
  return null;
74890
75110
  }
75111
+ function parseDataUriImages(htmlContent) {
75112
+ const imageMap = /* @__PURE__ */ new Map();
75113
+ const dataUriRegex = /<img\s+[^>]*src="\s*(data:image\/[^;]+;base64,[^"]+)\s*"[^>]*>/gi;
75114
+ const matches2 = [...htmlContent.matchAll(dataUriRegex)];
75115
+ if (matches2.length === 0) {
75116
+ return imageMap;
75117
+ }
75118
+ const dataUris = /* @__PURE__ */ new Set();
75119
+ for (const match of matches2) {
75120
+ dataUris.add(match[1]);
75121
+ }
75122
+ console.log(`Processing ${dataUris.size} inline base64 image(s)...`);
75123
+ for (const dataUri of dataUris) {
75124
+ try {
75125
+ const commaIndex = dataUri.indexOf(",");
75126
+ if (commaIndex === -1) {
75127
+ console.warn(`Invalid data URI format`);
75128
+ continue;
75129
+ }
75130
+ const base64Data = dataUri.slice(commaIndex + 1);
75131
+ const buffer2 = Buffer.from(base64Data, "base64");
75132
+ const data = new Uint8Array(buffer2);
75133
+ const dimensions = parseImageDimensions(data);
75134
+ if (!dimensions) {
75135
+ console.warn(`Could not parse dimensions for data URI image`);
75136
+ continue;
75137
+ }
75138
+ let { width, height } = dimensions;
75139
+ if (width > MAX_IMAGE_WIDTH) {
75140
+ const scale = MAX_IMAGE_WIDTH / width;
75141
+ width = MAX_IMAGE_WIDTH;
75142
+ height = Math.round(height * scale);
75143
+ }
75144
+ imageMap.set(dataUri, {
75145
+ data: buffer2,
75146
+ width,
75147
+ height
75148
+ });
75149
+ } catch {
75150
+ console.warn(`Failed to parse data URI image`);
75151
+ }
75152
+ }
75153
+ return imageMap;
75154
+ }
74891
75155
  async function fetchExternalImages(htmlContent) {
74892
75156
  const imageMap = /* @__PURE__ */ new Map();
74893
75157
  const imgRegex = /<img\s+[^>]*src="\s*(https?:\/\/[^"]+?)\s*"[^>]*>/gi;
@@ -74931,14 +75195,87 @@ async function fetchExternalImages(htmlContent) {
74931
75195
  );
74932
75196
  return imageMap;
74933
75197
  }
74934
- async function renderChartImages(browser2, htmlPath) {
75198
+ async function renderHtmlImages(browser2, htmlPath, elements) {
75199
+ const renderedImages = /* @__PURE__ */ new Map();
75200
+ const absoluteHtmlPath = path3.resolve(htmlPath);
75201
+ if (!fs3.existsSync(absoluteHtmlPath)) {
75202
+ return renderedImages;
75203
+ }
75204
+ const htmlImageElements = [];
75205
+ function collectImages(els) {
75206
+ for (const el of els) {
75207
+ if (el.type === "image") {
75208
+ htmlImageElements.push(el);
75209
+ } else if (el.type === "blockquote" && el.content) {
75210
+ collectImages(el.content);
75211
+ } else if (el.type === "two-column-layout") {
75212
+ collectImages(el.sidebar.content);
75213
+ collectImages(el.main.content);
75214
+ }
75215
+ }
75216
+ }
75217
+ collectImages(elements);
75218
+ if (htmlImageElements.length === 0) {
75219
+ return renderedImages;
75220
+ }
75221
+ console.log(`Rendering ${htmlImageElements.length} HTML image(s)...`);
75222
+ const page = await browser2.newPage({
75223
+ viewport: { width: 1200, height: 800 }
75224
+ });
75225
+ try {
75226
+ await page.goto(`file://${absoluteHtmlPath}`, {
75227
+ waitUntil: "networkidle"
75228
+ });
75229
+ await page.waitForTimeout(500);
75230
+ const domImageCount = await page.evaluate(() => {
75231
+ let imageIndex = 0;
75232
+ for (const img of Array.from(document.querySelectorAll("img"))) {
75233
+ const src = img.getAttribute("src")?.trim();
75234
+ if (!src) {
75235
+ continue;
75236
+ }
75237
+ img.setAttribute("data-docgen-image-index", String(imageIndex));
75238
+ imageIndex++;
75239
+ }
75240
+ return imageIndex;
75241
+ });
75242
+ if (domImageCount !== htmlImageElements.length) {
75243
+ console.warn(`HTML image count mismatch: parsed ${htmlImageElements.length}, DOM ${domImageCount}`);
75244
+ }
75245
+ for (let i = 0; i < htmlImageElements.length; i++) {
75246
+ const imageElement = htmlImageElements[i];
75247
+ if (!imageElement.imageKey) {
75248
+ continue;
75249
+ }
75250
+ const imgEl = await page.$(`img[data-docgen-image-index="${i}"]`);
75251
+ if (!imgEl) {
75252
+ continue;
75253
+ }
75254
+ const box = await imgEl.boundingBox();
75255
+ if (!box || box.width < 1 || box.height < 1) {
75256
+ continue;
75257
+ }
75258
+ const screenshot = await imgEl.screenshot({
75259
+ type: "png"
75260
+ });
75261
+ const scale = box.width > MAX_IMAGE_WIDTH ? MAX_IMAGE_WIDTH / box.width : 1;
75262
+ renderedImages.set(imageElement.imageKey, {
75263
+ data: screenshot,
75264
+ width: Math.round(box.width * scale),
75265
+ height: Math.round(box.height * scale)
75266
+ });
75267
+ }
75268
+ } finally {
75269
+ await page.close();
75270
+ }
75271
+ return renderedImages;
75272
+ }
75273
+ async function renderChartImages(browser2, htmlPath, elements) {
74935
75274
  const chartImages = /* @__PURE__ */ new Map();
74936
75275
  const absoluteHtmlPath = path3.resolve(htmlPath);
74937
75276
  if (!fs3.existsSync(absoluteHtmlPath)) {
74938
75277
  return chartImages;
74939
75278
  }
74940
- const htmlContent = fs3.readFileSync(absoluteHtmlPath, "utf-8");
74941
- const elements = parseHtmlContent(htmlContent);
74942
75279
  const svgChartElements = [];
74943
75280
  function collectSvgCharts(els) {
74944
75281
  for (const el of els) {
@@ -75050,21 +75387,32 @@ async function exportDocs(filePath, outDir, options = {}) {
75050
75387
  }
75051
75388
  console.log(`Exporting to DOCX: ${filePath}`);
75052
75389
  const html = fs3.readFileSync(absolutePath, "utf-8");
75390
+ const elements = parseHtmlContent(html);
75053
75391
  const baseName = outputName || path3.basename(filePath, ".html");
75054
75392
  const imageMap = await fetchExternalImages(html);
75393
+ const dataUriImages = parseDataUriImages(html);
75394
+ for (const [uri2, data] of dataUriImages) {
75395
+ imageMap.set(uri2, data);
75396
+ }
75055
75397
  const launchOptions = { headless: true };
75056
75398
  const proxyServer = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
75057
75399
  if (proxyServer) {
75058
75400
  launchOptions.proxy = { server: proxyServer };
75059
75401
  }
75060
75402
  const browser2 = await chromium.launch(launchOptions);
75403
+ let renderedImages;
75061
75404
  let chartImages;
75062
75405
  try {
75063
- chartImages = await renderChartImages(browser2, absolutePath);
75406
+ [renderedImages, chartImages] = await Promise.all([
75407
+ renderHtmlImages(browser2, absolutePath, elements),
75408
+ renderChartImages(browser2, absolutePath, elements)
75409
+ ]);
75064
75410
  } finally {
75065
75411
  await browser2.close();
75066
75412
  }
75067
- const elements = parseHtmlContent(html);
75413
+ for (const [imageKey, data] of renderedImages) {
75414
+ imageMap.set(imageKey, data);
75415
+ }
75068
75416
  const buffer2 = await createDocxBuffer(html, {
75069
75417
  title: baseName,
75070
75418
  elements,