@yinyoudexing/xml2word 0.1.2 → 0.1.4

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
@@ -104,8 +104,11 @@ fs.writeFileSync("out.docx", buf);
104
104
 
105
105
  ## HTML 支持范围(当前版本)
106
106
 
107
- - 支持:`p/span/strong/br`、`h1~h6`、`ul/ol/li`、`table/tr/td/th`
108
- - 支持:`text-align`、`font-size(pt/px)`、`color(rgb/#)`、`font-family`
107
+ - 支持:`div/p/span/strong/em/u/br`、`h1~h6`、`ul/ol/li`、`table/tr/td/th`
108
+ - 支持:`img(src=dataURL)`、`canvas(data-image=dataURL)`
109
+ - 支持:`text-align`、`vertical-align`、`font-size(pt/px)`、`color(rgb/#)`、`font-family`
110
+ - 支持:`background-color/background`(段落/单元格底色)、`white-space: nowrap`(表格单元格)
111
+ - 支持:表格边框(solid/dashed/dotted/double)、表格按内容估算列宽
109
112
  - 支持分页标记(会插入 Word 分页符):
110
113
  - `<div class="page-break"></div>`
111
114
  - `<hr class="page-break" />`
@@ -113,6 +116,6 @@ fs.writeFileSync("out.docx", buf);
113
116
  - 会跳过:`canvas`、编辑器辅助 DOM(如 ProseMirror widget)
114
117
 
115
118
  限制(需要额外实现才能完全还原):
116
- - 图片:HTML `<img>` 需要额外提供图片二进制并写入 docx 的 media 关系
119
+ - CSS 选择器:不解析 `<style>`,只读取标签上的 `style=""` 行内样式
117
120
  - 复杂 CSS:比如浮动/定位/复杂布局无法直接映射到 Word
118
121
  - 精准“自动分页”:如果需要指定分页位置,请在 HTML 中插入分页标记
@@ -42,6 +42,17 @@ function parseCssColorToHex(value) {
42
42
  if (hex) return hex.toUpperCase();
43
43
  return parseRgbToHex(v);
44
44
  }
