@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.
Files changed (220) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +319 -0
  3. package/THIRD_PARTY_NOTICES.md +56 -0
  4. package/dist/cell/cell.d.ts +234 -0
  5. package/dist/cell/index.d.ts +4 -0
  6. package/dist/cell/rich-text.d.ts +37 -0
  7. package/dist/cell-D9CaNKnU.mjs +320 -0
  8. package/dist/cell-D9CaNKnU.mjs.map +1 -0
  9. package/dist/cell-style-BEDjMX1y.mjs +1579 -0
  10. package/dist/cell-style-BEDjMX1y.mjs.map +1 -0
  11. package/dist/cell.mjs +2 -0
  12. package/dist/chart/chart-xml.d.ts +16 -0
  13. package/dist/chart/chart.d.ts +735 -0
  14. package/dist/chart/cx/chartex-xml.d.ts +6 -0
  15. package/dist/chart/cx/chartex.d.ts +279 -0
  16. package/dist/chart/index.d.ts +6 -0
  17. package/dist/chart/user-shapes-xml.d.ts +4 -0
  18. package/dist/chart/user-shapes.d.ts +61 -0
  19. package/dist/chart.mjs +232 -0
  20. package/dist/chart.mjs.map +1 -0
  21. package/dist/chartsheet/chartsheet-xml.d.ts +17 -0
  22. package/dist/chartsheet/chartsheet.d.ts +121 -0
  23. package/dist/chartsheet/index.d.ts +2 -0
  24. package/dist/chartsheet-C3-tqkPy.mjs +23 -0
  25. package/dist/chartsheet-C3-tqkPy.mjs.map +1 -0
  26. package/dist/chartsheet.mjs +2 -0
  27. package/dist/colors-ovWAwnZI.mjs +67 -0
  28. package/dist/colors-ovWAwnZI.mjs.map +1 -0
  29. package/dist/compat/numbers.d.ts +14 -0
  30. package/dist/coordinate-96Ecci4d.mjs +276 -0
  31. package/dist/coordinate-96Ecci4d.mjs.map +1 -0
  32. package/dist/datetime-B2ySVlXt.mjs +71 -0
  33. package/dist/datetime-B2ySVlXt.mjs.map +1 -0
  34. package/dist/defined-names-CviWmtQg.mjs +89 -0
  35. package/dist/defined-names-CviWmtQg.mjs.map +1 -0
  36. package/dist/differential-D4dg-qtZ.mjs +37 -0
  37. package/dist/differential-D4dg-qtZ.mjs.map +1 -0
  38. package/dist/drawing/anchor.d.ts +63 -0
  39. package/dist/drawing/dml/colors.d.ts +109 -0
  40. package/dist/drawing/dml/dml-xml.d.ts +35 -0
  41. package/dist/drawing/dml/effect.d.ts +92 -0
  42. package/dist/drawing/dml/fill.d.ts +115 -0
  43. package/dist/drawing/dml/geometry.d.ts +113 -0
  44. package/dist/drawing/dml/line.d.ts +41 -0
  45. package/dist/drawing/dml/shape-properties.d.ts +33 -0
  46. package/dist/drawing/dml/text.d.ts +218 -0
  47. package/dist/drawing/drawing-xml.d.ts +5 -0
  48. package/dist/drawing/drawing.d.ts +117 -0
  49. package/dist/drawing/image.d.ts +40 -0
  50. package/dist/drawing/index.d.ts +14 -0
  51. package/dist/drawing-BxzLuryn.mjs +415 -0
  52. package/dist/drawing-BxzLuryn.mjs.map +1 -0
  53. package/dist/drawing.mjs +119 -0
  54. package/dist/drawing.mjs.map +1 -0
  55. package/dist/escape-DFTE7ZJc.mjs +51 -0
  56. package/dist/escape-DFTE7ZJc.mjs.map +1 -0
  57. package/dist/exceptions-D-CFwxgm.mjs +37 -0
  58. package/dist/exceptions-D-CFwxgm.mjs.map +1 -0
  59. package/dist/formula/tokenizer.d.ts +61 -0
  60. package/dist/formula/translate.d.ts +67 -0
  61. package/dist/inference-B3ES3KEJ.mjs +42 -0
  62. package/dist/inference-B3ES3KEJ.mjs.map +1 -0
  63. package/dist/io/browser.d.ts +41 -0
  64. package/dist/io/index.d.ts +7 -0
  65. package/dist/io/load.d.ts +46 -0
  66. package/dist/io/node-fs.d.ts +62 -0
  67. package/dist/io/node-save.d.ts +3 -0
  68. package/dist/io/node.d.ts +17 -0
  69. package/dist/io/save.d.ts +14 -0
  70. package/dist/io/sink.d.ts +54 -0
  71. package/dist/io/source.d.ts +14 -0
  72. package/dist/io.mjs +212 -0
  73. package/dist/io.mjs.map +1 -0
  74. package/dist/load-D5cbhoGx.mjs +1069 -0
  75. package/dist/load-D5cbhoGx.mjs.map +1 -0
  76. package/dist/manifest-Dps1-OpP.mjs +801 -0
  77. package/dist/manifest-Dps1-OpP.mjs.map +1 -0
  78. package/dist/node.d.ts +3 -0
  79. package/dist/node.mjs +308 -0
  80. package/dist/node.mjs.map +1 -0
  81. package/dist/packaging/core.d.ts +45 -0
  82. package/dist/packaging/custom.d.ts +62 -0
  83. package/dist/packaging/extended.d.ts +45 -0
  84. package/dist/packaging/index.d.ts +10 -0
  85. package/dist/packaging/manifest.d.ts +24 -0
  86. package/dist/packaging/relationships.d.ts +30 -0
  87. package/dist/packaging.mjs +2 -0
  88. package/dist/parser-DuLejQy1.mjs +156 -0
  89. package/dist/parser-DuLejQy1.mjs.map +1 -0
  90. package/dist/reader-D1fNW9k1.mjs +534 -0
  91. package/dist/reader-D1fNW9k1.mjs.map +1 -0
  92. package/dist/save-RohQtgEZ.mjs +745 -0
  93. package/dist/save-RohQtgEZ.mjs.map +1 -0
  94. package/dist/schema/core.d.ts +133 -0
  95. package/dist/schema/index.d.ts +3 -0
  96. package/dist/schema/serialize.d.ts +6 -0
  97. package/dist/schema.mjs +2 -0
  98. package/dist/serialize-55EnT30e.mjs +254 -0
  99. package/dist/serialize-55EnT30e.mjs.map +1 -0
  100. package/dist/serializer-BwbgHYJV.mjs +116 -0
  101. package/dist/serializer-BwbgHYJV.mjs.map +1 -0
  102. package/dist/streaming/index.d.ts +2 -0
  103. package/dist/streaming/read-only.d.ts +38 -0
  104. package/dist/streaming/write-only.d.ts +47 -0
  105. package/dist/streaming.mjs +612 -0
  106. package/dist/streaming.mjs.map +1 -0
  107. package/dist/styles/alignment.d.ts +33 -0
  108. package/dist/styles/alignment.schema.d.ts +3 -0
  109. package/dist/styles/borders.d.ts +40 -0
  110. package/dist/styles/borders.schema.d.ts +4 -0
  111. package/dist/styles/cell-style.d.ts +270 -0
  112. package/dist/styles/colors.d.ts +128 -0
  113. package/dist/styles/colors.schema.d.ts +3 -0
  114. package/dist/styles/differential.d.ts +41 -0
  115. package/dist/styles/fills.d.ts +54 -0
  116. package/dist/styles/fills.schema.d.ts +6 -0
  117. package/dist/styles/fonts.d.ts +44 -0
  118. package/dist/styles/fonts.schema.d.ts +3 -0
  119. package/dist/styles/index.d.ts +21 -0
  120. package/dist/styles/named-styles.d.ts +52 -0
  121. package/dist/styles/numbers.d.ts +39 -0
  122. package/dist/styles/numbers.schema.d.ts +3 -0
  123. package/dist/styles/protection.d.ts +9 -0
  124. package/dist/styles/protection.schema.d.ts +3 -0
  125. package/dist/styles/stylesheet-reader.d.ts +7 -0
  126. package/dist/styles/stylesheet-writer.d.ts +3 -0
  127. package/dist/styles/stylesheet.d.ts +95 -0
  128. package/dist/styles.mjs +4 -0
  129. package/dist/stylesheet-writer-C2eRmn22.mjs +8624 -0
  130. package/dist/stylesheet-writer-C2eRmn22.mjs.map +1 -0
  131. package/dist/table-DkX6UniA.mjs +113 -0
  132. package/dist/table-DkX6UniA.mjs.map +1 -0
  133. package/dist/tree-Bbs1C8Rc.mjs +192 -0
  134. package/dist/tree-Bbs1C8Rc.mjs.map +1 -0
  135. package/dist/units-rOMQqXh2.mjs +41 -0
  136. package/dist/units-rOMQqXh2.mjs.map +1 -0
  137. package/dist/user-shapes-DfmCGKB0.mjs +252 -0
  138. package/dist/user-shapes-DfmCGKB0.mjs.map +1 -0
  139. package/dist/utf8-D91g1XTG.mjs +143 -0
  140. package/dist/utf8-D91g1XTG.mjs.map +1 -0
  141. package/dist/utils/coordinate.d.ts +103 -0
  142. package/dist/utils/css.d.ts +18 -0
  143. package/dist/utils/datetime.d.ts +38 -0
  144. package/dist/utils/escape.d.ts +34 -0
  145. package/dist/utils/exceptions.d.ts +34 -0
  146. package/dist/utils/index.d.ts +11 -0
  147. package/dist/utils/inference.d.ts +24 -0
  148. package/dist/utils/stable-stringify.d.ts +7 -0
  149. package/dist/utils/units.d.ts +14 -0
  150. package/dist/utils/utf8.d.ts +1 -0
  151. package/dist/utils.mjs +39 -0
  152. package/dist/utils.mjs.map +1 -0
  153. package/dist/workbook/calc-properties.d.ts +47 -0
  154. package/dist/workbook/defined-names.d.ts +121 -0
  155. package/dist/workbook/file-recovery.d.ts +11 -0
  156. package/dist/workbook/file-sharing.d.ts +14 -0
  157. package/dist/workbook/file-version.d.ts +13 -0
  158. package/dist/workbook/function-groups.d.ts +10 -0
  159. package/dist/workbook/index.d.ts +24 -0
  160. package/dist/workbook/protection.d.ts +35 -0
  161. package/dist/workbook/shared-strings.d.ts +57 -0
  162. package/dist/workbook/smart-tags.d.ts +13 -0
  163. package/dist/workbook/views.d.ts +89 -0
  164. package/dist/workbook/workbook-properties.d.ts +57 -0
  165. package/dist/workbook/workbook.d.ts +643 -0
  166. package/dist/workbook-HGYNRBlV.mjs +636 -0
  167. package/dist/workbook-HGYNRBlV.mjs.map +1 -0
  168. package/dist/workbook.mjs +58 -0
  169. package/dist/workbook.mjs.map +1 -0
  170. package/dist/worksheet/auto-filter.d.ts +34 -0
  171. package/dist/worksheet/cell-range.d.ts +121 -0
  172. package/dist/worksheet/comments-xml.d.ts +24 -0
  173. package/dist/worksheet/comments.d.ts +13 -0
  174. package/dist/worksheet/conditional-formatting.d.ts +150 -0
  175. package/dist/worksheet/custom-sheet-views.d.ts +43 -0
  176. package/dist/worksheet/data-consolidate.d.ts +29 -0
  177. package/dist/worksheet/data-validations.d.ts +72 -0
  178. package/dist/worksheet/dimensions.d.ts +40 -0
  179. package/dist/worksheet/errors.d.ts +40 -0
  180. package/dist/worksheet/hyperlinks.d.ts +42 -0
  181. package/dist/worksheet/index.d.ts +46 -0
  182. package/dist/worksheet/ole-objects.d.ts +37 -0
  183. package/dist/worksheet/page-setup.d.ts +173 -0
  184. package/dist/worksheet/phonetic.d.ts +11 -0
  185. package/dist/worksheet/properties.d.ts +34 -0
  186. package/dist/worksheet/protected-ranges.d.ts +19 -0
  187. package/dist/worksheet/protection.d.ts +44 -0
  188. package/dist/worksheet/reader.d.ts +38 -0
  189. package/dist/worksheet/scenarios.d.ts +36 -0
  190. package/dist/worksheet/smart-tags.d.ts +23 -0
  191. package/dist/worksheet/sort-state.d.ts +28 -0
  192. package/dist/worksheet/table-xml.d.ts +5 -0
  193. package/dist/worksheet/table.d.ts +80 -0
  194. package/dist/worksheet/views.d.ts +47 -0
  195. package/dist/worksheet/web-publish.d.ts +21 -0
  196. package/dist/worksheet/worksheet.d.ts +935 -0
  197. package/dist/worksheet/writer.d.ts +72 -0
  198. package/dist/worksheet-CmCNoIgD.mjs +1726 -0
  199. package/dist/worksheet-CmCNoIgD.mjs.map +1 -0
  200. package/dist/worksheet.mjs +247 -0
  201. package/dist/worksheet.mjs.map +1 -0
  202. package/dist/writer-DspzfkNA.mjs +221 -0
  203. package/dist/writer-DspzfkNA.mjs.map +1 -0
  204. package/dist/xml/index.d.ts +10 -0
  205. package/dist/xml/iterparse.d.ts +22 -0
  206. package/dist/xml/namespaces.d.ts +91 -0
  207. package/dist/xml/parser.d.ts +7 -0
  208. package/dist/xml/serializer.d.ts +14 -0
  209. package/dist/xml/stream-writer.d.ts +39 -0
  210. package/dist/xml/tree.d.ts +37 -0
  211. package/dist/xml.mjs +140 -0
  212. package/dist/xml.mjs.map +1 -0
  213. package/dist/zip/decompression-guard.d.ts +70 -0
  214. package/dist/zip/index.d.ts +6 -0
  215. package/dist/zip/random-access-reader.d.ts +16 -0
  216. package/dist/zip/reader.d.ts +45 -0
  217. package/dist/zip/writer.d.ts +65 -0
  218. package/dist/zip/zip64-patch.d.ts +12 -0
  219. package/dist/zip.mjs +3 -0
  220. 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