@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,636 @@
|
|
|
1
|
+
import { o as OpenXmlSchemaError } from "./exceptions-D-CFwxgm.mjs";
|
|
2
|
+
import { m as parseSheetRange, s as coordinateToTuple } from "./coordinate-96Ecci4d.mjs";
|
|
3
|
+
import { h as isFormulaValue } from "./cell-D9CaNKnU.mjs";
|
|
4
|
+
import { t as makeChartsheet } from "./chartsheet-C3-tqkPy.mjs";
|
|
5
|
+
import { a as makeChartDrawingItem, d as makeAbsoluteAnchor, o as makeDrawing } from "./drawing-BxzLuryn.mjs";
|
|
6
|
+
import { i as unescapeCellString, n as escapeXmlAttr, r as escapeXmlText, t as escapeCellString } from "./escape-DFTE7ZJc.mjs";
|
|
7
|
+
import { a as findChildren, ft as SHEET_MAIN_NS, i as findChild, jt as qname } from "./tree-Bbs1C8Rc.mjs";
|
|
8
|
+
import { t as parseXml } from "./parser-DuLejQy1.mjs";
|
|
9
|
+
import { Cn as parseRange, D as getCellHyperlink, Dn as rangeToString, E as getCellComment, L as getMergedRangeAt, Tn as rangeContainsCell, _ as countCellsByKind, at as makeWorksheet, bn as multiCellRangeContainsCell, nn as colorToHex, u as classifyCellValue, w as getCell, xt as setCellByCoord } from "./worksheet-CmCNoIgD.mjs";
|
|
10
|
+
import { _ as getCellNumberFormat, ft as makeStylesheet, g as getCellFont, h as getCellFill, m as getCellBorder, p as getCellAlignment, v as getCellProtection } from "./cell-style-BEDjMX1y.mjs";
|
|
11
|
+
//#region src/workbook/shared-strings.ts
|
|
12
|
+
const SST_TAG = `{${SHEET_MAIN_NS}}sst`;
|
|
13
|
+
const SI_TAG = `{${SHEET_MAIN_NS}}si`;
|
|
14
|
+
const T_TAG = `{${SHEET_MAIN_NS}}t`;
|
|
15
|
+
const R_TAG = `{${SHEET_MAIN_NS}}r`;
|
|
16
|
+
function makeSharedStrings() {
|
|
17
|
+
return {
|
|
18
|
+
entries: [],
|
|
19
|
+
index: /* @__PURE__ */ new Map()
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Insert a string and return its index. Idempotent: calling with the same value
|
|
24
|
+
* twice gives the same index. Empty strings are deduped just like everything
|
|
25
|
+
* else.
|
|
26
|
+
*/
|
|
27
|
+
function addSharedString(table, value) {
|
|
28
|
+
const cached = table.index.get(value);
|
|
29
|
+
if (cached !== void 0) return cached;
|
|
30
|
+
const id = table.entries.length;
|
|
31
|
+
table.entries.push(value);
|
|
32
|
+
table.index.set(value, id);
|
|
33
|
+
return id;
|
|
34
|
+
}
|
|
35
|
+
/** Look up a shared-string index by its literal text. Returns `undefined` for unknown values. */
|
|
36
|
+
function getSharedStringIndex(table, value) {
|
|
37
|
+
return table.index.get(value);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Read a shared-string by its 0-based index. Returns `undefined` for
|
|
41
|
+
* out-of-range. Rich-text entries surface their concatenated plain text so
|
|
42
|
+
* callers that want only the textual body don't need to know about the
|
|
43
|
+
* discriminated union.
|
|
44
|
+
*/
|
|
45
|
+
function getSharedStringAt(table, index) {
|
|
46
|
+
const entry = table.entries[index];
|
|
47
|
+
if (entry === void 0) return void 0;
|
|
48
|
+
if (typeof entry === "string") return entry;
|
|
49
|
+
return entry.runs.map((r) => r.text).join("");
|
|
50
|
+
}
|
|
51
|
+
/** Number of unique entries in the SST. */
|
|
52
|
+
function sharedStringCount(table) {
|
|
53
|
+
return table.entries.length;
|
|
54
|
+
}
|
|
55
|
+
/** Concatenate every `<t>` text node found inside an arbitrary XmlNode tree. */
|
|
56
|
+
const collectText = (node) => {
|
|
57
|
+
if (node.children.length === 1) {
|
|
58
|
+
const only = node.children[0];
|
|
59
|
+
if (only && only.name === T_TAG) return unescapeCellString(only.text ?? "");
|
|
60
|
+
}
|
|
61
|
+
let out = "";
|
|
62
|
+
for (const child of node.children) if (child.name === T_TAG) out += child.text ?? "";
|
|
63
|
+
else if (child.name === R_TAG) {
|
|
64
|
+
const t = findChild(child, T_TAG);
|
|
65
|
+
if (t?.text) out += t.text;
|
|
66
|
+
}
|
|
67
|
+
return unescapeCellString(out);
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Parse a `xl/sharedStrings.xml` payload. Returns the table directly (rather
|
|
71
|
+
* than just the array) so the worksheet writer can keep appending to it without
|
|
72
|
+
* rebuilding the index.
|
|
73
|
+
*
|
|
74
|
+
* Rich-text runs are preserved as their full per-run formatting so
|
|
75
|
+
* round-tripping a file with rich text doesn't drop the styling.
|
|
76
|
+
*/
|
|
77
|
+
function parseSharedStringsXml(bytes) {
|
|
78
|
+
const root = parseXml(bytes);
|
|
79
|
+
if (root.name !== SST_TAG) throw new OpenXmlSchemaError(`parseSharedStringsXml: root is "${root.name}", expected sst`);
|
|
80
|
+
const table = makeSharedStrings();
|
|
81
|
+
for (const si of findChildren(root, SI_TAG)) {
|
|
82
|
+
const entry = parseSi(si);
|
|
83
|
+
const id = table.entries.length;
|
|
84
|
+
table.entries.push(entry);
|
|
85
|
+
if (typeof entry === "string" && !table.index.has(entry)) table.index.set(entry, id);
|
|
86
|
+
}
|
|
87
|
+
return table;
|
|
88
|
+
}
|
|
89
|
+
const parseSi = (si) => {
|
|
90
|
+
const runEls = findChildren(si, R_TAG);
|
|
91
|
+
if (runEls.length > 0) {
|
|
92
|
+
const runs = [];
|
|
93
|
+
for (const rEl of runEls) {
|
|
94
|
+
const text = unescapeCellString(findChild(rEl, T_TAG)?.text ?? "");
|
|
95
|
+
const rPrEl = findChild(rEl, qname(SHEET_MAIN_NS, "rPr"));
|
|
96
|
+
const font = rPrEl ? parseRunPr(rPrEl) : void 0;
|
|
97
|
+
runs.push(font !== void 0 ? {
|
|
98
|
+
text,
|
|
99
|
+
font
|
|
100
|
+
} : { text });
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
kind: "rich-text",
|
|
104
|
+
runs: Object.freeze(runs)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return collectText(si);
|
|
108
|
+
};
|
|
109
|
+
const parseRunPr = (rPr) => {
|
|
110
|
+
const f = {};
|
|
111
|
+
for (const child of rPr.children) {
|
|
112
|
+
const local = child.name.replace(/^\{[^}]+\}/, "");
|
|
113
|
+
const valAttr = child.attrs["val"];
|
|
114
|
+
switch (local) {
|
|
115
|
+
case "rFont":
|
|
116
|
+
case "name":
|
|
117
|
+
if (valAttr !== void 0) f.name = valAttr;
|
|
118
|
+
break;
|
|
119
|
+
case "sz":
|
|
120
|
+
if (valAttr !== void 0) f.sz = Number.parseFloat(valAttr);
|
|
121
|
+
break;
|
|
122
|
+
case "b":
|
|
123
|
+
f.b = valAttr === void 0 ? true : valAttr !== "0" && valAttr !== "false";
|
|
124
|
+
break;
|
|
125
|
+
case "i":
|
|
126
|
+
f.i = valAttr === void 0 ? true : valAttr !== "0" && valAttr !== "false";
|
|
127
|
+
break;
|
|
128
|
+
case "u":
|
|
129
|
+
f.u = valAttr ?? "single";
|
|
130
|
+
break;
|
|
131
|
+
case "strike":
|
|
132
|
+
f.strike = valAttr === void 0 ? true : valAttr !== "0" && valAttr !== "false";
|
|
133
|
+
break;
|
|
134
|
+
case "vertAlign":
|
|
135
|
+
if (valAttr !== void 0) f.vertAlign = valAttr;
|
|
136
|
+
break;
|
|
137
|
+
case "family":
|
|
138
|
+
if (valAttr !== void 0) f.family = Number.parseInt(valAttr, 10);
|
|
139
|
+
break;
|
|
140
|
+
case "charset":
|
|
141
|
+
if (valAttr !== void 0) f.charset = Number.parseInt(valAttr, 10);
|
|
142
|
+
break;
|
|
143
|
+
case "scheme":
|
|
144
|
+
if (valAttr !== void 0) f.scheme = valAttr;
|
|
145
|
+
break;
|
|
146
|
+
case "color": {
|
|
147
|
+
const c = {};
|
|
148
|
+
if (child.attrs["rgb"] !== void 0) c.rgb = child.attrs["rgb"];
|
|
149
|
+
if (child.attrs["theme"] !== void 0) c.theme = Number.parseInt(child.attrs["theme"], 10);
|
|
150
|
+
if (child.attrs["indexed"] !== void 0) c.indexed = Number.parseInt(child.attrs["indexed"], 10);
|
|
151
|
+
if (child.attrs["tint"] !== void 0) c.tint = Number.parseFloat(child.attrs["tint"]);
|
|
152
|
+
if (child.attrs["auto"] !== void 0) c.auto = child.attrs["auto"] === "1" || child.attrs["auto"] === "true";
|
|
153
|
+
f.color = c;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return Object.keys(f).length === 0 ? void 0 : Object.freeze(f);
|
|
159
|
+
};
|
|
160
|
+
const XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
|
|
161
|
+
/**
|
|
162
|
+
* Serialise a SharedStringsTable to its OOXML bytes. The `count` attribute
|
|
163
|
+
* tracks total references (we don't know that here so we report the same as
|
|
164
|
+
* `uniqueCount` — readers tolerate the discrepancy and Excel ignores `count` in
|
|
165
|
+
* practice). `uniqueCount` always matches `entries.length`.
|
|
166
|
+
*/
|
|
167
|
+
function sharedStringsToBytes(table) {
|
|
168
|
+
return new TextEncoder().encode(serializeSharedStrings(table));
|
|
169
|
+
}
|
|
170
|
+
function serializeSharedStrings(table) {
|
|
171
|
+
const total = table.entries.length;
|
|
172
|
+
const parts = [XML_HEADER, `<sst xmlns="${SHEET_MAIN_NS}" count="${total}" uniqueCount="${total}">`];
|
|
173
|
+
for (const value of table.entries) parts.push(serializeSi(value));
|
|
174
|
+
parts.push("</sst>");
|
|
175
|
+
return parts.join("");
|
|
176
|
+
}
|
|
177
|
+
const serializeSi = (value) => {
|
|
178
|
+
if (typeof value === "string") return `<si><t${value.length > 0 && (value[0] === " " || value[value.length - 1] === " " || /[\t\n]/.test(value)) ? " xml:space=\"preserve\"" : ""}>${escapeXmlText(escapeCellString(value))}</t></si>`;
|
|
179
|
+
return `<si>${serializeRichTextRuns(value.runs)}</si>`;
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Serialise a sequence of `<r>...<r>` runs — shared by the SST `<si>` writer
|
|
183
|
+
* and the worksheet's inline-string (`t="inlineStr"`) cell writer.
|
|
184
|
+
*/
|
|
185
|
+
function serializeRichTextRuns(runs) {
|
|
186
|
+
const parts = [];
|
|
187
|
+
for (const run of runs) {
|
|
188
|
+
parts.push("<r>");
|
|
189
|
+
if (run.font) parts.push(serializeInlineFont(run.font));
|
|
190
|
+
const text = run.text;
|
|
191
|
+
const tAttr = text.length > 0 && (text[0] === " " || text[text.length - 1] === " " || /[\t\n]/.test(text)) ? " xml:space=\"preserve\"" : "";
|
|
192
|
+
parts.push(`<t${tAttr}>${escapeXmlText(escapeCellString(text))}</t>`);
|
|
193
|
+
parts.push("</r>");
|
|
194
|
+
}
|
|
195
|
+
return parts.join("");
|
|
196
|
+
}
|
|
197
|
+
const serializeInlineFont = (f) => {
|
|
198
|
+
const parts = ["<rPr>"];
|
|
199
|
+
if (f.name !== void 0) parts.push(`<rFont val="${escapeXmlAttr(f.name)}"/>`);
|
|
200
|
+
if (f.charset !== void 0) parts.push(`<charset val="${f.charset}"/>`);
|
|
201
|
+
if (f.family !== void 0) parts.push(`<family val="${f.family}"/>`);
|
|
202
|
+
if (f.b) parts.push("<b/>");
|
|
203
|
+
if (f.i) parts.push("<i/>");
|
|
204
|
+
if (f.strike) parts.push("<strike/>");
|
|
205
|
+
if (f.outline) parts.push("<outline/>");
|
|
206
|
+
if (f.shadow) parts.push("<shadow/>");
|
|
207
|
+
if (f.condense) parts.push("<condense/>");
|
|
208
|
+
if (f.extend) parts.push("<extend/>");
|
|
209
|
+
if (f.color) parts.push(serializeRunColor(f.color));
|
|
210
|
+
if (f.sz !== void 0) parts.push(`<sz val="${f.sz}"/>`);
|
|
211
|
+
if (f.u) parts.push(`<u val="${f.u}"/>`);
|
|
212
|
+
if (f.vertAlign) parts.push(`<vertAlign val="${f.vertAlign}"/>`);
|
|
213
|
+
if (f.scheme) parts.push(`<scheme val="${f.scheme}"/>`);
|
|
214
|
+
parts.push("</rPr>");
|
|
215
|
+
return parts.join("");
|
|
216
|
+
};
|
|
217
|
+
const serializeRunColor = (c) => {
|
|
218
|
+
const attrs = [];
|
|
219
|
+
if (c.rgb !== void 0) attrs.push(`rgb="${escapeXmlAttr(c.rgb)}"`);
|
|
220
|
+
else if (c.theme !== void 0) attrs.push(`theme="${c.theme}"`);
|
|
221
|
+
else if (c.indexed !== void 0) attrs.push(`indexed="${c.indexed}"`);
|
|
222
|
+
else if (c.auto !== void 0) attrs.push(`auto="${c.auto ? "1" : "0"}"`);
|
|
223
|
+
if (c.tint !== void 0) attrs.push(`tint="${c.tint}"`);
|
|
224
|
+
if (attrs.length === 0) {
|
|
225
|
+
const hex = colorToHex(c);
|
|
226
|
+
if (hex !== void 0) attrs.push(`rgb="${hex}"`);
|
|
227
|
+
}
|
|
228
|
+
return `<color${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""}/>`;
|
|
229
|
+
};
|
|
230
|
+
//#endregion
|
|
231
|
+
//#region src/workbook/workbook.ts
|
|
232
|
+
/** Build an empty Workbook ready to host worksheets. */
|
|
233
|
+
function createWorkbook(opts) {
|
|
234
|
+
return {
|
|
235
|
+
sheets: [],
|
|
236
|
+
activeSheetIndex: 0,
|
|
237
|
+
styles: makeStylesheet(),
|
|
238
|
+
date1904: opts?.date1904 ?? false,
|
|
239
|
+
authors: [],
|
|
240
|
+
definedNames: []
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Validate a sheet title against Excel's character + length rules. Returns the
|
|
245
|
+
* reason string when the title is rejected; `undefined` when valid. The same
|
|
246
|
+
* rules apply to worksheets and chartsheets.
|
|
247
|
+
*
|
|
248
|
+
* Rules:
|
|
249
|
+
* - Type must be `string`; non-empty; length ≤ 31.
|
|
250
|
+
* - May not contain any of `:`, `\`, `/`, `?`, `*`, `[`, `]`.
|
|
251
|
+
* - May not start or end with an apostrophe `'`.
|
|
252
|
+
* - May not be the literal `"History"` (case-insensitive — Excel
|
|
253
|
+
* reserves that name for the change-tracking sheet).
|
|
254
|
+
*
|
|
255
|
+
* Uniqueness is **not** checked here; pass through `addWorksheet` /
|
|
256
|
+
* `renameSheet` for the workbook-aware duplicate check.
|
|
257
|
+
*/
|
|
258
|
+
function validateSheetTitle(title) {
|
|
259
|
+
if (typeof title !== "string") return "must be a string";
|
|
260
|
+
if (title.length === 0) return "must be 1..31 chars";
|
|
261
|
+
if (title.length > 31) return "must be 1..31 chars";
|
|
262
|
+
if (/[:\\/?*[\]]/.test(title)) return "must not contain : \\ / ? * [ ]";
|
|
263
|
+
if (title.startsWith("'") || title.endsWith("'")) return "must not start or end with an apostrophe";
|
|
264
|
+
if (title.toLowerCase() === "history") return "\"History\" is reserved by Excel";
|
|
265
|
+
}
|
|
266
|
+
const validateUniqueTitle = (wb, title, ignoreIndex) => {
|
|
267
|
+
const reason = validateSheetTitle(title);
|
|
268
|
+
if (reason) throw new OpenXmlSchemaError(`Worksheet title "${title}": ${reason}`);
|
|
269
|
+
const lower = title.toLowerCase();
|
|
270
|
+
for (let i = 0; i < wb.sheets.length; i++) {
|
|
271
|
+
if (i === ignoreIndex) continue;
|
|
272
|
+
const s = wb.sheets[i];
|
|
273
|
+
if (s && s.sheet.title.toLowerCase() === lower) throw new OpenXmlSchemaError(`Worksheet title "${title}" is already in use`);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
const allocateSheetId = (wb) => {
|
|
277
|
+
const used = /* @__PURE__ */ new Set();
|
|
278
|
+
for (const s of wb.sheets) used.add(s.sheetId);
|
|
279
|
+
let n = 1;
|
|
280
|
+
while (used.has(n)) n++;
|
|
281
|
+
return n;
|
|
282
|
+
};
|
|
283
|
+
/** Add a Worksheet to the Workbook. Returns the sheet for further population. */
|
|
284
|
+
function addWorksheet(wb, title, opts) {
|
|
285
|
+
validateUniqueTitle(wb, title);
|
|
286
|
+
const sheet = makeWorksheet(title);
|
|
287
|
+
const ref = {
|
|
288
|
+
kind: "worksheet",
|
|
289
|
+
sheet,
|
|
290
|
+
sheetId: allocateSheetId(wb),
|
|
291
|
+
state: opts?.state ?? "visible"
|
|
292
|
+
};
|
|
293
|
+
if (opts?.index === void 0) wb.sheets.push(ref);
|
|
294
|
+
else {
|
|
295
|
+
if (opts.index < 0 || opts.index > wb.sheets.length) throw new OpenXmlSchemaError(`addWorksheet: index ${opts.index} out of range`);
|
|
296
|
+
wb.sheets.splice(opts.index, 0, ref);
|
|
297
|
+
}
|
|
298
|
+
return sheet;
|
|
299
|
+
}
|
|
300
|
+
/** Look up a Worksheet by title. Returns undefined for missing names or chartsheets. */
|
|
301
|
+
function getSheet(wb, title) {
|
|
302
|
+
for (const s of wb.sheets) if (s.kind === "worksheet" && s.sheet.title === title) return s.sheet;
|
|
303
|
+
}
|
|
304
|
+
/** Look up a Chartsheet by title. Returns undefined for missing names or worksheets. */
|
|
305
|
+
function getChartsheet(wb, title) {
|
|
306
|
+
for (const s of wb.sheets) if (s.kind === "chartsheet" && s.sheet.title === title) return s.sheet;
|
|
307
|
+
}
|
|
308
|
+
/** Add a Chartsheet to the Workbook. Returns the chartsheet for further population. */
|
|
309
|
+
function addChartsheet(wb, title, opts) {
|
|
310
|
+
validateUniqueTitle(wb, title);
|
|
311
|
+
const cs = makeChartsheet(title);
|
|
312
|
+
if (opts?.chart) cs.drawing = makeDrawing([makeChartDrawingItem(makeAbsoluteAnchor({
|
|
313
|
+
x: 0,
|
|
314
|
+
y: 0,
|
|
315
|
+
cx: 9144e3,
|
|
316
|
+
cy: 6858e3
|
|
317
|
+
}), opts.chart)]);
|
|
318
|
+
const ref = {
|
|
319
|
+
kind: "chartsheet",
|
|
320
|
+
sheet: cs,
|
|
321
|
+
sheetId: allocateSheetId(wb),
|
|
322
|
+
state: opts?.state ?? "visible"
|
|
323
|
+
};
|
|
324
|
+
if (opts?.index === void 0) wb.sheets.push(ref);
|
|
325
|
+
else {
|
|
326
|
+
if (opts.index < 0 || opts.index > wb.sheets.length) throw new OpenXmlSchemaError(`addChartsheet: index ${opts.index} out of range`);
|
|
327
|
+
wb.sheets.splice(opts.index, 0, ref);
|
|
328
|
+
}
|
|
329
|
+
return cs;
|
|
330
|
+
}
|
|
331
|
+
/** All worksheet titles, in display order. */
|
|
332
|
+
function sheetNames(wb) {
|
|
333
|
+
return wb.sheets.map((s) => s.sheet.title);
|
|
334
|
+
}
|
|
335
|
+
/** Remove a sheet by title. No-op if the title is not registered. */
|
|
336
|
+
function removeSheet(wb, title) {
|
|
337
|
+
const i = wb.sheets.findIndex((s) => s.sheet.title === title);
|
|
338
|
+
if (i < 0) return;
|
|
339
|
+
wb.sheets.splice(i, 1);
|
|
340
|
+
if (wb.activeSheetIndex >= wb.sheets.length) wb.activeSheetIndex = Math.max(0, wb.sheets.length - 1);
|
|
341
|
+
}
|
|
342
|
+
/** Set the active sheet by title; throws on unknown title. */
|
|
343
|
+
function setActiveSheet(wb, title) {
|
|
344
|
+
const i = wb.sheets.findIndex((s) => s.sheet.title === title);
|
|
345
|
+
if (i < 0) throw new OpenXmlSchemaError(`setActiveSheet: no sheet named "${title}"`);
|
|
346
|
+
wb.activeSheetIndex = i;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Rename a sheet from `oldTitle` to `newTitle`. Throws if no sheet matches
|
|
350
|
+
* `oldTitle`, or if `newTitle` collides with an existing sheet (Excel requires
|
|
351
|
+
* sheet names to be unique within a workbook).
|
|
352
|
+
*/
|
|
353
|
+
function renameSheet(wb, oldTitle, newTitle) {
|
|
354
|
+
const i = wb.sheets.findIndex((s) => s.sheet.title === oldTitle);
|
|
355
|
+
if (i < 0) throw new OpenXmlSchemaError(`renameSheet: no sheet named "${oldTitle}"`);
|
|
356
|
+
if (oldTitle === newTitle) return;
|
|
357
|
+
validateUniqueTitle(wb, newTitle, i);
|
|
358
|
+
const ref = wb.sheets[i];
|
|
359
|
+
if (ref) ref.sheet.title = newTitle;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Set the visibility state on a sheet by title. Throws on unknown title.
|
|
363
|
+
* Refuses to hide the last visible sheet: an .xlsx with every sheet hidden
|
|
364
|
+
* fails to open in Excel ("Excel cannot use the object linking and embedding
|
|
365
|
+
* features because no sheet is visible"). Catching it here keeps the
|
|
366
|
+
* workbook recoverable instead of producing a save Excel will reject.
|
|
367
|
+
*/
|
|
368
|
+
function setSheetState(wb, title, state) {
|
|
369
|
+
const ref = wb.sheets.find((s) => s.sheet.title === title);
|
|
370
|
+
if (!ref) throw new OpenXmlSchemaError(`setSheetState: no sheet named "${title}"`);
|
|
371
|
+
if (ref.state === state) return;
|
|
372
|
+
if (state !== "visible" && ref.state === "visible") {
|
|
373
|
+
let otherVisible = false;
|
|
374
|
+
for (const candidate of wb.sheets) if (candidate !== ref && candidate.state === "visible") {
|
|
375
|
+
otherVisible = true;
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
if (!otherVisible) throw new OpenXmlSchemaError(`setSheetState: cannot hide "${title}" — it's the last visible sheet, and Excel refuses to open a workbook with every sheet hidden. Make another sheet visible first (or call showSheet()).`);
|
|
379
|
+
}
|
|
380
|
+
ref.state = state;
|
|
381
|
+
}
|
|
382
|
+
/** Look up the current visibility state. Throws on unknown title. */
|
|
383
|
+
function getSheetState(wb, title) {
|
|
384
|
+
const ref = wb.sheets.find((s) => s.sheet.title === title);
|
|
385
|
+
if (!ref) throw new OpenXmlSchemaError(`getSheetState: no sheet named "${title}"`);
|
|
386
|
+
return ref.state;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Move a sheet to a new tab-strip position. `toIndex` is clamped to `[0,
|
|
390
|
+
* sheets.length - 1]`. Adjusts `activeSheetIndex` so the same sheet stays
|
|
391
|
+
* active across the move.
|
|
392
|
+
*/
|
|
393
|
+
function moveSheet(wb, title, toIndex) {
|
|
394
|
+
const from = wb.sheets.findIndex((s) => s.sheet.title === title);
|
|
395
|
+
if (from < 0) throw new OpenXmlSchemaError(`moveSheet: no sheet named "${title}"`);
|
|
396
|
+
if (!Number.isInteger(toIndex)) throw new OpenXmlSchemaError(`moveSheet: toIndex must be an integer; got ${toIndex}`);
|
|
397
|
+
const dest = Math.max(0, Math.min(wb.sheets.length - 1, toIndex));
|
|
398
|
+
if (from === dest) return;
|
|
399
|
+
const wasActive = wb.activeSheetIndex === from;
|
|
400
|
+
const [moved] = wb.sheets.splice(from, 1);
|
|
401
|
+
if (moved) wb.sheets.splice(dest, 0, moved);
|
|
402
|
+
if (wasActive) wb.activeSheetIndex = dest;
|
|
403
|
+
else {
|
|
404
|
+
let cur = wb.activeSheetIndex;
|
|
405
|
+
if (from < cur) cur -= 1;
|
|
406
|
+
if (dest <= cur) cur += 1;
|
|
407
|
+
wb.activeSheetIndex = Math.max(0, Math.min(wb.sheets.length - 1, cur));
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function getWorkbookStats(wb) {
|
|
411
|
+
let worksheetCount = 0;
|
|
412
|
+
let chartsheetCount = 0;
|
|
413
|
+
let cellCount = 0;
|
|
414
|
+
let formulaCount = 0;
|
|
415
|
+
let commentCount = 0;
|
|
416
|
+
let hyperlinkCount = 0;
|
|
417
|
+
let mergedRangeCount = 0;
|
|
418
|
+
let tableCount = 0;
|
|
419
|
+
for (const ref of wb.sheets) if (ref.kind === "worksheet") {
|
|
420
|
+
worksheetCount++;
|
|
421
|
+
const ws = ref.sheet;
|
|
422
|
+
for (const rowMap of ws.rows.values()) for (const cell of rowMap.values()) {
|
|
423
|
+
cellCount++;
|
|
424
|
+
if (isFormulaValue(cell.value)) formulaCount++;
|
|
425
|
+
}
|
|
426
|
+
commentCount += ws.legacyComments.length;
|
|
427
|
+
hyperlinkCount += ws.hyperlinks.length;
|
|
428
|
+
mergedRangeCount += ws.mergedCells.length;
|
|
429
|
+
tableCount += ws.tables.length;
|
|
430
|
+
} else chartsheetCount++;
|
|
431
|
+
return {
|
|
432
|
+
worksheetCount,
|
|
433
|
+
chartsheetCount,
|
|
434
|
+
cellCount,
|
|
435
|
+
formulaCount,
|
|
436
|
+
commentCount,
|
|
437
|
+
hyperlinkCount,
|
|
438
|
+
mergedRangeCount,
|
|
439
|
+
tableCount,
|
|
440
|
+
definedNameCount: wb.definedNames.length,
|
|
441
|
+
customPropertyCount: wb.customProperties?.properties.length ?? 0
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Workbook-wide value-kind histogram. Sums {@link countCellsByKind} across
|
|
446
|
+
* every Worksheet (chartsheets contribute no cells). Buckets have the same
|
|
447
|
+
* shape as the per-worksheet result; an empty workbook returns all-zero counts.
|
|
448
|
+
*/
|
|
449
|
+
function getWorkbookCellsByKind(wb) {
|
|
450
|
+
const out = {
|
|
451
|
+
null: 0,
|
|
452
|
+
string: 0,
|
|
453
|
+
number: 0,
|
|
454
|
+
boolean: 0,
|
|
455
|
+
date: 0,
|
|
456
|
+
duration: 0,
|
|
457
|
+
error: 0,
|
|
458
|
+
"rich-text": 0,
|
|
459
|
+
formula: 0
|
|
460
|
+
};
|
|
461
|
+
for (const ws of iterWorksheets(wb)) {
|
|
462
|
+
const partial = countCellsByKind(ws);
|
|
463
|
+
out.null += partial.null;
|
|
464
|
+
out.string += partial.string;
|
|
465
|
+
out.number += partial.number;
|
|
466
|
+
out.boolean += partial.boolean;
|
|
467
|
+
out.date += partial.date;
|
|
468
|
+
out.duration += partial.duration;
|
|
469
|
+
out.error += partial.error;
|
|
470
|
+
out["rich-text"] += partial["rich-text"];
|
|
471
|
+
out.formula += partial.formula;
|
|
472
|
+
}
|
|
473
|
+
return out;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Resolve a sheet-qualified A1 address (`'Sheet1!A1'`) to its Cell, or
|
|
477
|
+
* `undefined` when the cell isn't materialised. Throws on malformed addresses,
|
|
478
|
+
* missing sheets, or range inputs.
|
|
479
|
+
*/
|
|
480
|
+
function getCellAtAddress(wb, address) {
|
|
481
|
+
const { sheet: sheetTitle, range } = parseSheetRange(address);
|
|
482
|
+
if (range.includes(":")) throw new OpenXmlSchemaError(`getCellAtAddress: address "${address}" refers to a range, not a single cell`);
|
|
483
|
+
const ws = getSheet(wb, sheetTitle);
|
|
484
|
+
if (!ws) throw new OpenXmlSchemaError(`getCellAtAddress: sheet "${sheetTitle}" not found`);
|
|
485
|
+
const { col, row } = coordinateToTuple(range);
|
|
486
|
+
return getCell(ws, row, col);
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Set a single cell by sheet-qualified A1 address. Throws on malformed
|
|
490
|
+
* addresses, missing sheets, or range inputs.
|
|
491
|
+
*/
|
|
492
|
+
function setCellAtAddress(wb, address, value) {
|
|
493
|
+
const { sheet: sheetTitle, range } = parseSheetRange(address);
|
|
494
|
+
if (range.includes(":")) throw new OpenXmlSchemaError(`setCellAtAddress: address "${address}" refers to a range, not a single cell`);
|
|
495
|
+
const ws = getSheet(wb, sheetTitle);
|
|
496
|
+
if (!ws) throw new OpenXmlSchemaError(`setCellAtAddress: sheet "${sheetTitle}" not found`);
|
|
497
|
+
return setCellByCoord(ws, range, value);
|
|
498
|
+
}
|
|
499
|
+
function describeWorkbook(wb) {
|
|
500
|
+
let worksheetCount = 0;
|
|
501
|
+
let chartsheetCount = 0;
|
|
502
|
+
let cellCount = 0;
|
|
503
|
+
let formulaCount = 0;
|
|
504
|
+
let commentCount = 0;
|
|
505
|
+
let hyperlinkCount = 0;
|
|
506
|
+
let mergedRangeCount = 0;
|
|
507
|
+
let tableCount = 0;
|
|
508
|
+
const cellsByKind = {
|
|
509
|
+
null: 0,
|
|
510
|
+
string: 0,
|
|
511
|
+
number: 0,
|
|
512
|
+
boolean: 0,
|
|
513
|
+
date: 0,
|
|
514
|
+
duration: 0,
|
|
515
|
+
error: 0,
|
|
516
|
+
"rich-text": 0,
|
|
517
|
+
formula: 0
|
|
518
|
+
};
|
|
519
|
+
const sheets = wb.sheets.map((ref) => {
|
|
520
|
+
if (ref.kind === "chartsheet") {
|
|
521
|
+
chartsheetCount++;
|
|
522
|
+
return {
|
|
523
|
+
title: ref.sheet.title,
|
|
524
|
+
kind: "chartsheet",
|
|
525
|
+
state: ref.state,
|
|
526
|
+
cellCount: 0,
|
|
527
|
+
formulaCount: 0,
|
|
528
|
+
tableCount: 0,
|
|
529
|
+
drawingItemCount: ref.sheet.drawing?.items.length ?? 0
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
worksheetCount++;
|
|
533
|
+
const ws = ref.sheet;
|
|
534
|
+
let sheetCellCount = 0;
|
|
535
|
+
let sheetFormulaCount = 0;
|
|
536
|
+
for (const rowMap of ws.rows.values()) for (const cell of rowMap.values()) {
|
|
537
|
+
sheetCellCount++;
|
|
538
|
+
const bucket = classifyCellValue(cell.value);
|
|
539
|
+
cellsByKind[bucket]++;
|
|
540
|
+
if (isFormulaValue(cell.value)) sheetFormulaCount++;
|
|
541
|
+
}
|
|
542
|
+
cellCount += sheetCellCount;
|
|
543
|
+
formulaCount += sheetFormulaCount;
|
|
544
|
+
commentCount += ws.legacyComments.length;
|
|
545
|
+
hyperlinkCount += ws.hyperlinks.length;
|
|
546
|
+
mergedRangeCount += ws.mergedCells.length;
|
|
547
|
+
tableCount += ws.tables.length;
|
|
548
|
+
return {
|
|
549
|
+
title: ws.title,
|
|
550
|
+
kind: "worksheet",
|
|
551
|
+
state: ref.state,
|
|
552
|
+
cellCount: sheetCellCount,
|
|
553
|
+
formulaCount: sheetFormulaCount,
|
|
554
|
+
tableCount: ws.tables.length,
|
|
555
|
+
drawingItemCount: ws.drawing?.items.length ?? 0
|
|
556
|
+
};
|
|
557
|
+
});
|
|
558
|
+
return {
|
|
559
|
+
worksheetCount,
|
|
560
|
+
chartsheetCount,
|
|
561
|
+
cellCount,
|
|
562
|
+
formulaCount,
|
|
563
|
+
commentCount,
|
|
564
|
+
hyperlinkCount,
|
|
565
|
+
mergedRangeCount,
|
|
566
|
+
tableCount,
|
|
567
|
+
definedNameCount: wb.definedNames.length,
|
|
568
|
+
customPropertyCount: wb.customProperties?.properties.length ?? 0,
|
|
569
|
+
cellsByKind,
|
|
570
|
+
sheets
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
function getCellSummary(wb, sheetTitle, ref) {
|
|
574
|
+
const ws = getSheet(wb, sheetTitle);
|
|
575
|
+
if (!ws) throw new OpenXmlSchemaError(`getCellSummary: sheet "${sheetTitle}" not found`);
|
|
576
|
+
const { col, row } = coordinateToTuple(ref);
|
|
577
|
+
const cell = getCell(ws, row, col);
|
|
578
|
+
const probe = cell ?? {
|
|
579
|
+
row,
|
|
580
|
+
col,
|
|
581
|
+
value: null,
|
|
582
|
+
styleId: 0
|
|
583
|
+
};
|
|
584
|
+
const merged = getMergedRangeAt(ws, row, col);
|
|
585
|
+
const inTables = [];
|
|
586
|
+
for (const t of ws.tables) if (rangeContainsCell(parseRange(t.ref), row, col)) inTables.push(t.displayName);
|
|
587
|
+
let inDv = 0;
|
|
588
|
+
for (const dv of ws.dataValidations) if (multiCellRangeContainsCell(dv.sqref, row, col)) inDv++;
|
|
589
|
+
let inCf = 0;
|
|
590
|
+
for (const cf of ws.conditionalFormatting) if (multiCellRangeContainsCell(cf.sqref, row, col)) inCf++;
|
|
591
|
+
return {
|
|
592
|
+
ref,
|
|
593
|
+
sheet: sheetTitle,
|
|
594
|
+
exists: cell !== void 0,
|
|
595
|
+
value: cell?.value,
|
|
596
|
+
styleId: probe.styleId,
|
|
597
|
+
font: getCellFont(wb, probe),
|
|
598
|
+
fill: getCellFill(wb, probe),
|
|
599
|
+
border: getCellBorder(wb, probe),
|
|
600
|
+
alignment: getCellAlignment(wb, probe),
|
|
601
|
+
protection: getCellProtection(wb, probe),
|
|
602
|
+
numberFormat: getCellNumberFormat(wb, probe),
|
|
603
|
+
hyperlink: cell ? getCellHyperlink(ws, cell) : void 0,
|
|
604
|
+
comment: cell ? getCellComment(ws, cell) : void 0,
|
|
605
|
+
mergedRange: merged ? rangeToString(merged) : void 0,
|
|
606
|
+
inTables,
|
|
607
|
+
inDataValidations: inDv,
|
|
608
|
+
inConditionalFormatting: inCf
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Iterate over every Worksheet in the workbook (skips chartsheets). Yields each
|
|
613
|
+
* worksheet in tab-strip order.
|
|
614
|
+
*/
|
|
615
|
+
function* iterWorksheets(wb) {
|
|
616
|
+
for (const ref of wb.sheets) if (ref.kind === "worksheet") yield ref.sheet;
|
|
617
|
+
}
|
|
618
|
+
/** Currently active sheet (worksheet only), or undefined if the active slot is empty or a chartsheet. */
|
|
619
|
+
function getActiveSheet(wb) {
|
|
620
|
+
const ref = wb.sheets[wb.activeSheetIndex];
|
|
621
|
+
return ref?.kind === "worksheet" ? ref.sheet : void 0;
|
|
622
|
+
}
|
|
623
|
+
/** Read-only view onto the customXml/* pass-through parts. */
|
|
624
|
+
function listCustomXmlParts(wb) {
|
|
625
|
+
if (!wb.passthrough) return [];
|
|
626
|
+
const out = [];
|
|
627
|
+
for (const [path, content] of wb.passthrough) if (path.startsWith("customXml/")) out.push({
|
|
628
|
+
path,
|
|
629
|
+
content
|
|
630
|
+
});
|
|
631
|
+
return out;
|
|
632
|
+
}
|
|
633
|
+
//#endregion
|
|
634
|
+
export { sharedStringsToBytes as A, addSharedString as C, parseSharedStringsXml as D, makeSharedStrings as E, serializeRichTextRuns as O, validateSheetTitle as S, getSharedStringIndex as T, renameSheet as _, getActiveSheet as a, setSheetState as b, getChartsheet as c, getWorkbookCellsByKind as d, getWorkbookStats as f, removeSheet as g, moveSheet as h, describeWorkbook as i, sharedStringCount as k, getSheet as l, listCustomXmlParts as m, addWorksheet as n, getCellAtAddress as o, iterWorksheets as p, createWorkbook as r, getCellSummary as s, addChartsheet as t, getSheetState as u, setActiveSheet as v, getSharedStringAt as w, sheetNames as x, setCellAtAddress as y };
|
|
635
|
+
|
|
636
|
+
//# sourceMappingURL=workbook-HGYNRBlV.mjs.map
|