@office-kit/xlsx 0.8.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/LICENSE +21 -0
- package/README.md +319 -0
- package/THIRD_PARTY_NOTICES.md +56 -0
- package/dist/cell/cell.d.ts +234 -0
- package/dist/cell/index.d.ts +4 -0
- package/dist/cell/rich-text.d.ts +37 -0
- package/dist/cell-D9CaNKnU.mjs +320 -0
- package/dist/cell-D9CaNKnU.mjs.map +1 -0
- package/dist/cell-style-BEDjMX1y.mjs +1579 -0
- package/dist/cell-style-BEDjMX1y.mjs.map +1 -0
- package/dist/cell.mjs +2 -0
- package/dist/chart/chart-xml.d.ts +16 -0
- package/dist/chart/chart.d.ts +735 -0
- package/dist/chart/cx/chartex-xml.d.ts +6 -0
- package/dist/chart/cx/chartex.d.ts +279 -0
- package/dist/chart/index.d.ts +6 -0
- package/dist/chart/user-shapes-xml.d.ts +4 -0
- package/dist/chart/user-shapes.d.ts +61 -0
- package/dist/chart.mjs +232 -0
- package/dist/chart.mjs.map +1 -0
- package/dist/chartsheet/chartsheet-xml.d.ts +17 -0
- package/dist/chartsheet/chartsheet.d.ts +121 -0
- package/dist/chartsheet/index.d.ts +2 -0
- package/dist/chartsheet-C3-tqkPy.mjs +23 -0
- package/dist/chartsheet-C3-tqkPy.mjs.map +1 -0
- package/dist/chartsheet.mjs +2 -0
- package/dist/colors-ovWAwnZI.mjs +67 -0
- package/dist/colors-ovWAwnZI.mjs.map +1 -0
- package/dist/compat/numbers.d.ts +14 -0
- package/dist/coordinate-96Ecci4d.mjs +276 -0
- package/dist/coordinate-96Ecci4d.mjs.map +1 -0
- package/dist/datetime-B2ySVlXt.mjs +71 -0
- package/dist/datetime-B2ySVlXt.mjs.map +1 -0
- package/dist/defined-names-CviWmtQg.mjs +89 -0
- package/dist/defined-names-CviWmtQg.mjs.map +1 -0
- package/dist/differential-D4dg-qtZ.mjs +37 -0
- package/dist/differential-D4dg-qtZ.mjs.map +1 -0
- package/dist/drawing/anchor.d.ts +63 -0
- package/dist/drawing/dml/colors.d.ts +109 -0
- package/dist/drawing/dml/dml-xml.d.ts +35 -0
- package/dist/drawing/dml/effect.d.ts +92 -0
- package/dist/drawing/dml/fill.d.ts +115 -0
- package/dist/drawing/dml/geometry.d.ts +113 -0
- package/dist/drawing/dml/line.d.ts +41 -0
- package/dist/drawing/dml/shape-properties.d.ts +33 -0
- package/dist/drawing/dml/text.d.ts +218 -0
- package/dist/drawing/drawing-xml.d.ts +5 -0
- package/dist/drawing/drawing.d.ts +117 -0
- package/dist/drawing/image.d.ts +40 -0
- package/dist/drawing/index.d.ts +14 -0
- package/dist/drawing-BxzLuryn.mjs +415 -0
- package/dist/drawing-BxzLuryn.mjs.map +1 -0
- package/dist/drawing.mjs +119 -0
- package/dist/drawing.mjs.map +1 -0
- package/dist/escape-DFTE7ZJc.mjs +51 -0
- package/dist/escape-DFTE7ZJc.mjs.map +1 -0
- package/dist/exceptions-D-CFwxgm.mjs +37 -0
- package/dist/exceptions-D-CFwxgm.mjs.map +1 -0
- package/dist/formula/tokenizer.d.ts +61 -0
- package/dist/formula/translate.d.ts +67 -0
- package/dist/inference-B3ES3KEJ.mjs +42 -0
- package/dist/inference-B3ES3KEJ.mjs.map +1 -0
- package/dist/io/browser.d.ts +41 -0
- package/dist/io/index.d.ts +7 -0
- package/dist/io/load.d.ts +46 -0
- package/dist/io/node-fs.d.ts +62 -0
- package/dist/io/node-save.d.ts +3 -0
- package/dist/io/node.d.ts +17 -0
- package/dist/io/save.d.ts +14 -0
- package/dist/io/sink.d.ts +54 -0
- package/dist/io/source.d.ts +14 -0
- package/dist/io.mjs +212 -0
- package/dist/io.mjs.map +1 -0
- package/dist/load-D5cbhoGx.mjs +1069 -0
- package/dist/load-D5cbhoGx.mjs.map +1 -0
- package/dist/manifest-Dps1-OpP.mjs +801 -0
- package/dist/manifest-Dps1-OpP.mjs.map +1 -0
- package/dist/node.d.ts +3 -0
- package/dist/node.mjs +308 -0
- package/dist/node.mjs.map +1 -0
- package/dist/packaging/core.d.ts +45 -0
- package/dist/packaging/custom.d.ts +62 -0
- package/dist/packaging/extended.d.ts +45 -0
- package/dist/packaging/index.d.ts +10 -0
- package/dist/packaging/manifest.d.ts +24 -0
- package/dist/packaging/relationships.d.ts +30 -0
- package/dist/packaging.mjs +2 -0
- package/dist/parser-DuLejQy1.mjs +156 -0
- package/dist/parser-DuLejQy1.mjs.map +1 -0
- package/dist/reader-D1fNW9k1.mjs +534 -0
- package/dist/reader-D1fNW9k1.mjs.map +1 -0
- package/dist/save-RohQtgEZ.mjs +745 -0
- package/dist/save-RohQtgEZ.mjs.map +1 -0
- package/dist/schema/core.d.ts +133 -0
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/serialize.d.ts +6 -0
- package/dist/schema.mjs +2 -0
- package/dist/serialize-55EnT30e.mjs +254 -0
- package/dist/serialize-55EnT30e.mjs.map +1 -0
- package/dist/serializer-BwbgHYJV.mjs +116 -0
- package/dist/serializer-BwbgHYJV.mjs.map +1 -0
- package/dist/streaming/index.d.ts +2 -0
- package/dist/streaming/read-only.d.ts +38 -0
- package/dist/streaming/write-only.d.ts +47 -0
- package/dist/streaming.mjs +612 -0
- package/dist/streaming.mjs.map +1 -0
- package/dist/styles/alignment.d.ts +33 -0
- package/dist/styles/alignment.schema.d.ts +3 -0
- package/dist/styles/borders.d.ts +40 -0
- package/dist/styles/borders.schema.d.ts +4 -0
- package/dist/styles/cell-style.d.ts +270 -0
- package/dist/styles/colors.d.ts +128 -0
- package/dist/styles/colors.schema.d.ts +3 -0
- package/dist/styles/differential.d.ts +41 -0
- package/dist/styles/fills.d.ts +54 -0
- package/dist/styles/fills.schema.d.ts +6 -0
- package/dist/styles/fonts.d.ts +44 -0
- package/dist/styles/fonts.schema.d.ts +3 -0
- package/dist/styles/index.d.ts +21 -0
- package/dist/styles/named-styles.d.ts +52 -0
- package/dist/styles/numbers.d.ts +39 -0
- package/dist/styles/numbers.schema.d.ts +3 -0
- package/dist/styles/protection.d.ts +9 -0
- package/dist/styles/protection.schema.d.ts +3 -0
- package/dist/styles/stylesheet-reader.d.ts +7 -0
- package/dist/styles/stylesheet-writer.d.ts +3 -0
- package/dist/styles/stylesheet.d.ts +95 -0
- package/dist/styles.mjs +4 -0
- package/dist/stylesheet-writer-C2eRmn22.mjs +8624 -0
- package/dist/stylesheet-writer-C2eRmn22.mjs.map +1 -0
- package/dist/table-DkX6UniA.mjs +113 -0
- package/dist/table-DkX6UniA.mjs.map +1 -0
- package/dist/tree-Bbs1C8Rc.mjs +192 -0
- package/dist/tree-Bbs1C8Rc.mjs.map +1 -0
- package/dist/units-rOMQqXh2.mjs +41 -0
- package/dist/units-rOMQqXh2.mjs.map +1 -0
- package/dist/user-shapes-DfmCGKB0.mjs +252 -0
- package/dist/user-shapes-DfmCGKB0.mjs.map +1 -0
- package/dist/utf8-D91g1XTG.mjs +143 -0
- package/dist/utf8-D91g1XTG.mjs.map +1 -0
- package/dist/utils/coordinate.d.ts +103 -0
- package/dist/utils/css.d.ts +18 -0
- package/dist/utils/datetime.d.ts +38 -0
- package/dist/utils/escape.d.ts +34 -0
- package/dist/utils/exceptions.d.ts +34 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/inference.d.ts +24 -0
- package/dist/utils/stable-stringify.d.ts +7 -0
- package/dist/utils/units.d.ts +14 -0
- package/dist/utils/utf8.d.ts +1 -0
- package/dist/utils.mjs +39 -0
- package/dist/utils.mjs.map +1 -0
- package/dist/workbook/calc-properties.d.ts +47 -0
- package/dist/workbook/defined-names.d.ts +121 -0
- package/dist/workbook/file-recovery.d.ts +11 -0
- package/dist/workbook/file-sharing.d.ts +14 -0
- package/dist/workbook/file-version.d.ts +13 -0
- package/dist/workbook/function-groups.d.ts +10 -0
- package/dist/workbook/index.d.ts +24 -0
- package/dist/workbook/protection.d.ts +35 -0
- package/dist/workbook/shared-strings.d.ts +57 -0
- package/dist/workbook/smart-tags.d.ts +13 -0
- package/dist/workbook/views.d.ts +89 -0
- package/dist/workbook/workbook-properties.d.ts +57 -0
- package/dist/workbook/workbook.d.ts +643 -0
- package/dist/workbook-HGYNRBlV.mjs +636 -0
- package/dist/workbook-HGYNRBlV.mjs.map +1 -0
- package/dist/workbook.mjs +58 -0
- package/dist/workbook.mjs.map +1 -0
- package/dist/worksheet/auto-filter.d.ts +34 -0
- package/dist/worksheet/cell-range.d.ts +121 -0
- package/dist/worksheet/comments-xml.d.ts +24 -0
- package/dist/worksheet/comments.d.ts +13 -0
- package/dist/worksheet/conditional-formatting.d.ts +150 -0
- package/dist/worksheet/custom-sheet-views.d.ts +43 -0
- package/dist/worksheet/data-consolidate.d.ts +29 -0
- package/dist/worksheet/data-validations.d.ts +72 -0
- package/dist/worksheet/dimensions.d.ts +40 -0
- package/dist/worksheet/errors.d.ts +40 -0
- package/dist/worksheet/hyperlinks.d.ts +42 -0
- package/dist/worksheet/index.d.ts +46 -0
- package/dist/worksheet/ole-objects.d.ts +37 -0
- package/dist/worksheet/page-setup.d.ts +173 -0
- package/dist/worksheet/phonetic.d.ts +11 -0
- package/dist/worksheet/properties.d.ts +34 -0
- package/dist/worksheet/protected-ranges.d.ts +19 -0
- package/dist/worksheet/protection.d.ts +44 -0
- package/dist/worksheet/reader.d.ts +38 -0
- package/dist/worksheet/scenarios.d.ts +36 -0
- package/dist/worksheet/smart-tags.d.ts +23 -0
- package/dist/worksheet/sort-state.d.ts +28 -0
- package/dist/worksheet/table-xml.d.ts +5 -0
- package/dist/worksheet/table.d.ts +80 -0
- package/dist/worksheet/views.d.ts +47 -0
- package/dist/worksheet/web-publish.d.ts +21 -0
- package/dist/worksheet/worksheet.d.ts +935 -0
- package/dist/worksheet/writer.d.ts +72 -0
- package/dist/worksheet-CmCNoIgD.mjs +1726 -0
- package/dist/worksheet-CmCNoIgD.mjs.map +1 -0
- package/dist/worksheet.mjs +247 -0
- package/dist/worksheet.mjs.map +1 -0
- package/dist/writer-DspzfkNA.mjs +221 -0
- package/dist/writer-DspzfkNA.mjs.map +1 -0
- package/dist/xml/index.d.ts +10 -0
- package/dist/xml/iterparse.d.ts +22 -0
- package/dist/xml/namespaces.d.ts +91 -0
- package/dist/xml/parser.d.ts +7 -0
- package/dist/xml/serializer.d.ts +14 -0
- package/dist/xml/stream-writer.d.ts +39 -0
- package/dist/xml/tree.d.ts +37 -0
- package/dist/xml.mjs +140 -0
- package/dist/xml.mjs.map +1 -0
- package/dist/zip/decompression-guard.d.ts +70 -0
- package/dist/zip/index.d.ts +6 -0
- package/dist/zip/random-access-reader.d.ts +16 -0
- package/dist/zip/reader.d.ts +45 -0
- package/dist/zip/writer.d.ts +65 -0
- package/dist/zip/zip64-patch.d.ts +12 -0
- package/dist/zip.mjs +3 -0
- package/package.json +147 -0
|
@@ -0,0 +1,1069 @@
|
|
|
1
|
+
import { o as OpenXmlSchemaError } from "./exceptions-D-CFwxgm.mjs";
|
|
2
|
+
import { h as loadImage } from "./drawing-BxzLuryn.mjs";
|
|
3
|
+
import { At as parseQName, a as findChildren, c as ARC_CONTENT_TYPES, f as ARC_ROOT_RELS, ft as SHEET_MAIN_NS, g as ARC_WORKBOOK, h as ARC_THEME, i as findChild, jt as qname, l as ARC_CORE, lt as REL_NS, m as ARC_STYLE, p as ARC_SHARED_STRINGS, s as ARC_APP, u as ARC_CUSTOM } from "./tree-Bbs1C8Rc.mjs";
|
|
4
|
+
import { C as isChartExBytes, D as parseChartXml, E as findUserShapesRId, a as parseCommentsXml, b as parseUserShapesXml, c as NumberFormatSchema, d as BorderSchema, f as AlignmentSchema, g as parseChartsheetXml, l as FontSchema, m as parseDrawingXml, n as parseTableXml, s as ProtectionSchema, u as fillFromTree, w as parseChartExXml, y as parseWorksheetXml } from "./stylesheet-writer-C2eRmn22.mjs";
|
|
5
|
+
import { t as parseXml } from "./parser-DuLejQy1.mjs";
|
|
6
|
+
import { t as fromTree } from "./serialize-55EnT30e.mjs";
|
|
7
|
+
import { B as corePropsFromBytes, Q as findById, _ as customPropsFromBytes, c as extendedPropsFromBytes, et as indexRelsById, nt as relsFromBytes, o as manifestFromBytes } from "./manifest-Dps1-OpP.mjs";
|
|
8
|
+
import { D as parseSharedStringsXml, r as createWorkbook } from "./workbook-HGYNRBlV.mjs";
|
|
9
|
+
import { Zt as stableStringify, ft as makeStylesheet } from "./cell-style-BEDjMX1y.mjs";
|
|
10
|
+
import { a as makeDefinedName } from "./defined-names-CviWmtQg.mjs";
|
|
11
|
+
import { t as openZip } from "./reader-D1fNW9k1.mjs";
|
|
12
|
+
//#region src/styles/stylesheet-reader.ts
|
|
13
|
+
const STYLESHEET_TAG = qname(SHEET_MAIN_NS, "styleSheet");
|
|
14
|
+
const FONTS_TAG = qname(SHEET_MAIN_NS, "fonts");
|
|
15
|
+
const FILLS_TAG = qname(SHEET_MAIN_NS, "fills");
|
|
16
|
+
const BORDERS_TAG = qname(SHEET_MAIN_NS, "borders");
|
|
17
|
+
const NUMFMTS_TAG = qname(SHEET_MAIN_NS, "numFmts");
|
|
18
|
+
const NUMFMT_TAG = qname(SHEET_MAIN_NS, "numFmt");
|
|
19
|
+
const CELLXFS_TAG = qname(SHEET_MAIN_NS, "cellXfs");
|
|
20
|
+
const CELLSTYLEXFS_TAG = qname(SHEET_MAIN_NS, "cellStyleXfs");
|
|
21
|
+
const CELLSTYLES_TAG = qname(SHEET_MAIN_NS, "cellStyles");
|
|
22
|
+
const CELLSTYLE_TAG = qname(SHEET_MAIN_NS, "cellStyle");
|
|
23
|
+
const DXFS_TAG = qname(SHEET_MAIN_NS, "dxfs");
|
|
24
|
+
const DXF_TAG = qname(SHEET_MAIN_NS, "dxf");
|
|
25
|
+
const XF_TAG = qname(SHEET_MAIN_NS, "xf");
|
|
26
|
+
const FONT_TAG = qname(SHEET_MAIN_NS, "font");
|
|
27
|
+
const FILL_TAG = qname(SHEET_MAIN_NS, "fill");
|
|
28
|
+
const BORDER_TAG = qname(SHEET_MAIN_NS, "border");
|
|
29
|
+
const NUMFMT_INNER_TAG = qname(SHEET_MAIN_NS, "numFmt");
|
|
30
|
+
const ALIGNMENT_TAG = qname(SHEET_MAIN_NS, "alignment");
|
|
31
|
+
const PROTECTION_TAG = qname(SHEET_MAIN_NS, "protection");
|
|
32
|
+
/**
|
|
33
|
+
* Parse `xl/styles.xml` and return a fully-populated {@link Stylesheet}. Slot
|
|
34
|
+
* ordering is preserved verbatim; the dedup index Maps are rebuilt after the
|
|
35
|
+
* fact so future `addFont` / `addCellXf` calls keep working.
|
|
36
|
+
*/
|
|
37
|
+
function parseStylesheetXml(bytes) {
|
|
38
|
+
const root = parseXml(bytes);
|
|
39
|
+
if (root.name !== STYLESHEET_TAG) throw new OpenXmlSchemaError(`parseStylesheetXml: root is "${root.name}", expected styleSheet`);
|
|
40
|
+
const ss = makeStylesheet();
|
|
41
|
+
ss.fonts.length = 0;
|
|
42
|
+
ss.fills.length = 0;
|
|
43
|
+
ss.borders.length = 0;
|
|
44
|
+
for (const fontEl of findInSection(root, FONTS_TAG, FONT_TAG)) ss.fonts.push(fromTree(fontEl, FontSchema));
|
|
45
|
+
for (const fillEl of findInSection(root, FILLS_TAG, FILL_TAG)) ss.fills.push(fillFromTree(fillEl));
|
|
46
|
+
for (const borderEl of findInSection(root, BORDERS_TAG, BORDER_TAG)) ss.borders.push(fromTree(borderEl, BorderSchema));
|
|
47
|
+
for (const numFmtEl of findInSection(root, NUMFMTS_TAG, NUMFMT_TAG)) {
|
|
48
|
+
const nf = parseNumFmt(numFmtEl);
|
|
49
|
+
ss.numFmts.set(nf.numFmtId, nf.formatCode);
|
|
50
|
+
}
|
|
51
|
+
for (const xfEl of findInSection(root, CELLSTYLEXFS_TAG, XF_TAG)) ss.cellStyleXfs.push(parseCellXf(xfEl));
|
|
52
|
+
for (const xfEl of findInSection(root, CELLXFS_TAG, XF_TAG)) ss.cellXfs.push(parseCellXf(xfEl));
|
|
53
|
+
const cellStylesEl = findChild(root, CELLSTYLES_TAG);
|
|
54
|
+
if (cellStylesEl) {
|
|
55
|
+
const named = [];
|
|
56
|
+
for (const cs of findChildren(cellStylesEl, CELLSTYLE_TAG)) {
|
|
57
|
+
const name = cs.attrs["name"];
|
|
58
|
+
const xfId = parseIntAttr(cs.attrs["xfId"], "xfId");
|
|
59
|
+
if (name === void 0 || xfId === void 0) continue;
|
|
60
|
+
const entry = {
|
|
61
|
+
name,
|
|
62
|
+
xfId,
|
|
63
|
+
...cs.attrs["builtinId"] !== void 0 ? { builtinId: parseIntAttr(cs.attrs["builtinId"], "builtinId") ?? 0 } : {},
|
|
64
|
+
...cs.attrs["iLevel"] !== void 0 ? { iLevel: parseIntAttr(cs.attrs["iLevel"], "iLevel") ?? 0 } : {},
|
|
65
|
+
...parseBoolAttr(cs.attrs["hidden"]) === true ? { hidden: true } : {},
|
|
66
|
+
...parseBoolAttr(cs.attrs["customBuiltin"]) === true ? { customBuiltin: true } : {}
|
|
67
|
+
};
|
|
68
|
+
named.push(entry);
|
|
69
|
+
}
|
|
70
|
+
if (named.length > 0) {
|
|
71
|
+
ss.namedStyles = named;
|
|
72
|
+
ss._namedStyleByName = new Map(named.map((n) => [n.name, n]));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const dxfsEl = findChild(root, DXFS_TAG);
|
|
76
|
+
if (dxfsEl) {
|
|
77
|
+
const dxfs = [];
|
|
78
|
+
for (const dxfEl of findChildren(dxfsEl, DXF_TAG)) {
|
|
79
|
+
const fontEl = findChild(dxfEl, FONT_TAG);
|
|
80
|
+
const numFmtEl = findChild(dxfEl, NUMFMT_INNER_TAG);
|
|
81
|
+
const fillEl = findChild(dxfEl, FILL_TAG);
|
|
82
|
+
const alignmentEl = findChild(dxfEl, ALIGNMENT_TAG);
|
|
83
|
+
const borderEl = findChild(dxfEl, BORDER_TAG);
|
|
84
|
+
const protectionEl = findChild(dxfEl, PROTECTION_TAG);
|
|
85
|
+
const dxf = {
|
|
86
|
+
...fontEl ? { font: fromTree(fontEl, FontSchema) } : {},
|
|
87
|
+
...numFmtEl ? { numFmt: fromTree(numFmtEl, NumberFormatSchema) } : {},
|
|
88
|
+
...fillEl ? { fill: fillFromTree(fillEl) } : {},
|
|
89
|
+
...alignmentEl ? { alignment: fromTree(alignmentEl, AlignmentSchema) } : {},
|
|
90
|
+
...borderEl ? { border: fromTree(borderEl, BorderSchema) } : {},
|
|
91
|
+
...protectionEl ? { protection: fromTree(protectionEl, ProtectionSchema) } : {}
|
|
92
|
+
};
|
|
93
|
+
dxfs.push(Object.freeze(dxf));
|
|
94
|
+
}
|
|
95
|
+
if (dxfs.length > 0) {
|
|
96
|
+
const w = ss;
|
|
97
|
+
w.dxfs = dxfs;
|
|
98
|
+
w._dxfIdByKey = new Map(dxfs.map((d, i) => [stableStringify(d), i]));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
rebuildIndexes(ss);
|
|
102
|
+
return ss;
|
|
103
|
+
}
|
|
104
|
+
/** Drill from `<styleSheet>` into a numbered section and yield every matching child. */
|
|
105
|
+
function findInSection(root, sectionTag, itemTag) {
|
|
106
|
+
const section = findChild(root, sectionTag);
|
|
107
|
+
if (!section) return [];
|
|
108
|
+
return findChildren(section, itemTag);
|
|
109
|
+
}
|
|
110
|
+
const parseNumFmt = (node) => {
|
|
111
|
+
const idAttr = node.attrs["numFmtId"];
|
|
112
|
+
const code = node.attrs["formatCode"];
|
|
113
|
+
if (idAttr === void 0) throw new OpenXmlSchemaError("styles: <numFmt> missing @numFmtId");
|
|
114
|
+
if (code === void 0) throw new OpenXmlSchemaError(`styles: <numFmt numFmtId="${idAttr}"> missing @formatCode`);
|
|
115
|
+
const numFmtId = Number.parseInt(idAttr, 10);
|
|
116
|
+
if (!Number.isInteger(numFmtId) || numFmtId < 0) throw new OpenXmlSchemaError(`styles: <numFmt numFmtId="${idAttr}"> is not a non-negative integer`);
|
|
117
|
+
return {
|
|
118
|
+
numFmtId,
|
|
119
|
+
formatCode: code
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
const parseIntAttr = (raw, label) => {
|
|
123
|
+
if (raw === void 0) return void 0;
|
|
124
|
+
const n = Number.parseInt(raw, 10);
|
|
125
|
+
if (!Number.isInteger(n) || n < 0) throw new OpenXmlSchemaError(`styles: <xf ${label}="${raw}"> is not a non-negative integer`);
|
|
126
|
+
return n;
|
|
127
|
+
};
|
|
128
|
+
const parseBoolAttr = (raw) => {
|
|
129
|
+
if (raw === void 0) return void 0;
|
|
130
|
+
if (raw === "1" || raw === "true") return true;
|
|
131
|
+
if (raw === "0" || raw === "false") return false;
|
|
132
|
+
};
|
|
133
|
+
const parseCellXf = (node) => {
|
|
134
|
+
const fontId = parseIntAttr(node.attrs["fontId"], "fontId") ?? 0;
|
|
135
|
+
const fillId = parseIntAttr(node.attrs["fillId"], "fillId") ?? 0;
|
|
136
|
+
const borderId = parseIntAttr(node.attrs["borderId"], "borderId") ?? 0;
|
|
137
|
+
const numFmtId = parseIntAttr(node.attrs["numFmtId"], "numFmtId") ?? 0;
|
|
138
|
+
const xfId = parseIntAttr(node.attrs["xfId"], "xfId");
|
|
139
|
+
const applyFont = parseBoolAttr(node.attrs["applyFont"]);
|
|
140
|
+
const applyFill = parseBoolAttr(node.attrs["applyFill"]);
|
|
141
|
+
const applyBorder = parseBoolAttr(node.attrs["applyBorder"]);
|
|
142
|
+
const applyNumberFormat = parseBoolAttr(node.attrs["applyNumberFormat"]);
|
|
143
|
+
const applyAlignment = parseBoolAttr(node.attrs["applyAlignment"]);
|
|
144
|
+
const applyProtection = parseBoolAttr(node.attrs["applyProtection"]);
|
|
145
|
+
const pivotButton = parseBoolAttr(node.attrs["pivotButton"]);
|
|
146
|
+
const quotePrefix = parseBoolAttr(node.attrs["quotePrefix"]);
|
|
147
|
+
const alignmentEl = findChild(node, ALIGNMENT_TAG);
|
|
148
|
+
const protectionEl = findChild(node, PROTECTION_TAG);
|
|
149
|
+
return {
|
|
150
|
+
fontId,
|
|
151
|
+
fillId,
|
|
152
|
+
borderId,
|
|
153
|
+
numFmtId,
|
|
154
|
+
...xfId !== void 0 ? { xfId } : {},
|
|
155
|
+
...alignmentEl ? { alignment: fromTree(alignmentEl, AlignmentSchema) } : {},
|
|
156
|
+
...protectionEl ? { protection: fromTree(protectionEl, ProtectionSchema) } : {},
|
|
157
|
+
...applyFont !== void 0 ? { applyFont } : {},
|
|
158
|
+
...applyFill !== void 0 ? { applyFill } : {},
|
|
159
|
+
...applyBorder !== void 0 ? { applyBorder } : {},
|
|
160
|
+
...applyNumberFormat !== void 0 ? { applyNumberFormat } : {},
|
|
161
|
+
...applyAlignment !== void 0 ? { applyAlignment } : {},
|
|
162
|
+
...applyProtection !== void 0 ? { applyProtection } : {},
|
|
163
|
+
...pivotButton !== void 0 ? { pivotButton } : {},
|
|
164
|
+
...quotePrefix !== void 0 ? { quotePrefix } : {}
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
/** Repopulate the `_*IdByKey` maps from the freshly-loaded pool entries. */
|
|
168
|
+
function rebuildIndexes(ss) {
|
|
169
|
+
ss._fontIdByKey = buildKeyIndex(ss.fonts);
|
|
170
|
+
ss._fillIdByKey = buildKeyIndex(ss.fills);
|
|
171
|
+
ss._borderIdByKey = buildKeyIndex(ss.borders);
|
|
172
|
+
ss._xfIdByKey = buildKeyIndex(ss.cellXfs);
|
|
173
|
+
ss._styleXfIdByKey = buildKeyIndex(ss.cellStyleXfs);
|
|
174
|
+
ss._numFmtIdByCode = /* @__PURE__ */ new Map();
|
|
175
|
+
for (const [id, code] of ss.numFmts) ss._numFmtIdByCode.set(code, id);
|
|
176
|
+
}
|
|
177
|
+
const buildKeyIndex = (arr) => {
|
|
178
|
+
const m = /* @__PURE__ */ new Map();
|
|
179
|
+
for (let i = 0; i < arr.length; i++) {
|
|
180
|
+
const key = stableStringify(arr[i]);
|
|
181
|
+
if (!m.has(key)) m.set(key, i);
|
|
182
|
+
}
|
|
183
|
+
return m;
|
|
184
|
+
};
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/io/load.ts
|
|
187
|
+
/** Office Document relationship type — the package-root pointer to `xl/workbook.xml`. */
|
|
188
|
+
const OFFICE_DOC_REL_TYPE = `${REL_NS}/officeDocument`;
|
|
189
|
+
/**
|
|
190
|
+
* Resolve an OPC relationship target against its source part path.
|
|
191
|
+
*
|
|
192
|
+
* - Targets starting with `/` are package-absolute.
|
|
193
|
+
* - Otherwise the target is relative to the source part's parent directory.
|
|
194
|
+
* - `..` segments collapse normally.
|
|
195
|
+
*/
|
|
196
|
+
function resolveRelTarget(sourcePartPath, target) {
|
|
197
|
+
if (target.startsWith("/")) return target.slice(1);
|
|
198
|
+
const lastSlash = sourcePartPath.lastIndexOf("/");
|
|
199
|
+
return normalizePath((lastSlash >= 0 ? sourcePartPath.slice(0, lastSlash + 1) : "") + target);
|
|
200
|
+
}
|
|
201
|
+
function normalizePath(path) {
|
|
202
|
+
const segments = path.split("/");
|
|
203
|
+
const out = [];
|
|
204
|
+
for (const seg of segments) {
|
|
205
|
+
if (seg === "" || seg === ".") continue;
|
|
206
|
+
if (seg === "..") {
|
|
207
|
+
out.pop();
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
out.push(seg);
|
|
211
|
+
}
|
|
212
|
+
return out.join("/");
|
|
213
|
+
}
|
|
214
|
+
/** Sibling rels-part path for a given part. `xl/workbook.xml` → `xl/_rels/workbook.xml.rels`. */
|
|
215
|
+
function relsPathFor(partPath) {
|
|
216
|
+
const i = partPath.lastIndexOf("/");
|
|
217
|
+
if (i < 0) return `_rels/${partPath}.rels`;
|
|
218
|
+
return `${partPath.slice(0, i)}/_rels/${partPath.slice(i + 1)}.rels`;
|
|
219
|
+
}
|
|
220
|
+
const SHEET_TAG = `{${SHEET_MAIN_NS}}sheet`;
|
|
221
|
+
const SHEETS_TAG = `{${SHEET_MAIN_NS}}sheets`;
|
|
222
|
+
const DEFINED_NAMES_TAG = `{${SHEET_MAIN_NS}}definedNames`;
|
|
223
|
+
const DEFINED_NAME_TAG = `{${SHEET_MAIN_NS}}definedName`;
|
|
224
|
+
const RID_ATTR = `{${REL_NS}}id`;
|
|
225
|
+
/** Extract the `<definedNames>/<definedName>` entries from a parsed `xl/workbook.xml`. */
|
|
226
|
+
function parseDefinedNames(workbookRoot) {
|
|
227
|
+
const wrapper = findChild(workbookRoot, DEFINED_NAMES_TAG);
|
|
228
|
+
if (!wrapper) return [];
|
|
229
|
+
const out = [];
|
|
230
|
+
for (const node of findChildren(wrapper, DEFINED_NAME_TAG)) {
|
|
231
|
+
const name = node.attrs["name"];
|
|
232
|
+
if (!name) throw new OpenXmlSchemaError("workbook.xml: <definedName> is missing 'name'");
|
|
233
|
+
const opts = {
|
|
234
|
+
name,
|
|
235
|
+
value: node.text ?? ""
|
|
236
|
+
};
|
|
237
|
+
const scopeAttr = node.attrs["localSheetId"];
|
|
238
|
+
if (scopeAttr !== void 0) {
|
|
239
|
+
const scope = Number.parseInt(scopeAttr, 10);
|
|
240
|
+
if (Number.isInteger(scope) && scope >= 0) opts.scope = scope;
|
|
241
|
+
}
|
|
242
|
+
if (node.attrs["hidden"] === "1" || node.attrs["hidden"] === "true") opts.hidden = true;
|
|
243
|
+
if (node.attrs["comment"] !== void 0) opts.comment = node.attrs["comment"];
|
|
244
|
+
out.push(makeDefinedName(opts));
|
|
245
|
+
}
|
|
246
|
+
return out;
|
|
247
|
+
}
|
|
248
|
+
const WORKBOOK_PR_TAG = `{${SHEET_MAIN_NS}}workbookPr`;
|
|
249
|
+
const WORKBOOK_PROTECTION_TAG = `{${SHEET_MAIN_NS}}workbookProtection`;
|
|
250
|
+
const BOOK_VIEWS_TAG = `{${SHEET_MAIN_NS}}bookViews`;
|
|
251
|
+
const WORKBOOK_VIEW_TAG = `{${SHEET_MAIN_NS}}workbookView`;
|
|
252
|
+
const CUSTOM_WORKBOOK_VIEWS_TAG = `{${SHEET_MAIN_NS}}customWorkbookViews`;
|
|
253
|
+
const CUSTOM_WORKBOOK_VIEW_TAG = `{${SHEET_MAIN_NS}}customWorkbookView`;
|
|
254
|
+
const CALC_PR_TAG = `{${SHEET_MAIN_NS}}calcPr`;
|
|
255
|
+
const FILE_VERSION_TAG = `{${SHEET_MAIN_NS}}fileVersion`;
|
|
256
|
+
const FILE_SHARING_TAG = `{${SHEET_MAIN_NS}}fileSharing`;
|
|
257
|
+
const OLE_SIZE_TAG = `{${SHEET_MAIN_NS}}oleSize`;
|
|
258
|
+
const FILE_RECOVERY_PR_TAG = `{${SHEET_MAIN_NS}}fileRecoveryPr`;
|
|
259
|
+
const PIVOT_CACHES_TAG = `{${SHEET_MAIN_NS}}pivotCaches`;
|
|
260
|
+
const PIVOT_CACHE_TAG = `{${SHEET_MAIN_NS}}pivotCache`;
|
|
261
|
+
const EXTERNAL_REFERENCES_TAG = `{${SHEET_MAIN_NS}}externalReferences`;
|
|
262
|
+
const EXTERNAL_REFERENCE_TAG = `{${SHEET_MAIN_NS}}externalReference`;
|
|
263
|
+
const SMART_TAG_PR_TAG = `{${SHEET_MAIN_NS}}smartTagPr`;
|
|
264
|
+
const SMART_TAG_TYPES_TAG = `{${SHEET_MAIN_NS}}smartTagTypes`;
|
|
265
|
+
const SMART_TAG_TYPE_TAG = `{${SHEET_MAIN_NS}}smartTagType`;
|
|
266
|
+
const FUNCTION_GROUPS_TAG = `{${SHEET_MAIN_NS}}functionGroups`;
|
|
267
|
+
const FUNCTION_GROUP_TAG = `{${SHEET_MAIN_NS}}functionGroup`;
|
|
268
|
+
/**
|
|
269
|
+
* Parse the `<workbookPr date1904>` flag. Mac-origin workbooks set
|
|
270
|
+
* `date1904="true"`; everything else uses the Windows 1900 epoch. The value
|
|
271
|
+
* drives Date / Duration cell serial conversion in worksheet/writer.ts and
|
|
272
|
+
* reader.ts.
|
|
273
|
+
*/
|
|
274
|
+
function parseDate1904(workbookRoot) {
|
|
275
|
+
const pr = findChild(workbookRoot, WORKBOOK_PR_TAG);
|
|
276
|
+
if (!pr) return false;
|
|
277
|
+
const v = pr.attrs["date1904"];
|
|
278
|
+
return v === "1" || v === "true";
|
|
279
|
+
}
|
|
280
|
+
/** Extract the `<sheets>/<sheet>` entries from a parsed `xl/workbook.xml`. */
|
|
281
|
+
function parseSheetEntries(workbookRoot) {
|
|
282
|
+
const sheets = findChild(workbookRoot, SHEETS_TAG);
|
|
283
|
+
if (!sheets) return [];
|
|
284
|
+
const out = [];
|
|
285
|
+
for (const node of findChildren(sheets, SHEET_TAG)) {
|
|
286
|
+
const name = node.attrs["name"];
|
|
287
|
+
const sheetIdAttr = node.attrs["sheetId"];
|
|
288
|
+
const rId = node.attrs[RID_ATTR];
|
|
289
|
+
if (!name) throw new OpenXmlSchemaError("workbook.xml: <sheet> is missing 'name'");
|
|
290
|
+
if (!sheetIdAttr) throw new OpenXmlSchemaError(`workbook.xml: <sheet name="${name}"> is missing 'sheetId'`);
|
|
291
|
+
if (!rId) throw new OpenXmlSchemaError(`workbook.xml: <sheet name="${name}"> is missing 'r:id'`);
|
|
292
|
+
const sheetId = Number.parseInt(sheetIdAttr, 10);
|
|
293
|
+
if (!Number.isInteger(sheetId) || sheetId < 1) throw new OpenXmlSchemaError(`workbook.xml: <sheet name="${name}"> sheetId "${sheetIdAttr}" is not a positive integer`);
|
|
294
|
+
const stateAttr = node.attrs["state"];
|
|
295
|
+
let state = "visible";
|
|
296
|
+
if (stateAttr === "hidden" || stateAttr === "veryHidden") state = stateAttr;
|
|
297
|
+
out.push({
|
|
298
|
+
name,
|
|
299
|
+
sheetId,
|
|
300
|
+
rId,
|
|
301
|
+
state
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
return out;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Load a workbook from any {@link XlsxSource}. Currently produces a scaffold
|
|
308
|
+
* Workbook: each Worksheet is empty (no cells / styles / shared strings / theme
|
|
309
|
+
* yet). The next phase-3 iterations layer those in atop the same skeleton.
|
|
310
|
+
*/
|
|
311
|
+
async function loadWorkbook(source, opts = {}) {
|
|
312
|
+
const archive = await openZip(source, opts.decompressionLimits === void 0 ? {} : { decompressionLimits: opts.decompressionLimits });
|
|
313
|
+
try {
|
|
314
|
+
return loadWorkbookFromArchive(archive);
|
|
315
|
+
} finally {
|
|
316
|
+
archive.close();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/** Internal: same as {@link loadWorkbook} but operating on an already-opened archive. */
|
|
320
|
+
function loadWorkbookFromArchive(archive) {
|
|
321
|
+
if (!archive.has("[Content_Types].xml")) throw new OpenXmlSchemaError(`loadWorkbook: missing "${ARC_CONTENT_TYPES}"`);
|
|
322
|
+
const manifest = manifestFromBytes(archive.read(ARC_CONTENT_TYPES));
|
|
323
|
+
if (!archive.has(ARC_ROOT_RELS)) throw new OpenXmlSchemaError(`loadWorkbook: missing "${ARC_ROOT_RELS}"`);
|
|
324
|
+
const officeRel = relsFromBytes(archive.read(ARC_ROOT_RELS)).rels.find((r) => r.type === OFFICE_DOC_REL_TYPE);
|
|
325
|
+
if (!officeRel) throw new OpenXmlSchemaError("loadWorkbook: root rels missing officeDocument relationship");
|
|
326
|
+
const workbookPath = resolveRelTarget("", officeRel.target);
|
|
327
|
+
if (workbookPath !== ARC_WORKBOOK) {
|
|
328
|
+
if (!archive.has(workbookPath)) throw new OpenXmlSchemaError(`loadWorkbook: workbook part "${workbookPath}" not found in archive`);
|
|
329
|
+
}
|
|
330
|
+
const wbRoot = parseXml(archive.read(workbookPath));
|
|
331
|
+
if (parseQName(wbRoot.name).local !== "workbook") throw new OpenXmlSchemaError(`loadWorkbook: ${workbookPath} root is "${wbRoot.name}", expected workbook`);
|
|
332
|
+
const sheetEntries = parseSheetEntries(wbRoot);
|
|
333
|
+
const definedNamesFromXml = parseDefinedNames(wbRoot);
|
|
334
|
+
const wbRelsPath = relsPathFor(workbookPath);
|
|
335
|
+
if (sheetEntries.length > 0 && !archive.has(wbRelsPath)) throw new OpenXmlSchemaError(`loadWorkbook: workbook has sheets but rels part "${wbRelsPath}" is missing`);
|
|
336
|
+
const wbRels = archive.has(wbRelsPath) ? relsFromBytes(archive.read(wbRelsPath)) : { rels: [] };
|
|
337
|
+
let sharedStrings;
|
|
338
|
+
if (archive.has(ARC_SHARED_STRINGS)) sharedStrings = parseSharedStringsXml(archive.read(ARC_SHARED_STRINGS));
|
|
339
|
+
else {
|
|
340
|
+
const sstRel = wbRels.rels.find((r) => r.type === `${REL_NS}/sharedStrings`);
|
|
341
|
+
if (sstRel) {
|
|
342
|
+
const sstPath = resolveRelTarget(workbookPath, sstRel.target);
|
|
343
|
+
if (archive.has(sstPath)) sharedStrings = parseSharedStringsXml(archive.read(sstPath));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
const sst = (sharedStrings?.entries ?? []).map((e) => typeof e === "string" ? e : e.runs.map((r) => r.text).join(""));
|
|
347
|
+
let styles;
|
|
348
|
+
if (archive.has(ARC_STYLE)) styles = parseStylesheetXml(archive.read(ARC_STYLE));
|
|
349
|
+
else {
|
|
350
|
+
const stylesRel = wbRels.rels.find((r) => r.type === `${REL_NS}/styles`);
|
|
351
|
+
if (stylesRel) {
|
|
352
|
+
const stylesPath = resolveRelTarget(workbookPath, stylesRel.target);
|
|
353
|
+
if (archive.has(stylesPath)) styles = parseStylesheetXml(archive.read(stylesPath));
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const properties = archive.has(ARC_CORE) ? corePropsFromBytes(archive.read(ARC_CORE)) : void 0;
|
|
357
|
+
const appProperties = archive.has(ARC_APP) ? extendedPropsFromBytes(archive.read(ARC_APP)) : void 0;
|
|
358
|
+
const customProperties = archive.has(ARC_CUSTOM) ? customPropsFromBytes(archive.read(ARC_CUSTOM)) : void 0;
|
|
359
|
+
const themeXml = (() => {
|
|
360
|
+
if (archive.has(ARC_THEME)) return archive.read(ARC_THEME);
|
|
361
|
+
const themeRel = wbRels.rels.find((r) => r.type === `${REL_NS}/theme`);
|
|
362
|
+
if (themeRel) {
|
|
363
|
+
const themePath = resolveRelTarget(workbookPath, themeRel.target);
|
|
364
|
+
if (archive.has(themePath)) return archive.read(themePath);
|
|
365
|
+
}
|
|
366
|
+
})();
|
|
367
|
+
const wb = createWorkbook({ date1904: parseDate1904(wbRoot) });
|
|
368
|
+
if (styles) wb.styles = styles;
|
|
369
|
+
if (properties) wb.properties = properties;
|
|
370
|
+
if (appProperties) wb.appProperties = appProperties;
|
|
371
|
+
if (customProperties) wb.customProperties = customProperties;
|
|
372
|
+
if (themeXml) wb.themeXml = themeXml;
|
|
373
|
+
if (definedNamesFromXml.length > 0) wb.definedNames = definedNamesFromXml;
|
|
374
|
+
const seenTitles = /* @__PURE__ */ new Set();
|
|
375
|
+
for (const entry of sheetEntries) {
|
|
376
|
+
if (seenTitles.has(entry.name)) throw new OpenXmlSchemaError(`loadWorkbook: duplicate sheet name "${entry.name}"`);
|
|
377
|
+
seenTitles.add(entry.name);
|
|
378
|
+
const rel = findById(wbRels, entry.rId);
|
|
379
|
+
if (!rel) throw new OpenXmlSchemaError(`loadWorkbook: sheet "${entry.name}" rId "${entry.rId}" has no matching rels entry`);
|
|
380
|
+
const sheetPath = resolveRelTarget(workbookPath, rel.target);
|
|
381
|
+
if (!archive.has(sheetPath)) throw new OpenXmlSchemaError(`loadWorkbook: sheet part "${sheetPath}" not found in archive`);
|
|
382
|
+
const sheetRelsPath = relsPathFor(sheetPath);
|
|
383
|
+
const sheetRels = archive.has(sheetRelsPath) ? relsFromBytes(archive.read(sheetRelsPath)) : void 0;
|
|
384
|
+
const sheetRelsById = sheetRels ? indexRelsById(sheetRels) : void 0;
|
|
385
|
+
const loadTable = sheetRelsById ? (relId) => {
|
|
386
|
+
const tRel = sheetRelsById.get(relId);
|
|
387
|
+
if (!tRel) return void 0;
|
|
388
|
+
const tablePath = resolveRelTarget(sheetPath, tRel.target);
|
|
389
|
+
if (!archive.has(tablePath)) return void 0;
|
|
390
|
+
return parseTableXml(archive.read(tablePath));
|
|
391
|
+
} : void 0;
|
|
392
|
+
const loadComments = sheetRelsById ? (relId) => {
|
|
393
|
+
const cRel = sheetRelsById.get(relId);
|
|
394
|
+
if (!cRel) return void 0;
|
|
395
|
+
const cPath = resolveRelTarget(sheetPath, cRel.target);
|
|
396
|
+
if (!archive.has(cPath)) return void 0;
|
|
397
|
+
return parseCommentsXml(archive.read(cPath));
|
|
398
|
+
} : void 0;
|
|
399
|
+
const loadDrawing = sheetRelsById ? (relId) => {
|
|
400
|
+
const dRel = sheetRelsById.get(relId);
|
|
401
|
+
if (!dRel) return void 0;
|
|
402
|
+
const dPath = resolveRelTarget(sheetPath, dRel.target);
|
|
403
|
+
if (!archive.has(dPath)) return void 0;
|
|
404
|
+
const drawing = parseDrawingXml(archive.read(dPath));
|
|
405
|
+
const dRelsPath = relsPathFor(dPath);
|
|
406
|
+
if (archive.has(dRelsPath)) {
|
|
407
|
+
const dRelsById = indexRelsById(relsFromBytes(archive.read(dRelsPath)));
|
|
408
|
+
for (const item of drawing.items) if (item.content.kind === "chart") {
|
|
409
|
+
const chartRId = item.content.chart.rId;
|
|
410
|
+
if (!chartRId) continue;
|
|
411
|
+
const chartRel = dRelsById.get(chartRId);
|
|
412
|
+
if (!chartRel) continue;
|
|
413
|
+
const chartPath = resolveRelTarget(dPath, chartRel.target);
|
|
414
|
+
if (archive.has(chartPath)) {
|
|
415
|
+
const chartBytes = archive.read(chartPath);
|
|
416
|
+
if (isChartExBytes(chartBytes)) item.content.chart.cxSpace = parseChartExXml(chartBytes);
|
|
417
|
+
else {
|
|
418
|
+
const space = parseChartXml(chartBytes);
|
|
419
|
+
const userShapesRId = findUserShapesRId(chartBytes);
|
|
420
|
+
if (userShapesRId) {
|
|
421
|
+
const chartRelsPath = relsPathFor(chartPath);
|
|
422
|
+
if (archive.has(chartRelsPath)) {
|
|
423
|
+
const usRel = indexRelsById(relsFromBytes(archive.read(chartRelsPath))).get(userShapesRId);
|
|
424
|
+
if (usRel) {
|
|
425
|
+
const usPath = resolveRelTarget(chartPath, usRel.target);
|
|
426
|
+
if (archive.has(usPath)) try {
|
|
427
|
+
space.userShapes = parseUserShapesXml(archive.read(usPath));
|
|
428
|
+
} catch {}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
item.content.chart.space = space;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
} else if (item.content.kind === "picture") {
|
|
436
|
+
const picRId = item.content.picture.rId;
|
|
437
|
+
if (!picRId) continue;
|
|
438
|
+
const picRel = dRelsById.get(picRId);
|
|
439
|
+
if (!picRel) continue;
|
|
440
|
+
const imgPath = resolveRelTarget(dPath, picRel.target);
|
|
441
|
+
if (archive.has(imgPath)) try {
|
|
442
|
+
item.content.picture.image = loadImage(archive.read(imgPath));
|
|
443
|
+
} catch {}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return drawing;
|
|
447
|
+
} : void 0;
|
|
448
|
+
if (rel.type === `${REL_NS}/chartsheet`) {
|
|
449
|
+
const chartsheet = parseChartsheetXml(archive.read(sheetPath), entry.name);
|
|
450
|
+
if (sheetRels) {
|
|
451
|
+
const drawingRel = sheetRels.rels.find((r) => r.type === `${REL_NS}/drawing`);
|
|
452
|
+
if (drawingRel && loadDrawing) {
|
|
453
|
+
const d = loadDrawing(drawingRel.id);
|
|
454
|
+
if (d) chartsheet.drawing = d;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
const ref = {
|
|
458
|
+
kind: "chartsheet",
|
|
459
|
+
sheet: chartsheet,
|
|
460
|
+
sheetId: entry.sheetId,
|
|
461
|
+
state: entry.state,
|
|
462
|
+
rId: entry.rId
|
|
463
|
+
};
|
|
464
|
+
wb.sheets.push(ref);
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
const ws = parseWorksheetXml(archive.read(sheetPath), entry.name, {
|
|
468
|
+
sharedStrings: sst,
|
|
469
|
+
...sheetRels ? { rels: sheetRels } : {},
|
|
470
|
+
...loadTable ? { loadTable } : {},
|
|
471
|
+
...loadComments ? { loadComments } : {},
|
|
472
|
+
...loadDrawing ? { loadDrawing } : {}
|
|
473
|
+
});
|
|
474
|
+
if (sheetRels) {
|
|
475
|
+
const extras = captureSheetRelsExtras(sheetRels);
|
|
476
|
+
if (extras.length > 0) ws.relsExtras = extras;
|
|
477
|
+
}
|
|
478
|
+
const ref = {
|
|
479
|
+
kind: "worksheet",
|
|
480
|
+
sheet: ws,
|
|
481
|
+
sheetId: entry.sheetId,
|
|
482
|
+
state: entry.state,
|
|
483
|
+
rId: entry.rId
|
|
484
|
+
};
|
|
485
|
+
wb.sheets.push(ref);
|
|
486
|
+
}
|
|
487
|
+
captureWorkbookXmlExtras(wbRoot, wb);
|
|
488
|
+
captureWorkbookRelsExtras(wbRels, wb);
|
|
489
|
+
capturePassthrough(archive, manifest, wb);
|
|
490
|
+
return wb;
|
|
491
|
+
}
|
|
492
|
+
const SHEET_MODELED_REL_TYPES = new Set([
|
|
493
|
+
`${REL_NS}/hyperlink`,
|
|
494
|
+
`${REL_NS}/table`,
|
|
495
|
+
`${REL_NS}/comments`,
|
|
496
|
+
`${REL_NS}/vmlDrawing`,
|
|
497
|
+
`${REL_NS}/drawing`
|
|
498
|
+
]);
|
|
499
|
+
/**
|
|
500
|
+
* Capture per-sheet rels entries that don't match a modeled type. The writer
|
|
501
|
+
* re-emits these verbatim alongside the freshly allocated modeled rels so
|
|
502
|
+
* captured passthrough parts (pivotTable / queryTable / slicer /
|
|
503
|
+
* printerSettings / oleObject / customProperty / threadedComment) remain
|
|
504
|
+
* reachable from the worksheet after a round-trip.
|
|
505
|
+
*/
|
|
506
|
+
function captureSheetRelsExtras(sheetRels) {
|
|
507
|
+
const extras = [];
|
|
508
|
+
for (const rel of sheetRels.rels) {
|
|
509
|
+
if (SHEET_MODELED_REL_TYPES.has(rel.type)) continue;
|
|
510
|
+
extras.push({
|
|
511
|
+
id: rel.id,
|
|
512
|
+
type: rel.type,
|
|
513
|
+
target: rel.target
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
return extras;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Walk top-level children of `<workbook>` and split anything that isn't
|
|
520
|
+
* `<sheets>` or `<definedNames>` into the before/after halves the writer
|
|
521
|
+
* inserts around the modeled elements. Order is preserved within each half so
|
|
522
|
+
* things like `<fileVersion>`, `<workbookPr>`, `<bookViews>`, `<calcPr>`,
|
|
523
|
+
* `<pivotCaches>`, `<extLst>` round-trip in document order.
|
|
524
|
+
*/
|
|
525
|
+
function captureWorkbookXmlExtras(wbRoot, wb) {
|
|
526
|
+
const beforeSheets = [];
|
|
527
|
+
const afterSheets = [];
|
|
528
|
+
let seenSheets = false;
|
|
529
|
+
for (const child of wbRoot.children) {
|
|
530
|
+
if (child.name === SHEETS_TAG) {
|
|
531
|
+
seenSheets = true;
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
if (child.name === DEFINED_NAMES_TAG) continue;
|
|
535
|
+
if (child.name === WORKBOOK_PROTECTION_TAG) {
|
|
536
|
+
wb.workbookProtection = parseWorkbookProtection(child);
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
if (child.name === WORKBOOK_PR_TAG) {
|
|
540
|
+
const wp = parseWorkbookProperties(child);
|
|
541
|
+
if (wp) wb.workbookProperties = wp;
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
if (child.name === FILE_SHARING_TAG) {
|
|
545
|
+
const fs = {};
|
|
546
|
+
const a = child.attrs;
|
|
547
|
+
const flag = (raw) => {
|
|
548
|
+
if (raw === "1" || raw === "true") return true;
|
|
549
|
+
if (raw === "0" || raw === "false") return false;
|
|
550
|
+
};
|
|
551
|
+
const ror = flag(a["readOnlyRecommended"]);
|
|
552
|
+
if (ror !== void 0) fs.readOnlyRecommended = ror;
|
|
553
|
+
if (a["userName"] !== void 0) fs.userName = a["userName"];
|
|
554
|
+
if (a["reservationPassword"] !== void 0) fs.reservationPassword = a["reservationPassword"];
|
|
555
|
+
if (a["algorithmName"] !== void 0) fs.algorithmName = a["algorithmName"];
|
|
556
|
+
if (a["hashValue"] !== void 0) fs.hashValue = a["hashValue"];
|
|
557
|
+
if (a["saltValue"] !== void 0) fs.saltValue = a["saltValue"];
|
|
558
|
+
if (a["spinCount"] !== void 0) {
|
|
559
|
+
const n = Number.parseInt(a["spinCount"], 10);
|
|
560
|
+
if (Number.isInteger(n)) fs.spinCount = n;
|
|
561
|
+
}
|
|
562
|
+
if (Object.keys(fs).length > 0) wb.fileSharing = fs;
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
if (child.name === FILE_VERSION_TAG) {
|
|
566
|
+
const fv = {};
|
|
567
|
+
if (child.attrs["appName"] !== void 0) fv.appName = child.attrs["appName"];
|
|
568
|
+
if (child.attrs["lastEdited"] !== void 0) fv.lastEdited = child.attrs["lastEdited"];
|
|
569
|
+
if (child.attrs["lowestEdited"] !== void 0) fv.lowestEdited = child.attrs["lowestEdited"];
|
|
570
|
+
if (child.attrs["rupBuild"] !== void 0) fv.rupBuild = child.attrs["rupBuild"];
|
|
571
|
+
if (child.attrs["codeName"] !== void 0) fv.codeName = child.attrs["codeName"];
|
|
572
|
+
if (Object.keys(fv).length > 0) wb.fileVersion = fv;
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
if (child.name === BOOK_VIEWS_TAG) {
|
|
576
|
+
const views = [];
|
|
577
|
+
for (const v of findChildren(child, WORKBOOK_VIEW_TAG)) views.push(parseWorkbookView(v));
|
|
578
|
+
if (views.length > 0) wb.bookViews = views;
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
if (child.name === CUSTOM_WORKBOOK_VIEWS_TAG) {
|
|
582
|
+
const cws = [];
|
|
583
|
+
for (const v of findChildren(child, CUSTOM_WORKBOOK_VIEW_TAG)) {
|
|
584
|
+
const parsed = parseCustomWorkbookView(v);
|
|
585
|
+
if (parsed) cws.push(parsed);
|
|
586
|
+
}
|
|
587
|
+
if (cws.length > 0) wb.customWorkbookViews = cws;
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
if (child.name === CALC_PR_TAG) {
|
|
591
|
+
const cp = parseCalcProperties(child);
|
|
592
|
+
if (cp) wb.calcProperties = cp;
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
if (child.name === OLE_SIZE_TAG) {
|
|
596
|
+
const ref = child.attrs["ref"];
|
|
597
|
+
if (ref) wb.oleSize = ref;
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
if (child.name === SMART_TAG_PR_TAG) {
|
|
601
|
+
const out = {};
|
|
602
|
+
const a = child.attrs;
|
|
603
|
+
if (a["embed"] === "1" || a["embed"] === "true") out.embed = true;
|
|
604
|
+
else if (a["embed"] === "0" || a["embed"] === "false") out.embed = false;
|
|
605
|
+
if (a["show"] === "all" || a["show"] === "noIndicator") out.show = a["show"];
|
|
606
|
+
if (Object.keys(out).length > 0) wb.smartTagPr = out;
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
if (child.name === SMART_TAG_TYPES_TAG) {
|
|
610
|
+
const tags = [];
|
|
611
|
+
for (const t of findChildren(child, SMART_TAG_TYPE_TAG)) {
|
|
612
|
+
const entry = {};
|
|
613
|
+
if (t.attrs["namespaceUri"] !== void 0) entry.namespaceUri = t.attrs["namespaceUri"];
|
|
614
|
+
if (t.attrs["name"] !== void 0) entry.name = t.attrs["name"];
|
|
615
|
+
if (t.attrs["url"] !== void 0) entry.url = t.attrs["url"];
|
|
616
|
+
if (Object.keys(entry).length > 0) tags.push(entry);
|
|
617
|
+
}
|
|
618
|
+
if (tags.length > 0) wb.smartTagTypes = tags;
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
if (child.name === FUNCTION_GROUPS_TAG) {
|
|
622
|
+
const fg = { groups: [] };
|
|
623
|
+
const bicgRaw = child.attrs["builtInGroupCount"];
|
|
624
|
+
if (bicgRaw !== void 0) {
|
|
625
|
+
const n = Number.parseInt(bicgRaw, 10);
|
|
626
|
+
if (Number.isInteger(n)) fg.builtInGroupCount = n;
|
|
627
|
+
}
|
|
628
|
+
for (const g of findChildren(child, FUNCTION_GROUP_TAG)) {
|
|
629
|
+
const name = g.attrs["name"];
|
|
630
|
+
if (name) fg.groups.push({ name });
|
|
631
|
+
}
|
|
632
|
+
if (fg.groups.length > 0 || fg.builtInGroupCount !== void 0) wb.functionGroups = fg;
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
if (child.name === EXTERNAL_REFERENCES_TAG) {
|
|
636
|
+
const refs = [];
|
|
637
|
+
for (const er of findChildren(child, EXTERNAL_REFERENCE_TAG)) {
|
|
638
|
+
const rId = er.attrs[`{${REL_NS}}id`];
|
|
639
|
+
if (rId) refs.push({ rId });
|
|
640
|
+
}
|
|
641
|
+
if (refs.length > 0) wb.externalReferences = refs;
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
if (child.name === PIVOT_CACHES_TAG) {
|
|
645
|
+
const caches = [];
|
|
646
|
+
for (const pc of findChildren(child, PIVOT_CACHE_TAG)) {
|
|
647
|
+
const cacheIdAttr = pc.attrs["cacheId"];
|
|
648
|
+
const rId = pc.attrs[`{${REL_NS}}id`];
|
|
649
|
+
if (cacheIdAttr === void 0 || !rId) continue;
|
|
650
|
+
const cacheId = Number.parseInt(cacheIdAttr, 10);
|
|
651
|
+
if (!Number.isInteger(cacheId)) continue;
|
|
652
|
+
caches.push({
|
|
653
|
+
cacheId,
|
|
654
|
+
rId
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
if (caches.length > 0) wb.pivotCaches = caches;
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
if (child.name === FILE_RECOVERY_PR_TAG) {
|
|
661
|
+
const fp = {};
|
|
662
|
+
const a = child.attrs;
|
|
663
|
+
const flag = (raw) => {
|
|
664
|
+
if (raw === "1" || raw === "true") return true;
|
|
665
|
+
if (raw === "0" || raw === "false") return false;
|
|
666
|
+
};
|
|
667
|
+
const ar = flag(a["autoRecover"]);
|
|
668
|
+
if (ar !== void 0) fp.autoRecover = ar;
|
|
669
|
+
const cs = flag(a["crashSave"]);
|
|
670
|
+
if (cs !== void 0) fp.crashSave = cs;
|
|
671
|
+
const del = flag(a["dataExtractLoad"]);
|
|
672
|
+
if (del !== void 0) fp.dataExtractLoad = del;
|
|
673
|
+
const rl = flag(a["repairLoad"]);
|
|
674
|
+
if (rl !== void 0) fp.repairLoad = rl;
|
|
675
|
+
if (Object.keys(fp).length > 0) wb.fileRecoveryPr = fp;
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
if (seenSheets) afterSheets.push(child);
|
|
679
|
+
else beforeSheets.push(child);
|
|
680
|
+
}
|
|
681
|
+
if (beforeSheets.length > 0 || afterSheets.length > 0) wb.workbookXmlExtras = {
|
|
682
|
+
beforeSheets,
|
|
683
|
+
afterSheets
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
const SHOW_OBJECTS_MODES = [
|
|
687
|
+
"all",
|
|
688
|
+
"placeholders",
|
|
689
|
+
"none"
|
|
690
|
+
];
|
|
691
|
+
const UPDATE_LINKS_MODES = [
|
|
692
|
+
"userSet",
|
|
693
|
+
"never",
|
|
694
|
+
"always"
|
|
695
|
+
];
|
|
696
|
+
const parseWorkbookProperties = (node) => {
|
|
697
|
+
const out = {};
|
|
698
|
+
const a = node.attrs;
|
|
699
|
+
const flag = (raw) => {
|
|
700
|
+
if (raw === "1" || raw === "true") return true;
|
|
701
|
+
if (raw === "0" || raw === "false") return false;
|
|
702
|
+
};
|
|
703
|
+
const intAttr = (k) => {
|
|
704
|
+
if (a[k] === void 0) return void 0;
|
|
705
|
+
const n = Number.parseInt(a[k], 10);
|
|
706
|
+
return Number.isInteger(n) ? n : void 0;
|
|
707
|
+
};
|
|
708
|
+
for (const k of [
|
|
709
|
+
"date1904",
|
|
710
|
+
"dateCompatibility",
|
|
711
|
+
"showBorderUnselectedTables",
|
|
712
|
+
"filterPrivacy",
|
|
713
|
+
"promptedSolutions",
|
|
714
|
+
"showInkAnnotation",
|
|
715
|
+
"backupFile",
|
|
716
|
+
"saveExternalLinkValues",
|
|
717
|
+
"hidePivotFieldList",
|
|
718
|
+
"showPivotChartFilter",
|
|
719
|
+
"allowRefreshQuery",
|
|
720
|
+
"publishItems",
|
|
721
|
+
"checkCompatibility",
|
|
722
|
+
"autoCompressPictures",
|
|
723
|
+
"refreshAllConnections"
|
|
724
|
+
]) {
|
|
725
|
+
const v = flag(a[k]);
|
|
726
|
+
if (v !== void 0) out[k] = v;
|
|
727
|
+
}
|
|
728
|
+
const showObjects = a["showObjects"];
|
|
729
|
+
if (showObjects && SHOW_OBJECTS_MODES.includes(showObjects)) out.showObjects = showObjects;
|
|
730
|
+
const updateLinks = a["updateLinks"];
|
|
731
|
+
if (updateLinks && UPDATE_LINKS_MODES.includes(updateLinks)) out.updateLinks = updateLinks;
|
|
732
|
+
if (a["codeName"] !== void 0) out.codeName = a["codeName"];
|
|
733
|
+
const dtv = intAttr("defaultThemeVersion");
|
|
734
|
+
if (dtv !== void 0) out.defaultThemeVersion = dtv;
|
|
735
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
736
|
+
};
|
|
737
|
+
const CALC_MODES = [
|
|
738
|
+
"manual",
|
|
739
|
+
"auto",
|
|
740
|
+
"autoNoTable"
|
|
741
|
+
];
|
|
742
|
+
const REF_MODES = ["A1", "R1C1"];
|
|
743
|
+
const parseCalcProperties = (node) => {
|
|
744
|
+
const out = {};
|
|
745
|
+
const a = node.attrs;
|
|
746
|
+
const flag = (raw) => {
|
|
747
|
+
if (raw === "1" || raw === "true") return true;
|
|
748
|
+
if (raw === "0" || raw === "false") return false;
|
|
749
|
+
};
|
|
750
|
+
const intAttr = (k) => {
|
|
751
|
+
if (a[k] === void 0) return void 0;
|
|
752
|
+
const n = Number.parseInt(a[k], 10);
|
|
753
|
+
return Number.isInteger(n) ? n : void 0;
|
|
754
|
+
};
|
|
755
|
+
const floatAttr = (k) => {
|
|
756
|
+
if (a[k] === void 0) return void 0;
|
|
757
|
+
const n = Number.parseFloat(a[k]);
|
|
758
|
+
return Number.isFinite(n) ? n : void 0;
|
|
759
|
+
};
|
|
760
|
+
const calcId = intAttr("calcId");
|
|
761
|
+
if (calcId !== void 0) out.calcId = calcId;
|
|
762
|
+
const calcMode = a["calcMode"];
|
|
763
|
+
if (calcMode && CALC_MODES.includes(calcMode)) out.calcMode = calcMode;
|
|
764
|
+
const fcol = flag(a["fullCalcOnLoad"]);
|
|
765
|
+
if (fcol !== void 0) out.fullCalcOnLoad = fcol;
|
|
766
|
+
const refMode = a["refMode"];
|
|
767
|
+
if (refMode && REF_MODES.includes(refMode)) out.refMode = refMode;
|
|
768
|
+
const iterate = flag(a["iterate"]);
|
|
769
|
+
if (iterate !== void 0) out.iterate = iterate;
|
|
770
|
+
const iterateCount = intAttr("iterateCount");
|
|
771
|
+
if (iterateCount !== void 0) out.iterateCount = iterateCount;
|
|
772
|
+
const iterateDelta = floatAttr("iterateDelta");
|
|
773
|
+
if (iterateDelta !== void 0) out.iterateDelta = iterateDelta;
|
|
774
|
+
const fullPrecision = flag(a["fullPrecision"]);
|
|
775
|
+
if (fullPrecision !== void 0) out.fullPrecision = fullPrecision;
|
|
776
|
+
const calcCompleted = flag(a["calcCompleted"]);
|
|
777
|
+
if (calcCompleted !== void 0) out.calcCompleted = calcCompleted;
|
|
778
|
+
const calcOnSave = flag(a["calcOnSave"]);
|
|
779
|
+
if (calcOnSave !== void 0) out.calcOnSave = calcOnSave;
|
|
780
|
+
const concurrentCalc = flag(a["concurrentCalc"]);
|
|
781
|
+
if (concurrentCalc !== void 0) out.concurrentCalc = concurrentCalc;
|
|
782
|
+
const concurrentManualCount = intAttr("concurrentManualCount");
|
|
783
|
+
if (concurrentManualCount !== void 0) out.concurrentManualCount = concurrentManualCount;
|
|
784
|
+
const forceFullCalc = flag(a["forceFullCalc"]);
|
|
785
|
+
if (forceFullCalc !== void 0) out.forceFullCalc = forceFullCalc;
|
|
786
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
787
|
+
};
|
|
788
|
+
const SHOW_COMMENTS_MODES = [
|
|
789
|
+
"commNone",
|
|
790
|
+
"commIndicator",
|
|
791
|
+
"commIndAndComment"
|
|
792
|
+
];
|
|
793
|
+
const SHOW_OBJECTS_CV_MODES = [
|
|
794
|
+
"all",
|
|
795
|
+
"placeholders",
|
|
796
|
+
"none"
|
|
797
|
+
];
|
|
798
|
+
const parseCustomWorkbookView = (node) => {
|
|
799
|
+
const a = node.attrs;
|
|
800
|
+
const name = a["name"];
|
|
801
|
+
const guid = a["guid"];
|
|
802
|
+
if (!name || !guid) return void 0;
|
|
803
|
+
const flag = (raw) => {
|
|
804
|
+
if (raw === "1" || raw === "true") return true;
|
|
805
|
+
if (raw === "0" || raw === "false") return false;
|
|
806
|
+
};
|
|
807
|
+
const intAttr = (k) => {
|
|
808
|
+
if (a[k] === void 0) return void 0;
|
|
809
|
+
const n = Number.parseInt(a[k], 10);
|
|
810
|
+
return Number.isInteger(n) ? n : void 0;
|
|
811
|
+
};
|
|
812
|
+
const out = {
|
|
813
|
+
name,
|
|
814
|
+
guid,
|
|
815
|
+
windowWidth: intAttr("windowWidth") ?? 0,
|
|
816
|
+
windowHeight: intAttr("windowHeight") ?? 0,
|
|
817
|
+
activeSheetId: intAttr("activeSheetId") ?? 0
|
|
818
|
+
};
|
|
819
|
+
for (const k of [
|
|
820
|
+
"autoUpdate",
|
|
821
|
+
"changesSavedWin",
|
|
822
|
+
"onlySync",
|
|
823
|
+
"personalView",
|
|
824
|
+
"includePrintSettings",
|
|
825
|
+
"includeHiddenRowCol",
|
|
826
|
+
"maximized",
|
|
827
|
+
"minimized",
|
|
828
|
+
"showHorizontalScroll",
|
|
829
|
+
"showVerticalScroll",
|
|
830
|
+
"showSheetTabs",
|
|
831
|
+
"showFormulaBar",
|
|
832
|
+
"showStatusbar"
|
|
833
|
+
]) {
|
|
834
|
+
const v = flag(a[k]);
|
|
835
|
+
if (v !== void 0) out[k] = v;
|
|
836
|
+
}
|
|
837
|
+
for (const k of [
|
|
838
|
+
"mergeInterval",
|
|
839
|
+
"xWindow",
|
|
840
|
+
"yWindow",
|
|
841
|
+
"tabRatio"
|
|
842
|
+
]) {
|
|
843
|
+
const v = intAttr(k);
|
|
844
|
+
if (v !== void 0) out[k] = v;
|
|
845
|
+
}
|
|
846
|
+
const sc = a["showComments"];
|
|
847
|
+
if (sc && SHOW_COMMENTS_MODES.includes(sc)) out.showComments = sc;
|
|
848
|
+
const so = a["showObjects"];
|
|
849
|
+
if (so && SHOW_OBJECTS_CV_MODES.includes(so)) out.showObjects = so;
|
|
850
|
+
return out;
|
|
851
|
+
};
|
|
852
|
+
const VISIBILITIES = [
|
|
853
|
+
"visible",
|
|
854
|
+
"hidden",
|
|
855
|
+
"veryHidden"
|
|
856
|
+
];
|
|
857
|
+
const parseWorkbookView = (node) => {
|
|
858
|
+
const out = {};
|
|
859
|
+
const a = node.attrs;
|
|
860
|
+
const flag = (raw) => {
|
|
861
|
+
if (raw === "1" || raw === "true") return true;
|
|
862
|
+
if (raw === "0" || raw === "false") return false;
|
|
863
|
+
};
|
|
864
|
+
const intAttr = (k) => {
|
|
865
|
+
if (a[k] === void 0) return void 0;
|
|
866
|
+
const n = Number.parseInt(a[k], 10);
|
|
867
|
+
return Number.isInteger(n) ? n : void 0;
|
|
868
|
+
};
|
|
869
|
+
const visibility = a["visibility"];
|
|
870
|
+
if (visibility && VISIBILITIES.includes(visibility)) out.visibility = visibility;
|
|
871
|
+
const minimized = flag(a["minimized"]);
|
|
872
|
+
if (minimized !== void 0) out.minimized = minimized;
|
|
873
|
+
const shScroll = flag(a["showHorizontalScroll"]);
|
|
874
|
+
if (shScroll !== void 0) out.showHorizontalScroll = shScroll;
|
|
875
|
+
const svScroll = flag(a["showVerticalScroll"]);
|
|
876
|
+
if (svScroll !== void 0) out.showVerticalScroll = svScroll;
|
|
877
|
+
const sst = flag(a["showSheetTabs"]);
|
|
878
|
+
if (sst !== void 0) out.showSheetTabs = sst;
|
|
879
|
+
const xWindow = intAttr("xWindow");
|
|
880
|
+
if (xWindow !== void 0) out.xWindow = xWindow;
|
|
881
|
+
const yWindow = intAttr("yWindow");
|
|
882
|
+
if (yWindow !== void 0) out.yWindow = yWindow;
|
|
883
|
+
const ww = intAttr("windowWidth");
|
|
884
|
+
if (ww !== void 0) out.windowWidth = ww;
|
|
885
|
+
const wh = intAttr("windowHeight");
|
|
886
|
+
if (wh !== void 0) out.windowHeight = wh;
|
|
887
|
+
const tr = intAttr("tabRatio");
|
|
888
|
+
if (tr !== void 0) out.tabRatio = tr;
|
|
889
|
+
const fs = intAttr("firstSheet");
|
|
890
|
+
if (fs !== void 0) out.firstSheet = fs;
|
|
891
|
+
const at = intAttr("activeTab");
|
|
892
|
+
if (at !== void 0) out.activeTab = at;
|
|
893
|
+
const adg = flag(a["autoFilterDateGrouping"]);
|
|
894
|
+
if (adg !== void 0) out.autoFilterDateGrouping = adg;
|
|
895
|
+
return out;
|
|
896
|
+
};
|
|
897
|
+
const parseWorkbookProtection = (node) => {
|
|
898
|
+
const out = {};
|
|
899
|
+
const a = node.attrs;
|
|
900
|
+
const flag = (raw) => {
|
|
901
|
+
if (raw === "1" || raw === "true") return true;
|
|
902
|
+
if (raw === "0" || raw === "false") return false;
|
|
903
|
+
};
|
|
904
|
+
if (a["workbookPassword"] !== void 0) out.workbookPassword = a["workbookPassword"];
|
|
905
|
+
if (a["workbookPasswordCharacterSet"] !== void 0) out.workbookPasswordCharacterSet = a["workbookPasswordCharacterSet"];
|
|
906
|
+
if (a["workbookAlgorithmName"] !== void 0) out.workbookAlgorithmName = a["workbookAlgorithmName"];
|
|
907
|
+
if (a["workbookHashValue"] !== void 0) out.workbookHashValue = a["workbookHashValue"];
|
|
908
|
+
if (a["workbookSaltValue"] !== void 0) out.workbookSaltValue = a["workbookSaltValue"];
|
|
909
|
+
if (a["workbookSpinCount"] !== void 0) {
|
|
910
|
+
const n = Number.parseInt(a["workbookSpinCount"], 10);
|
|
911
|
+
if (Number.isInteger(n)) out.workbookSpinCount = n;
|
|
912
|
+
}
|
|
913
|
+
if (a["revisionsPassword"] !== void 0) out.revisionsPassword = a["revisionsPassword"];
|
|
914
|
+
if (a["revisionsPasswordCharacterSet"] !== void 0) out.revisionsPasswordCharacterSet = a["revisionsPasswordCharacterSet"];
|
|
915
|
+
if (a["revisionsAlgorithmName"] !== void 0) out.revisionsAlgorithmName = a["revisionsAlgorithmName"];
|
|
916
|
+
if (a["revisionsHashValue"] !== void 0) out.revisionsHashValue = a["revisionsHashValue"];
|
|
917
|
+
if (a["revisionsSaltValue"] !== void 0) out.revisionsSaltValue = a["revisionsSaltValue"];
|
|
918
|
+
if (a["revisionsSpinCount"] !== void 0) {
|
|
919
|
+
const n = Number.parseInt(a["revisionsSpinCount"], 10);
|
|
920
|
+
if (Number.isInteger(n)) out.revisionsSpinCount = n;
|
|
921
|
+
}
|
|
922
|
+
const ls = flag(a["lockStructure"]);
|
|
923
|
+
if (ls !== void 0) out.lockStructure = ls;
|
|
924
|
+
const lw = flag(a["lockWindows"]);
|
|
925
|
+
if (lw !== void 0) out.lockWindows = lw;
|
|
926
|
+
const lr = flag(a["lockRevision"]);
|
|
927
|
+
if (lr !== void 0) out.lockRevision = lr;
|
|
928
|
+
return out;
|
|
929
|
+
};
|
|
930
|
+
/**
|
|
931
|
+
* Capture workbook-rels entries that don't match a modeled type so the writer
|
|
932
|
+
* can re-emit them with their original Id (and any captured `<pivotCaches
|
|
933
|
+
* r:id="…"/>` etc. still resolves after a round-trip). Modeled non-sheet rels
|
|
934
|
+
* (sst / styles / theme / vbaProject) keep their original Id via
|
|
935
|
+
* `wb.workbookRelOriginalIds` so the writer can prefer those over freshly
|
|
936
|
+
* allocated ones.
|
|
937
|
+
*/
|
|
938
|
+
function captureWorkbookRelsExtras(wbRels, wb) {
|
|
939
|
+
const SHEET_RELS = new Set([`${REL_NS}/worksheet`, `${REL_NS}/chartsheet`]);
|
|
940
|
+
const original = {};
|
|
941
|
+
const extras = [];
|
|
942
|
+
for (const rel of wbRels.rels) {
|
|
943
|
+
if (SHEET_RELS.has(rel.type)) continue;
|
|
944
|
+
if (rel.type === `${REL_NS}/sharedStrings`) {
|
|
945
|
+
original.sharedStrings = rel.id;
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
if (rel.type === `${REL_NS}/styles`) {
|
|
949
|
+
original.styles = rel.id;
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
if (rel.type === `${REL_NS}/theme`) {
|
|
953
|
+
original.theme = rel.id;
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
956
|
+
if (rel.type === `${REL_NS}/vbaProject`) {
|
|
957
|
+
original.vbaProject = rel.id;
|
|
958
|
+
continue;
|
|
959
|
+
}
|
|
960
|
+
extras.push({
|
|
961
|
+
id: rel.id,
|
|
962
|
+
type: rel.type,
|
|
963
|
+
target: rel.target
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
if (Object.keys(original).length > 0) wb.workbookRelOriginalIds = original;
|
|
967
|
+
if (extras.length > 0) wb.workbookRelsExtras = extras;
|
|
968
|
+
}
|
|
969
|
+
const PASSTHROUGH_PREFIXES = [
|
|
970
|
+
"xl/activeX/",
|
|
971
|
+
"xl/ctrlProps/",
|
|
972
|
+
"xl/embeddings/",
|
|
973
|
+
"xl/externalLinks/",
|
|
974
|
+
"xl/model/",
|
|
975
|
+
"xl/persons/",
|
|
976
|
+
"xl/pivotCache/",
|
|
977
|
+
"xl/pivotTables/",
|
|
978
|
+
"xl/printerSettings/",
|
|
979
|
+
"xl/queryTables/",
|
|
980
|
+
"xl/richData/",
|
|
981
|
+
"xl/slicerCaches/",
|
|
982
|
+
"xl/slicers/",
|
|
983
|
+
"xl/threadedComments/",
|
|
984
|
+
"xl/timelineCaches/",
|
|
985
|
+
"xl/timelines/",
|
|
986
|
+
"xl/workbookCache/",
|
|
987
|
+
"customUI/",
|
|
988
|
+
"customXml/"
|
|
989
|
+
];
|
|
990
|
+
/**
|
|
991
|
+
* Excel emits both form-control VMLs and comment VMLs at
|
|
992
|
+
* `xl/drawings/vmlDrawingN.vml`. Filename alone can't tell them apart, but
|
|
993
|
+
* ECMA-376 §17.18.51 requires comment shapes to carry `<x:ClientData
|
|
994
|
+
* ObjectType="Note">`, so a byte-search for that marker decides which path the
|
|
995
|
+
* file belongs on:
|
|
996
|
+
*
|
|
997
|
+
* - With marker → comment VML; the comments writer regenerates
|
|
998
|
+
* these from `Worksheet.legacyComments`, so we must not capture them as
|
|
999
|
+
* passthrough (would duplicate the entry on save).
|
|
1000
|
+
* - Without marker → control / OLE / shape VML; capture as
|
|
1001
|
+
* passthrough so form controls survive load → save → load.
|
|
1002
|
+
*/
|
|
1003
|
+
const COMMENT_VML_MARKER = "ObjectType=\"Note\"";
|
|
1004
|
+
const LATIN1_DECODER = new TextDecoder("latin1");
|
|
1005
|
+
const isVmlDrawing = (path) => path.startsWith("xl/drawings/") && path.endsWith(".vml");
|
|
1006
|
+
const containsCommentMarker = (bytes) => LATIN1_DECODER.decode(bytes).includes(COMMENT_VML_MARKER);
|
|
1007
|
+
/**
|
|
1008
|
+
* Top-level xl/*.xml files that aren't modeled but Excel relies on (or
|
|
1009
|
+
* harmlessly preserves). Captured by exact path; their content types come
|
|
1010
|
+
* through the manifest Override map.
|
|
1011
|
+
*
|
|
1012
|
+
* - `xl/calcChain.xml` — calculation order hint (Excel rebuilds
|
|
1013
|
+
* it on first open if missing, but losing it forces a full recalc).
|
|
1014
|
+
* - `xl/connections.xml` — external data connection metadata.
|
|
1015
|
+
* - `xl/persons/` — threaded-comment author registry
|
|
1016
|
+
* (Excel 365). Captured under the prefix list below.
|
|
1017
|
+
* - `xl/metadata.xml` — Excel 365 dynamic-array cell metadata.
|
|
1018
|
+
* - `xl/SheetMetadata.xml` — variant casing of the same.
|
|
1019
|
+
*/
|
|
1020
|
+
const PASSTHROUGH_EXACT_PATHS = new Set([
|
|
1021
|
+
"xl/calcChain.xml",
|
|
1022
|
+
"xl/connections.xml",
|
|
1023
|
+
"xl/metadata.xml",
|
|
1024
|
+
"xl/SheetMetadata.xml",
|
|
1025
|
+
"docProps/thumbnail.jpeg",
|
|
1026
|
+
"docProps/thumbnail.jpg",
|
|
1027
|
+
"docProps/thumbnail.png",
|
|
1028
|
+
"docProps/thumbnail.wmf",
|
|
1029
|
+
"docProps/thumbnail.emf"
|
|
1030
|
+
]);
|
|
1031
|
+
const isPassthroughPath = (path, bytes) => {
|
|
1032
|
+
if (PASSTHROUGH_EXACT_PATHS.has(path)) return true;
|
|
1033
|
+
if (PASSTHROUGH_PREFIXES.some((p) => path.startsWith(p))) return true;
|
|
1034
|
+
if (isVmlDrawing(path) && bytes) return !containsCommentMarker(bytes);
|
|
1035
|
+
return false;
|
|
1036
|
+
};
|
|
1037
|
+
/**
|
|
1038
|
+
* Walk the archive after the modeled parts are loaded and capture any remaining
|
|
1039
|
+
* content into `wb.passthrough`. The dedicated VBA project binaries land on
|
|
1040
|
+
* their own slots so the writer can promote the workbook content type to xlsm.
|
|
1041
|
+
*/
|
|
1042
|
+
function capturePassthrough(archive, manifest, wb) {
|
|
1043
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
1044
|
+
for (const o of manifest.overrides) overrides.set(o.partName.replace(/^\//, ""), o.contentType);
|
|
1045
|
+
for (const path of archive.list()) {
|
|
1046
|
+
if (path === "xl/vbaProject.bin") {
|
|
1047
|
+
wb.vbaProject = archive.read(path);
|
|
1048
|
+
continue;
|
|
1049
|
+
}
|
|
1050
|
+
if (path === "xl/vbaProjectSignature.bin") {
|
|
1051
|
+
wb.vbaSignature = archive.read(path);
|
|
1052
|
+
continue;
|
|
1053
|
+
}
|
|
1054
|
+
let cached;
|
|
1055
|
+
if (isVmlDrawing(path)) cached = archive.read(path);
|
|
1056
|
+
if (!isPassthroughPath(path, cached)) continue;
|
|
1057
|
+
if (!wb.passthrough) wb.passthrough = /* @__PURE__ */ new Map();
|
|
1058
|
+
wb.passthrough.set(path, cached ?? archive.read(path));
|
|
1059
|
+
const ct = overrides.get(path);
|
|
1060
|
+
if (ct !== void 0) {
|
|
1061
|
+
if (!wb.passthroughContentTypes) wb.passthroughContentTypes = /* @__PURE__ */ new Map();
|
|
1062
|
+
wb.passthroughContentTypes.set(path, ct);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
//#endregion
|
|
1067
|
+
export { resolveRelTarget as n, parseStylesheetXml as r, loadWorkbook as t };
|
|
1068
|
+
|
|
1069
|
+
//# sourceMappingURL=load-D5cbhoGx.mjs.map
|