@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,612 @@
|
|
|
1
|
+
import { i as OpenXmlIoError, o as OpenXmlSchemaError } from "./exceptions-D-CFwxgm.mjs";
|
|
2
|
+
import { s as coordinateToTuple } from "./coordinate-96Ecci4d.mjs";
|
|
3
|
+
import { t as ERROR_CODES } from "./inference-B3ES3KEJ.mjs";
|
|
4
|
+
import { n as escapeXmlAttr } from "./escape-DFTE7ZJc.mjs";
|
|
5
|
+
import { _ as ARC_WORKBOOK_RELS, a as findChildren, c as ARC_CONTENT_TYPES, f as ARC_ROOT_RELS, ft as SHEET_MAIN_NS, g as ARC_WORKBOOK, i as findChild, lt as REL_NS, m as ARC_STYLE, p as ARC_SHARED_STRINGS, pt as STYLES_TYPE, ut as SHARED_STRINGS_TYPE, wt as XLSX_TYPE, yt as WORKSHEET_TYPE } from "./tree-Bbs1C8Rc.mjs";
|
|
6
|
+
import { _ as serializeCell, t as stylesheetToBytes } from "./stylesheet-writer-C2eRmn22.mjs";
|
|
7
|
+
import { t as parseXml } from "./parser-DuLejQy1.mjs";
|
|
8
|
+
import { Q as findById, a as makeManifest, n as addOverride, nt as relsFromBytes, o as manifestFromBytes, rt as relsToBytes, s as manifestToBytes, t as addDefault, tt as makeRelationships } from "./manifest-Dps1-OpP.mjs";
|
|
9
|
+
import { A as sharedStringsToBytes, D as parseSharedStringsXml, E as makeSharedStrings, S as validateSheetTitle } from "./workbook-HGYNRBlV.mjs";
|
|
10
|
+
import { at as addNumFmt, et as addBorder, ft as makeStylesheet, it as addFont, nt as addCellXf, ot as defaultCellXf, rt as addFill } from "./cell-style-BEDjMX1y.mjs";
|
|
11
|
+
import { n as resolveRelTarget, r as parseStylesheetXml } from "./load-D5cbhoGx.mjs";
|
|
12
|
+
import { t as openZip } from "./reader-D1fNW9k1.mjs";
|
|
13
|
+
import { t as createZipWriter } from "./writer-DspzfkNA.mjs";
|
|
14
|
+
import { n as iterParse, t as utf8ByteLength } from "./utf8-D91g1XTG.mjs";
|
|
15
|
+
//#region src/streaming/read-only.ts
|
|
16
|
+
const SHEET_TAG = `{${SHEET_MAIN_NS}}sheet`;
|
|
17
|
+
const SHEETS_TAG = `{${SHEET_MAIN_NS}}sheets`;
|
|
18
|
+
const parseSheetList = (workbookXml, workbookPath, archive) => {
|
|
19
|
+
const sheetsEl = findChild(parseXml(workbookXml), SHEETS_TAG);
|
|
20
|
+
if (!sheetsEl) return [];
|
|
21
|
+
const wbRelsPath = relsPathFor(workbookPath);
|
|
22
|
+
const wbRels = archive.has(wbRelsPath) ? relsFromBytes(archive.read(wbRelsPath)) : { rels: [] };
|
|
23
|
+
const out = [];
|
|
24
|
+
for (const sheet of findChildren(sheetsEl, SHEET_TAG)) {
|
|
25
|
+
const name = sheet.attrs["name"];
|
|
26
|
+
const rId = sheet.attrs[`{${REL_NS}}id`];
|
|
27
|
+
if (!name || !rId) continue;
|
|
28
|
+
const rel = findById(wbRels, rId);
|
|
29
|
+
if (!rel) continue;
|
|
30
|
+
const partPath = resolveRelTarget(workbookPath, rel.target);
|
|
31
|
+
out.push({
|
|
32
|
+
name,
|
|
33
|
+
rId,
|
|
34
|
+
partPath
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
};
|
|
39
|
+
const relsPathFor = (partPath) => {
|
|
40
|
+
const i = partPath.lastIndexOf("/");
|
|
41
|
+
if (i < 0) return `_rels/${partPath}.rels`;
|
|
42
|
+
return `${partPath.slice(0, i)}/_rels/${partPath.slice(i + 1)}.rels`;
|
|
43
|
+
};
|
|
44
|
+
const localName = (qname) => {
|
|
45
|
+
const i = qname.lastIndexOf("}");
|
|
46
|
+
return i < 0 ? qname : qname.slice(i + 1);
|
|
47
|
+
};
|
|
48
|
+
const decodeCellValue = (t, vText, inlineText, sst) => {
|
|
49
|
+
switch (t) {
|
|
50
|
+
case "n": return vText !== void 0 && vText !== "" ? Number.parseFloat(vText) : null;
|
|
51
|
+
case "s": {
|
|
52
|
+
if (vText === void 0) return null;
|
|
53
|
+
const idx = Number.parseInt(vText, 10);
|
|
54
|
+
if (!Number.isInteger(idx) || idx < 0 || idx >= sst.length) return null;
|
|
55
|
+
return sst[idx] ?? null;
|
|
56
|
+
}
|
|
57
|
+
case "b": return vText === "1";
|
|
58
|
+
case "e":
|
|
59
|
+
if (!vText || !ERROR_CODES.has(vText)) return null;
|
|
60
|
+
return {
|
|
61
|
+
kind: "error",
|
|
62
|
+
code: vText
|
|
63
|
+
};
|
|
64
|
+
case "str": return vText ?? "";
|
|
65
|
+
case "inlineStr": return inlineText ?? "";
|
|
66
|
+
default: return vText !== void 0 && vText !== "" ? Number.parseFloat(vText) : null;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* SAX-iterate `<sheetData>/<row>/<c>` events out of the worksheet bytes (or a
|
|
71
|
+
* stream that yields them), yielding one `ReadOnlyCell[]` per row that matches
|
|
72
|
+
* `opts`.
|
|
73
|
+
*/
|
|
74
|
+
async function* iterSheetRows(sheetInput, sst, opts) {
|
|
75
|
+
const minRow = opts.minRow ?? 1;
|
|
76
|
+
const maxRow = opts.maxRow ?? Number.POSITIVE_INFINITY;
|
|
77
|
+
const minCol = opts.minCol ?? 1;
|
|
78
|
+
const maxCol = opts.maxCol ?? Number.POSITIVE_INFINITY;
|
|
79
|
+
let inSheetData = false;
|
|
80
|
+
let currentRow = -1;
|
|
81
|
+
let currentCells = [];
|
|
82
|
+
let cellOpen = false;
|
|
83
|
+
let cellRow = 0;
|
|
84
|
+
let cellCol = 0;
|
|
85
|
+
let cellType = "n";
|
|
86
|
+
let cellStyleId = 0;
|
|
87
|
+
let inV = false;
|
|
88
|
+
let vText = "";
|
|
89
|
+
let inIs = false;
|
|
90
|
+
let inIsT = false;
|
|
91
|
+
let isText = "";
|
|
92
|
+
for await (const ev of iterParse(sheetInput)) {
|
|
93
|
+
const e = ev;
|
|
94
|
+
if (e.kind === "start") {
|
|
95
|
+
const local = localName(e.name);
|
|
96
|
+
if (!inSheetData) {
|
|
97
|
+
if (local === "sheetData") inSheetData = true;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
switch (local) {
|
|
101
|
+
case "row": {
|
|
102
|
+
e.attrs;
|
|
103
|
+
const rRaw = e.attrs["r"];
|
|
104
|
+
currentRow = rRaw ? Number.parseInt(rRaw, 10) : currentRow + 1;
|
|
105
|
+
currentCells = [];
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case "c": {
|
|
109
|
+
if (currentRow < 0) break;
|
|
110
|
+
if (currentRow < minRow || currentRow > maxRow) break;
|
|
111
|
+
cellOpen = true;
|
|
112
|
+
cellType = e.attrs["t"] ?? "n";
|
|
113
|
+
const sRaw = e.attrs["s"];
|
|
114
|
+
cellStyleId = sRaw ? Number.parseInt(sRaw, 10) || 0 : 0;
|
|
115
|
+
const ref = e.attrs["r"];
|
|
116
|
+
if (ref) {
|
|
117
|
+
const tup = coordinateToTuple(ref);
|
|
118
|
+
cellRow = tup.row;
|
|
119
|
+
cellCol = tup.col;
|
|
120
|
+
} else {
|
|
121
|
+
cellRow = currentRow;
|
|
122
|
+
cellCol = (currentCells[currentCells.length - 1]?.col ?? 0) + 1;
|
|
123
|
+
}
|
|
124
|
+
vText = "";
|
|
125
|
+
isText = "";
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case "v":
|
|
129
|
+
if (cellOpen) inV = true;
|
|
130
|
+
break;
|
|
131
|
+
case "is":
|
|
132
|
+
if (cellOpen) inIs = true;
|
|
133
|
+
break;
|
|
134
|
+
case "t":
|
|
135
|
+
if (inIs) inIsT = true;
|
|
136
|
+
break;
|
|
137
|
+
default: break;
|
|
138
|
+
}
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (e.kind === "text") {
|
|
142
|
+
if (inV) vText += e.text;
|
|
143
|
+
else if (inIsT) isText += e.text;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const local = localName(e.name);
|
|
147
|
+
if (!inSheetData) continue;
|
|
148
|
+
switch (local) {
|
|
149
|
+
case "sheetData":
|
|
150
|
+
inSheetData = false;
|
|
151
|
+
return;
|
|
152
|
+
case "row":
|
|
153
|
+
if (currentRow >= minRow && currentRow <= maxRow && currentCells.length > 0) yield currentCells;
|
|
154
|
+
if (currentRow > maxRow) {
|
|
155
|
+
inSheetData = false;
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
currentRow = -1;
|
|
159
|
+
currentCells = [];
|
|
160
|
+
break;
|
|
161
|
+
case "c":
|
|
162
|
+
if (cellOpen && cellCol >= minCol && cellCol <= maxCol && cellRow >= minRow && cellRow <= maxRow) {
|
|
163
|
+
const value = decodeCellValue(cellType, vText, isText, sst);
|
|
164
|
+
currentCells.push({
|
|
165
|
+
row: cellRow,
|
|
166
|
+
col: cellCol,
|
|
167
|
+
value,
|
|
168
|
+
styleId: cellStyleId
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
cellOpen = false;
|
|
172
|
+
break;
|
|
173
|
+
case "v":
|
|
174
|
+
inV = false;
|
|
175
|
+
break;
|
|
176
|
+
case "is":
|
|
177
|
+
inIs = false;
|
|
178
|
+
break;
|
|
179
|
+
case "t":
|
|
180
|
+
if (inIs) inIsT = false;
|
|
181
|
+
break;
|
|
182
|
+
default: break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Build a sorted `[rowNum, byteOffset]` index for every `<row r="N">`
|
|
188
|
+
* occurrence in a worksheet's bytes. Pure byte-level scan (no SAX), cheap
|
|
189
|
+
* relative to the per-cell SAX walk: ~50 ns per row on M-series Node 22.
|
|
190
|
+
*
|
|
191
|
+
* `sheetDataEnd` is the byte offset of `</sheetData>` so callers can clip the
|
|
192
|
+
* slice that gets handed to saxes.
|
|
193
|
+
*/
|
|
194
|
+
const buildRowOffsetIndex = (bytes) => {
|
|
195
|
+
const out = [];
|
|
196
|
+
let sheetDataEnd = -1;
|
|
197
|
+
let i = 0;
|
|
198
|
+
while (i < bytes.length) {
|
|
199
|
+
if (bytes[i] !== 60) {
|
|
200
|
+
i++;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (sheetDataEnd < 0 && bytes[i + 1] === 47 && bytes[i + 2] === 115 && bytes[i + 3] === 104 && bytes[i + 4] === 101 && bytes[i + 5] === 101 && bytes[i + 6] === 116 && bytes[i + 7] === 68 && bytes[i + 8] === 97 && bytes[i + 9] === 116 && bytes[i + 10] === 97 && bytes[i + 11] === 62) {
|
|
204
|
+
sheetDataEnd = i;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
if (bytes[i + 1] !== 114 || bytes[i + 2] !== 111 || bytes[i + 3] !== 119) {
|
|
208
|
+
i++;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const next = bytes[i + 4];
|
|
212
|
+
if (next !== 32 && next !== 9 && next !== 10 && next !== 13 && next !== 62 && next !== 47) {
|
|
213
|
+
i++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const start = i;
|
|
217
|
+
let j = i + 4;
|
|
218
|
+
while (j < bytes.length && bytes[j] !== 62) j++;
|
|
219
|
+
if (j >= bytes.length) break;
|
|
220
|
+
const attrsBuf = bytes.subarray(start + 4, j);
|
|
221
|
+
const attrs = new TextDecoder("ascii", { fatal: false }).decode(attrsBuf);
|
|
222
|
+
const m = /\sr="(\d+)"/.exec(attrs);
|
|
223
|
+
if (m?.[1]) {
|
|
224
|
+
const row = Number.parseInt(m[1], 10);
|
|
225
|
+
if (Number.isInteger(row)) out.push({
|
|
226
|
+
row,
|
|
227
|
+
offset: start
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
i = j + 1;
|
|
231
|
+
}
|
|
232
|
+
if (sheetDataEnd < 0) sheetDataEnd = bytes.length;
|
|
233
|
+
return {
|
|
234
|
+
index: out,
|
|
235
|
+
sheetDataEnd
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* Binary-search the row index for the first entry with `row >= target`. Returns
|
|
240
|
+
* -1 when every recorded row is below the target.
|
|
241
|
+
*/
|
|
242
|
+
const firstRowAtOrAfter = (index, target) => {
|
|
243
|
+
let lo = 0;
|
|
244
|
+
let hi = index.length;
|
|
245
|
+
while (lo < hi) {
|
|
246
|
+
const mid = lo + hi >>> 1;
|
|
247
|
+
const entry = index[mid];
|
|
248
|
+
if (!entry || entry.row < target) lo = mid + 1;
|
|
249
|
+
else hi = mid;
|
|
250
|
+
}
|
|
251
|
+
return lo < index.length ? lo : -1;
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* Slice a worksheet's bytes to start at the row at index `idxPos` of the
|
|
255
|
+
* row-offset index, wrapping the result with a synthetic `<sheetData>` envelope
|
|
256
|
+
* so saxes parses it in the right namespace.
|
|
257
|
+
*/
|
|
258
|
+
const SHEET_DATA_OPEN = `<?xml version="1.0" encoding="UTF-8"?><sheetData xmlns="${SHEET_MAIN_NS}">`;
|
|
259
|
+
const SHEET_DATA_CLOSE = `</sheetData>`;
|
|
260
|
+
const sliceFromRow = (bytes, fromOffset, sheetDataEnd) => {
|
|
261
|
+
const prefix = new TextEncoder().encode(SHEET_DATA_OPEN);
|
|
262
|
+
const suffix = new TextEncoder().encode(SHEET_DATA_CLOSE);
|
|
263
|
+
const middle = bytes.subarray(fromOffset, sheetDataEnd);
|
|
264
|
+
const out = new Uint8Array(prefix.length + middle.length + suffix.length);
|
|
265
|
+
out.set(prefix, 0);
|
|
266
|
+
out.set(middle, prefix.length);
|
|
267
|
+
out.set(suffix, prefix.length + middle.length);
|
|
268
|
+
return out;
|
|
269
|
+
};
|
|
270
|
+
/**
|
|
271
|
+
* Factory: build a {@link ReadOnlyWorksheet} bound to a single worksheet part
|
|
272
|
+
* inside an opened archive. SAX iteration runs lazily — `iterRows` re-reads the
|
|
273
|
+
* part bytes each time so the caller can iterate the same sheet repeatedly
|
|
274
|
+
* without keeping a buffered decoder around.
|
|
275
|
+
*
|
|
276
|
+
* For `iterRows({ minRow > 1 })`, a row-offset index is built lazily on first
|
|
277
|
+
* use and cached; subsequent band queries jump straight to the byte offset of
|
|
278
|
+
* the first matching row instead of SAX-walking the entire `<sheetData>`.
|
|
279
|
+
*/
|
|
280
|
+
const makeStreamingReadOnlyWorksheet = (title, archive, partPath, sst) => {
|
|
281
|
+
let cached;
|
|
282
|
+
const ensureIndex = (bytes) => {
|
|
283
|
+
if (!cached) cached = buildRowOffsetIndex(bytes);
|
|
284
|
+
return cached;
|
|
285
|
+
};
|
|
286
|
+
const iterRows = (opts = {}) => {
|
|
287
|
+
const minRow = opts.minRow ?? 1;
|
|
288
|
+
if (minRow <= 1) return iterSheetRows(archive.readStream(partPath), sst, opts);
|
|
289
|
+
const bytes = archive.read(partPath);
|
|
290
|
+
const { index, sheetDataEnd } = ensureIndex(bytes);
|
|
291
|
+
if (index.length === 0) return iterSheetRows(bytes, sst, opts);
|
|
292
|
+
const pos = firstRowAtOrAfter(index, minRow);
|
|
293
|
+
if (pos < 0) return (async function* () {})();
|
|
294
|
+
const target = index[pos];
|
|
295
|
+
if (!target) return iterSheetRows(bytes, sst, opts);
|
|
296
|
+
return iterSheetRows(sliceFromRow(bytes, target.offset, sheetDataEnd), sst, opts);
|
|
297
|
+
};
|
|
298
|
+
const iterValues = async function* (opts = {}) {
|
|
299
|
+
for await (const row of iterRows(opts)) yield row.map((c) => c.value);
|
|
300
|
+
};
|
|
301
|
+
return {
|
|
302
|
+
title,
|
|
303
|
+
iterRows,
|
|
304
|
+
iterValues
|
|
305
|
+
};
|
|
306
|
+
};
|
|
307
|
+
/**
|
|
308
|
+
* Factory: build a {@link ReadOnlyWorkbook} from an opened archive + pre-parsed
|
|
309
|
+
* sheet list / styles / shared strings. Per the project-wide "no classes" rule
|
|
310
|
+
* (CLAUDE.md), the workbook is a plain object closing over the archive handle.
|
|
311
|
+
*/
|
|
312
|
+
const makeStreamingReadOnlyWorkbook = (sheetNames, styles, archive, entries, sst) => ({
|
|
313
|
+
sheetNames,
|
|
314
|
+
styles,
|
|
315
|
+
openWorksheet(name) {
|
|
316
|
+
const entry = entries.get(name);
|
|
317
|
+
if (!entry) throw new OpenXmlSchemaError(`loadWorkbookStream: no worksheet named "${name}"`);
|
|
318
|
+
return makeStreamingReadOnlyWorksheet(name, archive, entry.partPath, sst);
|
|
319
|
+
},
|
|
320
|
+
async close() {
|
|
321
|
+
archive.close();
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
/** Open an xlsx for read-only streaming access. */
|
|
325
|
+
async function loadWorkbookStream(source, opts = {}) {
|
|
326
|
+
const archive = await openZip(source, opts.decompressionLimits === void 0 ? {} : { decompressionLimits: opts.decompressionLimits });
|
|
327
|
+
if (!archive.has("[Content_Types].xml")) throw new OpenXmlSchemaError(`loadWorkbookStream: missing "${ARC_CONTENT_TYPES}"`);
|
|
328
|
+
manifestFromBytes(archive.read(ARC_CONTENT_TYPES));
|
|
329
|
+
if (!archive.has(ARC_ROOT_RELS)) throw new OpenXmlSchemaError(`loadWorkbookStream: missing "${ARC_ROOT_RELS}"`);
|
|
330
|
+
const officeDocRel = relsFromBytes(archive.read(ARC_ROOT_RELS)).rels.find((r) => r.type === `${REL_NS}/officeDocument`);
|
|
331
|
+
if (!officeDocRel) throw new OpenXmlSchemaError(`loadWorkbookStream: no officeDocument relationship in root rels`);
|
|
332
|
+
const workbookPath = resolveRelTarget("", officeDocRel.target);
|
|
333
|
+
if (!archive.has(workbookPath)) throw new OpenXmlSchemaError(`loadWorkbookStream: workbook part "${workbookPath}" missing`);
|
|
334
|
+
const sheetEntries = parseSheetList(archive.read(workbookPath), workbookPath, archive);
|
|
335
|
+
const entryMap = /* @__PURE__ */ new Map();
|
|
336
|
+
for (const e of sheetEntries) entryMap.set(e.name, e);
|
|
337
|
+
let sst = {
|
|
338
|
+
entries: [],
|
|
339
|
+
index: /* @__PURE__ */ new Map()
|
|
340
|
+
};
|
|
341
|
+
if (archive.has(ARC_SHARED_STRINGS)) sst = parseSharedStringsXml(archive.read(ARC_SHARED_STRINGS));
|
|
342
|
+
let styles = makeStylesheet();
|
|
343
|
+
if (archive.has(ARC_STYLE)) styles = parseStylesheetXml(archive.read(ARC_STYLE));
|
|
344
|
+
return makeStreamingReadOnlyWorkbook(sheetEntries.map((e) => e.name), styles, archive, entryMap, sst.entries.map((e) => typeof e === "string" ? e : e.runs.map((r) => r.text).join("")));
|
|
345
|
+
}
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region src/streaming/write-only.ts
|
|
348
|
+
const escapeAttr = escapeXmlAttr;
|
|
349
|
+
const validateTitle = (title, taken) => {
|
|
350
|
+
const reason = validateSheetTitle(title);
|
|
351
|
+
if (reason) throw new OpenXmlIoError(`Worksheet title "${title}": ${reason}`);
|
|
352
|
+
if (taken.has(title.toLowerCase())) throw new OpenXmlIoError(`Worksheet title "${title}" is already in use`);
|
|
353
|
+
};
|
|
354
|
+
/** Allocate a CellXf id for a style spec. Mirrors cell-style.ts but works directly on the pool. */
|
|
355
|
+
const allocateXfId = (ss, style) => {
|
|
356
|
+
let xf = {
|
|
357
|
+
fontId: 0,
|
|
358
|
+
fillId: 0,
|
|
359
|
+
borderId: 0,
|
|
360
|
+
numFmtId: 0
|
|
361
|
+
};
|
|
362
|
+
if (style.font !== void 0) xf = {
|
|
363
|
+
...xf,
|
|
364
|
+
fontId: addFont(ss, style.font),
|
|
365
|
+
applyFont: true
|
|
366
|
+
};
|
|
367
|
+
if (style.fill !== void 0) xf = {
|
|
368
|
+
...xf,
|
|
369
|
+
fillId: addFill(ss, style.fill),
|
|
370
|
+
applyFill: true
|
|
371
|
+
};
|
|
372
|
+
if (style.border !== void 0) xf = {
|
|
373
|
+
...xf,
|
|
374
|
+
borderId: addBorder(ss, style.border),
|
|
375
|
+
applyBorder: true
|
|
376
|
+
};
|
|
377
|
+
if (style.numberFormat !== void 0) xf = {
|
|
378
|
+
...xf,
|
|
379
|
+
numFmtId: addNumFmt(ss, style.numberFormat),
|
|
380
|
+
applyNumberFormat: true
|
|
381
|
+
};
|
|
382
|
+
if (style.alignment !== void 0) xf = {
|
|
383
|
+
...xf,
|
|
384
|
+
alignment: style.alignment,
|
|
385
|
+
applyAlignment: true
|
|
386
|
+
};
|
|
387
|
+
if (style.protection !== void 0) xf = {
|
|
388
|
+
...xf,
|
|
389
|
+
protection: style.protection,
|
|
390
|
+
applyProtection: true
|
|
391
|
+
};
|
|
392
|
+
return addCellXf(ss, xf);
|
|
393
|
+
};
|
|
394
|
+
/**
|
|
395
|
+
* Flush threshold for the worksheet's pending-row text buffer. Smaller values
|
|
396
|
+
* minimise heap; larger values amortise the TextEncoder + push overhead. 64 KB
|
|
397
|
+
* is a sweet spot — heap stays low and per-row JS work is dominated by the
|
|
398
|
+
* actual XML construction, not flushing.
|
|
399
|
+
*/
|
|
400
|
+
const FLUSH_THRESHOLD_BYTES = 64 * 1024;
|
|
401
|
+
/**
|
|
402
|
+
* Factory: build a {@link WriteOnlyWorksheet} that closes over the shared
|
|
403
|
+
* {@link WorkbookState}. Per the project-wide "no classes" rule (CLAUDE.md) the
|
|
404
|
+
* worksheet is a plain object holding the row buffer + column-width map in
|
|
405
|
+
* closure state.
|
|
406
|
+
*
|
|
407
|
+
* The worksheet streams its `<sheetData>` body chunk-by-chunk through the ZIP
|
|
408
|
+
* writer's `addStreamingEntry` API, so the heap footprint stays at one ~64 KB
|
|
409
|
+
* pending text buffer plus deflate scratch — no Cell objects, no all-rows
|
|
410
|
+
* accumulation. The XML envelope (decl / worksheet open / cols / sheetData
|
|
411
|
+
* open) flushes on the first `appendRow` (or `close()` if the sheet is empty);
|
|
412
|
+
* column widths staged via `setColumnWidth` *must* land before the first row.
|
|
413
|
+
*/
|
|
414
|
+
const makeWriteOnlyWorksheet = (state, title, sheetId) => {
|
|
415
|
+
let nextRow = 1;
|
|
416
|
+
let closed = false;
|
|
417
|
+
let headerFlushed = false;
|
|
418
|
+
const columnWidths = /* @__PURE__ */ new Map();
|
|
419
|
+
const dummyCtx = {
|
|
420
|
+
sharedStrings: state.sst,
|
|
421
|
+
rels: makeRelationships()
|
|
422
|
+
};
|
|
423
|
+
const encoder = new TextEncoder();
|
|
424
|
+
const stream = state.writer.addStreamingEntry(`xl/worksheets/sheet${sheetId}.xml`);
|
|
425
|
+
let pendingText = "";
|
|
426
|
+
let pendingBytes = 0;
|
|
427
|
+
const writeText = (text) => {
|
|
428
|
+
pendingText += text;
|
|
429
|
+
pendingBytes += utf8ByteLength(text);
|
|
430
|
+
if (pendingBytes >= FLUSH_THRESHOLD_BYTES) {
|
|
431
|
+
stream.write(encoder.encode(pendingText));
|
|
432
|
+
pendingText = "";
|
|
433
|
+
pendingBytes = 0;
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
const flushHeader = () => {
|
|
437
|
+
if (headerFlushed) return;
|
|
438
|
+
headerFlushed = true;
|
|
439
|
+
let header = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
|
|
440
|
+
header += `<worksheet xmlns="${SHEET_MAIN_NS}" xmlns:r="${REL_NS}">`;
|
|
441
|
+
if (columnWidths.size > 0) {
|
|
442
|
+
header += "<cols>";
|
|
443
|
+
const sorted = [...columnWidths.entries()].sort((a, b) => a[0] - b[0]);
|
|
444
|
+
for (const [col, width] of sorted) header += `<col min="${col}" max="${col}" width="${width}" customWidth="1"/>`;
|
|
445
|
+
header += "</cols>";
|
|
446
|
+
}
|
|
447
|
+
header += "<sheetData>";
|
|
448
|
+
writeText(header);
|
|
449
|
+
};
|
|
450
|
+
const appendRow = async (row) => {
|
|
451
|
+
if (closed) throw new OpenXmlIoError("appendRow: worksheet already closed");
|
|
452
|
+
flushHeader();
|
|
453
|
+
const r = nextRow++;
|
|
454
|
+
let xml = `<row r="${r}">`;
|
|
455
|
+
for (let i = 0; i < row.length; i++) {
|
|
456
|
+
const item = row[i];
|
|
457
|
+
if (item === void 0 || item === null) continue;
|
|
458
|
+
const col = i + 1;
|
|
459
|
+
let value;
|
|
460
|
+
let style;
|
|
461
|
+
if (item !== null && typeof item === "object" && "value" in item) {
|
|
462
|
+
const wrapped = item;
|
|
463
|
+
value = wrapped.value;
|
|
464
|
+
style = wrapped.style;
|
|
465
|
+
} else value = item;
|
|
466
|
+
const styleId = style ? allocateXfId(state.styles, style) : 0;
|
|
467
|
+
xml += serializeCell({
|
|
468
|
+
row: r,
|
|
469
|
+
col,
|
|
470
|
+
value,
|
|
471
|
+
styleId
|
|
472
|
+
}, dummyCtx);
|
|
473
|
+
}
|
|
474
|
+
xml += "</row>";
|
|
475
|
+
writeText(xml);
|
|
476
|
+
};
|
|
477
|
+
const setColumnWidth = (col, width) => {
|
|
478
|
+
if (closed) throw new OpenXmlIoError("setColumnWidth: worksheet already closed");
|
|
479
|
+
if (headerFlushed) throw new OpenXmlIoError("setColumnWidth: must be called before the first appendRow — column widths are emitted as part of the worksheet header");
|
|
480
|
+
columnWidths.set(col, width);
|
|
481
|
+
};
|
|
482
|
+
const close = async () => {
|
|
483
|
+
if (closed) return;
|
|
484
|
+
closed = true;
|
|
485
|
+
flushHeader();
|
|
486
|
+
writeText("</sheetData></worksheet>");
|
|
487
|
+
if (pendingText.length > 0) {
|
|
488
|
+
stream.write(encoder.encode(pendingText));
|
|
489
|
+
pendingText = "";
|
|
490
|
+
pendingBytes = 0;
|
|
491
|
+
}
|
|
492
|
+
await stream.end();
|
|
493
|
+
state.sheets.push({
|
|
494
|
+
title,
|
|
495
|
+
sheetId
|
|
496
|
+
});
|
|
497
|
+
state.hasOpenWorksheet = false;
|
|
498
|
+
};
|
|
499
|
+
return {
|
|
500
|
+
title,
|
|
501
|
+
appendRow,
|
|
502
|
+
setColumnWidth,
|
|
503
|
+
close
|
|
504
|
+
};
|
|
505
|
+
};
|
|
506
|
+
/**
|
|
507
|
+
* Factory: build a {@link WriteOnlyWorkbook} from a sink. State lives in a
|
|
508
|
+
* closure rather than on a class instance per the project-wide "no classes"
|
|
509
|
+
* rule (CLAUDE.md).
|
|
510
|
+
*/
|
|
511
|
+
const makeWriteOnlyWorkbook = (sink) => {
|
|
512
|
+
const styles = makeStylesheet();
|
|
513
|
+
addCellXf(styles, defaultCellXf());
|
|
514
|
+
const state = {
|
|
515
|
+
styles,
|
|
516
|
+
sst: makeSharedStrings(),
|
|
517
|
+
sheets: [],
|
|
518
|
+
finalised: false,
|
|
519
|
+
hasOpenWorksheet: false,
|
|
520
|
+
writer: createZipWriter(sink)
|
|
521
|
+
};
|
|
522
|
+
const addWorksheet = async (title) => {
|
|
523
|
+
if (state.finalised) throw new OpenXmlIoError("addWorksheet: workbook already finalised");
|
|
524
|
+
if (state.hasOpenWorksheet) throw new OpenXmlIoError("addWorksheet: previous worksheet still open — call close() before opening the next one");
|
|
525
|
+
validateTitle(title, new Set(state.sheets.map((s) => s.title.toLowerCase())));
|
|
526
|
+
state.hasOpenWorksheet = true;
|
|
527
|
+
return makeWriteOnlyWorksheet(state, title, state.sheets.length + 1);
|
|
528
|
+
};
|
|
529
|
+
const finalize = async () => {
|
|
530
|
+
if (state.finalised) throw new OpenXmlIoError("finalize: already finalised");
|
|
531
|
+
if (state.hasOpenWorksheet) throw new OpenXmlIoError("finalize: a worksheet is still open — call close() before finalising");
|
|
532
|
+
state.finalised = true;
|
|
533
|
+
const writer = state.writer;
|
|
534
|
+
try {
|
|
535
|
+
await finalizeImpl(state, writer);
|
|
536
|
+
} catch (err) {
|
|
537
|
+
writer.abort(err);
|
|
538
|
+
throw err;
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
const abort = (cause) => {
|
|
542
|
+
if (state.finalised) return;
|
|
543
|
+
state.finalised = true;
|
|
544
|
+
state.writer.abort(cause);
|
|
545
|
+
};
|
|
546
|
+
return {
|
|
547
|
+
addWorksheet,
|
|
548
|
+
finalize,
|
|
549
|
+
abort
|
|
550
|
+
};
|
|
551
|
+
};
|
|
552
|
+
async function finalizeImpl(state, writer) {
|
|
553
|
+
await writer.addEntry(ARC_STYLE, stylesheetToBytes(state.styles));
|
|
554
|
+
if (state.sst.entries.length > 0) await writer.addEntry(ARC_SHARED_STRINGS, sharedStringsToBytes(state.sst));
|
|
555
|
+
const workbookXml = serializeWorkbookXml(state.sheets);
|
|
556
|
+
await writer.addEntry(ARC_WORKBOOK, new TextEncoder().encode(workbookXml));
|
|
557
|
+
const wbRels = makeRelationships();
|
|
558
|
+
state.sheets.forEach((s, i) => {
|
|
559
|
+
wbRels.rels.push({
|
|
560
|
+
id: `rId${i + 1}`,
|
|
561
|
+
type: `${REL_NS}/worksheet`,
|
|
562
|
+
target: `worksheets/sheet${s.sheetId}.xml`
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
if (state.sst.entries.length > 0) wbRels.rels.push({
|
|
566
|
+
id: `rId${wbRels.rels.length + 1}`,
|
|
567
|
+
type: `${REL_NS}/sharedStrings`,
|
|
568
|
+
target: "sharedStrings.xml"
|
|
569
|
+
});
|
|
570
|
+
wbRels.rels.push({
|
|
571
|
+
id: `rId${wbRels.rels.length + 1}`,
|
|
572
|
+
type: `${REL_NS}/styles`,
|
|
573
|
+
target: "styles.xml"
|
|
574
|
+
});
|
|
575
|
+
await writer.addEntry(ARC_WORKBOOK_RELS, relsToBytes(wbRels));
|
|
576
|
+
const rootRels = makeRelationships();
|
|
577
|
+
rootRels.rels.push({
|
|
578
|
+
id: "rId1",
|
|
579
|
+
type: `${REL_NS}/officeDocument`,
|
|
580
|
+
target: "xl/workbook.xml"
|
|
581
|
+
});
|
|
582
|
+
await writer.addEntry(ARC_ROOT_RELS, relsToBytes(rootRels));
|
|
583
|
+
const manifest = makeManifest();
|
|
584
|
+
addDefault(manifest, "rels", "application/vnd.openxmlformats-package.relationships+xml");
|
|
585
|
+
addDefault(manifest, "xml", "application/xml");
|
|
586
|
+
addOverride(manifest, `/${ARC_WORKBOOK}`, XLSX_TYPE);
|
|
587
|
+
for (const s of state.sheets) addOverride(manifest, `/xl/worksheets/sheet${s.sheetId}.xml`, WORKSHEET_TYPE);
|
|
588
|
+
addOverride(manifest, `/${ARC_STYLE}`, STYLES_TYPE);
|
|
589
|
+
if (state.sst.entries.length > 0) addOverride(manifest, `/${ARC_SHARED_STRINGS}`, SHARED_STRINGS_TYPE);
|
|
590
|
+
await writer.addEntry(ARC_CONTENT_TYPES, manifestToBytes(manifest));
|
|
591
|
+
await writer.finalize();
|
|
592
|
+
}
|
|
593
|
+
const serializeWorkbookXml = (sheets) => {
|
|
594
|
+
const parts = [
|
|
595
|
+
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>",
|
|
596
|
+
`<workbook xmlns="${SHEET_MAIN_NS}" xmlns:r="${REL_NS}">`,
|
|
597
|
+
"<sheets>"
|
|
598
|
+
];
|
|
599
|
+
sheets.forEach((s, i) => {
|
|
600
|
+
parts.push(`<sheet name="${escapeAttr(s.title)}" sheetId="${s.sheetId}" r:id="rId${i + 1}"/>`);
|
|
601
|
+
});
|
|
602
|
+
parts.push("</sheets></workbook>");
|
|
603
|
+
return parts.join("");
|
|
604
|
+
};
|
|
605
|
+
/** Open a workbook for streaming write-only output. */
|
|
606
|
+
async function createWriteOnlyWorkbook(sink, _opts = {}) {
|
|
607
|
+
return makeWriteOnlyWorkbook(sink);
|
|
608
|
+
}
|
|
609
|
+
//#endregion
|
|
610
|
+
export { createWriteOnlyWorkbook, loadWorkbookStream };
|
|
611
|
+
|
|
612
|
+
//# sourceMappingURL=streaming.mjs.map
|