odf.js 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1243,6 +1243,17 @@ function childrenWithTag(element, tag) {
1243
1243
  for (const child of element.children) if (child.type === "element" && child.tag === tag) out.push(child);
1244
1244
  return out;
1245
1245
  }
1246
+ function* walk(nodes) {
1247
+ for (const node of nodes) {
1248
+ yield node;
1249
+ if (node.type === "element") yield* walk(node.children);
1250
+ }
1251
+ }
1252
+ function elementsWithTag(nodes, tag) {
1253
+ const out = [];
1254
+ for (const node of walk(nodes)) if (node.type === "element" && node.tag === tag) out.push(node);
1255
+ return out;
1256
+ }
1246
1257
  function attrValue(element, name) {
1247
1258
  return element.attributes.find((attribute) => attribute.name === name)?.value;
1248
1259
  }
@@ -1522,13 +1533,14 @@ function collectStyles(pkg) {
1522
1533
  defaultByFamily
1523
1534
  };
1524
1535
  }
1525
- function resolveStyle(styleName, family, pkg) {
1536
+ function resolveStyleElementChain(styleName, family, pkg) {
1526
1537
  const { byName, defaultByFamily } = collectStyles(pkg);
1527
1538
  const diagnostics = [];
1539
+ const elements = [];
1528
1540
  const defaultElement = defaultByFamily.get(family);
1529
- let properties = defaultElement === void 0 ? {} : parseStyleElementProperties(defaultElement).properties;
1541
+ if (defaultElement !== void 0) elements.push(defaultElement);
1530
1542
  if (styleName === void 0) return {
1531
- properties,
1543
+ elements,
1532
1544
  diagnostics
1533
1545
  };
1534
1546
  const chain = [];
@@ -1556,7 +1568,16 @@ function resolveStyle(styleName, family, pkg) {
1556
1568
  currentName = attrValue(element, "style:parent-style-name");
1557
1569
  }
1558
1570
  chain.reverse();
1559
- for (const element of chain) properties = {
1571
+ elements.push(...chain);
1572
+ return {
1573
+ elements,
1574
+ diagnostics
1575
+ };
1576
+ }
1577
+ function resolveStyle(styleName, family, pkg) {
1578
+ const { elements, diagnostics } = resolveStyleElementChain(styleName, family, pkg);
1579
+ let properties = {};
1580
+ for (const element of elements) properties = {
1560
1581
  ...properties,
1561
1582
  ...parseStyleElementProperties(element).properties
1562
1583
  };
@@ -1565,6 +1586,10 @@ function resolveStyle(styleName, family, pkg) {
1565
1586
  diagnostics
1566
1587
  };
1567
1588
  }
1589
+ function findStyleElement(styleName, family, pkg) {
1590
+ const { byName } = collectStyles(pkg);
1591
+ return byName.get(nameKey(family, styleName));
1592
+ }
1568
1593
  //#endregion
1569
1594
  //#region src/typed/shared/metadata.ts
1570
1595
  const META_PART = "meta.xml";
@@ -1603,6 +1628,376 @@ function readOdfMetadata(pkg) {
1603
1628
  return metadata;
1604
1629
  }
1605
1630
  //#endregion
1631
+ //#region src/typed/shared/paragraph.ts
1632
+ function collectRuns(nodes, baseProperties, pkg, out) {
1633
+ for (const node of nodes) {
1634
+ if (node.type === "text") {
1635
+ if (node.value.length > 0) out.push(runFromText(decodeXmlText(node.value), baseProperties));
1636
+ continue;
1637
+ }
1638
+ if (node.type !== "element") continue;
1639
+ if (node.tag === "text:s") out.push(runFromText(" ".repeat(getOdfSpaceCount(node)), baseProperties));
1640
+ else if (node.tag === "text:tab") out.push(runFromText(" ", baseProperties));
1641
+ else if (node.tag === "text:line-break") out.push(runFromText("\n", baseProperties));
1642
+ else if (node.tag === "text:span") {
1643
+ const styleName = attrValue(node, "text:style-name");
1644
+ const spanProperties = {
1645
+ ...baseProperties,
1646
+ ...resolveStyle(styleName, "text", pkg).properties
1647
+ };
1648
+ collectRuns(node.children, spanProperties, pkg, out);
1649
+ }
1650
+ }
1651
+ }
1652
+ function runFromText(text, properties) {
1653
+ return {
1654
+ text,
1655
+ bold: properties.bold,
1656
+ italic: properties.italic,
1657
+ underline: properties.underline,
1658
+ strike: properties.strike,
1659
+ fontFamily: properties.fontFamily,
1660
+ sizePt: properties.sizePt,
1661
+ color: properties.color
1662
+ };
1663
+ }
1664
+ function readOdfParagraph(pElement, pkg) {
1665
+ const styleName = attrValue(pElement, "text:style-name");
1666
+ const paragraphProperties = resolveStyle(styleName, "paragraph", pkg).properties;
1667
+ const runs = [];
1668
+ collectRuns(pElement.children, paragraphProperties, pkg, runs);
1669
+ return {
1670
+ kind: "paragraph",
1671
+ runs,
1672
+ styleId: styleName,
1673
+ alignment: paragraphProperties.alignment,
1674
+ spacingBeforePt: paragraphProperties.spacingBeforePt,
1675
+ spacingAfterPt: paragraphProperties.spacingAfterPt,
1676
+ lineSpacing: paragraphProperties.lineSpacing,
1677
+ indentLeftPt: paragraphProperties.indentLeftPt,
1678
+ indentFirstLinePt: paragraphProperties.indentFirstLinePt
1679
+ };
1680
+ }
1681
+ //#endregion
1682
+ //#region src/typed/shared/table.ts
1683
+ function readRepeatCount(element, attrName) {
1684
+ const raw = attrValue(element, attrName);
1685
+ if (raw === void 0) return 1;
1686
+ const parsed = Number.parseInt(raw, 10);
1687
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
1688
+ }
1689
+ function resolveColumnWidthPt(columnElement, pkg) {
1690
+ const styleName = attrValue(columnElement, "table:style-name");
1691
+ const styleElement = styleName === void 0 ? void 0 : findStyleElement(styleName, "table-column", pkg);
1692
+ const props = styleElement === void 0 ? void 0 : childrenWithTag(styleElement, "style:table-column-properties")[0];
1693
+ const widthValue = props === void 0 ? void 0 : attrValue(props, "style:column-width");
1694
+ return widthValue === void 0 ? 0 : parseOdfLength(widthValue) ?? 0;
1695
+ }
1696
+ function resolveRowHeightPt(rowElement, pkg) {
1697
+ const styleName = attrValue(rowElement, "table:style-name");
1698
+ const styleElement = styleName === void 0 ? void 0 : findStyleElement(styleName, "table-row", pkg);
1699
+ const props = styleElement === void 0 ? void 0 : childrenWithTag(styleElement, "style:table-row-properties")[0];
1700
+ const heightValue = props === void 0 ? void 0 : attrValue(props, "style:row-height");
1701
+ return heightValue === void 0 ? void 0 : parseOdfLength(heightValue);
1702
+ }
1703
+ function readTableCellBackground(cellElement, pkg) {
1704
+ const styleName = attrValue(cellElement, "table:style-name");
1705
+ const styleElement = styleName === void 0 ? void 0 : findStyleElement(styleName, "table-cell", pkg);
1706
+ const props = styleElement === void 0 ? void 0 : childrenWithTag(styleElement, "style:table-cell-properties")[0];
1707
+ const value = props === void 0 ? void 0 : attrValue(props, "fo:background-color");
1708
+ return value === void 0 ? void 0 : parseOdfColor(value);
1709
+ }
1710
+ function readTableCell(cellElement, pkg) {
1711
+ const blocks = childrenWithTag(cellElement, "text:p").map((p) => readOdfParagraph(p, pkg));
1712
+ const colSpanRaw = attrValue(cellElement, "table:number-columns-spanned");
1713
+ const rowSpanRaw = attrValue(cellElement, "table:number-rows-spanned");
1714
+ return {
1715
+ blocks,
1716
+ colSpan: colSpanRaw === void 0 ? void 0 : Number.parseInt(colSpanRaw, 10),
1717
+ rowSpan: rowSpanRaw === void 0 ? void 0 : Number.parseInt(rowSpanRaw, 10),
1718
+ background: readTableCellBackground(cellElement, pkg)
1719
+ };
1720
+ }
1721
+ function readTableRow(rowElement, pkg) {
1722
+ const cells = [];
1723
+ for (const child of rowElement.children) {
1724
+ if (child.type !== "element") continue;
1725
+ if (child.tag === "table:covered-table-cell") {
1726
+ const repeat = readRepeatCount(child, "table:number-columns-repeated");
1727
+ for (let i = 0; i < repeat; i++) cells.push({ blocks: [] });
1728
+ } else if (child.tag === "table:table-cell") {
1729
+ const cell = readTableCell(child, pkg);
1730
+ const repeat = readRepeatCount(child, "table:number-columns-repeated");
1731
+ for (let i = 0; i < repeat; i++) cells.push(cell);
1732
+ }
1733
+ }
1734
+ return {
1735
+ cells,
1736
+ heightPt: resolveRowHeightPt(rowElement, pkg)
1737
+ };
1738
+ }
1739
+ function readOdfTable(tableElement, pkg) {
1740
+ const columnWidthsPt = [];
1741
+ for (const column of childrenWithTag(tableElement, "table:table-column")) {
1742
+ const widthPt = resolveColumnWidthPt(column, pkg);
1743
+ const repeat = readRepeatCount(column, "table:number-columns-repeated");
1744
+ for (let i = 0; i < repeat; i++) columnWidthsPt.push(widthPt);
1745
+ }
1746
+ const rows = [];
1747
+ for (const rowElement of childrenWithTag(tableElement, "table:table-row")) {
1748
+ const row = readTableRow(rowElement, pkg);
1749
+ const repeat = readRepeatCount(rowElement, "table:number-rows-repeated");
1750
+ for (let i = 0; i < repeat; i++) rows.push(row);
1751
+ }
1752
+ return {
1753
+ kind: "table",
1754
+ rows,
1755
+ columnWidthsPt
1756
+ };
1757
+ }
1758
+ //#endregion
1759
+ //#region src/typed/shared/transform.ts
1760
+ const FUNCTION_PATTERN = /([a-zA-Z]+)\s*\(\s*([^)]*?)\s*\)/g;
1761
+ function parseOdfTransform(value) {
1762
+ const functions = [];
1763
+ for (const match of value.matchAll(FUNCTION_PATTERN)) {
1764
+ const name = match[1];
1765
+ const argsRaw = match[2];
1766
+ if (name === void 0 || argsRaw === void 0) continue;
1767
+ const args = argsRaw.split(/\s+/).filter((arg) => arg.length > 0);
1768
+ if (name === "rotate") {
1769
+ const angleArg = args[0];
1770
+ if (angleArg === void 0) continue;
1771
+ const angleRad = Number(angleArg);
1772
+ if (!Number.isFinite(angleRad)) continue;
1773
+ functions.push({
1774
+ kind: "rotate",
1775
+ angleRad
1776
+ });
1777
+ } else if (name === "translate") {
1778
+ const xArg = args[0];
1779
+ if (xArg === void 0) continue;
1780
+ const yArg = args[1];
1781
+ const xPt = parseOdfLength(xArg);
1782
+ const yPt = yArg === void 0 ? 0 : parseOdfLength(yArg);
1783
+ if (xPt === void 0 || yPt === void 0) continue;
1784
+ functions.push({
1785
+ kind: "translate",
1786
+ xPt,
1787
+ yPt
1788
+ });
1789
+ }
1790
+ }
1791
+ return functions;
1792
+ }
1793
+ function applyOdfTransform(functions, point) {
1794
+ let current = point;
1795
+ for (const fn of functions) if (fn.kind === "rotate") {
1796
+ const cos = Math.cos(fn.angleRad);
1797
+ const sin = Math.sin(fn.angleRad);
1798
+ current = {
1799
+ xPt: current.xPt * cos + current.yPt * sin,
1800
+ yPt: current.yPt * cos - current.xPt * sin
1801
+ };
1802
+ } else current = {
1803
+ xPt: current.xPt + fn.xPt,
1804
+ yPt: current.yPt + fn.yPt
1805
+ };
1806
+ return current;
1807
+ }
1808
+ function netRotationDeg(functions) {
1809
+ let totalRad = 0;
1810
+ for (const fn of functions) if (fn.kind === "rotate") totalRad += fn.angleRad;
1811
+ return -totalRad * 180 / Math.PI;
1812
+ }
1813
+ function resolveOdfShapeGeometry(element) {
1814
+ const transformValue = attrValue(element, "draw:transform");
1815
+ if (transformValue === void 0) {
1816
+ const box = parseBox(element);
1817
+ return box === void 0 ? void 0 : {
1818
+ frame: box,
1819
+ rotationDeg: void 0
1820
+ };
1821
+ }
1822
+ const widthValue = attrValue(element, "svg:width");
1823
+ const heightValue = attrValue(element, "svg:height");
1824
+ if (widthValue === void 0 || heightValue === void 0) return;
1825
+ const widthPt = parseOdfLength(widthValue);
1826
+ const heightPt = parseOdfLength(heightValue);
1827
+ if (widthPt === void 0 || heightPt === void 0) return;
1828
+ const functions = parseOdfTransform(transformValue);
1829
+ const center = applyOdfTransform(functions, {
1830
+ xPt: widthPt / 2,
1831
+ yPt: heightPt / 2
1832
+ });
1833
+ const rotationDeg = netRotationDeg(functions);
1834
+ return {
1835
+ frame: {
1836
+ xPt: center.xPt - widthPt / 2,
1837
+ yPt: center.yPt - heightPt / 2,
1838
+ widthPt,
1839
+ heightPt
1840
+ },
1841
+ rotationDeg: rotationDeg === 0 ? void 0 : rotationDeg
1842
+ };
1843
+ }
1844
+ function composeOdfGroupTransform(groupFunctions, child) {
1845
+ if (groupFunctions.length === 0) return child;
1846
+ const newCenter = applyOdfTransform(groupFunctions, {
1847
+ xPt: child.frame.xPt + child.frame.widthPt / 2,
1848
+ yPt: child.frame.yPt + child.frame.heightPt / 2
1849
+ });
1850
+ const newRotationDeg = (child.rotationDeg ?? 0) + netRotationDeg(groupFunctions);
1851
+ return {
1852
+ frame: {
1853
+ xPt: newCenter.xPt - child.frame.widthPt / 2,
1854
+ yPt: newCenter.yPt - child.frame.heightPt / 2,
1855
+ widthPt: child.frame.widthPt,
1856
+ heightPt: child.frame.heightPt
1857
+ },
1858
+ rotationDeg: newRotationDeg === 0 ? void 0 : newRotationDeg
1859
+ };
1860
+ }
1861
+ //#endregion
1862
+ //#region src/typed/draw/shapes.ts
1863
+ const ZERO_INSETS = {
1864
+ insetLeftPt: 0,
1865
+ insetTopPt: 0,
1866
+ insetRightPt: 0,
1867
+ insetBottomPt: 0
1868
+ };
1869
+ function readPaddingPt(props, attrName) {
1870
+ const value = attrValue(props, attrName);
1871
+ return value === void 0 ? void 0 : parseOdfLength(value);
1872
+ }
1873
+ function readFrameInsets(frame, pkg) {
1874
+ const { elements } = resolveStyleElementChain(attrValue(frame, "draw:style-name"), "graphic", pkg);
1875
+ let insets = ZERO_INSETS;
1876
+ for (const element of elements) {
1877
+ const props = childrenWithTag(element, "style:graphic-properties")[0];
1878
+ if (props === void 0) continue;
1879
+ insets = {
1880
+ insetLeftPt: readPaddingPt(props, "fo:padding-left") ?? insets.insetLeftPt,
1881
+ insetTopPt: readPaddingPt(props, "fo:padding-top") ?? insets.insetTopPt,
1882
+ insetRightPt: readPaddingPt(props, "fo:padding-right") ?? insets.insetRightPt,
1883
+ insetBottomPt: readPaddingPt(props, "fo:padding-bottom") ?? insets.insetBottomPt
1884
+ };
1885
+ }
1886
+ return insets;
1887
+ }
1888
+ function readDrawImageBlock(image, frameBox, pkg) {
1889
+ const href = attrValue(image, "xlink:href");
1890
+ const part = href === void 0 ? void 0 : pkg.parts[href];
1891
+ if (part?.kind !== "binary") return;
1892
+ const format = sniffImageFormat(base64ToBytes(part.base64));
1893
+ if (format === void 0) return;
1894
+ return {
1895
+ kind: "image",
1896
+ format,
1897
+ base64: part.base64,
1898
+ widthPt: frameBox.widthPt,
1899
+ heightPt: frameBox.heightPt
1900
+ };
1901
+ }
1902
+ function readDrawFrameContent(frame, frameBox, pkg) {
1903
+ const table = childrenWithTag(frame, "table:table")[0];
1904
+ if (table !== void 0) return [readOdfTable(table, pkg)];
1905
+ const textBox = childrenWithTag(frame, "draw:text-box")[0];
1906
+ if (textBox !== void 0) return elementsWithTag(textBox.children, "text:p").map((p) => readOdfParagraph(p, pkg));
1907
+ const image = childrenWithTag(frame, "draw:image")[0];
1908
+ if (image !== void 0) {
1909
+ const block = readDrawImageBlock(image, frameBox, pkg);
1910
+ return block === void 0 ? [] : [block];
1911
+ }
1912
+ return [];
1913
+ }
1914
+ function readDrawFrame(frame, groupFunctions, pkg) {
1915
+ const ownGeometry = resolveOdfShapeGeometry(frame);
1916
+ if (ownGeometry === void 0) return;
1917
+ const geometry = composeOdfGroupTransform(groupFunctions, ownGeometry);
1918
+ return {
1919
+ name: attrValue(frame, "draw:name"),
1920
+ frame: geometry.frame,
1921
+ rotationDeg: geometry.rotationDeg,
1922
+ ...readFrameInsets(frame, pkg),
1923
+ blocks: readDrawFrameContent(frame, geometry.frame, pkg)
1924
+ };
1925
+ }
1926
+ function readOwnTransformFunctions(element) {
1927
+ const value = attrValue(element, "draw:transform");
1928
+ return value === void 0 ? [] : parseOdfTransform(value);
1929
+ }
1930
+ function walkDrawShapes(children, groupFunctions, pkg, out) {
1931
+ for (const node of children) {
1932
+ if (node.type !== "element") continue;
1933
+ if (node.tag === "draw:frame") {
1934
+ const shape = readDrawFrame(node, groupFunctions, pkg);
1935
+ if (shape !== void 0) out.push(shape);
1936
+ } else if (node.tag === "draw:g") {
1937
+ const ownFunctions = readOwnTransformFunctions(node);
1938
+ const nested = ownFunctions.length === 0 ? groupFunctions : [...ownFunctions, ...groupFunctions];
1939
+ walkDrawShapes(node.children, nested, pkg, out);
1940
+ }
1941
+ }
1942
+ }
1943
+ //#endregion
1944
+ //#region src/typed/odp/read.ts
1945
+ const CONTENT_PART = "content.xml";
1946
+ const STYLES_PART = "styles.xml";
1947
+ const AUTOMATIC_STYLE_PARTS = [CONTENT_PART, STYLES_PART];
1948
+ function findMasterPageElement(pkg, masterPageName) {
1949
+ if (masterPageName === void 0) return;
1950
+ const stylesPart = pkg.parts[STYLES_PART];
1951
+ if (stylesPart?.kind !== "xml") return;
1952
+ const root = rootElement(stylesPart.nodes);
1953
+ const masterStyles = root === void 0 ? void 0 : findChildElement(root.children, "office:master-styles");
1954
+ if (masterStyles === void 0) return;
1955
+ return childrenWithTag(masterStyles, "style:master-page").find((element) => attrValue(element, "style:name") === masterPageName);
1956
+ }
1957
+ function findPageLayoutElement(pkg, pageLayoutName) {
1958
+ if (pageLayoutName === void 0) return;
1959
+ for (const partPath of AUTOMATIC_STYLE_PARTS) {
1960
+ const part = pkg.parts[partPath];
1961
+ if (part?.kind !== "xml") continue;
1962
+ const root = rootElement(part.nodes);
1963
+ const automaticStyles = root === void 0 ? void 0 : findChildElement(root.children, "office:automatic-styles");
1964
+ if (automaticStyles === void 0) continue;
1965
+ const found = childrenWithTag(automaticStyles, "style:page-layout").find((element) => attrValue(element, "style:name") === pageLayoutName);
1966
+ if (found !== void 0) return found;
1967
+ }
1968
+ }
1969
+ function readSlideSize(page, pkg) {
1970
+ const masterPage = findMasterPageElement(pkg, attrValue(page, "draw:master-page-name"));
1971
+ const pageLayout = findPageLayoutElement(pkg, masterPage === void 0 ? void 0 : attrValue(masterPage, "style:page-layout-name"));
1972
+ const properties = pageLayout === void 0 ? void 0 : childrenWithTag(pageLayout, "style:page-layout-properties")[0];
1973
+ return (properties === void 0 ? void 0 : parsePageSize(properties)) ?? document_content_model.SLIDE_SIZE_WIDESCREEN;
1974
+ }
1975
+ function readSlideNotes(page) {
1976
+ const notes = childrenWithTag(page, "presentation:notes")[0];
1977
+ if (notes === void 0) return "";
1978
+ return elementsWithTag(notes.children, "text:p").map(decodeOdfText).join("\n");
1979
+ }
1980
+ function readSlide(page, pkg) {
1981
+ const shapes = [];
1982
+ walkDrawShapes(page.children, [], pkg, shapes);
1983
+ return {
1984
+ size: readSlideSize(page, pkg),
1985
+ shapes,
1986
+ notes: readSlideNotes(page)
1987
+ };
1988
+ }
1989
+ function readOdp(pkg) {
1990
+ const contentPart = pkg.parts[CONTENT_PART];
1991
+ const root = contentPart?.kind === "xml" ? rootElement(contentPart.nodes) : void 0;
1992
+ const body = root === void 0 ? void 0 : findChildElement(root.children, "office:body");
1993
+ const presentation = body === void 0 ? void 0 : findChildElement(body.children, "office:presentation");
1994
+ const pages = presentation === void 0 ? [] : childrenWithTag(presentation, "draw:page");
1995
+ return {
1996
+ metadata: readOdfMetadata(pkg),
1997
+ slides: pages.map((page) => readSlide(page, pkg))
1998
+ };
1999
+ }
2000
+ //#endregion
1606
2001
  Object.defineProperty(exports, "AlignmentSchema", {
1607
2002
  enumerable: true,
1608
2003
  get: function() {
@@ -1633,6 +2028,7 @@ exports.XmlNodeSchema = XmlNodeSchema;
1633
2028
  exports.XmlPartSchema = XmlPartSchema;
1634
2029
  exports.XmlPiSchema = XmlPiSchema;
1635
2030
  exports.XmlTextSchema = XmlTextSchema;
2031
+ exports.applyOdfTransform = applyOdfTransform;
1636
2032
  exports.attrValue = attrValue;
1637
2033
  exports.base64ToBytes = base64ToBytes;
1638
2034
  exports.buildManifest = buildManifest;
@@ -1643,14 +2039,17 @@ exports.canonicalPropertiesString = canonicalPropertiesString;
1643
2039
  exports.cellReference = cellReference;
1644
2040
  exports.childrenWithTag = childrenWithTag;
1645
2041
  exports.columnIndexToLetters = columnIndexToLetters;
2042
+ exports.composeOdfGroupTransform = composeOdfGroupTransform;
1646
2043
  exports.decodeOdfText = decodeOdfText;
1647
2044
  exports.decodePackage = decodePackage;
1648
2045
  exports.decodeXmlText = decodeXmlText;
1649
2046
  exports.el = el;
2047
+ exports.elementsWithTag = elementsWithTag;
1650
2048
  exports.encodePackage = encodePackage;
1651
2049
  exports.encodeXmlText = encodeXmlText;
1652
2050
  exports.ensureSpan = ensureSpan;
1653
2051
  exports.findChildElement = findChildElement;
2052
+ exports.findStyleElement = findStyleElement;
1654
2053
  exports.formatOdfColor = formatOdfColor;
1655
2054
  exports.formatOdfLength = formatOdfLength;
1656
2055
  exports.formatPercentageMultiplier = formatPercentageMultiplier;
@@ -1660,6 +2059,7 @@ exports.isStyleFamily = isStyleFamily;
1660
2059
  exports.isXmlNode = isXmlNode;
1661
2060
  exports.measureOdfNodeLength = measureOdfNodeLength;
1662
2061
  exports.mediaTypeForExtension = mediaTypeForExtension;
2062
+ exports.netRotationDeg = netRotationDeg;
1663
2063
  exports.packageCodec = packageCodec;
1664
2064
  exports.paragraphPropertiesToAttributes = paragraphPropertiesToAttributes;
1665
2065
  exports.parseBox = parseBox;
@@ -1667,16 +2067,23 @@ exports.parseLength = parseLength;
1667
2067
  exports.parseMargins = parseMargins;
1668
2068
  exports.parseOdfColor = parseOdfColor;
1669
2069
  exports.parseOdfLength = parseOdfLength;
2070
+ exports.parseOdfTransform = parseOdfTransform;
1670
2071
  exports.parsePackage = parsePackage;
1671
2072
  exports.parsePageSize = parsePageSize;
1672
2073
  exports.parseParagraphProperties = parseParagraphProperties;
1673
2074
  exports.parseStyleElementProperties = parseStyleElementProperties;
1674
2075
  exports.parseTextProperties = parseTextProperties;
1675
2076
  exports.parseXml = parseXml;
2077
+ exports.readDrawFrame = readDrawFrame;
1676
2078
  exports.readManifest = readManifest;
1677
2079
  exports.readMimetype = readMimetype;
1678
2080
  exports.readOdfMetadata = readOdfMetadata;
2081
+ exports.readOdfParagraph = readOdfParagraph;
2082
+ exports.readOdfTable = readOdfTable;
2083
+ exports.readOdp = readOdp;
2084
+ exports.resolveOdfShapeGeometry = resolveOdfShapeGeometry;
1679
2085
  exports.resolveStyle = resolveStyle;
2086
+ exports.resolveStyleElementChain = resolveStyleElementChain;
1680
2087
  exports.rootElement = rootElement;
1681
2088
  exports.serializePackage = serializePackage;
1682
2089
  exports.setDocumentMediaType = setDocumentMediaType;
@@ -1687,6 +2094,7 @@ exports.textPropertiesToAttributes = textPropertiesToAttributes;
1687
2094
  exports.txt = txt;
1688
2095
  exports.unzipPackage = unzipPackage;
1689
2096
  exports.validateManifest = validateManifest;
2097
+ exports.walkDrawShapes = walkDrawShapes;
1690
2098
  exports.writeManifest = writeManifest;
1691
2099
  exports.writeMimetype = writeMimetype;
1692
2100
  exports.xmlCodec = xmlCodec;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { Alignment, AlignmentSchema, Box, Color, LayoutMetadata, Margins, PageSize } from "document-content-model";
2
+ import { Alignment, AlignmentSchema, Box, Color, ContentParagraph, ContentShape, ContentSlide, ContentTable, LayoutMetadata, Margins, PageSize } from "document-content-model";
3
3
  //#region src/model/node.d.ts
4
4
  declare const AttributeSchema: z.ZodObject<{
5
5
  name: z.ZodString;
@@ -480,6 +480,7 @@ declare function ensureSpan(paragraph: XmlElement, start: number, end: number, s
480
480
  declare function rootElement(nodes: readonly XmlNode[]): XmlElement | undefined;
481
481
  declare function findChildElement(nodes: readonly XmlNode[], tag: string): XmlElement | undefined;
482
482
  declare function childrenWithTag(element: XmlElement, tag: string): XmlElement[];
483
+ declare function elementsWithTag(nodes: readonly XmlNode[], tag: string): XmlElement[];
483
484
  declare function attrValue(element: XmlElement, name: string): string | undefined;
484
485
  //#endregion
485
486
  //#region src/typed/shared/a1.d.ts
@@ -518,10 +519,56 @@ interface StyleCascadeResult {
518
519
  properties: StyleProperties;
519
520
  diagnostics: CascadeDiagnostic[];
520
521
  }
522
+ interface StyleElementChainResult {
523
+ elements: XmlElement[];
524
+ diagnostics: CascadeDiagnostic[];
525
+ }
526
+ declare function resolveStyleElementChain(styleName: string | undefined, family: StyleFamily, pkg: Package): StyleElementChainResult;
521
527
  declare function resolveStyle(styleName: string | undefined, family: StyleFamily, pkg: Package): StyleCascadeResult;
528
+ declare function findStyleElement(styleName: string, family: StyleFamily, pkg: Package): XmlElement | undefined;
522
529
  //#endregion
523
530
  //#region src/typed/shared/metadata.d.ts
524
531
  declare const META_PART = "meta.xml";
525
532
  declare function readOdfMetadata(pkg: Package): LayoutMetadata;
526
533
  //#endregion
527
- export { type Alignment, AlignmentSchema, type Attribute, AttributeSchema, type BinaryPart, BinaryPartSchema, type BuildManifestOptions, type CascadeDiagnostic, type ImageFormat, type InternRequest, type LengthUnit, MANIFEST_PART, META_PART, MIMETYPE_PART, type Manifest, type ManifestEntry, ManifestEntrySchema, type ManifestProblem, ManifestProblemSchema, ManifestSchema, ODF_MEDIA_TYPES, ODF_NAMESPACES, type OdfExtension, type OdfNamespacePrefix, type OtherPartRef, type Package, PackageSchema, type ParsedProperties, type Part, PartSchema, STYLE_FAMILIES, type StyleCascadeResult, type StyleFamily, type StyleProperties, StylePropertiesSchema, StyleRegistry, type StyleRegistryOptions, TableCursor, type XmlCdata, XmlCdataSchema, type XmlComment, XmlCommentSchema, type XmlDeclaration, XmlDeclarationSchema, type XmlElement, XmlElementSchema, type XmlNode, XmlNodeSchema, type XmlPart, XmlPartSchema, type XmlPi, XmlPiSchema, type XmlText, XmlTextSchema, type ZipEntry, attrValue, base64ToBytes, buildManifest, buildStylePropertyElements, buildXml, bytesToBase64, canonicalPropertiesString, cellReference, childrenWithTag, columnIndexToLetters, decodeOdfText, decodePackage, decodeXmlText, el, encodePackage, encodeXmlText, ensureSpan, findChildElement, formatOdfColor, formatOdfLength, formatPercentageMultiplier, formatPt, getOdfSpaceCount, isStyleFamily, isXmlNode, measureOdfNodeLength, mediaTypeForExtension, packageCodec, paragraphPropertiesToAttributes, parseBox, parseLength, parseMargins, parseOdfColor, parseOdfLength, parsePackage, parsePageSize, parseParagraphProperties, parseStyleElementProperties, parseTextProperties, parseXml, readManifest, readMimetype, readOdfMetadata, resolveStyle, rootElement, serializePackage, setDocumentMediaType, sniffImageFormat, sumOdfNodeLength, syncManifest, textPropertiesToAttributes, txt, unzipPackage, validateManifest, writeManifest, writeMimetype, xmlCodec, xmlnsAttributes, zipPackage };
534
+ //#region src/typed/shared/paragraph.d.ts
535
+ declare function readOdfParagraph(pElement: XmlElement, pkg: Package): ContentParagraph;
536
+ //#endregion
537
+ //#region src/typed/shared/table.d.ts
538
+ declare function readOdfTable(tableElement: XmlElement, pkg: Package): ContentTable;
539
+ //#endregion
540
+ //#region src/typed/shared/transform.d.ts
541
+ type OdfTransformFunction = {
542
+ readonly kind: 'rotate';
543
+ readonly angleRad: number;
544
+ } | {
545
+ readonly kind: 'translate';
546
+ readonly xPt: number;
547
+ readonly yPt: number;
548
+ };
549
+ interface OdfPoint {
550
+ readonly xPt: number;
551
+ readonly yPt: number;
552
+ }
553
+ declare function parseOdfTransform(value: string): OdfTransformFunction[];
554
+ declare function applyOdfTransform(functions: readonly OdfTransformFunction[], point: OdfPoint): OdfPoint;
555
+ declare function netRotationDeg(functions: readonly OdfTransformFunction[]): number;
556
+ interface OdfShapeGeometry {
557
+ readonly frame: Box;
558
+ readonly rotationDeg: number | undefined;
559
+ }
560
+ declare function resolveOdfShapeGeometry(element: XmlElement): OdfShapeGeometry | undefined;
561
+ declare function composeOdfGroupTransform(groupFunctions: readonly OdfTransformFunction[], child: OdfShapeGeometry): OdfShapeGeometry;
562
+ //#endregion
563
+ //#region src/typed/draw/shapes.d.ts
564
+ declare function readDrawFrame(frame: XmlElement, groupFunctions: readonly OdfTransformFunction[], pkg: Package): ContentShape | undefined;
565
+ declare function walkDrawShapes(children: readonly XmlNode[], groupFunctions: readonly OdfTransformFunction[], pkg: Package, out: ContentShape[]): void;
566
+ //#endregion
567
+ //#region src/typed/odp/read.d.ts
568
+ interface OdpDocument {
569
+ metadata: LayoutMetadata;
570
+ slides: ContentSlide[];
571
+ }
572
+ declare function readOdp(pkg: Package): OdpDocument;
573
+ //#endregion
574
+ export { type Alignment, AlignmentSchema, type Attribute, AttributeSchema, type BinaryPart, BinaryPartSchema, type BuildManifestOptions, type CascadeDiagnostic, type ImageFormat, type InternRequest, type LengthUnit, MANIFEST_PART, META_PART, MIMETYPE_PART, type Manifest, type ManifestEntry, ManifestEntrySchema, type ManifestProblem, ManifestProblemSchema, ManifestSchema, ODF_MEDIA_TYPES, ODF_NAMESPACES, type OdfExtension, type OdfNamespacePrefix, type OdfPoint, type OdfShapeGeometry, type OdfTransformFunction, type OdpDocument, type OtherPartRef, type Package, PackageSchema, type ParsedProperties, type Part, PartSchema, STYLE_FAMILIES, type StyleCascadeResult, type StyleElementChainResult, type StyleFamily, type StyleProperties, StylePropertiesSchema, StyleRegistry, type StyleRegistryOptions, TableCursor, type XmlCdata, XmlCdataSchema, type XmlComment, XmlCommentSchema, type XmlDeclaration, XmlDeclarationSchema, type XmlElement, XmlElementSchema, type XmlNode, XmlNodeSchema, type XmlPart, XmlPartSchema, type XmlPi, XmlPiSchema, type XmlText, XmlTextSchema, type ZipEntry, applyOdfTransform, attrValue, base64ToBytes, buildManifest, buildStylePropertyElements, buildXml, bytesToBase64, canonicalPropertiesString, cellReference, childrenWithTag, columnIndexToLetters, composeOdfGroupTransform, decodeOdfText, decodePackage, decodeXmlText, el, elementsWithTag, encodePackage, encodeXmlText, ensureSpan, findChildElement, findStyleElement, formatOdfColor, formatOdfLength, formatPercentageMultiplier, formatPt, getOdfSpaceCount, isStyleFamily, isXmlNode, measureOdfNodeLength, mediaTypeForExtension, netRotationDeg, packageCodec, paragraphPropertiesToAttributes, parseBox, parseLength, parseMargins, parseOdfColor, parseOdfLength, parseOdfTransform, parsePackage, parsePageSize, parseParagraphProperties, parseStyleElementProperties, parseTextProperties, parseXml, readDrawFrame, readManifest, readMimetype, readOdfMetadata, readOdfParagraph, readOdfTable, readOdp, resolveOdfShapeGeometry, resolveStyle, resolveStyleElementChain, rootElement, serializePackage, setDocumentMediaType, sniffImageFormat, sumOdfNodeLength, syncManifest, textPropertiesToAttributes, txt, unzipPackage, validateManifest, walkDrawShapes, writeManifest, writeMimetype, xmlCodec, xmlnsAttributes, zipPackage };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { Alignment, AlignmentSchema, Box, Color, LayoutMetadata, Margins, PageSize } from "document-content-model";
2
+ import { Alignment, AlignmentSchema, Box, Color, ContentParagraph, ContentShape, ContentSlide, ContentTable, LayoutMetadata, Margins, PageSize } from "document-content-model";
3
3
  //#region src/model/node.d.ts
4
4
  declare const AttributeSchema: z.ZodObject<{
5
5
  name: z.ZodString;
@@ -480,6 +480,7 @@ declare function ensureSpan(paragraph: XmlElement, start: number, end: number, s
480
480
  declare function rootElement(nodes: readonly XmlNode[]): XmlElement | undefined;
481
481
  declare function findChildElement(nodes: readonly XmlNode[], tag: string): XmlElement | undefined;
482
482
  declare function childrenWithTag(element: XmlElement, tag: string): XmlElement[];
483
+ declare function elementsWithTag(nodes: readonly XmlNode[], tag: string): XmlElement[];
483
484
  declare function attrValue(element: XmlElement, name: string): string | undefined;
484
485
  //#endregion
485
486
  //#region src/typed/shared/a1.d.ts
@@ -518,10 +519,56 @@ interface StyleCascadeResult {
518
519
  properties: StyleProperties;
519
520
  diagnostics: CascadeDiagnostic[];
520
521
  }
522
+ interface StyleElementChainResult {
523
+ elements: XmlElement[];
524
+ diagnostics: CascadeDiagnostic[];
525
+ }
526
+ declare function resolveStyleElementChain(styleName: string | undefined, family: StyleFamily, pkg: Package): StyleElementChainResult;
521
527
  declare function resolveStyle(styleName: string | undefined, family: StyleFamily, pkg: Package): StyleCascadeResult;
528
+ declare function findStyleElement(styleName: string, family: StyleFamily, pkg: Package): XmlElement | undefined;
522
529
  //#endregion
523
530
  //#region src/typed/shared/metadata.d.ts
524
531
  declare const META_PART = "meta.xml";
525
532
  declare function readOdfMetadata(pkg: Package): LayoutMetadata;
526
533
  //#endregion
527
- export { type Alignment, AlignmentSchema, type Attribute, AttributeSchema, type BinaryPart, BinaryPartSchema, type BuildManifestOptions, type CascadeDiagnostic, type ImageFormat, type InternRequest, type LengthUnit, MANIFEST_PART, META_PART, MIMETYPE_PART, type Manifest, type ManifestEntry, ManifestEntrySchema, type ManifestProblem, ManifestProblemSchema, ManifestSchema, ODF_MEDIA_TYPES, ODF_NAMESPACES, type OdfExtension, type OdfNamespacePrefix, type OtherPartRef, type Package, PackageSchema, type ParsedProperties, type Part, PartSchema, STYLE_FAMILIES, type StyleCascadeResult, type StyleFamily, type StyleProperties, StylePropertiesSchema, StyleRegistry, type StyleRegistryOptions, TableCursor, type XmlCdata, XmlCdataSchema, type XmlComment, XmlCommentSchema, type XmlDeclaration, XmlDeclarationSchema, type XmlElement, XmlElementSchema, type XmlNode, XmlNodeSchema, type XmlPart, XmlPartSchema, type XmlPi, XmlPiSchema, type XmlText, XmlTextSchema, type ZipEntry, attrValue, base64ToBytes, buildManifest, buildStylePropertyElements, buildXml, bytesToBase64, canonicalPropertiesString, cellReference, childrenWithTag, columnIndexToLetters, decodeOdfText, decodePackage, decodeXmlText, el, encodePackage, encodeXmlText, ensureSpan, findChildElement, formatOdfColor, formatOdfLength, formatPercentageMultiplier, formatPt, getOdfSpaceCount, isStyleFamily, isXmlNode, measureOdfNodeLength, mediaTypeForExtension, packageCodec, paragraphPropertiesToAttributes, parseBox, parseLength, parseMargins, parseOdfColor, parseOdfLength, parsePackage, parsePageSize, parseParagraphProperties, parseStyleElementProperties, parseTextProperties, parseXml, readManifest, readMimetype, readOdfMetadata, resolveStyle, rootElement, serializePackage, setDocumentMediaType, sniffImageFormat, sumOdfNodeLength, syncManifest, textPropertiesToAttributes, txt, unzipPackage, validateManifest, writeManifest, writeMimetype, xmlCodec, xmlnsAttributes, zipPackage };
534
+ //#region src/typed/shared/paragraph.d.ts
535
+ declare function readOdfParagraph(pElement: XmlElement, pkg: Package): ContentParagraph;
536
+ //#endregion
537
+ //#region src/typed/shared/table.d.ts
538
+ declare function readOdfTable(tableElement: XmlElement, pkg: Package): ContentTable;
539
+ //#endregion
540
+ //#region src/typed/shared/transform.d.ts
541
+ type OdfTransformFunction = {
542
+ readonly kind: 'rotate';
543
+ readonly angleRad: number;
544
+ } | {
545
+ readonly kind: 'translate';
546
+ readonly xPt: number;
547
+ readonly yPt: number;
548
+ };
549
+ interface OdfPoint {
550
+ readonly xPt: number;
551
+ readonly yPt: number;
552
+ }
553
+ declare function parseOdfTransform(value: string): OdfTransformFunction[];
554
+ declare function applyOdfTransform(functions: readonly OdfTransformFunction[], point: OdfPoint): OdfPoint;
555
+ declare function netRotationDeg(functions: readonly OdfTransformFunction[]): number;
556
+ interface OdfShapeGeometry {
557
+ readonly frame: Box;
558
+ readonly rotationDeg: number | undefined;
559
+ }
560
+ declare function resolveOdfShapeGeometry(element: XmlElement): OdfShapeGeometry | undefined;
561
+ declare function composeOdfGroupTransform(groupFunctions: readonly OdfTransformFunction[], child: OdfShapeGeometry): OdfShapeGeometry;
562
+ //#endregion
563
+ //#region src/typed/draw/shapes.d.ts
564
+ declare function readDrawFrame(frame: XmlElement, groupFunctions: readonly OdfTransformFunction[], pkg: Package): ContentShape | undefined;
565
+ declare function walkDrawShapes(children: readonly XmlNode[], groupFunctions: readonly OdfTransformFunction[], pkg: Package, out: ContentShape[]): void;
566
+ //#endregion
567
+ //#region src/typed/odp/read.d.ts
568
+ interface OdpDocument {
569
+ metadata: LayoutMetadata;
570
+ slides: ContentSlide[];
571
+ }
572
+ declare function readOdp(pkg: Package): OdpDocument;
573
+ //#endregion
574
+ export { type Alignment, AlignmentSchema, type Attribute, AttributeSchema, type BinaryPart, BinaryPartSchema, type BuildManifestOptions, type CascadeDiagnostic, type ImageFormat, type InternRequest, type LengthUnit, MANIFEST_PART, META_PART, MIMETYPE_PART, type Manifest, type ManifestEntry, ManifestEntrySchema, type ManifestProblem, ManifestProblemSchema, ManifestSchema, ODF_MEDIA_TYPES, ODF_NAMESPACES, type OdfExtension, type OdfNamespacePrefix, type OdfPoint, type OdfShapeGeometry, type OdfTransformFunction, type OdpDocument, type OtherPartRef, type Package, PackageSchema, type ParsedProperties, type Part, PartSchema, STYLE_FAMILIES, type StyleCascadeResult, type StyleElementChainResult, type StyleFamily, type StyleProperties, StylePropertiesSchema, StyleRegistry, type StyleRegistryOptions, TableCursor, type XmlCdata, XmlCdataSchema, type XmlComment, XmlCommentSchema, type XmlDeclaration, XmlDeclarationSchema, type XmlElement, XmlElementSchema, type XmlNode, XmlNodeSchema, type XmlPart, XmlPartSchema, type XmlPi, XmlPiSchema, type XmlText, XmlTextSchema, type ZipEntry, applyOdfTransform, attrValue, base64ToBytes, buildManifest, buildStylePropertyElements, buildXml, bytesToBase64, canonicalPropertiesString, cellReference, childrenWithTag, columnIndexToLetters, composeOdfGroupTransform, decodeOdfText, decodePackage, decodeXmlText, el, elementsWithTag, encodePackage, encodeXmlText, ensureSpan, findChildElement, findStyleElement, formatOdfColor, formatOdfLength, formatPercentageMultiplier, formatPt, getOdfSpaceCount, isStyleFamily, isXmlNode, measureOdfNodeLength, mediaTypeForExtension, netRotationDeg, packageCodec, paragraphPropertiesToAttributes, parseBox, parseLength, parseMargins, parseOdfColor, parseOdfLength, parseOdfTransform, parsePackage, parsePageSize, parseParagraphProperties, parseStyleElementProperties, parseTextProperties, parseXml, readDrawFrame, readManifest, readMimetype, readOdfMetadata, readOdfParagraph, readOdfTable, readOdp, resolveOdfShapeGeometry, resolveStyle, resolveStyleElementChain, rootElement, serializePackage, setDocumentMediaType, sniffImageFormat, sumOdfNodeLength, syncManifest, textPropertiesToAttributes, txt, unzipPackage, validateManifest, walkDrawShapes, writeManifest, writeMimetype, xmlCodec, xmlnsAttributes, zipPackage };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { XMLBuilder, XMLParser } from "fast-xml-parser";
3
3
  import { unzipSync, zipSync } from "fflate";
4
- import { AlignmentSchema, AlignmentSchema as AlignmentSchema$1, ColorSchema, colorToRgbHex, rgbHexToColor } from "document-content-model";
4
+ import { AlignmentSchema, AlignmentSchema as AlignmentSchema$1, ColorSchema, SLIDE_SIZE_WIDESCREEN, colorToRgbHex, rgbHexToColor } from "document-content-model";
5
5
  //#region src/model/node.ts
6
6
  const AttributeSchema = z.object({
7
7
  name: z.string(),
@@ -1242,6 +1242,17 @@ function childrenWithTag(element, tag) {
1242
1242
  for (const child of element.children) if (child.type === "element" && child.tag === tag) out.push(child);
1243
1243
  return out;
1244
1244
  }
1245
+ function* walk(nodes) {
1246
+ for (const node of nodes) {
1247
+ yield node;
1248
+ if (node.type === "element") yield* walk(node.children);
1249
+ }
1250
+ }
1251
+ function elementsWithTag(nodes, tag) {
1252
+ const out = [];
1253
+ for (const node of walk(nodes)) if (node.type === "element" && node.tag === tag) out.push(node);
1254
+ return out;
1255
+ }
1245
1256
  function attrValue(element, name) {
1246
1257
  return element.attributes.find((attribute) => attribute.name === name)?.value;
1247
1258
  }
@@ -1521,13 +1532,14 @@ function collectStyles(pkg) {
1521
1532
  defaultByFamily
1522
1533
  };
1523
1534
  }
1524
- function resolveStyle(styleName, family, pkg) {
1535
+ function resolveStyleElementChain(styleName, family, pkg) {
1525
1536
  const { byName, defaultByFamily } = collectStyles(pkg);
1526
1537
  const diagnostics = [];
1538
+ const elements = [];
1527
1539
  const defaultElement = defaultByFamily.get(family);
1528
- let properties = defaultElement === void 0 ? {} : parseStyleElementProperties(defaultElement).properties;
1540
+ if (defaultElement !== void 0) elements.push(defaultElement);
1529
1541
  if (styleName === void 0) return {
1530
- properties,
1542
+ elements,
1531
1543
  diagnostics
1532
1544
  };
1533
1545
  const chain = [];
@@ -1555,7 +1567,16 @@ function resolveStyle(styleName, family, pkg) {
1555
1567
  currentName = attrValue(element, "style:parent-style-name");
1556
1568
  }
1557
1569
  chain.reverse();
1558
- for (const element of chain) properties = {
1570
+ elements.push(...chain);
1571
+ return {
1572
+ elements,
1573
+ diagnostics
1574
+ };
1575
+ }
1576
+ function resolveStyle(styleName, family, pkg) {
1577
+ const { elements, diagnostics } = resolveStyleElementChain(styleName, family, pkg);
1578
+ let properties = {};
1579
+ for (const element of elements) properties = {
1559
1580
  ...properties,
1560
1581
  ...parseStyleElementProperties(element).properties
1561
1582
  };
@@ -1564,6 +1585,10 @@ function resolveStyle(styleName, family, pkg) {
1564
1585
  diagnostics
1565
1586
  };
1566
1587
  }
1588
+ function findStyleElement(styleName, family, pkg) {
1589
+ const { byName } = collectStyles(pkg);
1590
+ return byName.get(nameKey(family, styleName));
1591
+ }
1567
1592
  //#endregion
1568
1593
  //#region src/typed/shared/metadata.ts
1569
1594
  const META_PART = "meta.xml";
@@ -1602,4 +1627,374 @@ function readOdfMetadata(pkg) {
1602
1627
  return metadata;
1603
1628
  }
1604
1629
  //#endregion
1605
- export { AlignmentSchema, AttributeSchema, BinaryPartSchema, MANIFEST_PART, META_PART, MIMETYPE_PART, ManifestEntrySchema, ManifestProblemSchema, ManifestSchema, ODF_MEDIA_TYPES, ODF_NAMESPACES, PackageSchema, PartSchema, STYLE_FAMILIES, StylePropertiesSchema, StyleRegistry, TableCursor, XmlCdataSchema, XmlCommentSchema, XmlDeclarationSchema, XmlElementSchema, XmlNodeSchema, XmlPartSchema, XmlPiSchema, XmlTextSchema, attrValue, base64ToBytes, buildManifest, buildStylePropertyElements, buildXml, bytesToBase64, canonicalPropertiesString, cellReference, childrenWithTag, columnIndexToLetters, decodeOdfText, decodePackage, decodeXmlText, el, encodePackage, encodeXmlText, ensureSpan, findChildElement, formatOdfColor, formatOdfLength, formatPercentageMultiplier, formatPt, getOdfSpaceCount, isStyleFamily, isXmlNode, measureOdfNodeLength, mediaTypeForExtension, packageCodec, paragraphPropertiesToAttributes, parseBox, parseLength, parseMargins, parseOdfColor, parseOdfLength, parsePackage, parsePageSize, parseParagraphProperties, parseStyleElementProperties, parseTextProperties, parseXml, readManifest, readMimetype, readOdfMetadata, resolveStyle, rootElement, serializePackage, setDocumentMediaType, sniffImageFormat, sumOdfNodeLength, syncManifest, textPropertiesToAttributes, txt, unzipPackage, validateManifest, writeManifest, writeMimetype, xmlCodec, xmlnsAttributes, zipPackage };
1630
+ //#region src/typed/shared/paragraph.ts
1631
+ function collectRuns(nodes, baseProperties, pkg, out) {
1632
+ for (const node of nodes) {
1633
+ if (node.type === "text") {
1634
+ if (node.value.length > 0) out.push(runFromText(decodeXmlText(node.value), baseProperties));
1635
+ continue;
1636
+ }
1637
+ if (node.type !== "element") continue;
1638
+ if (node.tag === "text:s") out.push(runFromText(" ".repeat(getOdfSpaceCount(node)), baseProperties));
1639
+ else if (node.tag === "text:tab") out.push(runFromText(" ", baseProperties));
1640
+ else if (node.tag === "text:line-break") out.push(runFromText("\n", baseProperties));
1641
+ else if (node.tag === "text:span") {
1642
+ const styleName = attrValue(node, "text:style-name");
1643
+ const spanProperties = {
1644
+ ...baseProperties,
1645
+ ...resolveStyle(styleName, "text", pkg).properties
1646
+ };
1647
+ collectRuns(node.children, spanProperties, pkg, out);
1648
+ }
1649
+ }
1650
+ }
1651
+ function runFromText(text, properties) {
1652
+ return {
1653
+ text,
1654
+ bold: properties.bold,
1655
+ italic: properties.italic,
1656
+ underline: properties.underline,
1657
+ strike: properties.strike,
1658
+ fontFamily: properties.fontFamily,
1659
+ sizePt: properties.sizePt,
1660
+ color: properties.color
1661
+ };
1662
+ }
1663
+ function readOdfParagraph(pElement, pkg) {
1664
+ const styleName = attrValue(pElement, "text:style-name");
1665
+ const paragraphProperties = resolveStyle(styleName, "paragraph", pkg).properties;
1666
+ const runs = [];
1667
+ collectRuns(pElement.children, paragraphProperties, pkg, runs);
1668
+ return {
1669
+ kind: "paragraph",
1670
+ runs,
1671
+ styleId: styleName,
1672
+ alignment: paragraphProperties.alignment,
1673
+ spacingBeforePt: paragraphProperties.spacingBeforePt,
1674
+ spacingAfterPt: paragraphProperties.spacingAfterPt,
1675
+ lineSpacing: paragraphProperties.lineSpacing,
1676
+ indentLeftPt: paragraphProperties.indentLeftPt,
1677
+ indentFirstLinePt: paragraphProperties.indentFirstLinePt
1678
+ };
1679
+ }
1680
+ //#endregion
1681
+ //#region src/typed/shared/table.ts
1682
+ function readRepeatCount(element, attrName) {
1683
+ const raw = attrValue(element, attrName);
1684
+ if (raw === void 0) return 1;
1685
+ const parsed = Number.parseInt(raw, 10);
1686
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
1687
+ }
1688
+ function resolveColumnWidthPt(columnElement, pkg) {
1689
+ const styleName = attrValue(columnElement, "table:style-name");
1690
+ const styleElement = styleName === void 0 ? void 0 : findStyleElement(styleName, "table-column", pkg);
1691
+ const props = styleElement === void 0 ? void 0 : childrenWithTag(styleElement, "style:table-column-properties")[0];
1692
+ const widthValue = props === void 0 ? void 0 : attrValue(props, "style:column-width");
1693
+ return widthValue === void 0 ? 0 : parseOdfLength(widthValue) ?? 0;
1694
+ }
1695
+ function resolveRowHeightPt(rowElement, pkg) {
1696
+ const styleName = attrValue(rowElement, "table:style-name");
1697
+ const styleElement = styleName === void 0 ? void 0 : findStyleElement(styleName, "table-row", pkg);
1698
+ const props = styleElement === void 0 ? void 0 : childrenWithTag(styleElement, "style:table-row-properties")[0];
1699
+ const heightValue = props === void 0 ? void 0 : attrValue(props, "style:row-height");
1700
+ return heightValue === void 0 ? void 0 : parseOdfLength(heightValue);
1701
+ }
1702
+ function readTableCellBackground(cellElement, pkg) {
1703
+ const styleName = attrValue(cellElement, "table:style-name");
1704
+ const styleElement = styleName === void 0 ? void 0 : findStyleElement(styleName, "table-cell", pkg);
1705
+ const props = styleElement === void 0 ? void 0 : childrenWithTag(styleElement, "style:table-cell-properties")[0];
1706
+ const value = props === void 0 ? void 0 : attrValue(props, "fo:background-color");
1707
+ return value === void 0 ? void 0 : parseOdfColor(value);
1708
+ }
1709
+ function readTableCell(cellElement, pkg) {
1710
+ const blocks = childrenWithTag(cellElement, "text:p").map((p) => readOdfParagraph(p, pkg));
1711
+ const colSpanRaw = attrValue(cellElement, "table:number-columns-spanned");
1712
+ const rowSpanRaw = attrValue(cellElement, "table:number-rows-spanned");
1713
+ return {
1714
+ blocks,
1715
+ colSpan: colSpanRaw === void 0 ? void 0 : Number.parseInt(colSpanRaw, 10),
1716
+ rowSpan: rowSpanRaw === void 0 ? void 0 : Number.parseInt(rowSpanRaw, 10),
1717
+ background: readTableCellBackground(cellElement, pkg)
1718
+ };
1719
+ }
1720
+ function readTableRow(rowElement, pkg) {
1721
+ const cells = [];
1722
+ for (const child of rowElement.children) {
1723
+ if (child.type !== "element") continue;
1724
+ if (child.tag === "table:covered-table-cell") {
1725
+ const repeat = readRepeatCount(child, "table:number-columns-repeated");
1726
+ for (let i = 0; i < repeat; i++) cells.push({ blocks: [] });
1727
+ } else if (child.tag === "table:table-cell") {
1728
+ const cell = readTableCell(child, pkg);
1729
+ const repeat = readRepeatCount(child, "table:number-columns-repeated");
1730
+ for (let i = 0; i < repeat; i++) cells.push(cell);
1731
+ }
1732
+ }
1733
+ return {
1734
+ cells,
1735
+ heightPt: resolveRowHeightPt(rowElement, pkg)
1736
+ };
1737
+ }
1738
+ function readOdfTable(tableElement, pkg) {
1739
+ const columnWidthsPt = [];
1740
+ for (const column of childrenWithTag(tableElement, "table:table-column")) {
1741
+ const widthPt = resolveColumnWidthPt(column, pkg);
1742
+ const repeat = readRepeatCount(column, "table:number-columns-repeated");
1743
+ for (let i = 0; i < repeat; i++) columnWidthsPt.push(widthPt);
1744
+ }
1745
+ const rows = [];
1746
+ for (const rowElement of childrenWithTag(tableElement, "table:table-row")) {
1747
+ const row = readTableRow(rowElement, pkg);
1748
+ const repeat = readRepeatCount(rowElement, "table:number-rows-repeated");
1749
+ for (let i = 0; i < repeat; i++) rows.push(row);
1750
+ }
1751
+ return {
1752
+ kind: "table",
1753
+ rows,
1754
+ columnWidthsPt
1755
+ };
1756
+ }
1757
+ //#endregion
1758
+ //#region src/typed/shared/transform.ts
1759
+ const FUNCTION_PATTERN = /([a-zA-Z]+)\s*\(\s*([^)]*?)\s*\)/g;
1760
+ function parseOdfTransform(value) {
1761
+ const functions = [];
1762
+ for (const match of value.matchAll(FUNCTION_PATTERN)) {
1763
+ const name = match[1];
1764
+ const argsRaw = match[2];
1765
+ if (name === void 0 || argsRaw === void 0) continue;
1766
+ const args = argsRaw.split(/\s+/).filter((arg) => arg.length > 0);
1767
+ if (name === "rotate") {
1768
+ const angleArg = args[0];
1769
+ if (angleArg === void 0) continue;
1770
+ const angleRad = Number(angleArg);
1771
+ if (!Number.isFinite(angleRad)) continue;
1772
+ functions.push({
1773
+ kind: "rotate",
1774
+ angleRad
1775
+ });
1776
+ } else if (name === "translate") {
1777
+ const xArg = args[0];
1778
+ if (xArg === void 0) continue;
1779
+ const yArg = args[1];
1780
+ const xPt = parseOdfLength(xArg);
1781
+ const yPt = yArg === void 0 ? 0 : parseOdfLength(yArg);
1782
+ if (xPt === void 0 || yPt === void 0) continue;
1783
+ functions.push({
1784
+ kind: "translate",
1785
+ xPt,
1786
+ yPt
1787
+ });
1788
+ }
1789
+ }
1790
+ return functions;
1791
+ }
1792
+ function applyOdfTransform(functions, point) {
1793
+ let current = point;
1794
+ for (const fn of functions) if (fn.kind === "rotate") {
1795
+ const cos = Math.cos(fn.angleRad);
1796
+ const sin = Math.sin(fn.angleRad);
1797
+ current = {
1798
+ xPt: current.xPt * cos + current.yPt * sin,
1799
+ yPt: current.yPt * cos - current.xPt * sin
1800
+ };
1801
+ } else current = {
1802
+ xPt: current.xPt + fn.xPt,
1803
+ yPt: current.yPt + fn.yPt
1804
+ };
1805
+ return current;
1806
+ }
1807
+ function netRotationDeg(functions) {
1808
+ let totalRad = 0;
1809
+ for (const fn of functions) if (fn.kind === "rotate") totalRad += fn.angleRad;
1810
+ return -totalRad * 180 / Math.PI;
1811
+ }
1812
+ function resolveOdfShapeGeometry(element) {
1813
+ const transformValue = attrValue(element, "draw:transform");
1814
+ if (transformValue === void 0) {
1815
+ const box = parseBox(element);
1816
+ return box === void 0 ? void 0 : {
1817
+ frame: box,
1818
+ rotationDeg: void 0
1819
+ };
1820
+ }
1821
+ const widthValue = attrValue(element, "svg:width");
1822
+ const heightValue = attrValue(element, "svg:height");
1823
+ if (widthValue === void 0 || heightValue === void 0) return;
1824
+ const widthPt = parseOdfLength(widthValue);
1825
+ const heightPt = parseOdfLength(heightValue);
1826
+ if (widthPt === void 0 || heightPt === void 0) return;
1827
+ const functions = parseOdfTransform(transformValue);
1828
+ const center = applyOdfTransform(functions, {
1829
+ xPt: widthPt / 2,
1830
+ yPt: heightPt / 2
1831
+ });
1832
+ const rotationDeg = netRotationDeg(functions);
1833
+ return {
1834
+ frame: {
1835
+ xPt: center.xPt - widthPt / 2,
1836
+ yPt: center.yPt - heightPt / 2,
1837
+ widthPt,
1838
+ heightPt
1839
+ },
1840
+ rotationDeg: rotationDeg === 0 ? void 0 : rotationDeg
1841
+ };
1842
+ }
1843
+ function composeOdfGroupTransform(groupFunctions, child) {
1844
+ if (groupFunctions.length === 0) return child;
1845
+ const newCenter = applyOdfTransform(groupFunctions, {
1846
+ xPt: child.frame.xPt + child.frame.widthPt / 2,
1847
+ yPt: child.frame.yPt + child.frame.heightPt / 2
1848
+ });
1849
+ const newRotationDeg = (child.rotationDeg ?? 0) + netRotationDeg(groupFunctions);
1850
+ return {
1851
+ frame: {
1852
+ xPt: newCenter.xPt - child.frame.widthPt / 2,
1853
+ yPt: newCenter.yPt - child.frame.heightPt / 2,
1854
+ widthPt: child.frame.widthPt,
1855
+ heightPt: child.frame.heightPt
1856
+ },
1857
+ rotationDeg: newRotationDeg === 0 ? void 0 : newRotationDeg
1858
+ };
1859
+ }
1860
+ //#endregion
1861
+ //#region src/typed/draw/shapes.ts
1862
+ const ZERO_INSETS = {
1863
+ insetLeftPt: 0,
1864
+ insetTopPt: 0,
1865
+ insetRightPt: 0,
1866
+ insetBottomPt: 0
1867
+ };
1868
+ function readPaddingPt(props, attrName) {
1869
+ const value = attrValue(props, attrName);
1870
+ return value === void 0 ? void 0 : parseOdfLength(value);
1871
+ }
1872
+ function readFrameInsets(frame, pkg) {
1873
+ const { elements } = resolveStyleElementChain(attrValue(frame, "draw:style-name"), "graphic", pkg);
1874
+ let insets = ZERO_INSETS;
1875
+ for (const element of elements) {
1876
+ const props = childrenWithTag(element, "style:graphic-properties")[0];
1877
+ if (props === void 0) continue;
1878
+ insets = {
1879
+ insetLeftPt: readPaddingPt(props, "fo:padding-left") ?? insets.insetLeftPt,
1880
+ insetTopPt: readPaddingPt(props, "fo:padding-top") ?? insets.insetTopPt,
1881
+ insetRightPt: readPaddingPt(props, "fo:padding-right") ?? insets.insetRightPt,
1882
+ insetBottomPt: readPaddingPt(props, "fo:padding-bottom") ?? insets.insetBottomPt
1883
+ };
1884
+ }
1885
+ return insets;
1886
+ }
1887
+ function readDrawImageBlock(image, frameBox, pkg) {
1888
+ const href = attrValue(image, "xlink:href");
1889
+ const part = href === void 0 ? void 0 : pkg.parts[href];
1890
+ if (part?.kind !== "binary") return;
1891
+ const format = sniffImageFormat(base64ToBytes(part.base64));
1892
+ if (format === void 0) return;
1893
+ return {
1894
+ kind: "image",
1895
+ format,
1896
+ base64: part.base64,
1897
+ widthPt: frameBox.widthPt,
1898
+ heightPt: frameBox.heightPt
1899
+ };
1900
+ }
1901
+ function readDrawFrameContent(frame, frameBox, pkg) {
1902
+ const table = childrenWithTag(frame, "table:table")[0];
1903
+ if (table !== void 0) return [readOdfTable(table, pkg)];
1904
+ const textBox = childrenWithTag(frame, "draw:text-box")[0];
1905
+ if (textBox !== void 0) return elementsWithTag(textBox.children, "text:p").map((p) => readOdfParagraph(p, pkg));
1906
+ const image = childrenWithTag(frame, "draw:image")[0];
1907
+ if (image !== void 0) {
1908
+ const block = readDrawImageBlock(image, frameBox, pkg);
1909
+ return block === void 0 ? [] : [block];
1910
+ }
1911
+ return [];
1912
+ }
1913
+ function readDrawFrame(frame, groupFunctions, pkg) {
1914
+ const ownGeometry = resolveOdfShapeGeometry(frame);
1915
+ if (ownGeometry === void 0) return;
1916
+ const geometry = composeOdfGroupTransform(groupFunctions, ownGeometry);
1917
+ return {
1918
+ name: attrValue(frame, "draw:name"),
1919
+ frame: geometry.frame,
1920
+ rotationDeg: geometry.rotationDeg,
1921
+ ...readFrameInsets(frame, pkg),
1922
+ blocks: readDrawFrameContent(frame, geometry.frame, pkg)
1923
+ };
1924
+ }
1925
+ function readOwnTransformFunctions(element) {
1926
+ const value = attrValue(element, "draw:transform");
1927
+ return value === void 0 ? [] : parseOdfTransform(value);
1928
+ }
1929
+ function walkDrawShapes(children, groupFunctions, pkg, out) {
1930
+ for (const node of children) {
1931
+ if (node.type !== "element") continue;
1932
+ if (node.tag === "draw:frame") {
1933
+ const shape = readDrawFrame(node, groupFunctions, pkg);
1934
+ if (shape !== void 0) out.push(shape);
1935
+ } else if (node.tag === "draw:g") {
1936
+ const ownFunctions = readOwnTransformFunctions(node);
1937
+ const nested = ownFunctions.length === 0 ? groupFunctions : [...ownFunctions, ...groupFunctions];
1938
+ walkDrawShapes(node.children, nested, pkg, out);
1939
+ }
1940
+ }
1941
+ }
1942
+ //#endregion
1943
+ //#region src/typed/odp/read.ts
1944
+ const CONTENT_PART = "content.xml";
1945
+ const STYLES_PART = "styles.xml";
1946
+ const AUTOMATIC_STYLE_PARTS = [CONTENT_PART, STYLES_PART];
1947
+ function findMasterPageElement(pkg, masterPageName) {
1948
+ if (masterPageName === void 0) return;
1949
+ const stylesPart = pkg.parts[STYLES_PART];
1950
+ if (stylesPart?.kind !== "xml") return;
1951
+ const root = rootElement(stylesPart.nodes);
1952
+ const masterStyles = root === void 0 ? void 0 : findChildElement(root.children, "office:master-styles");
1953
+ if (masterStyles === void 0) return;
1954
+ return childrenWithTag(masterStyles, "style:master-page").find((element) => attrValue(element, "style:name") === masterPageName);
1955
+ }
1956
+ function findPageLayoutElement(pkg, pageLayoutName) {
1957
+ if (pageLayoutName === void 0) return;
1958
+ for (const partPath of AUTOMATIC_STYLE_PARTS) {
1959
+ const part = pkg.parts[partPath];
1960
+ if (part?.kind !== "xml") continue;
1961
+ const root = rootElement(part.nodes);
1962
+ const automaticStyles = root === void 0 ? void 0 : findChildElement(root.children, "office:automatic-styles");
1963
+ if (automaticStyles === void 0) continue;
1964
+ const found = childrenWithTag(automaticStyles, "style:page-layout").find((element) => attrValue(element, "style:name") === pageLayoutName);
1965
+ if (found !== void 0) return found;
1966
+ }
1967
+ }
1968
+ function readSlideSize(page, pkg) {
1969
+ const masterPage = findMasterPageElement(pkg, attrValue(page, "draw:master-page-name"));
1970
+ const pageLayout = findPageLayoutElement(pkg, masterPage === void 0 ? void 0 : attrValue(masterPage, "style:page-layout-name"));
1971
+ const properties = pageLayout === void 0 ? void 0 : childrenWithTag(pageLayout, "style:page-layout-properties")[0];
1972
+ return (properties === void 0 ? void 0 : parsePageSize(properties)) ?? SLIDE_SIZE_WIDESCREEN;
1973
+ }
1974
+ function readSlideNotes(page) {
1975
+ const notes = childrenWithTag(page, "presentation:notes")[0];
1976
+ if (notes === void 0) return "";
1977
+ return elementsWithTag(notes.children, "text:p").map(decodeOdfText).join("\n");
1978
+ }
1979
+ function readSlide(page, pkg) {
1980
+ const shapes = [];
1981
+ walkDrawShapes(page.children, [], pkg, shapes);
1982
+ return {
1983
+ size: readSlideSize(page, pkg),
1984
+ shapes,
1985
+ notes: readSlideNotes(page)
1986
+ };
1987
+ }
1988
+ function readOdp(pkg) {
1989
+ const contentPart = pkg.parts[CONTENT_PART];
1990
+ const root = contentPart?.kind === "xml" ? rootElement(contentPart.nodes) : void 0;
1991
+ const body = root === void 0 ? void 0 : findChildElement(root.children, "office:body");
1992
+ const presentation = body === void 0 ? void 0 : findChildElement(body.children, "office:presentation");
1993
+ const pages = presentation === void 0 ? [] : childrenWithTag(presentation, "draw:page");
1994
+ return {
1995
+ metadata: readOdfMetadata(pkg),
1996
+ slides: pages.map((page) => readSlide(page, pkg))
1997
+ };
1998
+ }
1999
+ //#endregion
2000
+ export { AlignmentSchema, AttributeSchema, BinaryPartSchema, MANIFEST_PART, META_PART, MIMETYPE_PART, ManifestEntrySchema, ManifestProblemSchema, ManifestSchema, ODF_MEDIA_TYPES, ODF_NAMESPACES, PackageSchema, PartSchema, STYLE_FAMILIES, StylePropertiesSchema, StyleRegistry, TableCursor, XmlCdataSchema, XmlCommentSchema, XmlDeclarationSchema, XmlElementSchema, XmlNodeSchema, XmlPartSchema, XmlPiSchema, XmlTextSchema, applyOdfTransform, attrValue, base64ToBytes, buildManifest, buildStylePropertyElements, buildXml, bytesToBase64, canonicalPropertiesString, cellReference, childrenWithTag, columnIndexToLetters, composeOdfGroupTransform, decodeOdfText, decodePackage, decodeXmlText, el, elementsWithTag, encodePackage, encodeXmlText, ensureSpan, findChildElement, findStyleElement, formatOdfColor, formatOdfLength, formatPercentageMultiplier, formatPt, getOdfSpaceCount, isStyleFamily, isXmlNode, measureOdfNodeLength, mediaTypeForExtension, netRotationDeg, packageCodec, paragraphPropertiesToAttributes, parseBox, parseLength, parseMargins, parseOdfColor, parseOdfLength, parseOdfTransform, parsePackage, parsePageSize, parseParagraphProperties, parseStyleElementProperties, parseTextProperties, parseXml, readDrawFrame, readManifest, readMimetype, readOdfMetadata, readOdfParagraph, readOdfTable, readOdp, resolveOdfShapeGeometry, resolveStyle, resolveStyleElementChain, rootElement, serializePackage, setDocumentMediaType, sniffImageFormat, sumOdfNodeLength, syncManifest, textPropertiesToAttributes, txt, unzipPackage, validateManifest, walkDrawShapes, writeManifest, writeMimetype, xmlCodec, xmlnsAttributes, zipPackage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "odf.js",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "Type-safe, lossless round-trip conversion between OpenDocument Format packages (odt, ods, odp) and JSON, hand-written and dependency-minimal, built on Zod 4 codecs.",
5
5
  "type": "module",
6
6
  "repository": {