45
+ function extractBackgroundFillHex(css) {
46
+ const raw = (css["background-color"] ?? css.background)?.trim();
47
+ if (!raw) return void 0;
48
+ const direct = parseCssColorToHex(raw);
49
+ if (direct) return direct;
50
+ const hex = raw.match(/#([0-9a-fA-F]{6})/)?.[0];
51
+ if (hex) return parseCssColorToHex(hex);
52
+ const rgb = raw.match(/rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)/)?.[0];
53
+ if (rgb) return parseCssColorToHex(rgb);
54
+ return void 0;
55
+ }
45
56
  function parseFontSizeToHalfPoints(value) {
46
57
  if (!value) return void 0;
47
58
  const v = value.trim().toLowerCase();
@@ -361,6 +372,8 @@ function buildParagraphPrXml(node, baseFontHalfPoints, extraInd, pStyleId) {
361
372
  const css = parseStyleAttribute(node.attribs?.style);
362
373
  const parts = [];
363
374
  if (pStyleId) parts.push(`<w:pStyle w:val="${escapeXmlText(pStyleId)}"/>`);
375
+ const shdHex = extractBackgroundFillHex(css);
376
+ if (shdHex) parts.push(`<w:shd w:val="clear" w:color="auto" w:fill="${shdHex}"/>`);
364
377
  const align = css["text-align"]?.trim().toLowerCase();
365
378
  const jcVal = align === "center" ? "center" : align === "right" ? "right" : align === "justify" ? "both" : void 0;
366
379
  if (jcVal) parts.push(`<w:jc w:val="${jcVal}"/>`);
@@ -412,14 +425,15 @@ function buildParagraphPrXml(node, baseFontHalfPoints, extraInd, pStyleId) {
412
425
  return `<w:pPr>${parts.join("")}</w:pPr>`;
413
426
  }
414
427
  function buildParagraphXmlFromContainer(node, baseStyle, extraInd, pStyleId, result) {
415
- const baseFontHalfPoints = baseStyle.fontSizeHalfPoints ?? inferFirstFontSizeHalfPoints(node) ?? 28;
428
+ const containerStyle = mergeTextStyle(baseStyle, styleFromElement(node));
429
+ const baseFontHalfPoints = containerStyle.fontSizeHalfPoints ?? inferFirstFontSizeHalfPoints(node) ?? 28;
416
430
  const pPrXml = buildParagraphPrXml(node, baseFontHalfPoints, extraInd, pStyleId);
417
431
  const runs = [];
418
432
  const res = result ?? {
419
433
  bodyXml: "",
420
434
  images: []
421
435
  };
422
- for (const c of node.children ?? []) collectInlineRuns(c, baseStyle, runs, res);
436
+ for (const c of node.children ?? []) collectInlineRuns(c, containerStyle, runs, res);
423
437
  const rXml = [];
424
438
  for (const token of runs) {
425
439
  if (token.kind === "br") {
@@ -465,7 +479,7 @@ function buildListBlocks(listNode, ordered, level, result) {
465
479
  const hangingTwips = 360;
466
480
  for (const li of liNodes) {
467
481
  const nestedLists = [];
468
- const baseStyle = {};
482
+ const baseStyle = styleFromElement(li);
469
483
  const runs = [];
470
484
  for (const c of li.children ?? []) {
471
485
  if (c.type === "tag") {
@@ -776,6 +790,70 @@ function buildParagraphXmlFromSingleInlineNode(node, baseStyle, result) {
776
790
  };
777
791
  return buildParagraphXmlFromContainer(wrapper, baseStyle, void 0, void 0, result);
778
792
  }
793
+ function isRecognizedBlockTag(tag) {
794
+ if (!tag) return false;
795
+ if (tag === "p") return true;
796
+ if (tag === "table") return true;
797
+ if (tag === "ul" || tag === "ol") return true;
798
+ if (tag === "img" || tag === "canvas") return true;
799
+ if (/^h[1-6]$/.test(tag)) return true;
800
+ if (tag === "pre") return true;
801
+ return false;
802
+ }
803
+ function collectDivBlocks(node, out, result) {
804
+ const parentStyle = node.attribs?.style;
805
+ const inlineBuffer = [];
806
+ const flushInline = () => {
807
+ const wrapper = {
808
+ type: "tag",
809
+ name: "p",
810
+ attribs: { style: parentStyle },
811
+ children: inlineBuffer.splice(0)
812
+ };
813
+ const pXml = buildParagraphXmlFromContainer(wrapper, {}, void 0, void 0, result);
814
+ if (pXml) out.push(pXml);
815
+ };
816
+ const children = node.children ?? [];
817
+ for (const child of children) {
818
+ if (child.type === "tag") {
819
+ const tag = child.name?.toLowerCase();
820
+ if (isExplicitPageBreak(child)) {
821
+ if (inlineBuffer.length) flushInline();
822
+ out.push(PAGE_BREAK_XML);
823
+ continue;
824
+ }
825
+ if (isRecognizedBlockTag(tag)) {
826
+ if (inlineBuffer.length) flushInline();
827
+ collectBodyBlocks(child, out, result);
828
+ continue;
829
+ }
830
+ if (tag === "div") {
831
+ const childHasRecognizedBlocks = (child.children ?? []).some((gc) => {
832
+ if (gc.type !== "tag") return false;
833
+ return isRecognizedBlockTag(gc.name?.toLowerCase());
834
+ });
835
+ if (childHasRecognizedBlocks) {
836
+ if (inlineBuffer.length) flushInline();
837
+ collectBodyBlocks(child, out, result);
838
+ continue;
839
+ }
840
+ if (inlineBuffer.length) flushInline();
841
+ const mergedStyle = [parentStyle, child.attribs?.style].filter(Boolean).join(";");
842
+ const wrapper = {
843
+ type: "tag",
844
+ name: "p",
845
+ attribs: { style: mergedStyle || void 0 },
846
+ children: child.children ?? []
847
+ };
848
+ const pXml = buildParagraphXmlFromContainer(wrapper, {}, void 0, void 0, result);
849
+ if (pXml) out.push(pXml);
850
+ continue;
851
+ }
852
+ }
853
+ inlineBuffer.push(child);
854
+ }
855
+ if (inlineBuffer.length) flushInline();
856
+ }
779
857
  function collectBodyBlocks(node, out, result) {
780
858
  if (isSkippableSubtree(node)) return;
781
859
  if (node.type === "tag") {
@@ -809,6 +887,10 @@ function collectBodyBlocks(node, out, result) {
809
887
  out.push(...buildListBlocks(node, tag === "ol", 0, result));
810
888
  return;
811
889
  }
890
+ if (tag === "div") {
891
+ collectDivBlocks(node, out, result);
892
+ return;
893
+ }
812
894
  }
813
895
  for (const c of node.children ?? []) collectBodyBlocks(c, out, result);
814
896
  }
@@ -874,4 +956,4 @@ export {
874
956
  htmlToWordBodyXml,
875
957
  textToWordBodyXml
876
958
  };
877
- //# sourceMappingURL=htmlToWordBodyXml-LY6DZSTW.js.map
959
+ //# sourceMappingURL=htmlToWordBodyXml-SIVUZ7K7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/htmlToWordBodyXml.ts"],"sourcesContent":["import { parseDocument } from \"htmlparser2\";\n\ntype HtmlNode = {\n type?: string;\n name?: string;\n data?: string;\n attribs?: Record<string, string | undefined>;\n children?: HtmlNode[];\n};\n\ntype TextStyle = {\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n colorHex?: string;\n fontFamily?: string;\n fontSizeHalfPoints?: number;\n};\n\nfunction escapeXmlText(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n\nfunction shouldPreserveSpace(text: string): boolean {\n if (!text) return false;\n return /^\\s/.test(text) || /\\s$/.test(text) || /\\s{2,}/.test(text);\n}\n\nfunction shouldKeepWhitespaceOnlyRun(text: string): boolean {\n if (!text) return false;\n if (/\\r|\\n/.test(text)) return false;\n if (text.includes(\"\\u00a0\")) return true;\n return /\\s{2,}/.test(text);\n}\n\nfunction parseStyleAttribute(style: string | undefined): Record<string, string> {\n if (!style) return {};\n const normalized = style.replace(/\\r/g, \"\\n\");\n const parts = normalized.split(\";\");\n const entries: [string, string][] = [];\n for (const part of parts) {\n const idx = part.indexOf(\":\");\n if (idx <= 0) continue;\n const key = part.slice(0, idx).trim().toLowerCase();\n const val = part.slice(idx + 1).trim();\n if (!key || !val) continue;\n entries.push([key, val]);\n }\n return Object.fromEntries(entries);\n}\n\nfunction parseRgbToHex(value: string): string | undefined {\n const m = value\n .trim()\n .toLowerCase()\n .match(/^rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\)$/);\n if (!m) return undefined;\n const nums = [Number(m[1]), Number(m[2]), Number(m[3])];\n if (nums.some((n) => Number.isNaN(n) || n < 0 || n > 255)) return undefined;\n return nums.map((n) => n.toString(16).padStart(2, \"0\")).join(\"\").toUpperCase();\n}\n\nfunction parseCssColorToHex(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const v = value.trim();\n const hex = v.match(/^#([0-9a-fA-F]{6})$/)?.[1];\n if (hex) return hex.toUpperCase();\n return parseRgbToHex(v);\n}\n\nfunction extractBackgroundFillHex(css: Record<string, string>): string | undefined {\n const raw = (css[\"background-color\"] ?? css.background)?.trim();\n if (!raw) return undefined;\n const direct = parseCssColorToHex(raw);\n if (direct) return direct;\n const hex = raw.match(/#([0-9a-fA-F]{6})/)?.[0];\n if (hex) return parseCssColorToHex(hex);\n const rgb = raw.match(/rgb\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*\\)/)?.[0];\n if (rgb) return parseCssColorToHex(rgb);\n return undefined;\n}\n\nfunction parseFontSizeToHalfPoints(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const v = value.trim().toLowerCase();\n const pt = v.match(/^(\\d+(?:\\.\\d+)?)pt$/);\n if (pt) return Math.max(1, Math.round(Number(pt[1]) * 2));\n const px = v.match(/^(\\d+(?:\\.\\d+)?)px$/);\n if (px) {\n const ptValue = (Number(px[1]) * 72) / 96;\n return Math.max(1, Math.round(ptValue * 2));\n }\n return undefined;\n}\n\nfunction normalizeFontFamily(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const first = value.split(\",\")[0]?.trim();\n if (!first) return undefined;\n return first.replace(/^[\"']|[\"']$/g, \"\");\n}\n\nfunction mergeTextStyle(base: TextStyle, patch: TextStyle): TextStyle {\n return {\n bold: patch.bold ?? base.bold,\n italic: patch.italic ?? base.italic,\n underline: patch.underline ?? base.underline,\n colorHex: patch.colorHex ?? base.colorHex,\n fontFamily: patch.fontFamily ?? base.fontFamily,\n fontSizeHalfPoints: patch.fontSizeHalfPoints ?? base.fontSizeHalfPoints,\n };\n}\n\nfunction styleFromElement(node: HtmlNode): TextStyle {\n const tag = node.name?.toLowerCase();\n const styleAttr = node.attribs?.style;\n const css = parseStyleAttribute(styleAttr);\n\n const boldFromCss = (() => {\n const v = css[\"font-weight\"]?.trim().toLowerCase();\n if (!v) return undefined;\n if (v === \"bold\" || v === \"bolder\") return true;\n const n = Number(v);\n if (!Number.isNaN(n)) return n >= 600;\n return undefined;\n })();\n\n const italicFromCss = (() => {\n const v = css[\"font-style\"]?.trim().toLowerCase();\n if (!v) return undefined;\n if (v === \"italic\" || v === \"oblique\") return true;\n return undefined;\n })();\n\n const underlineFromCss = (() => {\n const v = css[\"text-decoration\"]?.trim().toLowerCase();\n if (!v) return undefined;\n return v.includes(\"underline\");\n })();\n\n const tagBold = tag === \"b\" || tag === \"strong\" ? true : undefined;\n const tagItalic = tag === \"i\" || tag === \"em\" ? true : undefined;\n const tagUnderline = tag === \"u\" ? true : undefined;\n\n return {\n bold: tagBold ?? boldFromCss,\n italic: tagItalic ?? italicFromCss,\n underline: tagUnderline ?? underlineFromCss,\n colorHex: parseCssColorToHex(css.color),\n fontFamily: normalizeFontFamily(css[\"font-family\"]),\n fontSizeHalfPoints: parseFontSizeToHalfPoints(css[\"font-size\"]),\n };\n}\n\nfunction getTextContent(node: HtmlNode): string {\n if (node.type === \"text\") return node.data ?? \"\";\n let out = \"\";\n const children = node.children ?? [];\n for (const c of children) out += getTextContent(c);\n return out;\n}\n\ntype RunToken =\n | { kind: \"text\"; text: string; style: TextStyle }\n | { kind: \"br\" }\n | { kind: \"image\"; image: EmbeddedImageRef };\n\ntype EmbeddedImage = {\n relationshipId: string;\n target: string;\n data: Uint8Array;\n contentType: string;\n widthPx: number;\n heightPx: number;\n};\n\nconst IMAGE_RELATIONSHIP_ID_OFFSET = 7;\n\ntype EmbeddedImageRef = {\n relationshipId: string;\n widthPx: number;\n heightPx: number;\n};\n\ntype HtmlToWordResult = {\n bodyXml: string;\n images: EmbeddedImage[];\n};\n\nfunction decodeBase64ToUint8Array(base64: string): Uint8Array {\n const BufferCtor = (globalThis as unknown as { Buffer?: typeof Buffer }).Buffer;\n if (BufferCtor) {\n return new Uint8Array(BufferCtor.from(base64, \"base64\"));\n }\n const atobFn = (globalThis as unknown as { atob?: (data: string) => string }).atob;\n if (!atobFn) {\n throw new Error(\"Base64 decode is not available in this environment.\");\n }\n const bin = atobFn(base64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nfunction parseImageDataUrl(\n src: string,\n): { contentType: string; data: Uint8Array; extension: \"png\" | \"jpeg\" } | undefined {\n const m = src.match(/^data:(image\\/png|image\\/jpeg);base64,([\\s\\S]+)$/i);\n if (!m) return undefined;\n const contentType = m[1].toLowerCase();\n const base64 = m[2].replace(/\\s+/g, \"\");\n const data = decodeBase64ToUint8Array(base64);\n const extension = contentType === \"image/png\" ? \"png\" : \"jpeg\";\n return { contentType, data, extension };\n}\n\nfunction parseCssLengthToPx(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const v = value.trim().toLowerCase();\n const px = v.match(/^(\\d+(?:\\.\\d+)?)px$/);\n if (px) return Math.max(1, Math.round(Number(px[1])));\n return undefined;\n}\n\nfunction readUInt32BE(bytes: Uint8Array, offset: number): number | undefined {\n if (offset < 0 || offset + 4 > bytes.length) return undefined;\n return (\n ((bytes[offset] ?? 0) << 24) |\n ((bytes[offset + 1] ?? 0) << 16) |\n ((bytes[offset + 2] ?? 0) << 8) |\n (bytes[offset + 3] ?? 0)\n ) >>> 0;\n}\n\nfunction parsePngDimensions(data: Uint8Array): { widthPx: number; heightPx: number } | undefined {\n if (data.length < 24) return undefined;\n const signature = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n for (let i = 0; i < signature.length; i++) {\n if ((data[i] ?? 0) !== signature[i]) return undefined;\n }\n const widthPx = readUInt32BE(data, 16);\n const heightPx = readUInt32BE(data, 20);\n if (!widthPx || !heightPx) return undefined;\n return { widthPx, heightPx };\n}\n\nfunction parseJpegDimensions(data: Uint8Array): { widthPx: number; heightPx: number } | undefined {\n if (data.length < 4) return undefined;\n if (data[0] !== 0xff || data[1] !== 0xd8) return undefined;\n\n let offset = 2;\n while (offset + 4 <= data.length) {\n if (data[offset] !== 0xff) {\n offset++;\n continue;\n }\n while (offset < data.length && data[offset] === 0xff) offset++;\n if (offset >= data.length) return undefined;\n\n const marker = data[offset] as number;\n offset++;\n\n const isStandalone = marker === 0xd9 || marker === 0xda;\n if (isStandalone) break;\n if (offset + 2 > data.length) return undefined;\n const length = ((data[offset] as number) << 8) | (data[offset + 1] as number);\n if (length < 2 || offset + length > data.length) return undefined;\n\n const isSof =\n marker === 0xc0 ||\n marker === 0xc1 ||\n marker === 0xc2 ||\n marker === 0xc3 ||\n marker === 0xc5 ||\n marker === 0xc6 ||\n marker === 0xc7 ||\n marker === 0xc9 ||\n marker === 0xca ||\n marker === 0xcb ||\n marker === 0xcd ||\n marker === 0xce ||\n marker === 0xcf;\n if (isSof) {\n if (offset + 7 > data.length) return undefined;\n const heightPx = ((data[offset + 3] as number) << 8) | (data[offset + 4] as number);\n const widthPx = ((data[offset + 5] as number) << 8) | (data[offset + 6] as number);\n if (!widthPx || !heightPx) return undefined;\n return { widthPx, heightPx };\n }\n\n offset += length;\n }\n\n return undefined;\n}\n\nfunction parseIntrinsicImageSizePx(\n contentType: string,\n data: Uint8Array,\n): { widthPx: number; heightPx: number } | undefined {\n if (contentType === \"image/png\") return parsePngDimensions(data);\n if (contentType === \"image/jpeg\") return parseJpegDimensions(data);\n return undefined;\n}\n\nfunction applyMaxBoxPx(\n size: { widthPx: number; heightPx: number },\n maxBox: { maxWidthPx: number; maxHeightPx: number },\n): { widthPx: number; heightPx: number } {\n const w = Math.max(1, Math.round(size.widthPx));\n const h = Math.max(1, Math.round(size.heightPx));\n const scale = Math.min(1, maxBox.maxWidthPx / w, maxBox.maxHeightPx / h);\n return { widthPx: Math.max(1, Math.round(w * scale)), heightPx: Math.max(1, Math.round(h * scale)) };\n}\n\nfunction computeImageSizePx(\n node: HtmlNode,\n intrinsic: { widthPx: number; heightPx: number } | undefined,\n): { widthPx: number; heightPx: number } {\n const wAttr = node.attribs?.width ? Number(node.attribs.width) : undefined;\n const hAttr = node.attribs?.height ? Number(node.attribs.height) : undefined;\n const css = parseStyleAttribute(node.attribs?.style);\n const wCss = parseCssLengthToPx(css.width);\n const hCss = parseCssLengthToPx(css.height);\n\n const widthAttrPx = Number.isFinite(wAttr) && wAttr ? Math.max(1, Math.round(wAttr)) : undefined;\n const heightAttrPx = Number.isFinite(hAttr) && hAttr ? Math.max(1, Math.round(hAttr)) : undefined;\n\n const ratio =\n intrinsic && intrinsic.widthPx > 0 && intrinsic.heightPx > 0\n ? intrinsic.heightPx / intrinsic.widthPx\n : widthAttrPx && heightAttrPx\n ? heightAttrPx / widthAttrPx\n : 0.5;\n\n const widthPx =\n typeof wCss === \"number\"\n ? wCss\n : typeof widthAttrPx === \"number\"\n ? widthAttrPx\n : intrinsic?.widthPx ?? 300;\n const heightPx =\n typeof hCss === \"number\"\n ? hCss\n : typeof heightAttrPx === \"number\"\n ? heightAttrPx\n : intrinsic?.heightPx ?? 150;\n\n const finalSize =\n typeof wCss === \"number\" && typeof hCss !== \"number\"\n ? { widthPx, heightPx: Math.max(1, Math.round(widthPx * ratio)) }\n : typeof hCss === \"number\" && typeof wCss !== \"number\"\n ? { widthPx: Math.max(1, Math.round(heightPx / ratio)), heightPx }\n : typeof widthAttrPx === \"number\" && typeof heightAttrPx !== \"number\" && intrinsic\n ? { widthPx, heightPx: Math.max(1, Math.round(widthPx * ratio)) }\n : typeof heightAttrPx === \"number\" && typeof widthAttrPx !== \"number\" && intrinsic\n ? { widthPx: Math.max(1, Math.round(heightPx / ratio)), heightPx }\n : { widthPx, heightPx };\n\n return applyMaxBoxPx(finalSize, { maxWidthPx: 624, maxHeightPx: 864 });\n}\n\nfunction collectInlineRuns(\n node: HtmlNode,\n inherited: TextStyle,\n out: RunToken[],\n result: HtmlToWordResult,\n): void {\n if (node.type === \"text\") {\n const text = node.data ?? \"\";\n if (text) out.push({ kind: \"text\", text, style: inherited });\n return;\n }\n\n if (node.type === \"tag\") {\n const tag = node.name?.toLowerCase();\n if (tag === \"br\") {\n out.push({ kind: \"br\" });\n return;\n }\n if (tag === \"img\") {\n const src = node.attribs?.src;\n if (!src) return;\n const parsed = parseImageDataUrl(src);\n if (!parsed) return;\n const intrinsic = parseIntrinsicImageSizePx(parsed.contentType, parsed.data);\n const { widthPx, heightPx } = computeImageSizePx(node, intrinsic);\n const id = result.images.length + 1;\n const relationshipId = `rId${id + IMAGE_RELATIONSHIP_ID_OFFSET}`;\n const target = `media/image${id}.${parsed.extension}`;\n result.images.push({\n relationshipId,\n target,\n data: parsed.data,\n contentType: parsed.contentType,\n widthPx,\n heightPx,\n });\n out.push({ kind: \"image\", image: { relationshipId, widthPx, heightPx } });\n return;\n }\n if (tag === \"canvas\") {\n const dataUrl = node.attribs?.[\"data-image\"] ?? node.attribs?.[\"data-src\"];\n if (!dataUrl) return;\n const parsed = parseImageDataUrl(dataUrl);\n if (!parsed) return;\n const bufferW = node.attribs?.width ? Number(node.attribs.width) : undefined;\n const bufferH = node.attribs?.height ? Number(node.attribs.height) : undefined;\n const intrinsic =\n Number.isFinite(bufferW) && bufferW && Number.isFinite(bufferH) && bufferH\n ? { widthPx: Math.max(1, Math.round(bufferW)), heightPx: Math.max(1, Math.round(bufferH)) }\n : parseIntrinsicImageSizePx(parsed.contentType, parsed.data);\n const { widthPx, heightPx } = computeImageSizePx(node, intrinsic);\n const id = result.images.length + 1;\n const relationshipId = `rId${id + IMAGE_RELATIONSHIP_ID_OFFSET}`;\n const target = `media/image${id}.${parsed.extension}`;\n result.images.push({\n relationshipId,\n target,\n data: parsed.data,\n contentType: parsed.contentType,\n widthPx,\n heightPx,\n });\n out.push({ kind: \"image\", image: { relationshipId, widthPx, heightPx } });\n return;\n }\n const next = mergeTextStyle(inherited, styleFromElement(node));\n const children = node.children ?? [];\n for (const c of children) collectInlineRuns(c, next, out, result);\n return;\n }\n\n const children = node.children ?? [];\n for (const c of children) collectInlineRuns(c, inherited, out, result);\n}\n\nfunction buildRunXml(style: TextStyle, text: string): string {\n const rPrParts: string[] = [];\n if (style.bold) rPrParts.push(\"<w:b/>\");\n if (style.italic) rPrParts.push(\"<w:i/>\");\n if (style.underline) rPrParts.push('<w:u w:val=\"single\"/>');\n if (style.colorHex) rPrParts.push(`<w:color w:val=\"${style.colorHex}\"/>`);\n if (style.fontFamily) {\n const ff = escapeXmlText(style.fontFamily);\n rPrParts.push(`<w:rFonts w:ascii=\"${ff}\" w:hAnsi=\"${ff}\" w:eastAsia=\"${ff}\"/>`);\n }\n if (typeof style.fontSizeHalfPoints === \"number\") {\n const sz = style.fontSizeHalfPoints;\n rPrParts.push(`<w:sz w:val=\"${sz}\"/><w:szCs w:val=\"${sz}\"/>`);\n }\n\n const rPrXml = rPrParts.length ? `<w:rPr>${rPrParts.join(\"\")}</w:rPr>` : \"\";\n const escaped = escapeXmlText(text);\n const preserve = shouldPreserveSpace(text) ? ' xml:space=\"preserve\"' : \"\";\n return `<w:r>${rPrXml}<w:t${preserve}>${escaped}</w:t></w:r>`;\n}\n\nfunction pxToEmu(px: number): number {\n return Math.max(1, Math.round(px * 9525));\n}\n\nfunction buildImageRunXml(image: EmbeddedImageRef): string {\n const cx = pxToEmu(image.widthPx);\n const cy = pxToEmu(image.heightPx);\n const docPrId = image.relationshipId.replace(/^rId/, \"\");\n const name = `Picture ${docPrId}`;\n\n return `<w:r><w:drawing xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\"><wp:inline distT=\"0\" distB=\"0\" distL=\"0\" distR=\"0\"><wp:extent cx=\"${cx}\" cy=\"${cy}\"/><wp:docPr id=\"${docPrId}\" name=\"${escapeXmlText(name)}\"/><a:graphic><a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\"><pic:pic><pic:nvPicPr><pic:cNvPr id=\"0\" name=\"${escapeXmlText(name)}\"/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip r:embed=\"${image.relationshipId}\"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm><a:off x=\"0\" y=\"0\"/><a:ext cx=\"${cx}\" cy=\"${cy}\"/></a:xfrm><a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing></w:r>`;\n}\n\nfunction hasClass(node: HtmlNode, className: string): boolean {\n const cls = node.attribs?.class;\n if (!cls) return false;\n return cls.split(/\\s+/).includes(className);\n}\n\nfunction isSkippableSubtree(node: HtmlNode): boolean {\n if (node.type !== \"tag\") return false;\n const tag = node.name?.toLowerCase();\n if (tag === \"button\") return true;\n if (tag === \"canvas\") {\n const dataUrl = node.attribs?.[\"data-image\"] ?? node.attribs?.[\"data-src\"];\n if (!dataUrl) return true;\n }\n if (tag === \"img\" && hasClass(node, \"ProseMirror-separator\")) return true;\n if (node.attribs?.id === \"pages\") return true;\n if (hasClass(node, \"ProseMirror-widget\")) return true;\n return false;\n}\n\nfunction parseCssLengthToTwips(\n value: string | undefined,\n baseFontHalfPoints: number,\n): number | undefined {\n if (!value) return undefined;\n const v = value.trim().toLowerCase();\n if (!v) return undefined;\n\n const pt = v.match(/^(-?\\d+(?:\\.\\d+)?)pt$/);\n if (pt) return Math.round(Number(pt[1]) * 20);\n\n const px = v.match(/^(-?\\d+(?:\\.\\d+)?)px$/);\n if (px) return Math.round((Number(px[1]) * 72 * 20) / 96);\n\n const em = v.match(/^(-?\\d+(?:\\.\\d+)?)em$/);\n if (em) {\n const basePt = baseFontHalfPoints / 2;\n return Math.round(Number(em[1]) * basePt * 20);\n }\n\n const num = v.match(/^(-?\\d+(?:\\.\\d+)?)$/);\n if (num) return Math.round(Number(num[1]));\n\n return undefined;\n}\n\nfunction inferFirstFontSizeHalfPoints(node: HtmlNode): number | undefined {\n const stack: HtmlNode[] = [node];\n while (stack.length) {\n const cur = stack.pop() as HtmlNode;\n if (cur.type === \"tag\") {\n const css = parseStyleAttribute(cur.attribs?.style);\n const sz = parseFontSizeToHalfPoints(css[\"font-size\"]);\n if (typeof sz === \"number\") return sz;\n }\n const children = cur.children ?? [];\n for (let i = children.length - 1; i >= 0; i--) {\n stack.push(children[i] as HtmlNode);\n }\n }\n return undefined;\n}\n\nfunction buildParagraphPrXml(\n node: HtmlNode,\n baseFontHalfPoints: number,\n extraInd?: { leftTwips?: number; hangingTwips?: number },\n pStyleId?: string,\n): string {\n const css = parseStyleAttribute(node.attribs?.style);\n const parts: string[] = [];\n\n if (pStyleId) parts.push(`<w:pStyle w:val=\"${escapeXmlText(pStyleId)}\"/>`);\n\n const shdHex = extractBackgroundFillHex(css);\n if (shdHex) parts.push(`<w:shd w:val=\"clear\" w:color=\"auto\" w:fill=\"${shdHex}\"/>`);\n\n const align = css[\"text-align\"]?.trim().toLowerCase();\n const jcVal =\n align === \"center\"\n ? \"center\"\n : align === \"right\"\n ? \"right\"\n : align === \"justify\"\n ? \"both\"\n : undefined;\n if (jcVal) parts.push(`<w:jc w:val=\"${jcVal}\"/>`);\n\n const left = (() => {\n const marginLeft = parseCssLengthToTwips(css[\"margin-left\"], baseFontHalfPoints);\n const paddingLeft = parseCssLengthToTwips(css[\"padding-left\"], baseFontHalfPoints);\n const sum = (marginLeft ?? 0) + (paddingLeft ?? 0);\n if (!sum) return undefined;\n return Math.max(0, sum);\n })();\n\n const firstLine = (() => {\n const textIndent = parseCssLengthToTwips(css[\"text-indent\"], baseFontHalfPoints);\n if (typeof textIndent !== \"number\" || !textIndent) return undefined;\n return Math.max(0, textIndent);\n })();\n\n const indAttrs: string[] = [];\n const leftTwips = extraInd?.leftTwips ?? left;\n if (typeof leftTwips === \"number\") indAttrs.push(`w:left=\"${leftTwips}\"`);\n const hangingTwips = extraInd?.hangingTwips;\n if (typeof hangingTwips === \"number\") indAttrs.push(`w:hanging=\"${hangingTwips}\"`);\n if (typeof firstLine === \"number\") indAttrs.push(`w:firstLine=\"${firstLine}\"`);\n if (indAttrs.length) parts.push(`<w:ind ${indAttrs.join(\" \")}/>`);\n\n const before = parseCssLengthToTwips(css[\"margin-top\"], baseFontHalfPoints);\n const after = parseCssLengthToTwips(css[\"margin-bottom\"], baseFontHalfPoints);\n const lineHeight = (() => {\n const lh = css[\"line-height\"]?.trim().toLowerCase();\n if (!lh || lh === \"normal\") return undefined;\n\n const unitless = lh.match(/^(\\d+(?:\\.\\d+)?)$/);\n if (unitless) {\n const multiplier = Number(unitless[1]);\n if (!Number.isFinite(multiplier) || multiplier <= 0) return undefined;\n const basePt = baseFontHalfPoints / 2;\n return Math.round(basePt * multiplier * 20);\n }\n\n const twips = parseCssLengthToTwips(lh, baseFontHalfPoints);\n if (typeof twips !== \"number\") return undefined;\n return Math.max(1, twips);\n })();\n\n if (\n typeof before === \"number\" ||\n typeof after === \"number\" ||\n typeof lineHeight === \"number\"\n ) {\n const attrs: string[] = [];\n if (typeof before === \"number\") attrs.push(`w:before=\"${Math.max(0, before)}\"`);\n if (typeof after === \"number\") attrs.push(`w:after=\"${Math.max(0, after)}\"`);\n if (typeof lineHeight === \"number\") {\n attrs.push(`w:line=\"${lineHeight}\"`, 'w:lineRule=\"exact\"');\n }\n parts.push(`<w:spacing ${attrs.join(\" \")}/>`);\n }\n\n if (!parts.length) return \"\";\n return `<w:pPr>${parts.join(\"\")}</w:pPr>`;\n}\n\nfunction buildParagraphXmlFromContainer(\n node: HtmlNode,\n baseStyle: TextStyle,\n extraInd?: { leftTwips?: number; hangingTwips?: number },\n pStyleId?: string,\n result?: HtmlToWordResult,\n): string {\n const containerStyle = mergeTextStyle(baseStyle, styleFromElement(node));\n const baseFontHalfPoints =\n containerStyle.fontSizeHalfPoints ?? inferFirstFontSizeHalfPoints(node) ?? 28;\n const pPrXml = buildParagraphPrXml(node, baseFontHalfPoints, extraInd, pStyleId);\n\n const runs: RunToken[] = [];\n const res =\n result ??\n ({\n bodyXml: \"\",\n images: [],\n } as HtmlToWordResult);\n for (const c of node.children ?? []) collectInlineRuns(c, containerStyle, runs, res);\n\n const rXml: string[] = [];\n for (const token of runs) {\n if (token.kind === \"br\") {\n rXml.push(\"<w:r><w:br/></w:r>\");\n continue;\n }\n if (token.kind === \"image\") {\n rXml.push(buildImageRunXml(token.image));\n continue;\n }\n const text = token.text;\n if (!text) continue;\n if (!text.trim() && !shouldKeepWhitespaceOnlyRun(text)) continue;\n rXml.push(buildRunXml(token.style, text));\n }\n\n if (!rXml.length) return \"\";\n return `<w:p>${pPrXml}${rXml.join(\"\")}</w:p>`;\n}\n\nconst PAGE_BREAK_XML = '<w:p><w:r><w:br w:type=\"page\"/></w:r></w:p>';\n\nfunction isExplicitPageBreak(node: HtmlNode): boolean {\n if (node.type !== \"tag\") return false;\n const tag = node.name?.toLowerCase();\n const css = parseStyleAttribute(node.attribs?.style);\n const cls = node.attribs?.class ?? \"\";\n const classList = cls ? cls.split(/\\s+/) : [];\n\n if (tag === \"hr\" && classList.includes(\"page-break\")) return true;\n if (classList.includes(\"page-break\")) return true;\n if (node.attribs?.[\"data-page-break\"] === \"true\") return true;\n\n const after = css[\"page-break-after\"]?.toLowerCase() ?? css[\"break-after\"]?.toLowerCase();\n const before = css[\"page-break-before\"]?.toLowerCase() ?? css[\"break-before\"]?.toLowerCase();\n if (after?.includes(\"always\") || before?.includes(\"always\")) return true;\n\n return false;\n}\n\nfunction buildHeadingBaseStyle(level: number): TextStyle {\n const size = level === 1 ? 44 : level === 2 ? 32 : level === 3 ? 28 : level === 4 ? 24 : 22;\n return { bold: true, fontSizeHalfPoints: size };\n}\n\nfunction buildListBlocks(\n listNode: HtmlNode,\n ordered: boolean,\n level: number,\n result: HtmlToWordResult,\n): string[] {\n const liNodes = (listNode.children ?? []).filter(\n (c) => c.type === \"tag\" && c.name?.toLowerCase() === \"li\",\n );\n if (!liNodes.length) return [];\n\n const out: string[] = [];\n const numId = ordered ? 2 : 1;\n const ilvl = Math.max(0, Math.min(8, Math.floor(level)));\n const leftTwips = 720 * (ilvl + 1);\n const hangingTwips = 360;\n\n for (const li of liNodes) {\n const nestedLists: HtmlNode[] = [];\n const baseStyle: TextStyle = styleFromElement(li);\n const runs: RunToken[] = [];\n for (const c of li.children ?? []) {\n if (c.type === \"tag\") {\n const tag = c.name?.toLowerCase();\n if (tag === \"ul\" || tag === \"ol\") {\n nestedLists.push(c);\n continue;\n }\n }\n collectInlineRuns(c, baseStyle, runs, result);\n }\n\n const rXml: string[] = [];\n for (const token of runs) {\n if (token.kind === \"br\") {\n rXml.push(\"<w:r><w:br/></w:r>\");\n continue;\n }\n if (token.kind === \"image\") {\n rXml.push(buildImageRunXml(token.image));\n continue;\n }\n const text = token.text;\n if (!text) continue;\n if (!text.trim() && !shouldKeepWhitespaceOnlyRun(text)) continue;\n rXml.push(buildRunXml(token.style, text));\n }\n\n if (rXml.length) {\n const baseFontHalfPoints = inferFirstFontSizeHalfPoints(li) ?? 28;\n const pPrXml = buildParagraphPrXml(\n li,\n baseFontHalfPoints,\n { leftTwips, hangingTwips },\n undefined,\n );\n const numPrXml = `<w:numPr><w:ilvl w:val=\"${ilvl}\"/><w:numId w:val=\"${numId}\"/></w:numPr>`;\n const mergedPPrXml = pPrXml\n ? pPrXml.replace(\"<w:pPr>\", `<w:pPr>${numPrXml}`)\n : `<w:pPr>${numPrXml}<w:ind w:left=\"${leftTwips}\" w:hanging=\"${hangingTwips}\"/></w:pPr>`;\n out.push(`<w:p>${mergedPPrXml}${rXml.join(\"\")}</w:p>`);\n }\n\n for (const nested of nestedLists) {\n const nestedOrdered = nested.name?.toLowerCase() === \"ol\";\n out.push(...buildListBlocks(nested, nestedOrdered, ilvl + 1, result));\n }\n }\n\n return out;\n}\n\nfunction parseCellWidthTwips(node: HtmlNode): number | undefined {\n const css = parseStyleAttribute(node.attribs?.style);\n const width = parseCssLengthToTwips(css.width, 28);\n if (typeof width !== \"number\" || width <= 0) return undefined;\n return width;\n}\n\nfunction estimateTextWidthTwips(text: string, baseFontHalfPoints: number): number {\n const basePt = baseFontHalfPoints / 2;\n const cjkRegex = /[\\u3400-\\u4dbf\\u4e00-\\u9fff\\u3000-\\u303f\\uff00-\\uffef]/;\n let cjk = 0;\n let latin = 0;\n let spaces = 0;\n for (const ch of text) {\n if (ch === \" \" || ch === \"\\t\") {\n spaces++;\n continue;\n }\n if (cjkRegex.test(ch)) {\n cjk++;\n continue;\n }\n latin++;\n }\n const cjkTwips = Math.round(basePt * 20);\n const latinTwips = Math.round(basePt * 11);\n const spaceTwips = Math.round(basePt * 6);\n return cjk * cjkTwips + latin * latinTwips + spaces * spaceTwips;\n}\n\ntype WordBorder = { val: string; sz: number; colorHex?: string };\n\nfunction parseBorderShorthand(value: string | undefined, baseFontHalfPoints: number): WordBorder | undefined {\n if (!value) return undefined;\n const raw = value.trim().toLowerCase();\n if (!raw) return undefined;\n if (raw === \"none\" || raw === \"0\") return { val: \"nil\", sz: 0 };\n\n const tokens = raw.split(/\\s+/).filter(Boolean);\n if (!tokens.length) return undefined;\n\n const css = Object.fromEntries(tokens.map((t, i) => [`${i}`, t]));\n const widthToken = Object.values(css).find((t) => /^(?:\\d+(?:\\.\\d+)?)(?:px|pt)?$/.test(t));\n const styleToken = Object.values(css).find((t) =>\n [\"none\", \"solid\", \"dashed\", \"dotted\", \"double\", \"hidden\"].includes(t),\n );\n const colorToken = Object.values(css).find((t) => t.startsWith(\"#\") || t.startsWith(\"rgb(\"));\n\n const widthTwips = parseCssLengthToTwips(widthToken, baseFontHalfPoints);\n const sz = (() => {\n if (typeof widthTwips !== \"number\") return 4;\n if (widthTwips <= 0) return 0;\n return Math.max(2, Math.round(widthTwips * 0.4));\n })();\n\n const val = (() => {\n if (!styleToken) return \"single\";\n if (styleToken === \"none\" || styleToken === \"hidden\") return \"nil\";\n if (styleToken === \"solid\") return \"single\";\n if (styleToken === \"dashed\") return \"dashed\";\n if (styleToken === \"dotted\") return \"dotted\";\n if (styleToken === \"double\") return \"double\";\n return \"single\";\n })();\n\n const colorHex = parseCssColorToHex(colorToken);\n return { val, sz, colorHex };\n}\n\nfunction buildBorderTag(tag: string, border: WordBorder | undefined, fallbackColorHex: string): string {\n const b = border ?? { val: \"single\", sz: 4, colorHex: fallbackColorHex };\n const color = (b.colorHex ?? fallbackColorHex).toUpperCase();\n return `<w:${tag} w:val=\"${b.val}\" w:sz=\"${b.sz}\" w:space=\"0\" w:color=\"${color}\"/>`;\n}\n\nfunction injectTableCellParagraphSpacing(pXml: string): string {\n if (!pXml.includes(\"<w:p\")) return pXml;\n if (!pXml.includes(\"<w:p>\")) return pXml;\n const spacingXml = '<w:spacing w:before=\"0\" w:after=\"0\" w:line=\"360\" w:lineRule=\"auto\"/><w:wordWrap w:val=\"1\"/>';\n if (pXml.includes(\"<w:pPr>\")) {\n if (pXml.includes(\"<w:spacing \")) return pXml;\n return pXml.replace(\"<w:pPr>\", `<w:pPr>${spacingXml}`);\n }\n return pXml.replace(\"<w:p>\", `<w:p><w:pPr>${spacingXml}</w:pPr>`);\n}\n\nfunction buildTableCellBlocksXml(cell: HtmlNode, baseStyle: TextStyle, result: HtmlToWordResult): string {\n const children = cell.children ?? [];\n const hasBlocks = children.some((c) => {\n if (c.type !== \"tag\") return false;\n const tag = c.name?.toLowerCase();\n return tag === \"p\" || tag === \"ul\" || tag === \"ol\" || tag === \"img\" || tag === \"canvas\" || /^h[1-6]$/.test(tag ?? \"\");\n });\n\n const out: string[] = [];\n if (!hasBlocks) {\n const p = buildParagraphXmlFromContainer(cell, baseStyle, undefined, undefined, result);\n if (p) out.push(p);\n return out.length ? out.map(injectTableCellParagraphSpacing).join(\"\") : \"<w:p/>\";\n }\n\n for (const c of children) {\n if (c.type === \"tag\") {\n const tag = c.name?.toLowerCase();\n if (tag === \"p\") {\n const p = buildParagraphXmlFromContainer(c, baseStyle, undefined, undefined, result);\n if (p) out.push(p);\n continue;\n }\n if (tag && /^h[1-6]$/.test(tag)) {\n const level = Number(tag.slice(1));\n const p = buildParagraphXmlFromContainer(c, baseStyle, undefined, `Heading${level}`, result);\n if (p) out.push(p);\n continue;\n }\n if (tag === \"ul\" || tag === \"ol\") {\n out.push(...buildListBlocks(c, tag === \"ol\", 0, result));\n continue;\n }\n if (tag === \"img\" || tag === \"canvas\") {\n const p = buildParagraphXmlFromSingleInlineNode(c, baseStyle, result);\n if (p) out.push(p);\n continue;\n }\n }\n }\n\n if (!out.length) return \"<w:p/>\";\n return out.map(injectTableCellParagraphSpacing).join(\"\");\n}\n\nfunction buildTableXml(tableNode: HtmlNode, result: HtmlToWordResult): string {\n const rows: HtmlNode[] = [];\n const stack: HtmlNode[] = [...(tableNode.children ?? [])];\n while (stack.length) {\n const n = stack.shift() as HtmlNode;\n if (n.type === \"tag\" && n.name?.toLowerCase() === \"tr\") rows.push(n);\n if (n.children?.length) stack.unshift(...n.children);\n }\n\n const rowCells = rows.map((tr) =>\n (tr.children ?? []).filter((c) => c.type === \"tag\" && (c.name === \"td\" || c.name === \"th\")),\n );\n const colCount = Math.max(0, ...rowCells.map((cells) => cells.length));\n const maxTableWidthTwips = 9360;\n\n const estimatedColWidths = new Array(colCount).fill(0).map((_, i) => {\n let explicit: number | undefined;\n let estimated = 0;\n for (const cells of rowCells) {\n const cell = cells[i] as HtmlNode | undefined;\n if (!cell) continue;\n const w = parseCellWidthTwips(cell);\n if (typeof w === \"number\") explicit = explicit ?? w;\n const text = getTextContent(cell).replace(/\\s+/g, \" \").trim();\n if (!text) continue;\n const baseFontHalfPoints = inferFirstFontSizeHalfPoints(cell) ?? 28;\n const wTwips = estimateTextWidthTwips(text, baseFontHalfPoints) + 240;\n estimated = Math.max(estimated, wTwips);\n }\n const base = typeof explicit === \"number\" ? explicit : estimated || Math.round(maxTableWidthTwips / Math.max(1, colCount));\n return Math.max(720, Math.min(6000, Math.round(base)));\n });\n\n const normalizedColWidths = (() => {\n const sum = estimatedColWidths.reduce((a, b) => a + b, 0);\n if (!sum) return estimatedColWidths;\n if (sum <= maxTableWidthTwips) return estimatedColWidths;\n const scaled = estimatedColWidths.map((w) =>\n Math.max(720, Math.floor((w * maxTableWidthTwips) / sum)),\n );\n const scaledSum = scaled.reduce((a, b) => a + b, 0);\n const diff = maxTableWidthTwips - scaledSum;\n if (diff !== 0 && scaled.length) scaled[scaled.length - 1] = Math.max(720, scaled[scaled.length - 1] + diff);\n return scaled;\n })();\n\n const tblGrid = `<w:tblGrid>${normalizedColWidths.map((w) => `<w:gridCol w:w=\"${w}\"/>`).join(\"\")}</w:tblGrid>`;\n\n const rowXml: string[] = [];\n for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {\n const tr = rows[rowIdx] as HtmlNode;\n const cells = rowCells[rowIdx] ?? [];\n\n const cellXml: string[] = [];\n for (let i = 0; i < cells.length; i++) {\n const cell = cells[i] as HtmlNode;\n const isHeader = cell.name === \"th\";\n const baseStyle: TextStyle = isHeader ? { bold: true } : {};\n const paragraphs = buildTableCellBlocksXml(cell, baseStyle, result);\n const css = parseStyleAttribute(cell.attribs?.style);\n const widthTwips = parseCellWidthTwips(cell) ?? normalizedColWidths[i];\n const tcW =\n typeof widthTwips === \"number\"\n ? `<w:tcW w:w=\"${widthTwips}\" w:type=\"dxa\"/>`\n : `<w:tcW w:w=\"0\" w:type=\"auto\"/>`;\n const vAlign = (() => {\n const v = css[\"vertical-align\"]?.trim().toLowerCase();\n if (!v) return \"\";\n if (v === \"middle\" || v === \"center\") return '<w:vAlign w:val=\"center\"/>';\n if (v === \"bottom\") return '<w:vAlign w:val=\"bottom\"/>';\n if (v === \"top\") return '<w:vAlign w:val=\"top\"/>';\n return \"\";\n })();\n const shd = (() => {\n const hex = parseCssColorToHex(css[\"background-color\"]);\n if (!hex) return \"\";\n return `<w:shd w:val=\"clear\" w:color=\"auto\" w:fill=\"${hex}\"/>`;\n })();\n const noWrap = (() => {\n const ws = css[\"white-space\"]?.trim().toLowerCase();\n if (ws?.includes(\"nowrap\")) return \"<w:noWrap/>\";\n return \"\";\n })();\n const cellBorder = (() => {\n const bAll = parseBorderShorthand(css.border, 28);\n const bTop = parseBorderShorthand(css[\"border-top\"] ?? css.border, 28);\n const bLeft = parseBorderShorthand(css[\"border-left\"] ?? css.border, 28);\n const bBottom = parseBorderShorthand(css[\"border-bottom\"] ?? css.border, 28);\n const bRight = parseBorderShorthand(css[\"border-right\"] ?? css.border, 28);\n const any =\n bAll || css.border || css[\"border-top\"] || css[\"border-left\"] || css[\"border-bottom\"] || css[\"border-right\"];\n if (!any) return \"\";\n const fallback = bAll?.colorHex ?? \"D9D9D9\";\n return `<w:tcBorders>${buildBorderTag(\"top\", bTop, fallback)}${buildBorderTag(\n \"left\",\n bLeft,\n fallback,\n )}${buildBorderTag(\"bottom\", bBottom, fallback)}${buildBorderTag(\n \"right\",\n bRight,\n fallback,\n )}</w:tcBorders>`;\n })();\n cellXml.push(`<w:tc><w:tcPr>${tcW}${vAlign}${shd}${noWrap}${cellBorder}</w:tcPr>${paragraphs}</w:tc>`);\n }\n if (cellXml.length) rowXml.push(`<w:tr>${cellXml.join(\"\")}</w:tr>`);\n }\n\n const tblCss = parseStyleAttribute(tableNode.attribs?.style);\n const tblAlign = (() => {\n const ml = tblCss[\"margin-left\"]?.trim().toLowerCase();\n const mr = tblCss[\"margin-right\"]?.trim().toLowerCase();\n const m = tblCss.margin?.trim().toLowerCase();\n if ((ml === \"auto\" && mr === \"auto\") || (m?.includes(\"auto\") ?? false)) return '<w:tblJc w:val=\"center\"/>';\n const ta = tblCss[\"text-align\"]?.trim().toLowerCase();\n if (ta === \"center\") return '<w:tblJc w:val=\"center\"/>';\n if (ta === \"right\") return '<w:tblJc w:val=\"right\"/>';\n return \"\";\n })();\n const tblBorder = (() => {\n const border = parseBorderShorthand(tblCss.border, 28);\n if (tblCss.border) {\n const fallback = border?.colorHex ?? \"D9D9D9\";\n return `<w:tblBorders>${buildBorderTag(\"top\", border, fallback)}${buildBorderTag(\n \"left\",\n border,\n fallback,\n )}${buildBorderTag(\"bottom\", border, fallback)}${buildBorderTag(\n \"right\",\n border,\n fallback,\n )}${buildBorderTag(\"insideH\", border, fallback)}${buildBorderTag(\n \"insideV\",\n border,\n fallback,\n )}</w:tblBorders>`;\n }\n const fallback = \"D9D9D9\";\n return `<w:tblBorders>${buildBorderTag(\"top\", undefined, fallback)}${buildBorderTag(\n \"left\",\n undefined,\n fallback,\n )}${buildBorderTag(\"bottom\", undefined, fallback)}${buildBorderTag(\n \"right\",\n undefined,\n fallback,\n )}${buildBorderTag(\"insideH\", undefined, fallback)}${buildBorderTag(\"insideV\", undefined, fallback)}</w:tblBorders>`;\n })();\n const tblW = `<w:tblW w:w=\"${normalizedColWidths.reduce((a, b) => a + b, 0)}\" w:type=\"dxa\"/>`;\n const tblPr = `<w:tblPr>${tblW}<w:tblLayout w:type=\"fixed\"/>${tblAlign}${tblBorder}</w:tblPr>`;\n return `<w:tbl>${tblPr}${tblGrid}${rowXml.join(\"\")}</w:tbl>`;\n}\n\nfunction buildParagraphXmlFromSingleInlineNode(\n node: HtmlNode,\n baseStyle: TextStyle,\n result: HtmlToWordResult,\n): string {\n const wrapper: HtmlNode = {\n type: \"tag\",\n name: \"p\",\n attribs: { style: \"text-align: center;\" },\n children: [node],\n };\n return buildParagraphXmlFromContainer(wrapper, baseStyle, undefined, undefined, result);\n}\n\nfunction isRecognizedBlockTag(tag: string | undefined): boolean {\n if (!tag) return false;\n if (tag === \"p\") return true;\n if (tag === \"table\") return true;\n if (tag === \"ul\" || tag === \"ol\") return true;\n if (tag === \"img\" || tag === \"canvas\") return true;\n if (/^h[1-6]$/.test(tag)) return true;\n if (tag === \"pre\") return true;\n return false;\n}\n\nfunction collectDivBlocks(node: HtmlNode, out: string[], result: HtmlToWordResult): void {\n const parentStyle = node.attribs?.style;\n const inlineBuffer: HtmlNode[] = [];\n\n const flushInline = () => {\n const wrapper: HtmlNode = {\n type: \"tag\",\n name: \"p\",\n attribs: { style: parentStyle },\n children: inlineBuffer.splice(0),\n };\n const pXml = buildParagraphXmlFromContainer(wrapper, {}, undefined, undefined, result);\n if (pXml) out.push(pXml);\n };\n\n const children = node.children ?? [];\n for (const child of children) {\n if (child.type === \"tag\") {\n const tag = child.name?.toLowerCase();\n if (isExplicitPageBreak(child)) {\n if (inlineBuffer.length) flushInline();\n out.push(PAGE_BREAK_XML);\n continue;\n }\n if (isRecognizedBlockTag(tag)) {\n if (inlineBuffer.length) flushInline();\n collectBodyBlocks(child, out, result);\n continue;\n }\n if (tag === \"div\") {\n const childHasRecognizedBlocks = (child.children ?? []).some((gc) => {\n if (gc.type !== \"tag\") return false;\n return isRecognizedBlockTag(gc.name?.toLowerCase());\n });\n if (childHasRecognizedBlocks) {\n if (inlineBuffer.length) flushInline();\n collectBodyBlocks(child, out, result);\n continue;\n }\n if (inlineBuffer.length) flushInline();\n const mergedStyle = [parentStyle, child.attribs?.style].filter(Boolean).join(\";\");\n const wrapper: HtmlNode = {\n type: \"tag\",\n name: \"p\",\n attribs: { style: mergedStyle || undefined },\n children: child.children ?? [],\n };\n const pXml = buildParagraphXmlFromContainer(wrapper, {}, undefined, undefined, result);\n if (pXml) out.push(pXml);\n continue;\n }\n }\n inlineBuffer.push(child);\n }\n\n if (inlineBuffer.length) flushInline();\n}\n\nfunction collectBodyBlocks(node: HtmlNode, out: string[], result: HtmlToWordResult): void {\n if (isSkippableSubtree(node)) return;\n\n if (node.type === \"tag\") {\n const tag = node.name?.toLowerCase();\n\n if (isExplicitPageBreak(node)) {\n out.push(PAGE_BREAK_XML);\n return;\n }\n\n if (tag === \"p\") {\n const pXml = buildParagraphXmlFromContainer(node, {}, undefined, undefined, result);\n if (pXml) out.push(pXml);\n return;\n }\n\n if (tag === \"img\" || tag === \"canvas\") {\n const pXml = buildParagraphXmlFromSingleInlineNode(node, {}, result);\n if (pXml) out.push(pXml);\n return;\n }\n\n if (tag && /^h[1-6]$/.test(tag)) {\n const level = Number(tag.slice(1));\n const hXml = buildParagraphXmlFromContainer(node, {}, undefined, `Heading${level}`, result);\n if (hXml) out.push(hXml);\n return;\n }\n\n if (tag === \"table\") {\n const tblXml = buildTableXml(node, result);\n if (tblXml) out.push(tblXml);\n return;\n }\n\n if (tag === \"ul\" || tag === \"ol\") {\n out.push(...buildListBlocks(node, tag === \"ol\", 0, result));\n return;\n }\n\n if (tag === \"div\") {\n collectDivBlocks(node, out, result);\n return;\n }\n }\n\n for (const c of node.children ?? []) collectBodyBlocks(c, out, result);\n}\n\nexport function textToWordBodyXml(text: string): string {\n const normalized = text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n if (!normalized.trim()) {\n throw new Error(\"Text is empty.\");\n }\n\n const lines = normalized.split(\"\\n\");\n const out: string[] = [];\n for (const line of lines) {\n if (!line) {\n out.push(\"<w:p/>\");\n continue;\n }\n out.push(`<w:p>${buildRunXml({}, line)}</w:p>`);\n }\n return out.join(\"\");\n}\n\nfunction htmlToWordBody(html: string): HtmlToWordResult {\n const normalized = html.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n const doc = parseDocument(normalized, {\n lowerCaseAttributeNames: true,\n lowerCaseTags: true,\n recognizeSelfClosing: true,\n }) as unknown as HtmlNode;\n\n const result: HtmlToWordResult = { bodyXml: \"\", images: [] };\n const out: string[] = [];\n collectBodyBlocks(doc, out, result);\n result.bodyXml = out.join(\"\");\n return result;\n}\n\n/**\n * 把 HTML 字符串转换成 WordprocessingML 的 body 片段(由 <w:p> / <w:tbl> 等组成)。\n * 说明:\n * - 这个函数只生成 body 内容,不生成完整的 <w:document> 包装\n * - 支持:p/span/strong/br、h1~h6、ul/ol/li、table/tr/td/th、基础分页标记\n * - 不支持:canvas 图表、复杂 CSS、HTML 图片(需要额外提供图片二进制)\n */\nexport function htmlToWordBodyXml(html: string): string {\n const { bodyXml } = htmlToWordBody(html);\n if (!bodyXml) {\n const text = getTextContent(\n parseDocument(html, {\n lowerCaseAttributeNames: true,\n lowerCaseTags: true,\n recognizeSelfClosing: true,\n }) as unknown as HtmlNode,\n );\n return textToWordBodyXml(text);\n }\n return bodyXml;\n}\n\nexport function htmlToWordBodyWithAssets(html: string): HtmlToWordResult {\n const result = htmlToWordBody(html);\n if (!result.bodyXml) {\n const text = getTextContent(\n parseDocument(html, {\n lowerCaseAttributeNames: true,\n lowerCaseTags: true,\n recognizeSelfClosing: true,\n }) as unknown as HtmlNode,\n );\n return { bodyXml: textToWordBodyXml(text), images: [] };\n }\n return result;\n}\n"],"mappings":"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","names":["children","fallback"]}
package/dist/index.cjs CHANGED
@@ -598,6 +598,17 @@ function parseCssColorToHex(value) {
598
598
  if (hex) return hex.toUpperCase();
599
599
  return parseRgbToHex(v);
600
600
  }
601
+ function extractBackgroundFillHex(css) {
602
+ const raw = (css["background-color"] ?? css.background)?.trim();
603
+ if (!raw) return void 0;
604
+ const direct = parseCssColorToHex(raw);
605
+ if (direct) return direct;
606
+ const hex = raw.match(/#([0-9a-fA-F]{6})/)?.[0];
607
+ if (hex) return parseCssColorToHex(hex);
608
+ const rgb = raw.match(/rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)/)?.[0];
609
+ if (rgb) return parseCssColorToHex(rgb);
610
+ return void 0;
611
+ }
601
612
  function parseFontSizeToHalfPoints(value) {
602
613
  if (!value) return void 0;
603
614
  const v = value.trim().toLowerCase();
@@ -916,6 +927,8 @@ function buildParagraphPrXml(node, baseFontHalfPoints, extraInd, pStyleId) {
916
927
  const css = parseStyleAttribute(node.attribs?.style);
917
928
  const parts = [];
918
929
  if (pStyleId) parts.push(`<w:pStyle w:val="${escapeXmlText(pStyleId)}"/>`);
930
+ const shdHex = extractBackgroundFillHex(css);
931
+ if (shdHex) parts.push(`<w:shd w:val="clear" w:color="auto" w:fill="${shdHex}"/>`);
919
932
  const align = css["text-align"]?.trim().toLowerCase();
920
933
  const jcVal = align === "center" ? "center" : align === "right" ? "right" : align === "justify" ? "both" : void 0;
921
934
  if (jcVal) parts.push(`<w:jc w:val="${jcVal}"/>`);
@@ -967,14 +980,15 @@ function buildParagraphPrXml(node, baseFontHalfPoints, extraInd, pStyleId) {
967
980
  return `<w:pPr>${parts.join("")}</w:pPr>`;
968
981
  }
969
982
  function buildParagraphXmlFromContainer(node, baseStyle, extraInd, pStyleId, result) {
970
- const baseFontHalfPoints = baseStyle.fontSizeHalfPoints ?? inferFirstFontSizeHalfPoints(node) ?? 28;
983
+ const containerStyle = mergeTextStyle(baseStyle, styleFromElement(node));
984
+ const baseFontHalfPoints = containerStyle.fontSizeHalfPoints ?? inferFirstFontSizeHalfPoints(node) ?? 28;
971
985
  const pPrXml = buildParagraphPrXml(node, baseFontHalfPoints, extraInd, pStyleId);
972
986
  const runs = [];
973
987
  const res = result ?? {
974
988
  bodyXml: "",
975
989
  images: []
976
990
  };
977
- for (const c of node.children ?? []) collectInlineRuns(c, baseStyle, runs, res);
991
+ for (const c of node.children ?? []) collectInlineRuns(c, containerStyle, runs, res);
978
992
  const rXml = [];
979
993
  for (const token of runs) {
980
994
  if (token.kind === "br") {
@@ -1019,7 +1033,7 @@ function buildListBlocks(listNode, ordered, level, result) {
1019
1033
  const hangingTwips = 360;
1020
1034
  for (const li of liNodes) {
1021
1035
  const nestedLists = [];
1022
- const baseStyle = {};
1036
+ const baseStyle = styleFromElement(li);
1023
1037
  const runs = [];
1024
1038
  for (const c of li.children ?? []) {
1025
1039
  if (c.type === "tag") {
@@ -1330,6 +1344,70 @@ function buildParagraphXmlFromSingleInlineNode(node, baseStyle, result) {
1330
1344
  };
1331
1345
  return buildParagraphXmlFromContainer(wrapper, baseStyle, void 0, void 0, result);
1332
1346
  }
1347
+ function isRecognizedBlockTag(tag) {
1348
+ if (!tag) return false;
1349
+ if (tag === "p") return true;
1350
+ if (tag === "table") return true;
1351
+ if (tag === "ul" || tag === "ol") return true;
1352
+ if (tag === "img" || tag === "canvas") return true;
1353
+ if (/^h[1-6]$/.test(tag)) return true;
1354
+ if (tag === "pre") return true;
1355
+ return false;
1356
+ }
1357
+ function collectDivBlocks(node, out, result) {
1358
+ const parentStyle = node.attribs?.style;
1359
+ const inlineBuffer = [];
1360
+ const flushInline = () => {
1361
+ const wrapper = {
1362
+ type: "tag",
1363
+ name: "p",
1364
+ attribs: { style: parentStyle },
1365
+ children: inlineBuffer.splice(0)
1366
+ };
1367
+ const pXml = buildParagraphXmlFromContainer(wrapper, {}, void 0, void 0, result);
1368
+ if (pXml) out.push(pXml);
1369
+ };
1370
+ const children = node.children ?? [];
1371
+ for (const child of children) {
1372
+ if (child.type === "tag") {
1373
+ const tag = child.name?.toLowerCase();
1374
+ if (isExplicitPageBreak(child)) {
1375
+ if (inlineBuffer.length) flushInline();
1376
+ out.push(PAGE_BREAK_XML);
1377
+ continue;
1378
+ }
1379
+ if (isRecognizedBlockTag(tag)) {
1380
+ if (inlineBuffer.length) flushInline();
1381
+ collectBodyBlocks(child, out, result);
1382
+ continue;
1383
+ }
1384
+ if (tag === "div") {
1385
+ const childHasRecognizedBlocks = (child.children ?? []).some((gc) => {
1386
+ if (gc.type !== "tag") return false;
1387
+ return isRecognizedBlockTag(gc.name?.toLowerCase());
1388
+ });
1389
+ if (childHasRecognizedBlocks) {
1390
+ if (inlineBuffer.length) flushInline();
1391
+ collectBodyBlocks(child, out, result);
1392
+ continue;
1393
+ }
1394
+ if (inlineBuffer.length) flushInline();
1395
+ const mergedStyle = [parentStyle, child.attribs?.style].filter(Boolean).join(";");
1396
+ const wrapper = {
1397
+ type: "tag",
1398
+ name: "p",
1399
+ attribs: { style: mergedStyle || void 0 },
1400
+ children: child.children ?? []
1401
+ };
1402
+ const pXml = buildParagraphXmlFromContainer(wrapper, {}, void 0, void 0, result);
1403
+ if (pXml) out.push(pXml);
1404
+ continue;
1405
+ }
1406
+ }
1407
+ inlineBuffer.push(child);
1408
+ }
1409
+ if (inlineBuffer.length) flushInline();
1410
+ }
1333
1411
  function collectBodyBlocks(node, out, result) {
1334
1412
  if (isSkippableSubtree(node)) return;
1335
1413
  if (node.type === "tag") {
@@ -1363,6 +1441,10 @@ function collectBodyBlocks(node, out, result) {
1363
1441
  out.push(...buildListBlocks(node, tag === "ol", 0, result));
1364
1442
  return;
1365
1443
  }
1444
+ if (tag === "div") {
1445
+ collectDivBlocks(node, out, result);
1446
+ return;
1447
+ }
1366
1448
  }
1367
1449
  for (const c of node.children ?? []) collectBodyBlocks(c, out, result);
1368
1450
  }