ooxml-core 0.5.0 → 0.7.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 (95) hide show
  1. package/README.md +1 -0
  2. package/dist/digest/algorithm-names.d.ts +20 -0
  3. package/dist/digest/algorithm-names.d.ts.map +1 -0
  4. package/dist/digest/base64.d.ts +8 -0
  5. package/dist/digest/base64.d.ts.map +1 -0
  6. package/dist/digest/digest.d.ts +13 -0
  7. package/dist/digest/digest.d.ts.map +1 -0
  8. package/dist/digest/index.cjs +594 -0
  9. package/dist/digest/index.d.ts +8 -0
  10. package/dist/digest/index.d.ts.map +1 -0
  11. package/dist/digest/index.mjs +581 -0
  12. package/dist/digest/password-hash.d.ts +30 -0
  13. package/dist/digest/password-hash.d.ts.map +1 -0
  14. package/dist/digest/sha1.d.ts +3 -0
  15. package/dist/digest/sha1.d.ts.map +1 -0
  16. package/dist/digest/sha256.d.ts +10 -0
  17. package/dist/digest/sha256.d.ts.map +1 -0
  18. package/dist/digest/sha512.d.ts +5 -0
  19. package/dist/digest/sha512.d.ts.map +1 -0
  20. package/dist/docx/block-parser.d.ts.map +1 -1
  21. package/dist/docx/embedded.cjs +131 -54
  22. package/dist/docx/embedded.mjs +131 -54
  23. package/dist/docx/equation.d.ts +8 -0
  24. package/dist/docx/equation.d.ts.map +1 -0
  25. package/dist/docx/index.cjs +131 -54
  26. package/dist/docx/index.mjs +131 -54
  27. package/dist/docx/layout/adapter.d.ts.map +1 -1
  28. package/dist/docx/layout/index.cjs +3 -1
  29. package/dist/docx/layout/index.mjs +3 -1
  30. package/dist/docx/load/index.cjs +133 -56
  31. package/dist/docx/load/index.mjs +133 -56
  32. package/dist/docx/model-run.d.ts +5 -0
  33. package/dist/docx/model-run.d.ts.map +1 -1
  34. package/dist/docx/parse-revisions.d.ts.map +1 -1
  35. package/dist/docx/parse-table.d.ts.map +1 -1
  36. package/dist/docx/write-inline.d.ts.map +1 -1
  37. package/dist/docx/write-table-margins.d.ts +5 -0
  38. package/dist/docx/write-table-margins.d.ts.map +1 -0
  39. package/dist/docx/write-table-properties.d.ts +3 -1
  40. package/dist/docx/write-table-properties.d.ts.map +1 -1
  41. package/dist/docx/write-table.d.ts.map +1 -1
  42. package/dist/index.cjs +598 -0
  43. package/dist/index.d.ts +1 -0
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.mjs +598 -1
  46. package/dist/visio/cell-formula.d.ts +9 -0
  47. package/dist/visio/cell-formula.d.ts.map +1 -0
  48. package/dist/visio/edit-commands.d.ts +33 -0
  49. package/dist/visio/edit-commands.d.ts.map +1 -0
  50. package/dist/visio/edit-geometry-admission.d.ts +10 -0
  51. package/dist/visio/edit-geometry-admission.d.ts.map +1 -0
  52. package/dist/visio/edit-geometry.d.ts +3 -0
  53. package/dist/visio/edit-geometry.d.ts.map +1 -0
  54. package/dist/visio/edit-recalculate-index.d.ts +25 -0
  55. package/dist/visio/edit-recalculate-index.d.ts.map +1 -0
  56. package/dist/visio/edit-recalculate.d.ts +11 -0
  57. package/dist/visio/edit-recalculate.d.ts.map +1 -0
  58. package/dist/visio/edit-scope.d.ts +5 -0
  59. package/dist/visio/edit-scope.d.ts.map +1 -0
  60. package/dist/visio/edit.d.ts +4 -8
  61. package/dist/visio/edit.d.ts.map +1 -1
  62. package/dist/visio/formula-evaluate.d.ts +10 -0
  63. package/dist/visio/formula-evaluate.d.ts.map +1 -0
  64. package/dist/visio/formula-theme.d.ts +2 -0
  65. package/dist/visio/formula-theme.d.ts.map +1 -0
  66. package/dist/visio/formula.d.ts +52 -0
  67. package/dist/visio/formula.d.ts.map +1 -0
  68. package/dist/visio/index.cjs +1605 -232
  69. package/dist/visio/index.d.ts +2 -1
  70. package/dist/visio/index.d.ts.map +1 -1
  71. package/dist/visio/index.mjs +1601 -233
  72. package/dist/xlsx/edit/history.d.ts +1 -1
  73. package/dist/xlsx/edit/history.d.ts.map +1 -1
  74. package/dist/xlsx/edit/index.d.ts +1 -1
  75. package/dist/xlsx/edit/index.d.ts.map +1 -1
  76. package/dist/xlsx/edit/protection.d.ts +18 -6
  77. package/dist/xlsx/edit/protection.d.ts.map +1 -1
  78. package/dist/xlsx/edit/types.d.ts +2 -2
  79. package/dist/xlsx/index.cjs +671 -28
  80. package/dist/xlsx/index.mjs +670 -29
  81. package/dist/xlsx/load/index.cjs +56 -19
  82. package/dist/xlsx/load/index.mjs +56 -19
  83. package/dist/xlsx/model.d.ts +21 -0
  84. package/dist/xlsx/model.d.ts.map +1 -1
  85. package/dist/xlsx/read/load.d.ts.map +1 -1
  86. package/dist/xlsx/read/password-hash.d.ts +15 -0
  87. package/dist/xlsx/read/password-hash.d.ts.map +1 -0
  88. package/dist/xlsx/read/sheet-props.d.ts.map +1 -1
  89. package/dist/xlsx/read/workbook-part.d.ts +3 -1
  90. package/dist/xlsx/read/workbook-part.d.ts.map +1 -1
  91. package/dist/xlsx/write/password-hash.d.ts +8 -0
  92. package/dist/xlsx/write/password-hash.d.ts.map +1 -0
  93. package/dist/xlsx/write/sheet-props.d.ts.map +1 -1
  94. package/dist/xlsx/write/workbook-part.d.ts.map +1 -1
  95. package/package.json +6 -1
