@bendyline/squisq-formats 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/{chunk-2KPARF2P.js → chunk-74GO3FVS.js} +3 -3
  2. package/dist/{chunk-WC7WULGV.js → chunk-7ARKUCQT.js} +9 -1
  3. package/dist/chunk-7ARKUCQT.js.map +1 -0
  4. package/dist/{chunk-LXYLOOST.js → chunk-DTDF6QDP.js} +3 -3
  5. package/dist/chunk-DTDF6QDP.js.map +1 -0
  6. package/dist/{chunk-QRVN6A6E.js → chunk-EW54IRRS.js} +4 -4
  7. package/dist/{chunk-U32AG3G3.js → chunk-KURGXM4I.js} +2 -2
  8. package/dist/{chunk-CRAVSMPZ.js → chunk-NNHKUXKA.js} +292 -70
  9. package/dist/chunk-NNHKUXKA.js.map +1 -0
  10. package/dist/{chunk-VSYHZECT.js → chunk-QFLDYKCR.js} +2 -2
  11. package/dist/{chunk-ABVI556T.js → chunk-RLU7UFYU.js} +5 -5
  12. package/dist/{chunk-XKUMNGBW.js → chunk-SC67HYQJ.js} +2 -2
  13. package/dist/{chunk-VJJM2SSH.js → chunk-UGYF5AZE.js} +3 -3
  14. package/dist/{chunk-HTW2M27H.js → chunk-WQSHGBLN.js} +1 -1
  15. package/dist/docx/index.js +4 -3
  16. package/dist/{extract-H6RXJMHP.js → extract-OJ7ZQV6P.js} +4 -4
  17. package/dist/html/index.js +1 -1
  18. package/dist/index.js +11 -11
  19. package/dist/infer/index.js +4 -4
  20. package/dist/{layouts-QVPK3ZCU.js → layouts-5VDIRPIJ.js} +3 -3
  21. package/dist/ooxml/index.js +3 -3
  22. package/dist/pptx/index.js +4 -4
  23. package/dist/registry/index.js +1 -1
  24. package/dist/xlsx/index.js +3 -3
  25. package/package.json +2 -2
  26. package/src/__tests__/docxExport.test.ts +34 -0
  27. package/src/__tests__/docxImport.test.ts +121 -0
  28. package/src/__tests__/html.test.ts +4 -0
  29. package/src/docx/export.ts +113 -5
  30. package/src/docx/import.ts +324 -69
  31. package/src/html/htmlTemplate.ts +2 -2
  32. package/src/ooxml/namespaces.ts +21 -0
  33. package/dist/chunk-CRAVSMPZ.js.map +0 -1
  34. package/dist/chunk-LXYLOOST.js.map +0 -1
  35. package/dist/chunk-WC7WULGV.js.map +0 -1
  36. /package/dist/{chunk-2KPARF2P.js.map → chunk-74GO3FVS.js.map} +0 -0
  37. /package/dist/{chunk-QRVN6A6E.js.map → chunk-EW54IRRS.js.map} +0 -0
  38. /package/dist/{chunk-U32AG3G3.js.map → chunk-KURGXM4I.js.map} +0 -0
  39. /package/dist/{chunk-VSYHZECT.js.map → chunk-QFLDYKCR.js.map} +0 -0
  40. /package/dist/{chunk-ABVI556T.js.map → chunk-RLU7UFYU.js.map} +0 -0
  41. /package/dist/{chunk-XKUMNGBW.js.map → chunk-SC67HYQJ.js.map} +0 -0
  42. /package/dist/{chunk-VJJM2SSH.js.map → chunk-UGYF5AZE.js.map} +0 -0
  43. /package/dist/{chunk-HTW2M27H.js.map → chunk-WQSHGBLN.js.map} +0 -0
  44. /package/dist/{extract-H6RXJMHP.js.map → extract-OJ7ZQV6P.js.map} +0 -0
  45. /package/dist/{layouts-QVPK3ZCU.js.map → layouts-5VDIRPIJ.js.map} +0 -0
@@ -5,9 +5,13 @@ import {
5
5
  import {
6
6
  stripHtmlTags
7
7
  } from "./chunk-PN52A5AA.js";
8
+ import {
9
+ baseDirOf,
10
+ resolveTarget
11
+ } from "./chunk-YRT7GQ5Y.js";
8
12
  import {
9
13
  createPackage
10
- } from "./chunk-U32AG3G3.js";
14
+ } from "./chunk-KURGXM4I.js";
11
15
  import {
12
16
  escapeXml,
13
17
  xmlDeclaration
@@ -15,7 +19,9 @@ import {
15
19
  import {
16
20
  CONTENT_TYPE_DOCX_DOCUMENT,
17
21
  CONTENT_TYPE_DOCX_FONT_TABLE,
22
+ CONTENT_TYPE_DOCX_FOOTER,
18
23
  CONTENT_TYPE_DOCX_FOOTNOTES,
24
+ CONTENT_TYPE_DOCX_HEADER,
19
25
  CONTENT_TYPE_DOCX_NUMBERING,
20
26
  CONTENT_TYPE_DOCX_SETTINGS,
21
27
  CONTENT_TYPE_DOCX_STYLES,
@@ -23,7 +29,9 @@ import {
23
29
  NS_R,
24
30
  NS_WML,
25
31
  REL_FONT_TABLE,
32
+ REL_FOOTER,
26
33
  REL_FOOTNOTES,
34
+ REL_HEADER,
27
35
  REL_HYPERLINK,
28
36
  REL_IMAGE,
29
37
  REL_NUMBERING,
@@ -34,7 +42,7 @@ import {
34
42
  getPartRelationships,
35
43
  getPartXml,
36
44
  openPackage
37
- } from "./chunk-WC7WULGV.js";
45
+ } from "./chunk-7ARKUCQT.js";
38
46
  import {
39
47
  buildContainer
40
48
  } from "./chunk-SSUPBUF5.js";
@@ -105,8 +113,28 @@ function pointsToTwips(points) {
105
113
  async function markdownDocToDocx(doc, options = {}) {
106
114
  const resolvedOptions = options.themeId !== void 0 ? options : { ...options, themeId: readFrontmatterThemeId(doc.frontmatter) };
107
115
  const ctx = new ExportContext(resolvedOptions, doc);
108
- const bodyXml = convertBlocks(doc.children, ctx);
109
- return buildDocxPackage(bodyXml, ctx, resolvedOptions);
116
+ const stories = partitionDocumentStories(doc.children);
117
+ ctx.setRelationshipSource("document");
118
+ const bodyXml = convertBlocks(stories.body, ctx);
119
+ ctx.setRelationshipSource("header");
120
+ const headerXml = convertBlocks(stories.header, ctx);
121
+ ctx.setRelationshipSource("footer");
122
+ const footerXml = convertBlocks(stories.footer, ctx);
123
+ ctx.setRelationshipSource("document");
124
+ return buildDocxPackage(bodyXml, headerXml, footerXml, ctx, resolvedOptions);
125
+ }
126
+ function partitionDocumentStories(nodes) {
127
+ const stories = { body: [], header: [], footer: [] };
128
+ for (const node of nodes) {
129
+ if (node.type === "containerDirective" && node.name === "docx-header") {
130
+ stories.header.push(...node.children);
131
+ } else if (node.type === "containerDirective" && node.name === "docx-footer") {
132
+ stories.footer.push(...node.children);
133
+ } else {
134
+ stories.body.push(node);
135
+ }
136
+ }
137
+ return stories;
110
138
  }
111
139
  async function docToDocx(doc, options = {}) {
112
140
  const markdownDoc = docToMarkdown(doc);
@@ -120,6 +148,7 @@ var ExportContext = class {
120
148
  // 0 is separator, start user footnotes at 1
121
149
  /** Relationships for word/_rels/document.xml.rels */
122
150
  this.relationships = [];
151
+ this.relationshipSource = "document";
123
152
  /** Numbering definitions (abstract + num) */
124
153
  this.numberingDefs = [];
125
154
  /** Footnote XML bodies (keyed by footnote id) */
@@ -162,6 +191,9 @@ var ExportContext = class {
162
191
  allocRelId() {
163
192
  return `rId${this.nextRelId++}`;
164
193
  }
194
+ setRelationshipSource(source) {
195
+ this.relationshipSource = source;
196
+ }
165
197
  /** Add a hyperlink relationship and return the rId */
166
198
  addHyperlink(url) {
167
199
  const id = this.allocRelId();
@@ -169,7 +201,8 @@ var ExportContext = class {
169
201
  id,
170
202
  type: REL_HYPERLINK,
171
203
  target: url,
172
- targetMode: "External"
204
+ targetMode: "External",
205
+ source: this.relationshipSource
173
206
  });
174
207
  return id;
175
208
  }
@@ -182,7 +215,8 @@ var ExportContext = class {
182
215
  this.relationships.push({
183
216
  id: relId,
184
217
  type: REL_IMAGE,
185
- target: `media/${filename}`
218
+ target: `media/${filename}`,
219
+ source: this.relationshipSource
186
220
  });
187
221
  return { relId, docPrId };
188
222
  }
@@ -257,6 +291,8 @@ function convertBlock(node, ctx, listDepth) {
257
291
  return convertMathBlock(node);
258
292
  case "footnoteDefinition":
259
293
  return convertFootnoteDefinition(node, ctx);
294
+ case "containerDirective":
295
+ return convertBlocks(node.children, ctx);
260
296
  default:
261
297
  return "";
262
298
  }
@@ -498,7 +534,7 @@ function convertFootnoteRef(node, ctx) {
498
534
  const fnId = ctx.getFootnoteId(node.identifier);
499
535
  return `<w:r><w:rPr><w:rStyle w:val="FootnoteReference"/><w:vertAlign w:val="superscript"/></w:rPr><w:footnoteReference w:id="${fnId}"/></w:r>`;
500
536
  }
501
- async function buildDocxPackage(bodyXml, ctx, options) {
537
+ async function buildDocxPackage(bodyXml, headerXml, footerXml, ctx, options) {
502
538
  const pkg = createPackage();
503
539
  let relCounter = 100;
504
540
  const stylesRelId = `rId${relCounter++}`;
@@ -506,8 +542,23 @@ async function buildDocxPackage(bodyXml, ctx, options) {
506
542
  const settingsRelId = `rId${relCounter++}`;
507
543
  const fontTableRelId = `rId${relCounter++}`;
508
544
  const footnotesRelId = `rId${relCounter++}`;
509
- const documentXml = buildDocumentXml(bodyXml, ctx.backgroundColor);
545
+ const headerRelId = `rId${relCounter++}`;
546
+ const footerRelId = `rId${relCounter++}`;
547
+ const hasHeader = headerXml.trim().length > 0;
548
+ const hasFooter = footerXml.trim().length > 0;
549
+ const documentXml = buildDocumentXml(
550
+ bodyXml,
551
+ ctx.backgroundColor,
552
+ hasHeader ? headerRelId : void 0,
553
+ hasFooter ? footerRelId : void 0
554
+ );
510
555
  pkg.addPart("word/document.xml", documentXml, CONTENT_TYPE_DOCX_DOCUMENT);
556
+ if (hasHeader) {
557
+ pkg.addPart("word/header1.xml", buildStoryXml("header", headerXml), CONTENT_TYPE_DOCX_HEADER);
558
+ }
559
+ if (hasFooter) {
560
+ pkg.addPart("word/footer1.xml", buildStoryXml("footer", footerXml), CONTENT_TYPE_DOCX_FOOTER);
561
+ }
511
562
  const stylesXml = buildStylesXml(options, ctx);
512
563
  pkg.addPart("word/styles.xml", stylesXml, CONTENT_TYPE_DOCX_STYLES);
513
564
  const settingsXml = buildSettingsXml(ctx.backgroundColor !== void 0);
@@ -556,8 +607,23 @@ async function buildDocxPackage(bodyXml, ctx, options) {
556
607
  target: "footnotes.xml"
557
608
  });
558
609
  }
559
- for (const rel of ctx.relationships) {
610
+ if (hasHeader) {
560
611
  pkg.addRelationship("word/document.xml", {
612
+ id: headerRelId,
613
+ type: REL_HEADER,
614
+ target: "header1.xml"
615
+ });
616
+ }
617
+ if (hasFooter) {
618
+ pkg.addRelationship("word/document.xml", {
619
+ id: footerRelId,
620
+ type: REL_FOOTER,
621
+ target: "footer1.xml"
622
+ });
623
+ }
624
+ for (const rel of ctx.relationships) {
625
+ const sourcePart = rel.source === "header" ? "word/header1.xml" : rel.source === "footer" ? "word/footer1.xml" : "word/document.xml";
626
+ pkg.addRelationship(sourcePart, {
561
627
  id: rel.id,
562
628
  type: rel.type,
563
629
  target: rel.target,
@@ -578,9 +644,14 @@ async function buildDocxPackage(bodyXml, ctx, options) {
578
644
  }
579
645
  return pkg.toArrayBuffer();
580
646
  }
581
- function buildDocumentXml(bodyXml, backgroundColor) {
647
+ function buildDocumentXml(bodyXml, backgroundColor, headerRelId, footerRelId) {
582
648
  const backgroundEl = backgroundColor ? `<w:background w:color="${backgroundColor}"/>` : "";
583
- return xmlDeclaration() + `<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="${NS_MC}" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="${NS_R}" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="${NS_WML}" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">` + backgroundEl + `<w:body>` + bodyXml + `<w:sectPr><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/><w:cols w:space="720"/></w:sectPr></w:body></w:document>`;
649
+ const storyReferences = (headerRelId ? `<w:headerReference w:type="default" r:id="${headerRelId}"/>` : "") + (footerRelId ? `<w:footerReference w:type="default" r:id="${footerRelId}"/>` : "");
650
+ return xmlDeclaration() + `<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="${NS_MC}" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="${NS_R}" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="${NS_WML}" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">` + backgroundEl + `<w:body>` + bodyXml + `<w:sectPr>` + storyReferences + `<w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/><w:cols w:space="720"/></w:sectPr></w:body></w:document>`;
651
+ }
652
+ function buildStoryXml(kind, bodyXml) {
653
+ const element = kind === "header" ? "hdr" : "ftr";
654
+ return xmlDeclaration() + `<w:${element} xmlns:w="${NS_WML}" xmlns:r="${NS_R}" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">` + bodyXml + `</w:${element}>`;
584
655
  }
585
656
  function buildStylesXml(options, ctx) {
586
657
  const font = ctx.font;
@@ -666,7 +737,7 @@ async function docxToMarkdownDoc(data, options = {}) {
666
737
  if (!body) {
667
738
  return { type: "document", children: [] };
668
739
  }
669
- const blocks = await convertBody(body, ctx);
740
+ const blocks = await convertDocumentStories(body, ctx);
670
741
  return { type: "document", children: blocks };
671
742
  }
672
743
  async function docxToDoc(data, options = {}) {
@@ -680,7 +751,7 @@ async function docxToContainer(data, options = {}) {
680
751
  if (!documentXml) return buildContainer("", []);
681
752
  const body = getFirstElement(documentXml, "body");
682
753
  if (!body) return buildContainer("", []);
683
- const blocks = await convertBody(body, ctx);
754
+ const blocks = await convertDocumentStories(body, ctx);
684
755
  const markdownDoc = { type: "document", children: blocks };
685
756
  return buildContainer(stringifyMarkdown(markdownDoc), ctx.extractedImages);
686
757
  }
@@ -693,6 +764,8 @@ async function buildImportContext(pkg, options) {
693
764
  documentRels: /* @__PURE__ */ new Map(),
694
765
  numbering: /* @__PURE__ */ new Map(),
695
766
  footnotes: /* @__PURE__ */ new Map(),
767
+ endnotes: /* @__PURE__ */ new Map(),
768
+ currentPartPath: "word/document.xml",
696
769
  pkg,
697
770
  options,
698
771
  extractedImages: /* @__PURE__ */ new Map(),
@@ -717,6 +790,7 @@ async function buildImportContext(pkg, options) {
717
790
  }
718
791
  await parseNumbering(pkg, ctx);
719
792
  await parseFootnotes(pkg, ctx);
793
+ await parseEndnotes(pkg, ctx);
720
794
  return ctx;
721
795
  }
722
796
  async function parseStyles(pkg, ctx) {
@@ -797,9 +871,67 @@ async function parseFootnotes(pkg, ctx) {
797
871
  ctx.footnotes.set(id, fn);
798
872
  }
799
873
  }
874
+ async function parseEndnotes(pkg, ctx) {
875
+ const doc = await getPartXml(pkg, "word/endnotes.xml");
876
+ if (!doc) return;
877
+ const endnoteEls = getAllElements(doc, "endnote");
878
+ for (const note of endnoteEls) {
879
+ const id = getAttr(note, "id");
880
+ const type = getAttr(note, "type");
881
+ if (!id || type === "separator" || type === "continuationSeparator") continue;
882
+ ctx.endnotes.set(id, note);
883
+ }
884
+ }
885
+ async function convertDocumentStories(body, ctx) {
886
+ const bodyBlocks = await convertBody(body, ctx);
887
+ const headers = await convertRelatedStories(body, ctx, "header");
888
+ const footers = await convertRelatedStories(body, ctx, "footer");
889
+ const noteDefinitions = await convertNoteDefinitions(ctx);
890
+ return [...bodyBlocks, ...headers, ...footers, ...noteDefinitions];
891
+ }
892
+ async function convertRelatedStories(body, ctx, kind) {
893
+ const relationshipTypeSuffix = `/${kind}`;
894
+ const referenceName = `${kind}Reference`;
895
+ const referenceTypes = /* @__PURE__ */ new Map();
896
+ for (const reference of getAllElements(body, referenceName)) {
897
+ const id = reference.getAttributeNS(NS_R, "id") ?? reference.getAttribute("r:id");
898
+ if (id) referenceTypes.set(id, getAttr(reference, "type") ?? "default");
899
+ }
900
+ const documentRelationships = ctx.documentRels;
901
+ const previousPartPath = ctx.currentPartPath;
902
+ const results = [];
903
+ for (const relationship of documentRelationships.values()) {
904
+ if (!relationship.type.endsWith(relationshipTypeSuffix)) continue;
905
+ const partPath = resolveTarget(baseDirOf("word/document.xml"), relationship.target);
906
+ const part = await getPartXml(ctx.pkg, partPath);
907
+ if (!part?.documentElement) continue;
908
+ const partRelationships = await getPartRelationships(ctx.pkg, partPath);
909
+ ctx.documentRels = new Map(partRelationships.map((rel) => [rel.id, rel]));
910
+ ctx.currentPartPath = partPath;
911
+ try {
912
+ const children = await convertBody(part.documentElement, ctx);
913
+ if (children.length === 0) continue;
914
+ results.push({
915
+ type: "containerDirective",
916
+ name: `docx-${kind}`,
917
+ attributes: {
918
+ type: referenceTypes.get(relationship.id) ?? "default",
919
+ source: partPath
920
+ },
921
+ children
922
+ });
923
+ } finally {
924
+ ctx.documentRels = documentRelationships;
925
+ ctx.currentPartPath = previousPartPath;
926
+ }
927
+ }
928
+ return results;
929
+ }
800
930
  async function convertBody(body, ctx) {
931
+ return convertBlockElements(Array.from(body.children), ctx);
932
+ }
933
+ async function convertBlockElements(children, ctx) {
801
934
  const result = [];
802
- const children = Array.from(body.children);
803
935
  let i = 0;
804
936
  while (i < children.length) {
805
937
  const el = children[i];
@@ -821,12 +953,22 @@ async function convertBody(body, ctx) {
821
953
  const table = await convertTable2(el, ctx);
822
954
  if (table) result.push(table);
823
955
  i++;
956
+ } else if (localName === "sdt") {
957
+ const content = getFirstChildElement(el, "sdtContent");
958
+ if (content) result.push(...await convertBlockElements(Array.from(content.children), ctx));
959
+ i++;
960
+ } else if (localName === "ins" || localName === "moveTo" || localName === "customXml" || localName === "smartTag" || localName === "fldSimple") {
961
+ result.push(...await convertBlockElements(Array.from(el.children), ctx));
962
+ i++;
963
+ } else if (localName === "AlternateContent") {
964
+ const selected = getFirstChildElement(el, "Choice") ?? getFirstChildElement(el, "Fallback");
965
+ if (selected)
966
+ result.push(...await convertBlockElements(Array.from(selected.children), ctx));
967
+ i++;
824
968
  } else {
825
969
  i++;
826
970
  }
827
971
  }
828
- const footnoteNodes = await convertFootnoteDefinitions(ctx);
829
- result.push(...footnoteNodes);
830
972
  return result;
831
973
  }
832
974
  async function convertParagraph2(el, ctx) {
@@ -857,8 +999,10 @@ async function convertParagraph2(el, ctx) {
857
999
  return { type: "paragraph", children: inlines };
858
1000
  }
859
1001
  async function convertRuns(paragraphEl, ctx) {
1002
+ return mergeAdjacentText(await convertInlineElements(Array.from(paragraphEl.children), ctx));
1003
+ }
1004
+ async function convertInlineElements(children, ctx) {
860
1005
  const result = [];
861
- const children = Array.from(paragraphEl.children);
862
1006
  for (const child of children) {
863
1007
  const localName = child.localName;
864
1008
  if (localName === "r") {
@@ -867,9 +1011,23 @@ async function convertRuns(paragraphEl, ctx) {
867
1011
  } else if (localName === "hyperlink") {
868
1012
  const link = await convertHyperlink(child, ctx);
869
1013
  if (link) result.push(link);
1014
+ } else if (localName === "sdt") {
1015
+ const content = getFirstChildElement(child, "sdtContent");
1016
+ if (content) {
1017
+ result.push(...await convertInlineElements(Array.from(content.children), ctx));
1018
+ }
1019
+ } else if (localName === "ins" || localName === "moveTo" || localName === "customXml" || localName === "smartTag" || localName === "fldSimple") {
1020
+ result.push(...await convertInlineElements(Array.from(child.children), ctx));
1021
+ } else if (localName === "AlternateContent") {
1022
+ const selected = getFirstChildElement(child, "Choice") ?? getFirstChildElement(child, "Fallback");
1023
+ if (selected) {
1024
+ result.push(...await convertInlineElements(Array.from(selected.children), ctx));
1025
+ }
1026
+ } else if (localName === "drawing" || localName === "pict") {
1027
+ result.push(...await convertDrawingContent(child, ctx));
870
1028
  }
871
1029
  }
872
- return mergeAdjacentText(result);
1030
+ return result;
873
1031
  }
874
1032
  async function convertRun(runEl, ctx) {
875
1033
  const result = [];
@@ -895,8 +1053,10 @@ async function convertRun(runEl, ctx) {
895
1053
  }
896
1054
  result.push(node);
897
1055
  }
898
- } else if (localName === "br") {
1056
+ } else if (localName === "br" || localName === "cr") {
899
1057
  result.push({ type: "break" });
1058
+ } else if (localName === "tab") {
1059
+ result.push({ type: "text", value: " " });
900
1060
  } else if (localName === "footnoteReference") {
901
1061
  const fnId = getAttr(child, "id");
902
1062
  if (fnId && fnId !== "0" && fnId !== "-1") {
@@ -905,13 +1065,79 @@ async function convertRun(runEl, ctx) {
905
1065
  identifier: `fn${fnId}`
906
1066
  });
907
1067
  }
908
- } else if (localName === "drawing" || localName === "pict") {
909
- const img = await extractImage(child, ctx);
910
- if (img) result.push(img);
1068
+ } else if (localName === "endnoteReference") {
1069
+ const noteId = getAttr(child, "id");
1070
+ if (noteId && noteId !== "0" && noteId !== "-1") {
1071
+ result.push({
1072
+ type: "footnoteReference",
1073
+ identifier: `endnote${noteId}`
1074
+ });
1075
+ }
1076
+ } else if (localName === "drawing" || localName === "pict" || localName === "object") {
1077
+ result.push(...await convertDrawingContent(child, ctx));
1078
+ } else if (localName === "AlternateContent") {
1079
+ const selected = getFirstChildElement(child, "Choice") ?? getFirstChildElement(child, "Fallback");
1080
+ if (selected) {
1081
+ result.push(...await convertInlineElements(Array.from(selected.children), ctx));
1082
+ }
1083
+ }
1084
+ }
1085
+ return result;
1086
+ }
1087
+ async function convertDrawingContent(el, ctx) {
1088
+ const result = [];
1089
+ const textBoxes = findDescendants(el, "txbxContent");
1090
+ for (const textBox of textBoxes) {
1091
+ const inlines = await flattenContainerToInlines(textBox, ctx);
1092
+ appendInlineGroup(result, inlines);
1093
+ }
1094
+ const image = await extractImage(el, ctx);
1095
+ if (image) result.push(image);
1096
+ if (textBoxes.length > 0 && result.length > 0) {
1097
+ if (result[0]?.type !== "break") result.unshift({ type: "break" });
1098
+ if (result[result.length - 1]?.type !== "break") {
1099
+ result.push({ type: "break" });
911
1100
  }
912
1101
  }
913
1102
  return result;
914
1103
  }
1104
+ async function flattenContainerToInlines(container, ctx) {
1105
+ const result = [];
1106
+ for (const child of Array.from(container.children)) {
1107
+ if (child.localName === "p") {
1108
+ appendInlineGroup(result, await convertRuns(child, ctx));
1109
+ } else if (child.localName === "tbl") {
1110
+ appendInlineGroup(result, await flattenTableToInlines(child, ctx));
1111
+ } else if (child.localName === "sdt") {
1112
+ const content = getFirstChildElement(child, "sdtContent");
1113
+ if (content) appendInlineGroup(result, await flattenContainerToInlines(content, ctx));
1114
+ } else if (child.localName === "ins" || child.localName === "moveTo" || child.localName === "customXml" || child.localName === "smartTag" || child.localName === "fldSimple") {
1115
+ appendInlineGroup(result, await flattenContainerToInlines(child, ctx));
1116
+ } else if (child.localName === "AlternateContent") {
1117
+ const selected = getFirstChildElement(child, "Choice") ?? getFirstChildElement(child, "Fallback");
1118
+ if (selected) appendInlineGroup(result, await flattenContainerToInlines(selected, ctx));
1119
+ } else if (child.localName === "r" || child.localName === "hyperlink") {
1120
+ appendInlineGroup(result, await convertInlineElements([child], ctx));
1121
+ }
1122
+ }
1123
+ return mergeAdjacentText(result);
1124
+ }
1125
+ async function flattenTableToInlines(table, ctx) {
1126
+ const result = [];
1127
+ for (const row of getAllChildElements(table, "tr")) {
1128
+ for (const cell of getAllChildElements(row, "tc")) {
1129
+ appendInlineGroup(result, await flattenContainerToInlines(cell, ctx));
1130
+ }
1131
+ }
1132
+ return mergeAdjacentText(result);
1133
+ }
1134
+ function appendInlineGroup(target, group) {
1135
+ if (group.length === 0) return;
1136
+ if (target.length > 0 && target[target.length - 1]?.type !== "break") {
1137
+ target.push({ type: "break" });
1138
+ }
1139
+ target.push(...group);
1140
+ }
915
1141
  function parseRunFormat(rPr, ctx) {
916
1142
  if (!rPr) return { bold: false, italic: false, strike: false, code: false };
917
1143
  const bold = hasChildElement(rPr, "b") && !isFalseToggle(getFirstChildElement(rPr, "b"));
@@ -940,12 +1166,7 @@ async function convertHyperlink(el, ctx) {
940
1166
  const anchor = el.getAttributeNS(NS_WML, "anchor") ?? el.getAttribute("w:anchor");
941
1167
  if (anchor) url = `#${anchor}`;
942
1168
  }
943
- const inlines = [];
944
- for (const child of Array.from(el.children)) {
945
- if (child.localName === "r") {
946
- inlines.push(...await convertRun(child, ctx));
947
- }
948
- }
1169
+ const inlines = await convertInlineElements(Array.from(el.children), ctx);
949
1170
  if (inlines.length === 0) return null;
950
1171
  return {
951
1172
  type: "link",
@@ -955,22 +1176,14 @@ async function convertHyperlink(el, ctx) {
955
1176
  }
956
1177
  async function extractImage(el, ctx) {
957
1178
  const blip = findDescendant(el, "blip");
958
- if (!blip) {
959
- return { type: "image", url: "", alt: "Image" };
960
- }
961
- const rId = blip.getAttributeNS(NS_R, "embed") ?? blip.getAttribute("r:embed");
962
- if (!rId) {
963
- return { type: "image", url: "", alt: "Image" };
964
- }
1179
+ const imageData = findDescendant(el, "imagedata");
1180
+ const rId = blip ? blip.getAttributeNS(NS_R, "embed") ?? blip.getAttribute("r:embed") : imageData?.getAttributeNS(NS_R, "id") ?? imageData?.getAttribute("r:id") ?? imageData?.getAttribute("o:relid");
1181
+ if (!rId) return null;
965
1182
  const rel = ctx.documentRels.get(rId);
966
- if (!rel) {
967
- return { type: "image", url: "", alt: "Image" };
968
- }
969
- const target = rel.target.startsWith("/") ? rel.target.slice(1) : `word/${rel.target}`;
1183
+ if (!rel || rel.targetMode === "External") return null;
1184
+ const target = resolveTarget(baseDirOf(ctx.currentPartPath), rel.target);
970
1185
  const data = await getPartBinary(ctx.pkg, target);
971
- if (!data) {
972
- return { type: "image", url: "", alt: "Image" };
973
- }
1186
+ if (!data) return null;
974
1187
  const dot = target.lastIndexOf(".");
975
1188
  const ext = dot !== -1 ? target.slice(dot).toLowerCase() : ".png";
976
1189
  const mimeType = extToMime(ext);
@@ -978,7 +1191,8 @@ async function extractImage(el, ctx) {
978
1191
  const imagePath = `images/image${ctx.imageCounter}${ext}`;
979
1192
  ctx.extractedImages.set(imagePath, { data, mimeType });
980
1193
  const docPr = findDescendant(el, "docPr");
981
- const alt = docPr?.getAttribute("descr") || docPr?.getAttribute("title") || "Image";
1194
+ const shape = findDescendant(el, "shape");
1195
+ const alt = docPr?.getAttribute("descr") || docPr?.getAttribute("title") || shape?.getAttribute("alt") || shape?.getAttribute("title") || "Image";
982
1196
  return {
983
1197
  type: "image",
984
1198
  url: imagePath,
@@ -993,6 +1207,14 @@ function findDescendant(el, localName) {
993
1207
  }
994
1208
  return null;
995
1209
  }
1210
+ function findDescendants(el, localName) {
1211
+ const results = [];
1212
+ for (const child of Array.from(el.children)) {
1213
+ if (child.localName === localName) results.push(child);
1214
+ results.push(...findDescendants(child, localName));
1215
+ }
1216
+ return results;
1217
+ }
996
1218
  async function collectList(elements, startIdx, ctx) {
997
1219
  const firstNumPr = getNumPr(elements[startIdx]);
998
1220
  const { numId } = firstNumPr;
@@ -1020,6 +1242,8 @@ async function collectList(elements, startIdx, ctx) {
1020
1242
  children: nested.items
1021
1243
  };
1022
1244
  lastItem.children.push(nestedList);
1245
+ } else {
1246
+ items.push(...nested.items);
1023
1247
  }
1024
1248
  i += nested.consumed;
1025
1249
  consumed += nested.consumed;
@@ -1100,42 +1324,40 @@ async function convertTableRow2(trEl, ctx, isHeader) {
1100
1324
  return { type: "tableRow", children: cells };
1101
1325
  }
1102
1326
  async function convertTableCell2(tcEl, ctx, isHeader) {
1103
- const inlines = [];
1104
- const paragraphs = getAllChildElements(tcEl, "p");
1105
- for (let pi = 0; pi < paragraphs.length; pi++) {
1106
- if (pi > 0) {
1107
- inlines.push({ type: "break" });
1108
- }
1109
- const runs = await convertRuns(paragraphs[pi], ctx);
1110
- inlines.push(...runs);
1111
- }
1327
+ const inlines = await flattenContainerToInlines(tcEl, ctx);
1112
1328
  return {
1113
1329
  type: "tableCell",
1114
1330
  isHeader,
1115
1331
  children: mergeAdjacentText(inlines)
1116
1332
  };
1117
1333
  }
1118
- async function convertFootnoteDefinitions(ctx) {
1334
+ async function convertNoteDefinitions(ctx) {
1335
+ return [
1336
+ ...await convertNotePartDefinitions(ctx, ctx.footnotes, "fn", "word/footnotes.xml"),
1337
+ ...await convertNotePartDefinitions(ctx, ctx.endnotes, "endnote", "word/endnotes.xml")
1338
+ ];
1339
+ }
1340
+ async function convertNotePartDefinitions(ctx, notes, identifierPrefix, partPath) {
1119
1341
  const results = [];
1120
- for (const [id, el] of ctx.footnotes) {
1121
- const children = [];
1122
- const paragraphs = getAllChildElements(el, "p");
1123
- for (const p of paragraphs) {
1124
- const inlines = await convertRuns(p, ctx);
1125
- if (inlines.length > 0) {
1126
- children.push({
1127
- type: "paragraph",
1128
- children: inlines
1342
+ const previousRelationships = ctx.documentRels;
1343
+ const previousPartPath = ctx.currentPartPath;
1344
+ const partRelationships = await getPartRelationships(ctx.pkg, partPath);
1345
+ ctx.documentRels = new Map(partRelationships.map((rel) => [rel.id, rel]));
1346
+ ctx.currentPartPath = partPath;
1347
+ try {
1348
+ for (const [id, el] of notes) {
1349
+ const children = await convertBody(el, ctx);
1350
+ if (children.length > 0) {
1351
+ results.push({
1352
+ type: "footnoteDefinition",
1353
+ identifier: `${identifierPrefix}${id}`,
1354
+ children
1129
1355
  });
1130
1356
  }
1131
1357
  }
1132
- if (children.length > 0) {
1133
- results.push({
1134
- type: "footnoteDefinition",
1135
- identifier: `fn${id}`,
1136
- children
1137
- });
1138
- }
1358
+ } finally {
1359
+ ctx.documentRels = previousRelationships;
1360
+ ctx.currentPartPath = previousPartPath;
1139
1361
  }
1140
1362
  return results;
1141
1363
  }
@@ -1209,4 +1431,4 @@ export {
1209
1431
  docxToDoc,
1210
1432
  docxToContainer
1211
1433
  };
1212
- //# sourceMappingURL=chunk-CRAVSMPZ.js.map
1434
+ //# sourceMappingURL=chunk-NNHKUXKA.js.map