@@ -1659,6 +1659,46 @@ function orderSectionProperties(sectPr) {
1659
1659
  orderChildren(sectPr, SECTPR_ORDER);
1660
1660
  }
1661
1661
 
1662
+ // src/docx/write-table-margins.ts
1663
+ var SIDES2 = ["top", "left", "bottom", "right"];
1664
+ var ORDER = ["top", "start", "left", "bottom", "end", "right"];
1665
+ function patchMarginProperties(doc, host, propertiesTag, marginTag, propertiesOrder, next, base) {
1666
+ const changed = SIDES2.filter((side) => next?.[side] !== base?.[side]);
1667
+ if (!changed.length) return;
1668
+ for (const side of changed) {
1669
+ const value = next?.[side];
1670
+ if (value !== void 0 && (!Number.isSafeInteger(value) || value < 0))
1671
+ throw new Error("Table cell margins must be nonnegative whole twips.");
1672
+ }
1673
+ let properties = first2(host, propertiesTag);
1674
+ if (!properties) {
1675
+ properties = makeW(doc, propertiesTag);
1676
+ host.insertBefore(properties, host.firstChild);
1677
+ }
1678
+ let margins = first2(properties, marginTag);
1679
+ if (!margins) {
1680
+ margins = makeW(doc, marginTag);
1681
+ properties.appendChild(margins);
1682
+ }
1683
+ for (const side of changed) {
1684
+ const logical = side === "left" ? "start" : side === "right" ? "end" : side;
1685
+ const edge = first2(margins, logical) ?? first2(margins, side) ?? makeW(doc, side);
1686
+ for (const alias of /* @__PURE__ */ new Set([side, logical]))
1687
+ for (const old of children2(margins, alias)) margins.removeChild(old);
1688
+ const value = next?.[side];
1689
+ if (value === void 0) continue;
1690
+ edge.setAttributeNS(WORD_NS, "w:w", String(value));
1691
+ edge.setAttributeNS(WORD_NS, "w:type", "dxa");
1692
+ margins.appendChild(edge);
1693
+ }
1694
+ if (!Array.from(margins.childNodes).some((node) => node.nodeType === 1) && !margins.attributes.length)
1695
+ properties.removeChild(margins);
1696
+ else orderChildren(margins, ORDER);
1697
+ orderChildren(properties, propertiesOrder);
1698
+ if (!Array.from(properties.childNodes).some((node) => node.nodeType === 1) && !properties.attributes.length)
1699
+ host.removeChild(properties);
1700
+ }
1701
+
1662
1702
  // src/docx/write-table-properties.ts
1663
1703
  var ROW_ORDER = [
1664
1704
  "cnfStyle",
@@ -1718,26 +1758,15 @@ function patchRowProperties(doc, tr, next, base) {
1718
1758
  orderChildren(props, ROW_ORDER);
1719
1759
  }
1720
1760
  function patchTableMargins(doc, table, node, base) {
1721
- if (JSON.stringify(table.cellMargins ?? {}) === JSON.stringify(base?.cellMargins ?? {})) return;
1722
- let props = first2(node, "tblPr");
1723
- if (!props) {
1724
- props = makeW(doc, "tblPr");
1725
- node.insertBefore(props, node.firstChild);
1726
- }
1727
- let margins = first2(props, "tblCellMar");
1728
- if (!margins) {
1729
- margins = makeW(doc, "tblCellMar");
1730
- props.appendChild(margins);
1731
- }
1732
- const built = buildMargins(doc, table.cellMargins ?? {}, "tblCellMar");
1733
- for (const side of ["top", "left", "bottom", "right"]) {
1734
- if (table.cellMargins?.[side] === base?.cellMargins?.[side]) continue;
1735
- for (const old of children2(margins, side)) margins.removeChild(old);
1736
- const replacement = first2(built, side);
1737
- if (replacement) margins.appendChild(replacement);
1738
- }
1739
- orderChildren(margins, ["top", "left", "start", "bottom", "right", "end"]);
1740
- orderChildren(props, TABLE_ORDER);
1761
+ patchMarginProperties(
1762
+ doc,
1763
+ node,
1764
+ "tblPr",
1765
+ "tblCellMar",
1766
+ TABLE_ORDER,
1767
+ table.cellMargins,
1768
+ base?.cellMargins
1769
+ );
1741
1770
  }
1742
1771
  var CELL_ORDER = [
1743
1772
  "cnfStyle",
@@ -1761,6 +1790,9 @@ var CELL_ORDER = [
1761
1790
  ];
1762
1791
  var CELL_BORDER_ORDER = ["top", "start", "left", "bottom", "end", "right", "insideH", "insideV"];
1763
1792
  var CELL_SIDES = ["top", "left", "bottom", "right"];
1793
+ function patchCellMargins(doc, tc, next, base) {
1794
+ patchMarginProperties(doc, tc, "tcPr", "tcMar", CELL_ORDER, next, base);
1795
+ }
1764
1796
  function patchCellBorders(doc, tc, next, base) {
1765
1797
  const changed = CELL_SIDES.filter(
1766
1798
  (side) => JSON.stringify(next?.[side]) !== JSON.stringify(base?.[side])
@@ -1848,13 +1880,7 @@ var TABLE_DESCRIPTOR_KEYS = [
1848
1880
  "style",
1849
1881
  "look"
1850
1882
  ];
1851
- var CELL_DESCRIPTOR_KEYS = [
1852
- "gridSpan",
1853
- "verticalMerge",
1854
- "widthTwips",
1855
- "verticalAlign",
1856
- "margins"
1857
- ];
1883
+ var CELL_DESCRIPTOR_KEYS = ["gridSpan", "verticalMerge", "widthTwips", "verticalAlign"];
1858
1884
  function pick(source, keys) {
1859
1885
  const record = source;
1860
1886
  const result = {};
@@ -1880,7 +1906,7 @@ function assertNoDescriptorEdits(table, base) {
1880
1906
  if (!source) continue;
1881
1907
  if (JSON.stringify(pick(cell, CELL_DESCRIPTOR_KEYS)) !== JSON.stringify(pick(source, CELL_DESCRIPTOR_KEYS)))
1882
1908
  throw new Error(
1883
- "Cannot edit table cell width, merge, vertical alignment, or margins on an existing cell; only cell text, borders and shading are supported. The original DOCX package remains unchanged."
1909
+ "Cannot edit table cell width, merge or vertical alignment on an existing cell; only cell text, borders, shading and margins are supported. The original DOCX package remains unchanged."
1884
1910
  );
1885
1911
  }
1886
1912
  }
@@ -1950,6 +1976,7 @@ function writeTable(doc, table, node, base, writeParagraph, replaceSlots2) {
1950
1976
  const tc = source?.cell ?? makeW(doc, "tc");
1951
1977
  patchCellBorders(doc, tc, cell.borders, source?.model.borders);
1952
1978
  patchCellShading(doc, tc, cell, source?.model);
1979
+ patchCellMargins(doc, tc, cell.margins, source?.model.margins);
1953
1980
  const oldParagraphs = children2(tc, "p");
1954
1981
  const nextParagraphs = cell.paragraphs.map((paragraph) => {
1955
1982
  const index = source?.paragraphs.findIndex((p) => p.id === paragraph.id) ?? -1;
@@ -1980,13 +2007,13 @@ function writeTable(doc, table, node, base, writeParagraph, replaceSlots2) {
1980
2007
  }
1981
2008
 
1982
2009
  // src/docx/page-borders.ts
1983
- var SIDES2 = ["top", "left", "bottom", "right"];
2010
+ var SIDES3 = ["top", "left", "bottom", "right"];
1984
2011
  var ATTRIBUTES = ["offsetFrom", "display", "zOrder"];
1985
2012
  var setW4 = (element, name, value) => element.setAttributeNS(WORD_NS, `w:${name}`, value);
1986
2013
  function parsePageBorders(element) {
1987
2014
  if (!element) return void 0;
1988
2015
  const result = {};
1989
- for (const side of SIDES2) {
2016
+ for (const side of SIDES3) {
1990
2017
  const source = first2(element, side);
1991
2018
  const value = borderSide(source);
1992
2019
  const art = getW(source, "art");
@@ -2024,7 +2051,7 @@ function patchPageBorders(doc, sectPr, next, base, create) {
2024
2051
  return;
2025
2052
  }
2026
2053
  const element = create(doc, sectPr, "pgBorders");
2027
- for (const side of SIDES2) {
2054
+ for (const side of SIDES3) {
2028
2055
  if (JSON.stringify(next[side]) === JSON.stringify(base?.[side])) continue;
2029
2056
  for (const old of children2(element, side)) element.removeChild(old);
2030
2057
  const value = next[side];
@@ -2349,7 +2376,7 @@ function applySectionEdits(doc, body, blocks, sections, base, references = /* @_
2349
2376
  }
2350
2377
 
2351
2378
  // src/docx/write-paragraph-decoration.ts
2352
- var SIDES3 = ["top", "left", "bottom", "right", "between"];
2379
+ var SIDES4 = ["top", "left", "bottom", "right", "between"];
2353
2380
  function wordColor(color) {
2354
2381
  const hex = /^#?([0-9a-f]{6})$/i.exec(color ?? "")?.[1];
2355
2382
  return hex ? hex.toUpperCase() : "auto";
@@ -2383,7 +2410,7 @@ function updateBorders(doc, props, paragraph, base) {
2383
2410
  const borders = paragraph.borders;
2384
2411
  if (!borders) return;
2385
2412
  const pBdr = makeW(doc, "pBdr");
2386
- for (const side of SIDES3) {
2413
+ for (const side of SIDES4) {
2387
2414
  const value = borders[side];
2388
2415
  if (value) pBdr.appendChild(borderElement(doc, side, value));
2389
2416
  }
@@ -4670,6 +4697,30 @@ function createRun(doc, run, base, old, allocator) {
4670
4697
  if (!run.text) node.appendChild(makeW(doc, "t"));
4671
4698
  return node;
4672
4699
  }
4700
+ var MATH_NAMESPACES = /* @__PURE__ */ new Set([
4701
+ "http://schemas.openxmlformats.org/officeDocument/2006/math",
4702
+ "http://purl.oclc.org/ooxml/officeDocument/math"
4703
+ ]);
4704
+ function isEquationElement(element) {
4705
+ return MATH_NAMESPACES.has(element.namespaceURI ?? "") && (element.localName === "oMath" || element.localName === "oMathPara");
4706
+ }
4707
+ function parseEquation(element) {
4708
+ if (!isEquationElement(element)) return void 0;
4709
+ return {
4710
+ text: "",
4711
+ equation: {
4712
+ omml: new xmldom.XMLSerializer().serializeToString(element),
4713
+ display: element.localName === "oMathPara"
4714
+ }
4715
+ };
4716
+ }
4717
+ function preserveEquation(run, base, old) {
4718
+ if (!old || !isEquationElement(old) || !base?.equation || run.text !== "" || run.equation?.omml !== base.equation.omml || run.equation?.display !== base.equation.display)
4719
+ throw new Error(
4720
+ "Equation editing or insertion is unsupported; imported OMML must remain unchanged."
4721
+ );
4722
+ return old.cloneNode(true);
4723
+ }
4673
4724
 
4674
4725
  // src/docx/breaks.ts
4675
4726
  function hasSpecialBreak(element) {
@@ -4768,10 +4819,11 @@ function collectParagraphRuns(node, parseRun3, parseOther, resolveLink, active =
4768
4819
  if (!isCommentReferenceRun(item)) push(parseRun3(item));
4769
4820
  } else if (named2(item, "hyperlink")) {
4770
4821
  const link = resolveLink?.(item);
4771
- for (const run of children2(item, "r")) {
4772
- const parsed = parseRun3(run);
4773
- if (link) parsed.link = link;
4774
- push(parsed);
4822
+ for (const child3 of Array.from(item.childNodes).filter(isElement)) {
4823
+ for (const parsed of named2(child3, "r") ? [parseRun3(child3)] : parseOther?.(child3) ?? []) {
4824
+ if (link) parsed.link = link;
4825
+ push(parsed);
4826
+ }
4775
4827
  }
4776
4828
  } else if ((!item.namespaceURI || item.namespaceURI === WORD_NS) && Object.hasOwn(REVISION_WRAPPERS, item.localName)) {
4777
4829
  const kind = expectDefined(
@@ -4782,7 +4834,12 @@ function collectParagraphRuns(node, parseRun3, parseOther, resolveLink, active =
4782
4834
  const revision = revisionFrom(item, kind);
4783
4835
  const range = kind === "moveFrom" || kind === "moveTo" ? moves[kind].at(-1) : void 0;
4784
4836
  if (range) revision.move = { name: range.name, rangeId: range.id };
4785
- for (const run of children2(item, "r")) push(parseRun3(run, revision));
4837
+ for (const child3 of Array.from(item.childNodes).filter(isElement)) {
4838
+ for (const parsed of named2(child3, "r") ? [parseRun3(child3, revision)] : parseOther?.(child3) ?? []) {
4839
+ parsed.revision = revision;
4840
+ push(parsed);
4841
+ }
4842
+ }
4786
4843
  } else if (trackMoveRange(item, moves)) {
4787
4844
  continue;
4788
4845
  } else if (named2(item, "commentRangeStart")) {
@@ -4829,7 +4886,9 @@ function runsOf(parent, container, slots) {
4829
4886
  if (child3.nodeType === 3 && child3.textContent?.trim()) return false;
4830
4887
  continue;
4831
4888
  }
4832
- if (named2(child3, "r")) {
4889
+ if (isEquationElement(child3)) {
4890
+ slots.push({ element: child3, ...container && { container } });
4891
+ } else if (named2(child3, "r")) {
4833
4892
  if (isCommentReferenceRun(child3)) continue;
4834
4893
  if (!runIsSafe(child3)) return false;
4835
4894
  slots.push({ element: child3, ...container && { container } });
@@ -4853,7 +4912,9 @@ function collectInlineSlots(paragraph) {
4853
4912
  if (child3.nodeType === 3 && child3.textContent?.trim()) return void 0;
4854
4913
  continue;
4855
4914
  }
4856
- if (named2(child3, "r")) {
4915
+ if (isEquationElement(child3)) {
4916
+ slots.push({ element: child3 });
4917
+ } else if (named2(child3, "r")) {
4857
4918
  if (isCommentReferenceRun(child3)) continue;
4858
4919
  if (!runIsSafe(child3)) return void 0;
4859
4920
  slots.push({ element: child3 });
@@ -4869,7 +4930,7 @@ function collectInlineSlots(paragraph) {
4869
4930
  }
4870
4931
  function replaceableInlineChildren(paragraph) {
4871
4932
  return Array.from(paragraph.childNodes).filter(
4872
- (child3) => isElement(child3) && (named2(child3, "r") || named2(child3, "hyperlink") || named2(child3, "fldSimple") || isRevisionWrapperElement(child3) || isCommentAnchorElement(child3))
4933
+ (child3) => isElement(child3) && (isEquationElement(child3) || named2(child3, "r") || named2(child3, "hyperlink") || named2(child3, "fldSimple") || isRevisionWrapperElement(child3) || isCommentAnchorElement(child3))
4873
4934
  );
4874
4935
  }
4875
4936
  function sameLink(a, b) {
@@ -4894,7 +4955,7 @@ function newHyperlink(doc, link, allocator) {
4894
4955
  }
4895
4956
  function runNodes(doc, run, base, old, opens, closes, allocator) {
4896
4957
  const nodes = opens.flatMap((edge) => rangeStartNodes(doc, edge));
4897
- const node = createRun(doc, run, base, old, allocator);
4958
+ const node = run.equation ? preserveEquation(run, base, old) : createRun(doc, run, base, old, allocator);
4898
4959
  const revision = run.revision;
4899
4960
  if (revision && ["insert", "delete", "moveFrom", "moveTo"].includes(revision.kind)) {
4900
4961
  if (revision.kind === "delete" || revision.kind === "moveFrom") convertToDeleteText(doc, node);
@@ -4906,15 +4967,23 @@ function runNodes(doc, run, base, old, opens, closes, allocator) {
4906
4967
  function buildInlineContent(doc, runs, base, slots, allocator, ranges) {
4907
4968
  const { opens, closes } = rangeEdges(runs, ranges);
4908
4969
  const runAt = (at) => expectDefined(runs[at], `run ${at}`);
4909
- const nodesFor = (index2) => runNodes(
4910
- doc,
4911
- runAt(index2),
4912
- base?.[index2],
4913
- slots[index2]?.element,
4914
- opens.get(index2) ?? [],
4915
- closes.get(index2) ?? [],
4916
- allocator
4917
- );
4970
+ const nodesFor = (index2) => {
4971
+ const run = runAt(index2);
4972
+ const sourceIndex = run.equation ? base?.findIndex(
4973
+ (source2) => source2.equation?.omml === run.equation?.omml && source2.equation?.display === run.equation?.display
4974
+ ) : index2;
4975
+ const source = sourceIndex === void 0 ? void 0 : base?.[sourceIndex];
4976
+ const old = sourceIndex === void 0 ? void 0 : slots[sourceIndex]?.element;
4977
+ return runNodes(
4978
+ doc,
4979
+ run,
4980
+ !run.equation && source?.equation ? void 0 : source,
4981
+ !run.equation && old && isEquationElement(old) ? void 0 : old,
4982
+ opens.get(index2) ?? [],
4983
+ closes.get(index2) ?? [],
4984
+ allocator
4985
+ );
4986
+ };
4918
4987
  const output = [];
4919
4988
  let index = 0;
4920
4989
  while (index < runs.length) {
@@ -6615,7 +6684,9 @@ function parseMargins(element) {
6615
6684
  ["left", "start"],
6616
6685
  ["right", "end"]
6617
6686
  ]) {
6618
- const value = dxa(getW(first2(element, side) ?? first2(element, logical), "w"));
6687
+ const edge = first2(element, logical) ?? first2(element, side);
6688
+ const type = getW(edge, "type") ?? "dxa";
6689
+ const value = type === "nil" ? parseSignedTwips("0") : type === "dxa" ? parseSignedTwips(getW(edge, "w")) : void 0;
6619
6690
  if (value !== void 0) parsed[side] = value;
6620
6691
  }
6621
6692
  return Object.keys(parsed).length ? parsed : void 0;
@@ -6820,13 +6891,19 @@ function parseParagraph2(node, id) {
6820
6891
  node,
6821
6892
  (element, revision) => trackField(element, parseRun2(element, revision)),
6822
6893
  (item) => {
6894
+ const equation = parseEquation(item);
6895
+ if (equation) return [equation];
6823
6896
  if (!named2(item, "fldSimple")) return void 0;
6824
6897
  const instr = getW(item, "instr") ?? "";
6825
6898
  const link = parseSimpleHyperlinkField(instr);
6826
- const results = children2(item, "r").map((run) => parseRun2(run));
6899
+ const results = Array.from(item.childNodes).filter(isElement).flatMap((child3) => {
6900
+ const equation2 = parseEquation(child3);
6901
+ return equation2 ? [equation2] : named2(child3, "r") ? [parseRun2(child3)] : [];
6902
+ });
6827
6903
  if (link) return results.map((run) => ({ ...run, link }));
6828
6904
  const field = { instr: instr.trim(), simple: true };
6829
- if (!results.some((run) => run.text)) return [{ text: fieldPlaceholderText(instr), field }];
6905
+ if (!results.some((run) => run.text || run.equation))
6906
+ return [{ text: fieldPlaceholderText(instr), field }];
6830
6907
  return results.map((run) => ({ ...run, field }));
6831
6908
  },
6832
6909
  (hyperlink) => {
@@ -1653,6 +1653,46 @@ function orderSectionProperties(sectPr) {
1653
1653
  orderChildren(sectPr, SECTPR_ORDER);
1654
1654
  }
1655
1655
 
1656
+ // src/docx/write-table-margins.ts
1657
+ var SIDES2 = ["top", "left", "bottom", "right"];
1658
+ var ORDER = ["top", "start", "left", "bottom", "end", "right"];
1659
+ function patchMarginProperties(doc, host, propertiesTag, marginTag, propertiesOrder, next, base) {
1660
+ const changed = SIDES2.filter((side) => next?.[side] !== base?.[side]);
1661
+ if (!changed.length) return;
1662
+ for (const side of changed) {
1663
+ const value = next?.[side];
1664
+ if (value !== void 0 && (!Number.isSafeInteger(value) || value < 0))
1665
+ throw new Error("Table cell margins must be nonnegative whole twips.");
1666
+ }
1667
+ let properties = first2(host, propertiesTag);
1668
+ if (!properties) {
1669
+ properties = makeW(doc, propertiesTag);
1670
+ host.insertBefore(properties, host.firstChild);
1671
+ }
1672
+ let margins = first2(properties, marginTag);
1673
+ if (!margins) {
1674
+ margins = makeW(doc, marginTag);
1675
+ properties.appendChild(margins);
1676
+ }
1677
+ for (const side of changed) {
1678
+ const logical = side === "left" ? "start" : side === "right" ? "end" : side;
1679
+ const edge = first2(margins, logical) ?? first2(margins, side) ?? makeW(doc, side);
1680
+ for (const alias of /* @__PURE__ */ new Set([side, logical]))
1681
+ for (const old of children2(margins, alias)) margins.removeChild(old);
1682
+ const value = next?.[side];
1683
+ if (value === void 0) continue;
1684
+ edge.setAttributeNS(WORD_NS, "w:w", String(value));
1685
+ edge.setAttributeNS(WORD_NS, "w:type", "dxa");
1686
+ margins.appendChild(edge);
1687
+ }
1688
+ if (!Array.from(margins.childNodes).some((node) => node.nodeType === 1) && !margins.attributes.length)
1689
+ properties.removeChild(margins);
1690
+ else orderChildren(margins, ORDER);
1691
+ orderChildren(properties, propertiesOrder);
1692
+ if (!Array.from(properties.childNodes).some((node) => node.nodeType === 1) && !properties.attributes.length)
1693
+ host.removeChild(properties);
1694
+ }
1695
+
1656
1696
  // src/docx/write-table-properties.ts
1657
1697
  var ROW_ORDER = [
1658
1698
  "cnfStyle",
@@ -1712,26 +1752,15 @@ function patchRowProperties(doc, tr, next, base) {
1712
1752
  orderChildren(props, ROW_ORDER);
1713
1753
  }
1714
1754
  function patchTableMargins(doc, table, node, base) {
1715
- if (JSON.stringify(table.cellMargins ?? {}) === JSON.stringify(base?.cellMargins ?? {})) return;
1716
- let props = first2(node, "tblPr");
1717
- if (!props) {
1718
- props = makeW(doc, "tblPr");
1719
- node.insertBefore(props, node.firstChild);
1720
- }
1721
- let margins = first2(props, "tblCellMar");
1722
- if (!margins) {
1723
- margins = makeW(doc, "tblCellMar");
1724
- props.appendChild(margins);
1725
- }
1726
- const built = buildMargins(doc, table.cellMargins ?? {}, "tblCellMar");
1727
- for (const side of ["top", "left", "bottom", "right"]) {
1728
- if (table.cellMargins?.[side] === base?.cellMargins?.[side]) continue;
1729
- for (const old of children2(margins, side)) margins.removeChild(old);
1730
- const replacement = first2(built, side);
1731
- if (replacement) margins.appendChild(replacement);
1732
- }
1733
- orderChildren(margins, ["top", "left", "start", "bottom", "right", "end"]);
1734
- orderChildren(props, TABLE_ORDER);
1755
+ patchMarginProperties(
1756
+ doc,
1757
+ node,
1758
+ "tblPr",
1759
+ "tblCellMar",
1760
+ TABLE_ORDER,
1761
+ table.cellMargins,
1762
+ base?.cellMargins
1763
+ );
1735
1764
  }
1736
1765
  var CELL_ORDER = [
1737
1766
  "cnfStyle",
@@ -1755,6 +1784,9 @@ var CELL_ORDER = [
1755
1784
  ];
1756
1785
  var CELL_BORDER_ORDER = ["top", "start", "left", "bottom", "end", "right", "insideH", "insideV"];
1757
1786
  var CELL_SIDES = ["top", "left", "bottom", "right"];
1787
+ function patchCellMargins(doc, tc, next, base) {
1788
+ patchMarginProperties(doc, tc, "tcPr", "tcMar", CELL_ORDER, next, base);
1789
+ }
1758
1790
  function patchCellBorders(doc, tc, next, base) {
1759
1791
  const changed = CELL_SIDES.filter(
1760
1792
  (side) => JSON.stringify(next?.[side]) !== JSON.stringify(base?.[side])
@@ -1842,13 +1874,7 @@ var TABLE_DESCRIPTOR_KEYS = [
1842
1874
  "style",
1843
1875
  "look"
1844
1876
  ];
1845
- var CELL_DESCRIPTOR_KEYS = [
1846
- "gridSpan",
1847
- "verticalMerge",
1848
- "widthTwips",
1849
- "verticalAlign",
1850
- "margins"
1851
- ];
1877
+ var CELL_DESCRIPTOR_KEYS = ["gridSpan", "verticalMerge", "widthTwips", "verticalAlign"];
1852
1878
  function pick(source, keys) {
1853
1879
  const record = source;
1854
1880
  const result = {};
@@ -1874,7 +1900,7 @@ function assertNoDescriptorEdits(table, base) {
1874
1900
  if (!source) continue;
1875
1901
  if (JSON.stringify(pick(cell, CELL_DESCRIPTOR_KEYS)) !== JSON.stringify(pick(source, CELL_DESCRIPTOR_KEYS)))
1876
1902
  throw new Error(
1877
- "Cannot edit table cell width, merge, vertical alignment, or margins on an existing cell; only cell text, borders and shading are supported. The original DOCX package remains unchanged."
1903
+ "Cannot edit table cell width, merge or vertical alignment on an existing cell; only cell text, borders, shading and margins are supported. The original DOCX package remains unchanged."
1878
1904
  );
1879
1905
  }
1880
1906
  }
@@ -1944,6 +1970,7 @@ function writeTable(doc, table, node, base, writeParagraph, replaceSlots2) {
1944
1970
  const tc = source?.cell ?? makeW(doc, "tc");
1945
1971
  patchCellBorders(doc, tc, cell.borders, source?.model.borders);
1946
1972
  patchCellShading(doc, tc, cell, source?.model);
1973
+ patchCellMargins(doc, tc, cell.margins, source?.model.margins);
1947
1974
  const oldParagraphs = children2(tc, "p");
1948
1975
  const nextParagraphs = cell.paragraphs.map((paragraph) => {
1949
1976
  const index = source?.paragraphs.findIndex((p) => p.id === paragraph.id) ?? -1;
@@ -1974,13 +2001,13 @@ function writeTable(doc, table, node, base, writeParagraph, replaceSlots2) {
1974
2001
  }
1975
2002
 
1976
2003
  // src/docx/page-borders.ts
1977
- var SIDES2 = ["top", "left", "bottom", "right"];
2004
+ var SIDES3 = ["top", "left", "bottom", "right"];
1978
2005
  var ATTRIBUTES = ["offsetFrom", "display", "zOrder"];
1979
2006
  var setW4 = (element, name, value) => element.setAttributeNS(WORD_NS, `w:${name}`, value);
1980
2007
  function parsePageBorders(element) {
1981
2008
  if (!element) return void 0;
1982
2009
  const result = {};
1983
- for (const side of SIDES2) {
2010
+ for (const side of SIDES3) {
1984
2011
  const source = first2(element, side);
1985
2012
  const value = borderSide(source);
1986
2013
  const art = getW(source, "art");
@@ -2018,7 +2045,7 @@ function patchPageBorders(doc, sectPr, next, base, create) {
2018
2045
  return;
2019
2046
  }
2020
2047
  const element = create(doc, sectPr, "pgBorders");
2021
- for (const side of SIDES2) {
2048
+ for (const side of SIDES3) {
2022
2049
  if (JSON.stringify(next[side]) === JSON.stringify(base?.[side])) continue;
2023
2050
  for (const old of children2(element, side)) element.removeChild(old);
2024
2051
  const value = next[side];
@@ -2343,7 +2370,7 @@ function applySectionEdits(doc, body, blocks, sections, base, references = /* @_
2343
2370
  }
2344
2371
 
2345
2372
  // src/docx/write-paragraph-decoration.ts
2346
- var SIDES3 = ["top", "left", "bottom", "right", "between"];
2373
+ var SIDES4 = ["top", "left", "bottom", "right", "between"];
2347
2374
  function wordColor(color) {
2348
2375
  const hex = /^#?([0-9a-f]{6})$/i.exec(color ?? "")?.[1];
2349
2376
  return hex ? hex.toUpperCase() : "auto";
@@ -2377,7 +2404,7 @@ function updateBorders(doc, props, paragraph, base) {
2377
2404
  const borders = paragraph.borders;
2378
2405
  if (!borders) return;
2379
2406
  const pBdr = makeW(doc, "pBdr");
2380
- for (const side of SIDES3) {
2407
+ for (const side of SIDES4) {
2381
2408
  const value = borders[side];
2382
2409
  if (value) pBdr.appendChild(borderElement(doc, side, value));
2383
2410
  }
@@ -4664,6 +4691,30 @@ function createRun(doc, run, base, old, allocator) {
4664
4691
  if (!run.text) node.appendChild(makeW(doc, "t"));
4665
4692
  return node;
4666
4693
  }
4694
+ var MATH_NAMESPACES = /* @__PURE__ */ new Set([
4695
+ "http://schemas.openxmlformats.org/officeDocument/2006/math",
4696
+ "http://purl.oclc.org/ooxml/officeDocument/math"
4697
+ ]);
4698
+ function isEquationElement(element) {
4699
+ return MATH_NAMESPACES.has(element.namespaceURI ?? "") && (element.localName === "oMath" || element.localName === "oMathPara");
4700
+ }
4701
+ function parseEquation(element) {
4702
+ if (!isEquationElement(element)) return void 0;
4703
+ return {
4704
+ text: "",
4705
+ equation: {
4706
+ omml: new XMLSerializer().serializeToString(element),
4707
+ display: element.localName === "oMathPara"
4708
+ }
4709
+ };
4710
+ }
4711
+ function preserveEquation(run, base, old) {
4712
+ if (!old || !isEquationElement(old) || !base?.equation || run.text !== "" || run.equation?.omml !== base.equation.omml || run.equation?.display !== base.equation.display)
4713
+ throw new Error(
4714
+ "Equation editing or insertion is unsupported; imported OMML must remain unchanged."
4715
+ );
4716
+ return old.cloneNode(true);
4717
+ }
4667
4718
 
4668
4719
  // src/docx/breaks.ts
4669
4720
  function hasSpecialBreak(element) {
@@ -4762,10 +4813,11 @@ function collectParagraphRuns(node, parseRun3, parseOther, resolveLink, active =
4762
4813
  if (!isCommentReferenceRun(item)) push(parseRun3(item));
4763
4814
  } else if (named2(item, "hyperlink")) {
4764
4815
  const link = resolveLink?.(item);
4765
- for (const run of children2(item, "r")) {
4766
- const parsed = parseRun3(run);
4767
- if (link) parsed.link = link;
4768
- push(parsed);
4816
+ for (const child3 of Array.from(item.childNodes).filter(isElement)) {
4817
+ for (const parsed of named2(child3, "r") ? [parseRun3(child3)] : parseOther?.(child3) ?? []) {
4818
+ if (link) parsed.link = link;
4819
+ push(parsed);
4820
+ }
4769
4821
  }
4770
4822
  } else if ((!item.namespaceURI || item.namespaceURI === WORD_NS) && Object.hasOwn(REVISION_WRAPPERS, item.localName)) {
4771
4823
  const kind = expectDefined(
@@ -4776,7 +4828,12 @@ function collectParagraphRuns(node, parseRun3, parseOther, resolveLink, active =
4776
4828
  const revision = revisionFrom(item, kind);
4777
4829
  const range = kind === "moveFrom" || kind === "moveTo" ? moves[kind].at(-1) : void 0;
4778
4830
  if (range) revision.move = { name: range.name, rangeId: range.id };
4779
- for (const run of children2(item, "r")) push(parseRun3(run, revision));
4831
+ for (const child3 of Array.from(item.childNodes).filter(isElement)) {
4832
+ for (const parsed of named2(child3, "r") ? [parseRun3(child3, revision)] : parseOther?.(child3) ?? []) {
4833
+ parsed.revision = revision;
4834
+ push(parsed);
4835
+ }
4836
+ }
4780
4837
  } else if (trackMoveRange(item, moves)) {
4781
4838
  continue;
4782
4839
  } else if (named2(item, "commentRangeStart")) {
@@ -4823,7 +4880,9 @@ function runsOf(parent, container, slots) {
4823
4880
  if (child3.nodeType === 3 && child3.textContent?.trim()) return false;
4824
4881
  continue;
4825
4882
  }
4826
- if (named2(child3, "r")) {
4883
+ if (isEquationElement(child3)) {
4884
+ slots.push({ element: child3, ...container && { container } });
4885
+ } else if (named2(child3, "r")) {
4827
4886
  if (isCommentReferenceRun(child3)) continue;
4828
4887
  if (!runIsSafe(child3)) return false;
4829
4888
  slots.push({ element: child3, ...container && { container } });
@@ -4847,7 +4906,9 @@ function collectInlineSlots(paragraph) {
4847
4906
  if (child3.nodeType === 3 && child3.textContent?.trim()) return void 0;
4848
4907
  continue;
4849
4908
  }
4850
- if (named2(child3, "r")) {
4909
+ if (isEquationElement(child3)) {
4910
+ slots.push({ element: child3 });
4911
+ } else if (named2(child3, "r")) {
4851
4912
  if (isCommentReferenceRun(child3)) continue;
4852
4913
  if (!runIsSafe(child3)) return void 0;
4853
4914
  slots.push({ element: child3 });
@@ -4863,7 +4924,7 @@ function collectInlineSlots(paragraph) {
4863
4924
  }
4864
4925
  function replaceableInlineChildren(paragraph) {
4865
4926
  return Array.from(paragraph.childNodes).filter(
4866
- (child3) => isElement(child3) && (named2(child3, "r") || named2(child3, "hyperlink") || named2(child3, "fldSimple") || isRevisionWrapperElement(child3) || isCommentAnchorElement(child3))
4927
+ (child3) => isElement(child3) && (isEquationElement(child3) || named2(child3, "r") || named2(child3, "hyperlink") || named2(child3, "fldSimple") || isRevisionWrapperElement(child3) || isCommentAnchorElement(child3))
4867
4928
  );
4868
4929
  }
4869
4930
  function sameLink(a, b) {
@@ -4888,7 +4949,7 @@ function newHyperlink(doc, link, allocator) {
4888
4949
  }
4889
4950
  function runNodes(doc, run, base, old, opens, closes, allocator) {
4890
4951
  const nodes = opens.flatMap((edge) => rangeStartNodes(doc, edge));
4891
- const node = createRun(doc, run, base, old, allocator);
4952
+ const node = run.equation ? preserveEquation(run, base, old) : createRun(doc, run, base, old, allocator);
4892
4953
  const revision = run.revision;
4893
4954
  if (revision && ["insert", "delete", "moveFrom", "moveTo"].includes(revision.kind)) {
4894
4955
  if (revision.kind === "delete" || revision.kind === "moveFrom") convertToDeleteText(doc, node);
@@ -4900,15 +4961,23 @@ function runNodes(doc, run, base, old, opens, closes, allocator) {
4900
4961
  function buildInlineContent(doc, runs, base, slots, allocator, ranges) {
4901
4962
  const { opens, closes } = rangeEdges(runs, ranges);
4902
4963
  const runAt = (at) => expectDefined(runs[at], `run ${at}`);
4903
- const nodesFor = (index2) => runNodes(
4904
- doc,
4905
- runAt(index2),
4906
- base?.[index2],
4907
- slots[index2]?.element,
4908
- opens.get(index2) ?? [],
4909
- closes.get(index2) ?? [],
4910
- allocator
4911
- );
4964
+ const nodesFor = (index2) => {
4965
+ const run = runAt(index2);
4966
+ const sourceIndex = run.equation ? base?.findIndex(
4967
+ (source2) => source2.equation?.omml === run.equation?.omml && source2.equation?.display === run.equation?.display
4968
+ ) : index2;
4969
+ const source = sourceIndex === void 0 ? void 0 : base?.[sourceIndex];
4970
+ const old = sourceIndex === void 0 ? void 0 : slots[sourceIndex]?.element;
4971
+ return runNodes(
4972
+ doc,
4973
+ run,
4974
+ !run.equation && source?.equation ? void 0 : source,
4975
+ !run.equation && old && isEquationElement(old) ? void 0 : old,
4976
+ opens.get(index2) ?? [],
4977
+ closes.get(index2) ?? [],
4978
+ allocator
4979
+ );
4980
+ };
4912
4981
  const output = [];
4913
4982
  let index = 0;
4914
4983
  while (index < runs.length) {
@@ -6609,7 +6678,9 @@ function parseMargins(element) {
6609
6678
  ["left", "start"],
6610
6679
  ["right", "end"]
6611
6680
  ]) {
6612
- const value = dxa(getW(first2(element, side) ?? first2(element, logical), "w"));
6681
+ const edge = first2(element, logical) ?? first2(element, side);
6682
+ const type = getW(edge, "type") ?? "dxa";
6683
+ const value = type === "nil" ? parseSignedTwips("0") : type === "dxa" ? parseSignedTwips(getW(edge, "w")) : void 0;
6613
6684
  if (value !== void 0) parsed[side] = value;
6614
6685
  }
6615
6686
  return Object.keys(parsed).length ? parsed : void 0;
@@ -6814,13 +6885,19 @@ function parseParagraph2(node, id) {
6814
6885
  node,
6815
6886
  (element, revision) => trackField(element, parseRun2(element, revision)),
6816
6887
  (item) => {
6888
+ const equation = parseEquation(item);
6889
+ if (equation) return [equation];
6817
6890
  if (!named2(item, "fldSimple")) return void 0;
6818
6891
  const instr = getW(item, "instr") ?? "";
6819
6892
  const link = parseSimpleHyperlinkField(instr);
6820
- const results = children2(item, "r").map((run) => parseRun2(run));
6893
+ const results = Array.from(item.childNodes).filter(isElement).flatMap((child3) => {
6894
+ const equation2 = parseEquation(child3);
6895
+ return equation2 ? [equation2] : named2(child3, "r") ? [parseRun2(child3)] : [];
6896
+ });
6821
6897
  if (link) return results.map((run) => ({ ...run, link }));
6822
6898
  const field = { instr: instr.trim(), simple: true };
6823
- if (!results.some((run) => run.text)) return [{ text: fieldPlaceholderText(instr), field }];
6899
+ if (!results.some((run) => run.text || run.equation))
6900
+ return [{ text: fieldPlaceholderText(instr), field }];
6824
6901
  return results.map((run) => ({ ...run, field }));
6825
6902
  },
6826
6903
  (hyperlink) => {
@@ -0,0 +1,8 @@
1
+ import type { TextRun } from './model.js';
2
+ import type { XmlElement } from './xml.js';
3
+ export declare function isEquationElement(element: XmlElement): boolean;
4
+ /** Serializing the subtree supplies inherited namespaces, so consumers can parse it independently. */
5
+ export declare function parseEquation(element: XmlElement): TextRun | undefined;
6
+ /** Equation source may be relocated within its paragraph, but cannot be created or changed. */
7
+ export declare function preserveEquation(run: TextRun, base: TextRun | undefined, old: XmlElement | undefined): XmlElement;
8
+ //# sourceMappingURL=equation.d.ts.map