@justybase/spreadsheet-tasks 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -35,6 +35,9 @@ __export(index_exports, {
35
35
  ExcelReaderAbstract: () => ExcelReaderAbstract,
36
36
  F: () => F,
37
37
  INVALID_SHEET_NAME_CHARS: () => INVALID_SHEET_NAME_CHARS,
38
+ MAX_CELL_CHARS: () => MAX_CELL_CHARS,
39
+ MAX_COLS: () => MAX_COLS,
40
+ MAX_ROWS: () => MAX_ROWS,
38
41
  ReaderFactory: () => ReaderFactory,
39
42
  StreamingSheetState: () => StreamingSheetState,
40
43
  XlsbReader: () => XlsbReader,
@@ -45,13 +48,25 @@ __export(index_exports, {
45
48
  XlsxUpdater: () => XlsxUpdater,
46
49
  XlsxWriter: () => XlsxWriter,
47
50
  applyHeaderWidths: () => applyHeaderWidths,
51
+ assertCellTextLength: () => assertCellTextLength,
52
+ assertColumnCount: () => assertColumnCount,
53
+ assertRowCount: () => assertRowCount,
54
+ assertRowFitsColumns: () => assertRowFitsColumns,
55
+ columnIndexToLetter: () => columnIndexToLetter,
56
+ columnLetterToIndex: () => columnLetterToIndex,
48
57
  convertXlsbToXlsx: () => convertXlsbToXlsx,
49
58
  convertXlsxToXlsb: () => convertXlsxToXlsb,
50
59
  defaultColWidth: () => defaultColWidth,
60
+ escapeXmlText: () => escapeXmlText,
51
61
  getFormat: () => getFormat,
52
62
  initColWidths: () => initColWidths,
53
63
  isFormattedCell: () => isFormattedCell,
64
+ parseSharedStringsXml: () => parseSharedStringsXml,
65
+ parseTagAttributes: () => parseTagAttributes,
66
+ resolveRelTarget: () => resolveRelTarget,
54
67
  sanitizeSheetName: () => sanitizeSheetName,
68
+ trimTrailingEmptyRows: () => trimTrailingEmptyRows,
69
+ unescapeXml: () => unescapeXml,
55
70
  unwrapCell: () => unwrapCell,
56
71
  updateColWidthsFromRows: () => updateColWidthsFromRows
57
72
  });
@@ -171,6 +186,143 @@ var BigBuffer = class {
171
186
  }
172
187
  };
173
188
 
189
+ // src/Formats.ts
190
+ var F = {
191
+ THOUSANDS_SEP: "#,##0",
192
+ CURRENCY_PLN: '#,##0.00 "z\u0142"',
193
+ CURRENCY_EUR: "#,##0.00 \u20AC",
194
+ PERCENTAGE: "0%",
195
+ SCIENTIFIC: "0.00E+00",
196
+ TWO_DECIMALS: "#,##0.00",
197
+ TEXT: "@",
198
+ LEADING_ZEROS: "000000000",
199
+ DATE_SHORT: "dd.mm.yyyy",
200
+ DATE_LONG: "d mmmm yyyy",
201
+ DATE_DAY_MONTH_YEAR: "dd-mm-yyyy",
202
+ DATE_ISO: "yyyy-mm-dd",
203
+ DATE_MONTH_YEAR: "mmmm yyyy",
204
+ DATE_WEEKDAY: "dddd, d mmmm yyyy",
205
+ DATE_DAY_MONTH: "d mmmm",
206
+ DATE_YEAR_ONLY: "yyyy",
207
+ DATETIME_SHORT: "dd.mm.yyyy hh:mm",
208
+ DATETIME_LONG: "d mmmm yyyy hh:mm:ss",
209
+ TIME_HH_MM: "hh:mm",
210
+ TIME_HH_MM_SS: "hh:mm:ss",
211
+ TIME_12H: "h:mm AM/PM",
212
+ DATETIME_24H: "dd.mm.yyyy hh:mm:ss",
213
+ DATETIME_ISO: 'yyyy-mm-dd"T"hh:mm:ss',
214
+ TIME_MS: "hh:mm:ss.000"
215
+ };
216
+ function isFormattedCell(val) {
217
+ return val !== null && val !== void 0 && typeof val === "object" && "format" in val && typeof val.format === "string";
218
+ }
219
+ function unwrapCell(val) {
220
+ if (isFormattedCell(val)) {
221
+ return val.value;
222
+ }
223
+ return val;
224
+ }
225
+ function getFormat(val) {
226
+ if (isFormattedCell(val)) {
227
+ return val.format;
228
+ }
229
+ return null;
230
+ }
231
+
232
+ // src/writerHelpers.ts
233
+ var OA_EPOCH_1900 = Date.UTC(1899, 11, 30);
234
+ var MARCH_1_1900 = Date.UTC(1900, 2, 1);
235
+ function oaDateToTime(oaDate, epochMs) {
236
+ let serial = oaDate;
237
+ if (epochMs === OA_EPOCH_1900 && serial >= 1 && serial < 60) {
238
+ serial += 1;
239
+ }
240
+ return Math.round(serial * 864e5) + epochMs;
241
+ }
242
+ function timeToOaDate(timeMs, epochMs) {
243
+ let serial = (timeMs - epochMs) / 864e5;
244
+ if (epochMs === OA_EPOCH_1900 && timeMs < MARCH_1_1900) {
245
+ serial -= 1;
246
+ }
247
+ return serial;
248
+ }
249
+ var INVALID_SHEET_NAME_CHARS = /[\\/*?[\]:]/g;
250
+ function sanitizeSheetName(name, sheetCount) {
251
+ if (!name || typeof name !== "string") {
252
+ return `Sheet${sheetCount + 1}`;
253
+ }
254
+ let sanitized = name.replace(INVALID_SHEET_NAME_CHARS, "_");
255
+ if (sanitized.length > 31) {
256
+ sanitized = sanitized.substring(0, 31);
257
+ }
258
+ if (sanitized.trim().length === 0) {
259
+ sanitized = `Sheet${sheetCount + 1}`;
260
+ }
261
+ return sanitized;
262
+ }
263
+ var MAX_ROWS = 1048576;
264
+ var MAX_COLS = 16384;
265
+ var MAX_CELL_CHARS = 32767;
266
+ function assertCellTextLength(text) {
267
+ if (text.length > MAX_CELL_CHARS) {
268
+ throw new Error(
269
+ `Excel cell text exceeds ${MAX_CELL_CHARS} UTF-16 code units (got ${text.length}).`
270
+ );
271
+ }
272
+ }
273
+ function assertColumnCount(columnCount) {
274
+ if (!Number.isInteger(columnCount) || columnCount < 1 || columnCount > MAX_COLS) {
275
+ throw new Error(
276
+ `Excel column count must be 1..${MAX_COLS} (got ${columnCount}).`
277
+ );
278
+ }
279
+ }
280
+ function assertRowFitsColumns(kind, length, columnCount) {
281
+ if (length > columnCount) {
282
+ throw new Error(
283
+ `Excel ${kind} length ${length} exceeds columnCount ${columnCount}.`
284
+ );
285
+ }
286
+ }
287
+ function assertRowCount(totalRows) {
288
+ if (totalRows > MAX_ROWS) {
289
+ throw new Error(
290
+ `Excel row count exceeds ${MAX_ROWS} (got ${totalRows}).`
291
+ );
292
+ }
293
+ }
294
+ function initColWidths(columnCount) {
295
+ return new Array(columnCount).fill(-1);
296
+ }
297
+ function applyHeaderWidths(colWidths, headers, columnCount) {
298
+ for (let i = 0; i < columnCount; i++) {
299
+ const len = headers[i] ? headers[i].length + 1 : 0;
300
+ let width = 1.25 * len + 2;
301
+ if (width > 80) width = 80;
302
+ if (colWidths[i] < width) colWidths[i] = width;
303
+ }
304
+ }
305
+ function updateColWidthsFromRows(colWidths, rows, sampleLimit = 100) {
306
+ for (let r = 0; r < Math.min(rows.length, sampleLimit); r++) {
307
+ const row = rows[r];
308
+ for (let c = 0; c < row.length; c++) {
309
+ const raw = row[c];
310
+ if (raw === null || raw === void 0) continue;
311
+ const val = isFormattedCell(raw) ? raw.value : raw;
312
+ const len = val instanceof Date ? 20 : String(val).length + 1;
313
+ let width = 1.25 * len + 2;
314
+ if (width > 80) width = 80;
315
+ if (colWidths[c] < width) colWidths[c] = width;
316
+ }
317
+ }
318
+ }
319
+ function defaultColWidth(width, floor = false) {
320
+ if (width > 0) {
321
+ return floor ? Math.floor(width) : width;
322
+ }
323
+ return 10;
324
+ }
325
+
174
326
  // src/ExcelReaderAbstract.ts
175
327
  var ExcelReaderAbstract = class {
176
328
  constructor() {
@@ -185,8 +337,7 @@ var ExcelReaderAbstract = class {
185
337
  dispose() {
186
338
  }
187
339
  getDateTimeFromOaDate(oaDate) {
188
- const ms = oaDate * 864e5 + this._oaEpoch;
189
- return new Date(ms);
340
+ return new Date(oaDateToTime(oaDate, this._oaEpoch));
190
341
  }
191
342
  };
192
343
 
@@ -446,6 +597,208 @@ var BiffReaderWriter = class {
446
597
 
447
598
  // src/XlsbReader.ts
448
599
  var import_adm_zip = __toESM(require("adm-zip"));
600
+
601
+ // src/xmlUtils.ts
602
+ function hasInvalidControlChars(str) {
603
+ for (let i = 0; i < str.length; i++) {
604
+ const c = str.charCodeAt(i);
605
+ if (c < 32 && c !== 9 && c !== 10 && c !== 13) {
606
+ return true;
607
+ }
608
+ }
609
+ return false;
610
+ }
611
+ function stripInvalidControlChars(str) {
612
+ let out = "";
613
+ for (let i = 0; i < str.length; i++) {
614
+ const c = str.charCodeAt(i);
615
+ if (c === 9 || c === 10 || c === 13 || c >= 32 && c <= 55295 || c >= 57344 && c <= 65533) {
616
+ out += str[i];
617
+ }
618
+ }
619
+ return out;
620
+ }
621
+ function escapeXmlText(str) {
622
+ if (!/&|<|>|"|'/.test(str) && !hasInvalidControlChars(str)) {
623
+ return str;
624
+ }
625
+ let out = str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
626
+ if (hasInvalidControlChars(out)) {
627
+ out = stripInvalidControlChars(out);
628
+ }
629
+ return out;
630
+ }
631
+ function unescapeXml(str) {
632
+ if (!str || str.indexOf("&") === -1) return str;
633
+ return str.replace(/&(?:amp|lt|gt|quot|apos|#\d+|#x[0-9a-fA-F]+);/g, (entity) => {
634
+ switch (entity) {
635
+ case "&amp;":
636
+ return "&";
637
+ case "&lt;":
638
+ return "<";
639
+ case "&gt;":
640
+ return ">";
641
+ case "&quot;":
642
+ return '"';
643
+ case "&apos;":
644
+ return "'";
645
+ default: {
646
+ if (entity[1] === "#") {
647
+ const body = entity.slice(2, -1);
648
+ const code = body[0] === "x" || body[0] === "X" ? parseInt(body.slice(1), 16) : parseInt(body, 10);
649
+ if (Number.isFinite(code)) {
650
+ try {
651
+ return String.fromCodePoint(code);
652
+ } catch {
653
+ return entity;
654
+ }
655
+ }
656
+ }
657
+ return entity;
658
+ }
659
+ }
660
+ });
661
+ }
662
+ function parseTagAttributes(tag) {
663
+ const attrs = {};
664
+ const re = /([A-Za-z_][\w.:-]*)\s*=\s*("([^"]*)"|'([^']*)')/g;
665
+ let m;
666
+ while ((m = re.exec(tag)) !== null) {
667
+ const name = m[1];
668
+ const value = m[3] !== void 0 ? m[3] : m[4];
669
+ attrs[name] = value;
670
+ const colon = name.indexOf(":");
671
+ if (colon !== -1) {
672
+ const local = name.slice(colon + 1);
673
+ if (!(local in attrs)) attrs[local] = value;
674
+ }
675
+ }
676
+ return attrs;
677
+ }
678
+ function resolveRelTarget(target) {
679
+ if (!target) return target;
680
+ if (target.startsWith("/")) return target.slice(1);
681
+ if (target.startsWith("xl/")) return target;
682
+ return "xl/" + target;
683
+ }
684
+ function columnIndexToLetter(colIndex) {
685
+ let n = colIndex + 1;
686
+ let result = "";
687
+ while (n > 0) {
688
+ const rem = (n - 1) % 26;
689
+ result = String.fromCharCode(65 + rem) + result;
690
+ n = Math.floor((n - 1) / 26);
691
+ }
692
+ return result;
693
+ }
694
+ function columnLetterToIndex(letter) {
695
+ let column = 0;
696
+ const length = letter.length;
697
+ for (let i = 0; i < length; i++) {
698
+ column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
699
+ }
700
+ return column - 1;
701
+ }
702
+ function trimTrailingEmptyRows(rows) {
703
+ let end = rows.length;
704
+ while (end > 0 && rows[end - 1].every((v) => v === null || v === void 0)) {
705
+ end--;
706
+ }
707
+ return end === rows.length ? rows : rows.slice(0, end);
708
+ }
709
+ function parseSharedStringsXml(xml) {
710
+ const result = [];
711
+ const itemRegex = /<(?:(?:[A-Za-z_][\w.-]*):)?si\b[^>]*>([\s\S]*?)<\/(?:(?:[A-Za-z_][\w.-]*):)?si\s*>|<(?:(?:[A-Za-z_][\w.-]*):)?si\b[^>]*\/>/gi;
712
+ let itemMatch;
713
+ while ((itemMatch = itemRegex.exec(xml)) !== null) {
714
+ const full = itemMatch[0];
715
+ if (full.endsWith("/>") && itemMatch[1] === void 0) {
716
+ result.push("");
717
+ continue;
718
+ }
719
+ let content = itemMatch[1] ?? "";
720
+ content = content.replace(/<(?:(?:[A-Za-z_][\w.-]*):)?rPh\b[^>]*>[\s\S]*?<\/(?:(?:[A-Za-z_][\w.-]*):)?rPh\s*>/gi, "");
721
+ content = content.replace(/<(?:(?:[A-Za-z_][\w.-]*):)?rPh\b[^>]*\/>/gi, "");
722
+ const textRegex = /<(?:(?:[A-Za-z_][\w.-]*):)?t\b[^>]*>([\s\S]*?)<\/(?:(?:[A-Za-z_][\w.-]*):)?t\s*>/gi;
723
+ let value = "";
724
+ let textMatch;
725
+ while ((textMatch = textRegex.exec(content)) !== null) {
726
+ value += textMatch[1];
727
+ }
728
+ result.push(unescapeXml(value));
729
+ }
730
+ return result;
731
+ }
732
+
733
+ // src/biff12Utils.ts
734
+ function readVlq(buf, pos) {
735
+ let value = 0;
736
+ let shift = 0;
737
+ let byte;
738
+ do {
739
+ byte = buf[pos++];
740
+ value |= (byte & 127) << shift;
741
+ shift += 7;
742
+ } while ((byte & 128) !== 0);
743
+ return { value, nextPos: pos };
744
+ }
745
+ function vlqBytes(value) {
746
+ const out = [];
747
+ while (value >= 128) {
748
+ out.push(value & 127 | 128);
749
+ value >>>= 7;
750
+ }
751
+ out.push(value & 127);
752
+ return out;
753
+ }
754
+ function readRecord(buf, pos, rec) {
755
+ const idRes = readVlq(buf, pos);
756
+ if (idRes.nextPos > buf.length) return false;
757
+ const lenRes = readVlq(buf, idRes.nextPos);
758
+ if (lenRes.nextPos + lenRes.value > buf.length) return false;
759
+ rec.headerStart = pos;
760
+ rec.dataStart = lenRes.nextPos;
761
+ rec.dataEnd = lenRes.nextPos + lenRes.value;
762
+ rec.id = idRes.value;
763
+ rec.len = lenRes.value;
764
+ return true;
765
+ }
766
+ function buildRecord(id, payload) {
767
+ const idBytes = vlqBytes(id);
768
+ const lenBytes = vlqBytes(payload.length);
769
+ const header = Buffer.alloc(idBytes.length + lenBytes.length);
770
+ idBytes.forEach((b, i) => header[i] = b);
771
+ lenBytes.forEach((b, i) => header[idBytes.length + i] = b);
772
+ return Buffer.concat([header, payload]);
773
+ }
774
+ function readUtf16(buf, start, charCount) {
775
+ const end = start + charCount * 2;
776
+ if (end > buf.length) return "";
777
+ return buf.toString("utf16le", start, end);
778
+ }
779
+ function parseSharedStringsBin(buf) {
780
+ const values = [];
781
+ let total = 0;
782
+ let unique = 0;
783
+ let endSstOffset = buf.length;
784
+ const rec = { headerStart: 0, dataStart: 0, dataEnd: 0, id: 0, len: 0 };
785
+ let pos = 0;
786
+ while (readRecord(buf, pos, rec)) {
787
+ pos = rec.dataEnd;
788
+ if (rec.id === 159) {
789
+ total = buf.readUInt32LE(rec.dataStart);
790
+ unique = buf.readUInt32LE(rec.dataStart + 4);
791
+ } else if (rec.id === 19) {
792
+ const cch = buf.readUInt32LE(rec.dataStart + 1);
793
+ values.push(readUtf16(buf, rec.dataStart + 5, cch));
794
+ } else if (rec.id === 160) {
795
+ endSstOffset = rec.headerStart;
796
+ }
797
+ }
798
+ return { values, total, unique, endSstOffset };
799
+ }
800
+
801
+ // src/XlsbReader.ts
449
802
  var XlsbReader = class extends ExcelReaderAbstract {
450
803
  constructor() {
451
804
  super();
@@ -457,12 +810,29 @@ var XlsbReader = class extends ExcelReaderAbstract {
457
810
  this._reader = null;
458
811
  this._currentRow = [];
459
812
  this._pendingRowIndex = -1;
813
+ this._nextExpectedRow = 0;
460
814
  this._eof = false;
461
815
  this.xfIdToNumFmtId = [];
462
816
  this.customDateFormats = null;
463
817
  }
464
- async open(path7, readSharedStrings = true) {
465
- this.zip = new import_adm_zip.default(path7);
818
+ async open(path9, readSharedStrings = true) {
819
+ await this.close();
820
+ this.sheetNames = [];
821
+ this.sheets = [];
822
+ this.sharedStrings = [];
823
+ this.xfIdToNumFmtId = [];
824
+ this.customDateFormats = /* @__PURE__ */ new Set();
825
+ this.fieldCount = 0;
826
+ this.resultsCount = 0;
827
+ this.actualSheetName = "";
828
+ this._currentSheetIndex = -1;
829
+ this._currentRow = [];
830
+ this._pendingRowIndex = -1;
831
+ this._nextExpectedRow = 0;
832
+ this._eof = false;
833
+ this._reader = null;
834
+ this._oaEpoch = Date.UTC(1899, 11, 30);
835
+ this.zip = new import_adm_zip.default(path9);
466
836
  const wbEntry = this.zip.getEntry("xl/workbook.bin");
467
837
  if (wbEntry) {
468
838
  const buf = wbEntry.getData();
@@ -479,20 +849,39 @@ var XlsbReader = class extends ExcelReaderAbstract {
479
849
  const relsEntry = this.zip.getEntry("xl/_rels/workbook.bin.rels");
480
850
  if (relsEntry) {
481
851
  const xml = relsEntry.getData().toString("utf8");
482
- const relRegex = /<Relationship[^>]*Id="([^"]*)"[^>]*Target="([^"]*)"/g;
483
- let match;
852
+ const relTagRe = /<Relationship\b[^>]*>/g;
853
+ let tagMatch;
484
854
  const rIdToTarget = {};
485
- while ((match = relRegex.exec(xml)) !== null) {
486
- rIdToTarget[match[1]] = match[2];
855
+ while ((tagMatch = relTagRe.exec(xml)) !== null) {
856
+ const attrs = parseTagAttributes(tagMatch[0]);
857
+ const id = attrs["Id"] ?? attrs["id"];
858
+ const target = attrs["Target"] ?? attrs["target"];
859
+ if (id !== void 0 && target !== void 0) {
860
+ rIdToTarget[id] = target;
861
+ }
487
862
  }
488
863
  for (const sheet of this.sheets) {
489
- let target = rIdToTarget[sheet.rId];
864
+ const target = rIdToTarget[sheet.rId];
490
865
  if (target) {
491
- if (target.startsWith("/")) target = target.substring(1);
492
- if (!target.startsWith("xl/")) target = "xl/" + target;
493
- sheet.path = target;
866
+ sheet.path = resolveRelTarget(target);
867
+ }
868
+ }
869
+ }
870
+ try {
871
+ const raw = wbEntry ? wbEntry.getData() : null;
872
+ if (raw) {
873
+ const rec = { headerStart: 0, dataStart: 0, dataEnd: 0, id: 0, len: 0 };
874
+ let pos = 0;
875
+ while (readRecord(raw, pos, rec)) {
876
+ if (rec.id === 153 && rec.len >= 4) {
877
+ const is1904 = (raw[rec.dataStart] & 1) !== 0;
878
+ this._oaEpoch = is1904 ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, 30);
879
+ break;
880
+ }
881
+ pos = rec.dataEnd;
494
882
  }
495
883
  }
884
+ } catch {
496
885
  }
497
886
  if (readSharedStrings) {
498
887
  const ssPath = "xl/sharedStrings.bin";
@@ -507,8 +896,8 @@ var XlsbReader = class extends ExcelReaderAbstract {
507
896
  this.resultsCount = this.sheets.length;
508
897
  this._currentSheetIndex = -1;
509
898
  }
510
- _readSharedStrings(path7) {
511
- const entry = this.zip.getEntry(path7);
899
+ _readSharedStrings(path9) {
900
+ const entry = this.zip.getEntry(path9);
512
901
  if (!entry) return;
513
902
  const reader = new BiffReaderWriter(entry.getData());
514
903
  while (reader.readSharedStrings()) {
@@ -517,8 +906,8 @@ var XlsbReader = class extends ExcelReaderAbstract {
517
906
  }
518
907
  }
519
908
  }
520
- _readStyles(path7) {
521
- const entry = this.zip.getEntry(path7);
909
+ _readStyles(path9) {
910
+ const entry = this.zip.getEntry(path9);
522
911
  if (!entry) return;
523
912
  const reader = new BiffReaderWriter(entry.getData());
524
913
  while (reader.readStyles()) {
@@ -529,21 +918,54 @@ var XlsbReader = class extends ExcelReaderAbstract {
529
918
  getSheetNames() {
530
919
  return this.sheetNames;
531
920
  }
921
+ async selectSheet(nameOrIndex) {
922
+ let index = -1;
923
+ if (typeof nameOrIndex === "number") {
924
+ index = nameOrIndex;
925
+ } else {
926
+ index = this.sheetNames.indexOf(nameOrIndex);
927
+ if (index === -1) throw new Error(`Sheet '${nameOrIndex}' not found`);
928
+ }
929
+ if (index < 0 || index >= this.sheets.length) {
930
+ throw new Error(`Sheet index ${String(nameOrIndex)} out of range`);
931
+ }
932
+ this._currentSheetIndex = index;
933
+ if (!this._initSheet(index)) {
934
+ throw new Error(`XlsbReader: worksheet part missing for sheet '${this.sheetNames[index]}'.`);
935
+ }
936
+ }
937
+ async nextResult() {
938
+ const next = this._currentSheetIndex + 1;
939
+ if (next >= this.sheets.length) return false;
940
+ this._currentSheetIndex = next;
941
+ if (!this._initSheet(next)) {
942
+ throw new Error(`XlsbReader: worksheet part missing for sheet '${this.sheetNames[next]}'.`);
943
+ }
944
+ return true;
945
+ }
532
946
  async read() {
533
947
  if (this._currentSheetIndex === -1) {
534
948
  this._currentSheetIndex = 0;
535
949
  if (!this._initSheet(0)) return false;
536
950
  }
537
951
  if (this._eof) return false;
952
+ if (this._pendingRowIndex > this._nextExpectedRow && this._pendingRowIndex < MAX_ROWS) {
953
+ this._currentRow = [];
954
+ this._nextExpectedRow++;
955
+ return true;
956
+ }
538
957
  this._currentRow = [];
539
958
  while (true) {
540
959
  const hasRecord = this._reader.readWorksheet();
541
960
  if (!hasRecord) {
542
961
  this._eof = true;
962
+ this._nextExpectedRow = this._pendingRowIndex + 1;
543
963
  return true;
544
964
  }
545
965
  if (this._reader._rowIndex !== -1 && this._reader._rowIndex !== this._pendingRowIndex) {
966
+ const completed = this._pendingRowIndex;
546
967
  this._pendingRowIndex = this._reader._rowIndex;
968
+ this._nextExpectedRow = completed + 1;
547
969
  return true;
548
970
  }
549
971
  if (this._reader._readCell) {
@@ -584,13 +1006,17 @@ var XlsbReader = class extends ExcelReaderAbstract {
584
1006
  }
585
1007
  }
586
1008
  _initSheet(index) {
587
- if (index >= this.sheets.length) return false;
1009
+ if (index < 0 || index >= this.sheets.length) return false;
588
1010
  const sheet = this.sheets[index];
589
- const entry = this.zip.getEntry(sheet.path);
1011
+ const entry = sheet.path ? this.zip.getEntry(sheet.path) : void 0;
590
1012
  if (!entry) return false;
591
1013
  this._reader = new BiffReaderWriter(entry.getData());
592
1014
  this._eof = false;
593
1015
  this._pendingRowIndex = -1;
1016
+ this._nextExpectedRow = 0;
1017
+ this._currentRow = [];
1018
+ this.fieldCount = 0;
1019
+ this.actualSheetName = sheet.name;
594
1020
  while (this._reader.readWorksheet()) {
595
1021
  if (this._reader._rowIndex !== -1) {
596
1022
  this._pendingRowIndex = this._reader._rowIndex;
@@ -598,7 +1024,7 @@ var XlsbReader = class extends ExcelReaderAbstract {
598
1024
  }
599
1025
  }
600
1026
  this._eof = true;
601
- return false;
1027
+ return true;
602
1028
  }
603
1029
  getValue(i) {
604
1030
  if (i < 0 || i >= this._currentRow.length) return null;
@@ -608,84 +1034,15 @@ var XlsbReader = class extends ExcelReaderAbstract {
608
1034
 
609
1035
  // src/XlsxReader.ts
610
1036
  var import_yauzl = __toESM(require("yauzl"));
611
-
612
- // src/xmlUtils.ts
613
- function hasInvalidControlChars(str) {
614
- for (let i = 0; i < str.length; i++) {
615
- const c = str.charCodeAt(i);
616
- if (c < 32 && c !== 9 && c !== 10 && c !== 13) {
617
- return true;
618
- }
619
- }
620
- return false;
621
- }
622
- function stripInvalidControlChars(str) {
623
- let out = "";
624
- for (let i = 0; i < str.length; i++) {
625
- const c = str.charCodeAt(i);
626
- if (c === 9 || c === 10 || c === 13 || c >= 32 && c <= 55295 || c >= 57344 && c <= 65533) {
627
- out += str[i];
628
- }
629
- }
630
- return out;
631
- }
632
- function escapeXmlText(str) {
633
- if (!/&|<|>|"|'/.test(str) && !hasInvalidControlChars(str)) {
634
- return str;
635
- }
636
- let out = str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
637
- if (hasInvalidControlChars(out)) {
638
- out = stripInvalidControlChars(out);
639
- }
640
- return out;
641
- }
642
- function unescapeXml(str) {
643
- if (!str || str.indexOf("&") === -1) return str;
644
- return str.replace(/&#x([0-9a-f]+);/gi, (_match, hex) => String.fromCodePoint(parseInt(hex, 16))).replace(/&#(\d+);/g, (_match, decimal) => String.fromCodePoint(parseInt(decimal, 10))).replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'");
645
- }
646
- function columnIndexToLetter(colIndex) {
647
- let n = colIndex + 1;
648
- let result = "";
649
- while (n > 0) {
650
- const rem = (n - 1) % 26;
651
- result = String.fromCharCode(65 + rem) + result;
652
- n = Math.floor((n - 1) / 26);
653
- }
654
- return result;
655
- }
656
- function columnLetterToIndex(letter) {
657
- let column = 0;
658
- const length = letter.length;
659
- for (let i = 0; i < length; i++) {
660
- column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
661
- }
662
- return column - 1;
663
- }
664
- function trimTrailingEmptyRows(rows) {
665
- let end = rows.length;
666
- while (end > 0 && rows[end - 1].every((v) => v === null || v === void 0)) {
667
- end--;
668
- }
669
- return end === rows.length ? rows : rows.slice(0, end);
670
- }
671
- function parseSharedStringsXml(xml) {
672
- const result = [];
673
- const itemRegex = /<(?:(?:[A-Za-z_][\w.-]*):)?si\b[^>]*>([\s\S]*?)<\/(?:(?:[A-Za-z_][\w.-]*):)?si\s*>/gi;
674
- let itemMatch;
675
- while ((itemMatch = itemRegex.exec(xml)) !== null) {
676
- const content = itemMatch[1];
677
- const textRegex = /<(?:(?:[A-Za-z_][\w.-]*):)?t\b[^>]*>([\s\S]*?)<\/(?:(?:[A-Za-z_][\w.-]*):)?t\s*>/gi;
678
- let value = "";
679
- let textMatch;
680
- while ((textMatch = textRegex.exec(content)) !== null) {
681
- value += textMatch[1];
682
- }
683
- result.push(unescapeXml(value));
684
- }
685
- return result;
1037
+ function parseIsoDateUtc(value) {
1038
+ let text = value.trim().replace(" ", "T");
1039
+ if (!text) return null;
1040
+ if (!/z$|[+-]\d{2}:?\d{2}$/i.test(text) && text.includes("T")) {
1041
+ text += "Z";
1042
+ }
1043
+ const date = new Date(text);
1044
+ return Number.isNaN(date.getTime()) ? null : date;
686
1045
  }
687
-
688
- // src/XlsxReader.ts
689
1046
  var XlsxReader = class extends ExcelReaderAbstract {
690
1047
  constructor() {
691
1048
  super();
@@ -697,13 +1054,34 @@ var XlsxReader = class extends ExcelReaderAbstract {
697
1054
  this._currentSheetIndex = -1;
698
1055
  this._sheetXml = null;
699
1056
  this._xmlPos = 0;
1057
+ /** End of the sheetData element; row tags must not be searched past it. */
1058
+ this._xmlEnd = 0;
700
1059
  this._currentRow = [];
1060
+ this._expectedRowNum = 1;
1061
+ this._pendingEmptyCount = 0;
701
1062
  this.xfIdToNumFmtId = [];
702
1063
  this.customDateFormats = /* @__PURE__ */ new Set();
703
1064
  }
704
- async open(path7, readSharedStrings = true) {
705
- return new Promise((resolve4, reject) => {
706
- import_yauzl.default.open(path7, { lazyEntries: true, autoClose: false }, async (err, zipfile) => {
1065
+ async open(path9, readSharedStrings = true) {
1066
+ await this.close();
1067
+ this.sheetNames = [];
1068
+ this.sheets = [];
1069
+ this.sharedStrings = [];
1070
+ this.xfIdToNumFmtId = [];
1071
+ this.customDateFormats = /* @__PURE__ */ new Set();
1072
+ this.fieldCount = 0;
1073
+ this.resultsCount = 0;
1074
+ this.actualSheetName = "";
1075
+ this._currentSheetIndex = -1;
1076
+ this._sheetXml = null;
1077
+ this._xmlPos = 0;
1078
+ this._xmlEnd = 0;
1079
+ this._currentRow = [];
1080
+ this._expectedRowNum = 1;
1081
+ this._pendingEmptyCount = 0;
1082
+ this._oaEpoch = Date.UTC(1899, 11, 30);
1083
+ return new Promise((resolve6, reject) => {
1084
+ import_yauzl.default.open(path9, { lazyEntries: true, autoClose: false }, async (err, zipfile) => {
707
1085
  if (err) return reject(err);
708
1086
  this.zipfile = zipfile;
709
1087
  this.entries = /* @__PURE__ */ new Map();
@@ -716,28 +1094,40 @@ var XlsxReader = class extends ExcelReaderAbstract {
716
1094
  const wbRelsContent = await this._readZipEntryContent("xl/_rels/workbook.xml.rels");
717
1095
  const rIdToTarget = {};
718
1096
  if (wbRelsContent) {
719
- const relRegex = /<Relationship[^>]*Id="([^"]*)"[^>]*Target="([^"]*)"/g;
720
- let match;
721
- while ((match = relRegex.exec(wbRelsContent)) !== null) {
722
- rIdToTarget[match[1]] = match[2];
1097
+ const relTagRe = /<Relationship\b[^>]*>/g;
1098
+ let tagMatch;
1099
+ while ((tagMatch = relTagRe.exec(wbRelsContent)) !== null) {
1100
+ const attrs = parseTagAttributes(tagMatch[0]);
1101
+ const id = attrs["Id"] ?? attrs["id"];
1102
+ const target = attrs["Target"] ?? attrs["target"];
1103
+ if (id !== void 0 && target !== void 0) {
1104
+ rIdToTarget[id] = target;
1105
+ }
723
1106
  }
724
1107
  }
725
1108
  const wbContent = await this._readZipEntryContent("xl/workbook.xml");
726
1109
  if (wbContent) {
727
- const sheetRegex = /<sheet[^>]*name="([^"]*)"[^>]*sheetId="([^"]*)"[^>]*r:id="([^"]*)"/g;
728
- let match;
729
- while ((match = sheetRegex.exec(wbContent)) !== null) {
730
- const name = unescapeXml(match[1]);
731
- const sheetId = match[2];
732
- const rId = match[3];
1110
+ const sheetTagRe = /<sheet\b[^>]*>/g;
1111
+ let tagMatch;
1112
+ while ((tagMatch = sheetTagRe.exec(wbContent)) !== null) {
1113
+ const attrs = parseTagAttributes(tagMatch[0]);
1114
+ const rawName = attrs["name"];
1115
+ const sheetId = attrs["sheetId"] ?? "";
1116
+ const rId = attrs["r:id"] ?? attrs["id"] ?? attrs["rId"];
1117
+ if (rawName === void 0 || rId === void 0) continue;
1118
+ const name = unescapeXml(rawName);
733
1119
  const target = rIdToTarget[rId];
734
- let fullPath = target;
735
- if (!fullPath.startsWith("xl/")) {
736
- fullPath = "xl/" + fullPath;
737
- }
1120
+ if (!target) continue;
1121
+ const fullPath = resolveRelTarget(target);
738
1122
  this.sheetNames.push(name);
739
1123
  this.sheets.push({ name, sheetId, rId, path: fullPath });
740
1124
  }
1125
+ const wbPrMatch = /<workbookPr\b[^>]*>/i.exec(wbContent);
1126
+ if (wbPrMatch) {
1127
+ const wbPrAttrs = parseTagAttributes(wbPrMatch[0]);
1128
+ const v = (wbPrAttrs["date1904"] ?? "").trim().toLowerCase();
1129
+ this._oaEpoch = v === "1" || v === "true" ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, 30);
1130
+ }
741
1131
  }
742
1132
  if (readSharedStrings) {
743
1133
  const ssContent = await this._readZipEntryContent("xl/sharedStrings.xml");
@@ -751,7 +1141,7 @@ var XlsxReader = class extends ExcelReaderAbstract {
751
1141
  }
752
1142
  this.resultsCount = this.sheets.length;
753
1143
  this._currentSheetIndex = -1;
754
- resolve4();
1144
+ resolve6();
755
1145
  } catch (e) {
756
1146
  reject(e);
757
1147
  }
@@ -765,16 +1155,16 @@ var XlsxReader = class extends ExcelReaderAbstract {
765
1155
  this.zipfile.close();
766
1156
  }
767
1157
  }
768
- async _readZipEntryContent(path7) {
769
- const entry = this.entries.get(path7);
1158
+ async _readZipEntryContent(path9) {
1159
+ const entry = this.entries.get(path9);
770
1160
  if (!entry) return null;
771
- return new Promise((resolve4, reject) => {
1161
+ return new Promise((resolve6, reject) => {
772
1162
  this.zipfile.openReadStream(entry, (err, readStream) => {
773
1163
  if (err) return reject(err);
774
1164
  const chunks = [];
775
1165
  readStream.on("data", (chunk) => chunks.push(chunk));
776
1166
  readStream.on("end", () => {
777
- resolve4(Buffer.concat(chunks).toString("utf8"));
1167
+ resolve6(Buffer.concat(chunks).toString("utf8"));
778
1168
  });
779
1169
  readStream.on("error", reject);
780
1170
  });
@@ -822,6 +1212,27 @@ var XlsxReader = class extends ExcelReaderAbstract {
822
1212
  return false;
823
1213
  }
824
1214
  }
1215
+ async selectSheet(nameOrIndex) {
1216
+ let index = -1;
1217
+ if (typeof nameOrIndex === "number") {
1218
+ index = nameOrIndex;
1219
+ } else {
1220
+ index = this.sheetNames.indexOf(nameOrIndex);
1221
+ if (index === -1) throw new Error(`Sheet '${nameOrIndex}' not found`);
1222
+ }
1223
+ if (index < 0 || index >= this.sheets.length) {
1224
+ throw new Error(`Sheet index ${String(nameOrIndex)} out of range`);
1225
+ }
1226
+ this._currentSheetIndex = index;
1227
+ await this._initSheet(index);
1228
+ }
1229
+ async nextResult() {
1230
+ const next = this._currentSheetIndex + 1;
1231
+ if (next >= this.sheets.length) return false;
1232
+ this._currentSheetIndex = next;
1233
+ await this._initSheet(next);
1234
+ return true;
1235
+ }
825
1236
  async _initSheet(index) {
826
1237
  if (index >= this.sheets.length) return;
827
1238
  const sheet = this.sheets[index];
@@ -831,23 +1242,106 @@ var XlsxReader = class extends ExcelReaderAbstract {
831
1242
  this._sheetXml = "";
832
1243
  }
833
1244
  this._xmlPos = 0;
1245
+ this._xmlEnd = this._sheetXml.length;
1246
+ this._expectedRowNum = 1;
1247
+ this._pendingEmptyCount = 0;
1248
+ this._currentRow = [];
1249
+ this.fieldCount = 0;
834
1250
  const sd = this._sheetXml.indexOf("<sheetData>");
835
- if (sd !== -1) this._xmlPos = sd + 11;
1251
+ if (sd !== -1) {
1252
+ this._xmlPos = sd + 11;
1253
+ const se = this._sheetXml.indexOf("</sheetData>", this._xmlPos);
1254
+ if (se !== -1) this._xmlEnd = se;
1255
+ } else {
1256
+ const m = /<(?:[A-Za-z_][\w.-]*:)?sheetData\b[^>]*>/i.exec(this._sheetXml);
1257
+ if (m && m.index !== void 0) {
1258
+ this._xmlPos = m.index + m[0].length;
1259
+ if (/\/>\s*$/.test(m[0])) {
1260
+ this._xmlEnd = this._xmlPos;
1261
+ } else {
1262
+ const se = this._sheetXml.indexOf("</sheetData>", this._xmlPos);
1263
+ if (se !== -1) this._xmlEnd = se;
1264
+ }
1265
+ }
1266
+ }
836
1267
  }
837
1268
  _readNextRow() {
838
1269
  if (!this._sheetXml) return false;
839
- const rowStart = this._sheetXml.indexOf("<row", this._xmlPos);
1270
+ if (this._pendingEmptyCount > 0) {
1271
+ this._pendingEmptyCount--;
1272
+ this._currentRow = [];
1273
+ this._expectedRowNum++;
1274
+ return true;
1275
+ }
1276
+ const rowStart = this._findRowTagStart(this._xmlPos);
840
1277
  if (rowStart === -1) return false;
1278
+ const rowTagEnd = this._sheetXml.indexOf(">", rowStart);
1279
+ if (rowTagEnd === -1) return false;
1280
+ const rowTag = this._sheetXml.substring(rowStart, rowTagEnd + 1);
1281
+ const isSelfClosing = this._sheetXml.charCodeAt(rowTagEnd - 1) === 47;
1282
+ const rowAttrs = parseTagAttributes(rowTag);
1283
+ const rRaw = rowAttrs["r"];
1284
+ let rowNum = this._expectedRowNum;
1285
+ if (rRaw !== void 0) {
1286
+ const parsed = parseInt(rRaw, 10);
1287
+ if (Number.isFinite(parsed) && parsed >= 1 && parsed <= MAX_ROWS) rowNum = parsed;
1288
+ }
1289
+ if (rowNum > this._expectedRowNum) {
1290
+ const gap = rowNum - this._expectedRowNum;
1291
+ this._pendingEmptyCount = gap - 1;
1292
+ this._currentRow = [];
1293
+ this._expectedRowNum++;
1294
+ return true;
1295
+ }
1296
+ if (rowNum < this._expectedRowNum) {
1297
+ if (isSelfClosing) {
1298
+ this._xmlPos = rowTagEnd + 1;
1299
+ this._currentRow = [];
1300
+ return true;
1301
+ }
1302
+ const rowEnd2 = this._sheetXml.indexOf("</row>", rowStart);
1303
+ if (rowEnd2 === -1) return false;
1304
+ this._xmlPos = rowEnd2 + 6;
1305
+ this._parseRowByIndex(rowStart, rowEnd2);
1306
+ this._expectedRowNum = Math.max(this._expectedRowNum + 1, rowNum + 1);
1307
+ return true;
1308
+ }
1309
+ if (isSelfClosing) {
1310
+ this._xmlPos = rowTagEnd + 1;
1311
+ this._currentRow = [];
1312
+ this._expectedRowNum = rowNum + 1;
1313
+ return true;
1314
+ }
841
1315
  const rowEnd = this._sheetXml.indexOf("</row>", rowStart);
842
1316
  if (rowEnd === -1) return false;
843
1317
  this._xmlPos = rowEnd + 6;
844
1318
  this._parseRowByIndex(rowStart, rowEnd);
1319
+ this._expectedRowNum = rowNum + 1;
845
1320
  return true;
846
1321
  }
1322
+ /**
1323
+ * Find the next `<row …>` start, ignoring similarly named elements such as
1324
+ * `<rowBreaks>` that follow `</sheetData>`.
1325
+ */
1326
+ _findRowTagStart(from) {
1327
+ const xml = this._sheetXml;
1328
+ let pos = from;
1329
+ while (pos < this._xmlEnd) {
1330
+ const idx = xml.indexOf("<row", pos);
1331
+ if (idx === -1 || idx >= this._xmlEnd) return -1;
1332
+ const next = xml.charCodeAt(idx + 4);
1333
+ if (next === 62 || next === 47 || next === 32 || next === 9 || next === 10 || next === 13) {
1334
+ return idx;
1335
+ }
1336
+ pos = idx + 4;
1337
+ }
1338
+ return -1;
1339
+ }
847
1340
  _parseRowByIndex(rowStart, rowEnd) {
848
1341
  this._currentRow = [];
849
1342
  const xml = this._sheetXml;
850
1343
  let pos = xml.indexOf(">", rowStart) + 1;
1344
+ let nextCol = 0;
851
1345
  while (pos < rowEnd) {
852
1346
  const cStart = xml.indexOf("<c", pos);
853
1347
  if (cStart === -1 || cStart >= rowEnd) break;
@@ -881,6 +1375,7 @@ var XlsxReader = class extends ExcelReaderAbstract {
881
1375
  }
882
1376
  }
883
1377
  let val = null;
1378
+ let inlineVals = null;
884
1379
  if (xml.charCodeAt(nextTagClose - 1) === 47) {
885
1380
  pos = nextTagClose + 1;
886
1381
  } else {
@@ -895,20 +1390,28 @@ var XlsxReader = class extends ExcelReaderAbstract {
895
1390
  }
896
1391
  } else {
897
1392
  if (type === "inlineStr") {
898
- const tStart = xml.indexOf("<t", nextTagClose);
899
- if (tStart !== -1 && tStart < cellContentEnd) {
900
- const tContentStart = xml.indexOf(">", tStart) + 1;
1393
+ inlineVals = [];
1394
+ let tSearch = nextTagClose;
1395
+ while (true) {
1396
+ const tStart = xml.indexOf("<t", tSearch);
1397
+ if (tStart === -1 || tStart >= cellContentEnd) break;
1398
+ const tClose = xml.indexOf(">", tStart);
1399
+ if (tClose === -1 || tClose >= cellContentEnd) break;
1400
+ const tContentStart = tClose + 1;
901
1401
  const tEnd = xml.indexOf("</t>", tContentStart);
902
- if (tEnd !== -1 && tEnd < cellContentEnd) {
903
- val = xml.substring(tContentStart, tEnd);
904
- }
1402
+ if (tEnd === -1 || tEnd > cellContentEnd) break;
1403
+ inlineVals.push(xml.substring(tContentStart, tEnd));
1404
+ tSearch = tEnd + 4;
905
1405
  }
1406
+ if (inlineVals.length === 0) inlineVals = null;
906
1407
  }
907
1408
  }
908
1409
  pos = cellContentEnd + 4;
909
1410
  }
910
1411
  let finalVal = null;
911
- if (val !== null) {
1412
+ if (inlineVals !== null) {
1413
+ finalVal = unescapeXml(inlineVals.join(""));
1414
+ } else if (val !== null) {
912
1415
  if (type === "s") {
913
1416
  const idx = parseInt(val, 10);
914
1417
  finalVal = this.sharedStrings[idx];
@@ -916,6 +1419,12 @@ var XlsxReader = class extends ExcelReaderAbstract {
916
1419
  finalVal = val === "1" || val === "true";
917
1420
  } else if (type === "inlineStr") {
918
1421
  finalVal = unescapeXml(val);
1422
+ } else if (type === "str") {
1423
+ finalVal = unescapeXml(val);
1424
+ } else if (type === "e") {
1425
+ finalVal = unescapeXml(val);
1426
+ } else if (type === "d") {
1427
+ finalVal = parseIsoDateUtc(val) ?? unescapeXml(val);
919
1428
  } else if (type === "n" || type === "") {
920
1429
  finalVal = parseFloat(val);
921
1430
  if (styleIndex > 0 && this.xfIdToNumFmtId) {
@@ -933,10 +1442,10 @@ var XlsxReader = class extends ExcelReaderAbstract {
933
1442
  }
934
1443
  }
935
1444
  }
936
- if (colIndex !== -1) {
937
- this._currentRow[colIndex] = finalVal;
938
- if (colIndex >= this.fieldCount) this.fieldCount = colIndex + 1;
939
- }
1445
+ if (colIndex === -1) colIndex = nextCol;
1446
+ nextCol = colIndex + 1;
1447
+ this._currentRow[colIndex] = finalVal;
1448
+ if (colIndex >= this.fieldCount) this.fieldCount = colIndex + 1;
940
1449
  }
941
1450
  }
942
1451
  getValue(i) {
@@ -966,99 +1475,11 @@ var ReaderFactory = class {
966
1475
 
967
1476
  // src/XlsbWriter.ts
968
1477
  var fs = __toESM(require("fs"));
1478
+ var path2 = __toESM(require("path"));
1479
+ var import_crypto = require("crypto");
969
1480
  var import_archiver = __toESM(require("archiver"));
970
1481
  var import_stream = require("stream");
971
1482
 
972
- // src/Formats.ts
973
- var F = {
974
- THOUSANDS_SEP: "#,##0",
975
- CURRENCY_PLN: '#,##0.00 "z\u0142"',
976
- CURRENCY_EUR: "#,##0.00 \u20AC",
977
- PERCENTAGE: "0%",
978
- SCIENTIFIC: "0.00E+00",
979
- TWO_DECIMALS: "#,##0.00",
980
- TEXT: "@",
981
- LEADING_ZEROS: "000000000",
982
- DATE_SHORT: "dd.mm.yyyy",
983
- DATE_LONG: "d mmmm yyyy",
984
- DATE_DAY_MONTH_YEAR: "dd-mm-yyyy",
985
- DATE_ISO: "yyyy-mm-dd",
986
- DATE_MONTH_YEAR: "mmmm yyyy",
987
- DATE_WEEKDAY: "dddd, d mmmm yyyy",
988
- DATE_DAY_MONTH: "d mmmm",
989
- DATE_YEAR_ONLY: "yyyy",
990
- DATETIME_SHORT: "dd.mm.yyyy hh:mm",
991
- DATETIME_LONG: "d mmmm yyyy hh:mm:ss",
992
- TIME_HH_MM: "hh:mm",
993
- TIME_HH_MM_SS: "hh:mm:ss",
994
- TIME_12H: "h:mm AM/PM",
995
- DATETIME_24H: "dd.mm.yyyy hh:mm:ss",
996
- DATETIME_ISO: 'yyyy-mm-dd"T"hh:mm:ss',
997
- TIME_MS: "hh:mm:ss.000"
998
- };
999
- function isFormattedCell(val) {
1000
- return val !== null && val !== void 0 && typeof val === "object" && "format" in val && typeof val.format === "string";
1001
- }
1002
- function unwrapCell(val) {
1003
- if (isFormattedCell(val)) {
1004
- return val.value;
1005
- }
1006
- return val;
1007
- }
1008
- function getFormat(val) {
1009
- if (isFormattedCell(val)) {
1010
- return val.format;
1011
- }
1012
- return null;
1013
- }
1014
-
1015
- // src/writerHelpers.ts
1016
- var INVALID_SHEET_NAME_CHARS = /[\\/*?[\]:]/g;
1017
- function sanitizeSheetName(name, sheetCount) {
1018
- if (!name || typeof name !== "string") {
1019
- return `Sheet${sheetCount + 1}`;
1020
- }
1021
- let sanitized = name.replace(INVALID_SHEET_NAME_CHARS, "_");
1022
- if (sanitized.length > 31) {
1023
- sanitized = sanitized.substring(0, 31);
1024
- }
1025
- if (sanitized.trim().length === 0) {
1026
- sanitized = `Sheet${sheetCount + 1}`;
1027
- }
1028
- return sanitized;
1029
- }
1030
- function initColWidths(columnCount) {
1031
- return new Array(columnCount).fill(-1);
1032
- }
1033
- function applyHeaderWidths(colWidths, headers, columnCount) {
1034
- for (let i = 0; i < columnCount; i++) {
1035
- const len = headers[i] ? headers[i].length + 1 : 0;
1036
- let width = 1.25 * len + 2;
1037
- if (width > 80) width = 80;
1038
- if (colWidths[i] < width) colWidths[i] = width;
1039
- }
1040
- }
1041
- function updateColWidthsFromRows(colWidths, rows, sampleLimit = 100) {
1042
- for (let r = 0; r < Math.min(rows.length, sampleLimit); r++) {
1043
- const row = rows[r];
1044
- for (let c = 0; c < row.length; c++) {
1045
- const raw = row[c];
1046
- if (raw === null || raw === void 0) continue;
1047
- const val = isFormattedCell(raw) ? raw.value : raw;
1048
- const len = val instanceof Date ? 20 : String(val).length + 1;
1049
- let width = 1.25 * len + 2;
1050
- if (width > 80) width = 80;
1051
- if (colWidths[c] < width) colWidths[c] = width;
1052
- }
1053
- }
1054
- }
1055
- function defaultColWidth(width, floor = false) {
1056
- if (width > 0) {
1057
- return floor ? Math.floor(width) : width;
1058
- }
1059
- return 10;
1060
- }
1061
-
1062
1483
  // src/StreamingSheetState.ts
1063
1484
  var StreamingSheetState = class {
1064
1485
  constructor() {
@@ -1111,6 +1532,8 @@ var XlsbWriter = class _XlsbWriter {
1111
1532
  * @param filePath Destination `.xlsb` path on disk.
1112
1533
  */
1113
1534
  constructor(filePath) {
1535
+ this._outputError = null;
1536
+ this._finalized = false;
1114
1537
  this.sheetCount = 0;
1115
1538
  this.sheetList = [];
1116
1539
  this.sstDic = /* @__PURE__ */ new Map();
@@ -1121,8 +1544,20 @@ var XlsbWriter = class _XlsbWriter {
1121
1544
  this._nextXfIdx = 4;
1122
1545
  this._stFmtRecords = /* @__PURE__ */ new Map();
1123
1546
  this.stream = new StreamingSheetState();
1124
- this.output = fs.createWriteStream(filePath);
1547
+ this._targetPath = path2.resolve(filePath);
1548
+ fs.mkdirSync(path2.dirname(this._targetPath), { recursive: true });
1549
+ this._tempPath = path2.join(
1550
+ path2.dirname(this._targetPath),
1551
+ `.${path2.basename(this._targetPath)}.${(0, import_crypto.randomUUID)()}.tmp`
1552
+ );
1553
+ this.output = fs.createWriteStream(this._tempPath);
1554
+ this.output.on("error", (err) => {
1555
+ this._outputError = err;
1556
+ });
1125
1557
  this.archive = (0, import_archiver.default)("zip");
1558
+ this.archive.on("error", (err) => {
1559
+ this._outputError = err;
1560
+ });
1126
1561
  this.archive.pipe(this.output);
1127
1562
  this._oaEpoch = Date.UTC(1899, 11, 30);
1128
1563
  this._sheet1Bytes = Buffer.from([
@@ -2992,6 +3427,11 @@ var XlsbWriter = class _XlsbWriter {
2992
3427
  * @param options Optional settings (hidden, doAutofilter)
2993
3428
  */
2994
3429
  startSheet(sheetName, columnCount, headers, options = {}) {
3430
+ assertColumnCount(columnCount);
3431
+ if (headers !== void 0) {
3432
+ assertRowFitsColumns("header", headers.length, columnCount);
3433
+ for (const h of headers) assertCellTextLength(h);
3434
+ }
2995
3435
  const { hidden = false, doAutofilter = true, sampleRows } = options;
2996
3436
  this.addSheet(sheetName, hidden);
2997
3437
  this.stream.begin(columnCount, doAutofilter && headers !== void 0, new BigBuffer());
@@ -3057,6 +3497,7 @@ var XlsbWriter = class _XlsbWriter {
3057
3497
  `Row length mismatch. Expected ${this.stream.endCol - this.stream.startCol} columns, got ${row.length}`
3058
3498
  );
3059
3499
  }
3500
+ assertRowCount(this.stream.rowNum + 1);
3060
3501
  this.createRowHeader(bigBuf, this.stream.rowNum, this.stream.startCol, this.stream.endCol);
3061
3502
  for (let c = 0; c < row.length; c++) {
3062
3503
  const raw = row[c];
@@ -3079,7 +3520,7 @@ var XlsbWriter = class _XlsbWriter {
3079
3520
  } else if (typeof val === "boolean") {
3080
3521
  this.writeBool(bigBuf, val, c);
3081
3522
  } else if (val instanceof Date) {
3082
- const oaDate = (val.getTime() - this._oaEpoch) / 864e5;
3523
+ const oaDate = timeToOaDate(val.getTime(), this._oaEpoch);
3083
3524
  this.writeDouble(bigBuf, oaDate, c, fmtString !== null ? styleNum : 1);
3084
3525
  } else if (val !== null && val !== void 0) {
3085
3526
  this.writeString(bigBuf, val.toString(), c, false, fmtString !== null ? styleNum : void 0);
@@ -3136,6 +3577,16 @@ var XlsbWriter = class _XlsbWriter {
3136
3577
  } else if (headers) {
3137
3578
  columnCount = headers.length;
3138
3579
  }
3580
+ if (columnCount > 0) assertColumnCount(columnCount);
3581
+ const totalRowsCheck = rows.length + (headers ? 1 : 0);
3582
+ assertRowCount(totalRowsCheck);
3583
+ if (headers) {
3584
+ assertRowFitsColumns("header", headers.length, columnCount);
3585
+ for (const h of headers) assertCellTextLength(h);
3586
+ }
3587
+ for (let r = 0; r < rows.length; r++) {
3588
+ assertRowFitsColumns("row", rows[r].length, columnCount);
3589
+ }
3139
3590
  const colWidths = initColWidths(columnCount);
3140
3591
  if (headers) {
3141
3592
  applyHeaderWidths(colWidths, headers, columnCount);
@@ -3211,7 +3662,7 @@ var XlsbWriter = class _XlsbWriter {
3211
3662
  } else if (typeof val === "boolean") {
3212
3663
  this.writeBool(bigBuf, val, c);
3213
3664
  } else if (val instanceof Date) {
3214
- const oaDate = (val.getTime() - this._oaEpoch) / 864e5;
3665
+ const oaDate = timeToOaDate(val.getTime(), this._oaEpoch);
3215
3666
  this.writeDouble(bigBuf, oaDate, c, fmtString !== null ? styleNum : 1);
3216
3667
  } else if (val !== null && val !== void 0) {
3217
3668
  this.writeString(bigBuf, val.toString(), c, false, fmtString !== null ? styleNum : void 0);
@@ -3294,13 +3745,14 @@ var XlsbWriter = class _XlsbWriter {
3294
3745
  bigBuf.writeUnsafeByte(val ? 1 : 0);
3295
3746
  }
3296
3747
  writeDateTime(bigBuf, date, colNum) {
3297
- const oaDate = (date.getTime() - this._oaEpoch) / 864e5;
3748
+ const oaDate = timeToOaDate(date.getTime(), this._oaEpoch);
3298
3749
  this.writeDouble(bigBuf, oaDate, colNum, 1);
3299
3750
  }
3300
3751
  _getDateWidth(_date) {
3301
3752
  return 19;
3302
3753
  }
3303
3754
  writeString(bigBuf, val, colNum, bolded = false, styleOverride) {
3755
+ assertCellTextLength(val);
3304
3756
  let index;
3305
3757
  if (this.sstDic.has(val)) {
3306
3758
  index = this.sstDic.get(val);
@@ -3326,8 +3778,8 @@ var XlsbWriter = class _XlsbWriter {
3326
3778
  bigBuf.writeByte(159);
3327
3779
  bigBuf.writeByte(1);
3328
3780
  bigBuf.writeByte(8);
3329
- bigBuf.writeInt32LE(this.sstCntUnique);
3330
3781
  bigBuf.writeInt32LE(this.sstCntAll);
3782
+ bigBuf.writeInt32LE(this.sstCntUnique);
3331
3783
  for (const [txt] of this.sstDic) {
3332
3784
  const txtLen = txt.length;
3333
3785
  bigBuf.writeByte(19);
@@ -3380,8 +3832,61 @@ var XlsbWriter = class _XlsbWriter {
3380
3832
  * Must be awaited before the file is fully written.
3381
3833
  */
3382
3834
  finalize() {
3383
- return new Promise((resolve4, reject) => {
3835
+ return new Promise((resolve6, reject) => {
3836
+ if (this._finalized) {
3837
+ reject(new Error("XlsbWriter: already finalized"));
3838
+ return;
3839
+ }
3840
+ this._finalized = true;
3841
+ let settled = false;
3842
+ const cleanupTemp = () => {
3843
+ try {
3844
+ if (fs.existsSync(this._tempPath)) fs.rmSync(this._tempPath);
3845
+ } catch {
3846
+ }
3847
+ };
3848
+ const fail = (err) => {
3849
+ if (settled) return;
3850
+ settled = true;
3851
+ try {
3852
+ this.archive.abort();
3853
+ } catch {
3854
+ }
3855
+ try {
3856
+ this.output.destroy();
3857
+ } catch {
3858
+ }
3859
+ cleanupTemp();
3860
+ reject(err instanceof Error ? err : new Error(String(err)));
3861
+ };
3862
+ const succeed = () => {
3863
+ if (settled) return;
3864
+ if (this._outputError) {
3865
+ fail(this._outputError);
3866
+ return;
3867
+ }
3868
+ settled = true;
3869
+ try {
3870
+ const fd = fs.openSync(this._tempPath, "r+");
3871
+ try {
3872
+ fs.fsyncSync(fd);
3873
+ } finally {
3874
+ fs.closeSync(fd);
3875
+ }
3876
+ try {
3877
+ const existing = fs.statSync(this._targetPath);
3878
+ fs.chmodSync(this._tempPath, existing.mode & 511);
3879
+ } catch {
3880
+ }
3881
+ fs.renameSync(this._tempPath, this._targetPath);
3882
+ resolve6();
3883
+ } catch (err) {
3884
+ cleanupTemp();
3885
+ reject(err instanceof Error ? err : new Error(String(err)));
3886
+ }
3887
+ };
3384
3888
  try {
3889
+ if (this._outputError) throw this._outputError;
3385
3890
  this.saveSst();
3386
3891
  this.archive.append(this._buildStylesBin(), { name: "xl/styles.bin" });
3387
3892
  const wbBuffers = [];
@@ -3478,11 +3983,12 @@ var XlsbWriter = class _XlsbWriter {
3478
3983
  </Relationships>`;
3479
3984
  this.archive.append(wsRels, { name: `xl/worksheets/_rels/${sheet.nameInArchive}.rels` });
3480
3985
  }
3481
- this.output.on("close", () => resolve4());
3482
- this.archive.on("error", (err) => reject(err));
3986
+ this.output.once("close", succeed);
3987
+ this.output.once("error", fail);
3988
+ this.archive.once("error", fail);
3483
3989
  this.archive.finalize();
3484
3990
  } catch (err) {
3485
- reject(err);
3991
+ fail(err);
3486
3992
  }
3487
3993
  });
3488
3994
  }
@@ -3490,27 +3996,17 @@ var XlsbWriter = class _XlsbWriter {
3490
3996
 
3491
3997
  // src/XlsxWriter.ts
3492
3998
  var fs2 = __toESM(require("fs"));
3999
+ var path3 = __toESM(require("path"));
4000
+ var import_crypto2 = require("crypto");
3493
4001
  var import_archiver2 = __toESM(require("archiver"));
3494
4002
  var import_stream2 = require("stream");
3495
- var COLUMN_LETTERS = (() => {
3496
- const letters = [];
3497
- for (let i = 65; i < 91; i++) {
3498
- letters.push(String.fromCharCode(i));
3499
- }
3500
- const temp = [];
3501
- for (const p of letters) {
3502
- for (let i = 65; i < 91; i++) {
3503
- temp.push(p + String.fromCharCode(i));
3504
- }
3505
- }
3506
- letters.push(...temp);
3507
- return letters;
3508
- })();
3509
4003
  var XlsxWriter = class {
3510
4004
  /**
3511
4005
  * @param filePath Destination `.xlsx` path on disk.
3512
4006
  */
3513
4007
  constructor(filePath) {
4008
+ this._outputError = null;
4009
+ this._finalized = false;
3514
4010
  this.sheetCount = 0;
3515
4011
  this.sheetList = [];
3516
4012
  this.sstArray = [];
@@ -3524,13 +4020,25 @@ var XlsxWriter = class {
3524
4020
  this._nextXfIndex = 4;
3525
4021
  this.stream = new StreamingSheetState();
3526
4022
  this.currentColLetters = [];
3527
- this.output = fs2.createWriteStream(filePath);
4023
+ this._targetPath = path3.resolve(filePath);
4024
+ fs2.mkdirSync(path3.dirname(this._targetPath), { recursive: true });
4025
+ this._tempPath = path3.join(
4026
+ path3.dirname(this._targetPath),
4027
+ `.${path3.basename(this._targetPath)}.${(0, import_crypto2.randomUUID)()}.tmp`
4028
+ );
4029
+ this.output = fs2.createWriteStream(this._tempPath);
4030
+ this.output.on("error", (err) => {
4031
+ this._outputError = err;
4032
+ });
3528
4033
  this.archive = (0, import_archiver2.default)("zip");
4034
+ this.archive.on("error", (err) => {
4035
+ this._outputError = err;
4036
+ });
3529
4037
  this.archive.pipe(this.output);
3530
4038
  this._oaEpoch = Date.UTC(1899, 11, 30);
3531
4039
  }
3532
4040
  _getColumnLetter(colIndex) {
3533
- return colIndex < COLUMN_LETTERS.length ? COLUMN_LETTERS[colIndex] : "A";
4041
+ return columnIndexToLetter(colIndex);
3534
4042
  }
3535
4043
  /** @deprecated Internal; kept for unit-test access. Prefer sanitizeSheetName(). */
3536
4044
  _sanitizeSheetName(name) {
@@ -3582,6 +4090,11 @@ var XlsxWriter = class {
3582
4090
  * Start streaming a sheet. Call `writeRow` for each row, then `endSheet`.
3583
4091
  */
3584
4092
  startSheet(sheetName, columnCount, headers, options = {}) {
4093
+ assertColumnCount(columnCount);
4094
+ if (headers !== void 0) {
4095
+ assertRowFitsColumns("header", headers.length, columnCount);
4096
+ for (const h of headers) assertCellTextLength(h);
4097
+ }
3585
4098
  const { hidden = false, doAutofilter = true, sampleRows } = options;
3586
4099
  this.addSheet(sheetName, hidden);
3587
4100
  this.stream.begin(columnCount, doAutofilter && headers !== void 0, new BigBuffer());
@@ -3638,6 +4151,7 @@ var XlsxWriter = class {
3638
4151
  );
3639
4152
  }
3640
4153
  this.stream.rowNum++;
4154
+ assertRowCount(this.stream.rowNum);
3641
4155
  bigBuf.writeString(`<row r="${this.stream.rowNum}">`);
3642
4156
  for (let c = 0; c < row.length; c++) {
3643
4157
  const raw = row[c];
@@ -3701,6 +4215,16 @@ var XlsxWriter = class {
3701
4215
  } else if (headers) {
3702
4216
  columnCount = headers.length;
3703
4217
  }
4218
+ if (columnCount > 0) assertColumnCount(columnCount);
4219
+ const totalRows = rows.length + (headers ? 1 : 0);
4220
+ assertRowCount(totalRows);
4221
+ if (headers) {
4222
+ assertRowFitsColumns("header", headers.length, columnCount);
4223
+ for (const h of headers) assertCellTextLength(h);
4224
+ }
4225
+ for (let r = 0; r < rows.length; r++) {
4226
+ assertRowFitsColumns("row", rows[r].length, columnCount);
4227
+ }
3704
4228
  const colWidths = initColWidths(columnCount);
3705
4229
  const colLetters = new Array(columnCount);
3706
4230
  for (let i = 0; i < columnCount; i++) {
@@ -3712,7 +4236,6 @@ var XlsxWriter = class {
3712
4236
  updateColWidthsFromRows(colWidths, rows);
3713
4237
  bigBuf.writeString('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>');
3714
4238
  bigBuf.writeString('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">');
3715
- const totalRows = rows.length + (headers ? 1 : 0);
3716
4239
  if (totalRows > 0 && columnCount > 0) {
3717
4240
  bigBuf.writeString(`<dimension ref="A1:${colLetters[columnCount - 1]}${totalRows}"/>`);
3718
4241
  } else {
@@ -3798,6 +4321,7 @@ var XlsxWriter = class {
3798
4321
  });
3799
4322
  }
3800
4323
  _writeStringCell(bigBuf, val, colRef, rowNum, styleOverride) {
4324
+ assertCellTextLength(val);
3801
4325
  let index = this.sstMap.get(val);
3802
4326
  if (index === void 0) {
3803
4327
  index = this.sstArray.length;
@@ -3819,29 +4343,79 @@ var XlsxWriter = class {
3819
4343
  return xfIndex;
3820
4344
  }
3821
4345
  _toOADate(date) {
3822
- return (date.getTime() - this._oaEpoch) / 864e5;
4346
+ return timeToOaDate(date.getTime(), this._oaEpoch);
3823
4347
  }
3824
4348
  _getDateWidth(_date) {
3825
4349
  return 19;
3826
4350
  }
3827
4351
  /** Finalize the ZIP package and close the output stream. */
3828
4352
  finalize() {
3829
- return new Promise((resolve4, reject) => {
4353
+ return new Promise((resolve6, reject) => {
4354
+ if (this._finalized) {
4355
+ reject(new Error("XlsxWriter: already finalized"));
4356
+ return;
4357
+ }
4358
+ this._finalized = true;
4359
+ let settled = false;
4360
+ const cleanupTemp = () => {
4361
+ try {
4362
+ if (fs2.existsSync(this._tempPath)) fs2.rmSync(this._tempPath);
4363
+ } catch {
4364
+ }
4365
+ };
4366
+ const fail = (err) => {
4367
+ if (settled) return;
4368
+ settled = true;
4369
+ try {
4370
+ this.archive.abort();
4371
+ } catch {
4372
+ }
4373
+ try {
4374
+ this.output.destroy();
4375
+ } catch {
4376
+ }
4377
+ cleanupTemp();
4378
+ reject(err instanceof Error ? err : new Error(String(err)));
4379
+ };
4380
+ const succeed = () => {
4381
+ if (settled) return;
4382
+ if (this._outputError) {
4383
+ fail(this._outputError);
4384
+ return;
4385
+ }
4386
+ settled = true;
4387
+ try {
4388
+ const fd = fs2.openSync(this._tempPath, "r+");
4389
+ try {
4390
+ fs2.fsyncSync(fd);
4391
+ } finally {
4392
+ fs2.closeSync(fd);
4393
+ }
4394
+ try {
4395
+ const existing = fs2.statSync(this._targetPath);
4396
+ fs2.chmodSync(this._tempPath, existing.mode & 511);
4397
+ } catch {
4398
+ }
4399
+ fs2.renameSync(this._tempPath, this._targetPath);
4400
+ resolve6();
4401
+ } catch (err) {
4402
+ cleanupTemp();
4403
+ reject(err instanceof Error ? err : new Error(String(err)));
4404
+ }
4405
+ };
3830
4406
  try {
4407
+ if (this._outputError) throw this._outputError;
3831
4408
  this._writeSharedStrings();
3832
4409
  this._writeStyles();
3833
4410
  this._writeWorkbook();
3834
4411
  this._writeContentTypes();
3835
4412
  this._writeRels();
3836
- this.output.on("close", () => {
3837
- resolve4();
3838
- });
3839
- this.archive.on("error", (err) => {
3840
- reject(err);
3841
- });
4413
+ this.output.once("close", succeed);
4414
+ this.output.once("error", fail);
4415
+ this.archive.once("error", fail);
3842
4416
  this.archive.finalize();
3843
4417
  } catch (err) {
3844
- reject(err);
4418
+ fail(err);
3845
4419
  }
3846
4420
  });
3847
4421
  }
@@ -3973,13 +4547,13 @@ ${xfEntries.join("\n")}
3973
4547
  // src/XlsxUpdater.ts
3974
4548
  var fs5 = __toESM(require("fs"));
3975
4549
  var os = __toESM(require("os"));
3976
- var path4 = __toESM(require("path"));
4550
+ var path6 = __toESM(require("path"));
3977
4551
  var import_adm_zip2 = __toESM(require("adm-zip"));
3978
4552
 
3979
4553
  // src/atomicFile.ts
3980
4554
  var fs3 = __toESM(require("fs"));
3981
- var path2 = __toESM(require("path"));
3982
- var import_crypto = require("crypto");
4555
+ var path4 = __toESM(require("path"));
4556
+ var import_crypto3 = require("crypto");
3983
4557
  var realFileOperations = {
3984
4558
  exists: (filePath) => fs3.existsSync(filePath),
3985
4559
  rename: (sourcePath, destinationPath) => fs3.renameSync(sourcePath, destinationPath),
@@ -4002,7 +4576,7 @@ function readDestinationMode(target) {
4002
4576
  }
4003
4577
  }
4004
4578
  function installTemporaryOutput(temporaryPath, destinationPath, overwrite, operations = realFileOperations) {
4005
- const backupPath = `${destinationPath}.${(0, import_crypto.randomUUID)()}.replacement-backup`;
4579
+ const backupPath = `${destinationPath}.${(0, import_crypto3.randomUUID)()}.replacement-backup`;
4006
4580
  let backupCreated = false;
4007
4581
  let installed = false;
4008
4582
  if (operations.exists(destinationPath)) {
@@ -4050,11 +4624,11 @@ function installTemporaryOutput(temporaryPath, destinationPath, overwrite, opera
4050
4624
  }
4051
4625
  }
4052
4626
  function writeBufferAtomically(buffer, destinationPath) {
4053
- const target = path2.resolve(destinationPath);
4054
- fs3.mkdirSync(path2.dirname(target), { recursive: true });
4055
- const temporaryPath = path2.join(
4056
- path2.dirname(target),
4057
- `.${path2.basename(target)}.${(0, import_crypto.randomUUID)()}.tmp`
4627
+ const target = path4.resolve(destinationPath);
4628
+ fs3.mkdirSync(path4.dirname(target), { recursive: true });
4629
+ const temporaryPath = path4.join(
4630
+ path4.dirname(target),
4631
+ `.${path4.basename(target)}.${(0, import_crypto3.randomUUID)()}.tmp`
4058
4632
  );
4059
4633
  const destinationMode = readDestinationMode(target);
4060
4634
  try {
@@ -4090,8 +4664,8 @@ function writeBufferAtomically(buffer, destinationPath) {
4090
4664
 
4091
4665
  // src/streamingZip.ts
4092
4666
  var fs4 = __toESM(require("fs"));
4093
- var path3 = __toESM(require("path"));
4094
- var import_crypto2 = require("crypto");
4667
+ var path5 = __toESM(require("path"));
4668
+ var import_crypto4 = require("crypto");
4095
4669
  var import_promises = require("stream/promises");
4096
4670
  var import_stream3 = require("stream");
4097
4671
  var import_archiver3 = __toESM(require("archiver"));
@@ -4103,8 +4677,8 @@ function readDestinationMode2(target) {
4103
4677
  return void 0;
4104
4678
  }
4105
4679
  }
4106
- function appendAndWait(archive, source, name) {
4107
- return new Promise((resolve4, reject) => {
4680
+ function appendAndWait(archive, source, name, output) {
4681
+ return new Promise((resolve6, reject) => {
4108
4682
  const cleanup = () => {
4109
4683
  archive.off("entry", onEntry);
4110
4684
  archive.off("error", onError);
@@ -4112,10 +4686,13 @@ function appendAndWait(archive, source, name) {
4112
4686
  if (typeof maybeEmitter2.off === "function") {
4113
4687
  maybeEmitter2.off("error", onError);
4114
4688
  }
4689
+ if (output) {
4690
+ output.off("error", onError);
4691
+ }
4115
4692
  };
4116
4693
  const onEntry = () => {
4117
4694
  cleanup();
4118
- resolve4();
4695
+ resolve6();
4119
4696
  };
4120
4697
  const onError = (error) => {
4121
4698
  cleanup();
@@ -4123,6 +4700,9 @@ function appendAndWait(archive, source, name) {
4123
4700
  };
4124
4701
  archive.once("entry", onEntry);
4125
4702
  archive.once("error", onError);
4703
+ if (output) {
4704
+ output.once("error", onError);
4705
+ }
4126
4706
  const maybeEmitter = source;
4127
4707
  if (typeof maybeEmitter.once === "function") {
4128
4708
  maybeEmitter.once("error", onError);
@@ -4136,11 +4716,11 @@ function appendAndWait(archive, source, name) {
4136
4716
  });
4137
4717
  }
4138
4718
  async function writeAdmZipStreaming(zip, stagedParts, destinationPath) {
4139
- const target = path3.resolve(destinationPath);
4140
- fs4.mkdirSync(path3.dirname(target), { recursive: true });
4141
- const temporaryPath = path3.join(
4142
- path3.dirname(target),
4143
- `.${path3.basename(target)}.${(0, import_crypto2.randomUUID)()}.tmp`
4719
+ const target = path5.resolve(destinationPath);
4720
+ fs4.mkdirSync(path5.dirname(target), { recursive: true });
4721
+ const temporaryPath = path5.join(
4722
+ path5.dirname(target),
4723
+ `.${path5.basename(target)}.${(0, import_crypto4.randomUUID)()}.tmp`
4144
4724
  );
4145
4725
  const destinationMode = readDestinationMode2(target);
4146
4726
  let output = null;
@@ -4150,18 +4730,32 @@ async function writeAdmZipStreaming(zip, stagedParts, destinationPath) {
4150
4730
  temporaryPath,
4151
4731
  destinationMode !== void 0 ? { mode: destinationMode } : {}
4152
4732
  );
4733
+ let outputError = null;
4734
+ output.on("error", (err) => {
4735
+ outputError = err;
4736
+ try {
4737
+ archive == null ? void 0 : archive.abort();
4738
+ } catch {
4739
+ }
4740
+ });
4153
4741
  archive = (0, import_archiver3.default)("zip");
4742
+ archive.on("error", (err) => {
4743
+ outputError = err;
4744
+ });
4154
4745
  archive.pipe(output);
4155
4746
  for (const entry of zip.getEntries()) {
4747
+ if (outputError) throw outputError;
4156
4748
  const stagedPath = stagedParts.get(entry.entryName);
4157
4749
  if (stagedPath) {
4158
- await appendAndWait(archive, fs4.createReadStream(stagedPath), entry.entryName);
4750
+ await appendAndWait(archive, fs4.createReadStream(stagedPath), entry.entryName, output);
4159
4751
  } else {
4160
- await appendAndWait(archive, import_stream3.Readable.from([entry.getData()]), entry.entryName);
4752
+ await appendAndWait(archive, import_stream3.Readable.from([entry.getData()]), entry.entryName, output);
4161
4753
  }
4162
4754
  }
4755
+ if (outputError) throw outputError;
4163
4756
  await archive.finalize();
4164
4757
  await (0, import_promises.finished)(output);
4758
+ if (outputError) throw outputError;
4165
4759
  if (destinationMode !== void 0) {
4166
4760
  try {
4167
4761
  fs4.chmodSync(temporaryPath, destinationMode);
@@ -4195,6 +4789,23 @@ async function writeAdmZipStreaming(zip, stagedParts, destinationPath) {
4195
4789
  }
4196
4790
 
4197
4791
  // src/XlsxUpdater.ts
4792
+ function parseCellRange(ref) {
4793
+ const m = /^\$?([A-Za-z]+)\$?(\d+)(?::\$?([A-Za-z]+)\$?(\d+))?$/.exec(ref.trim());
4794
+ if (!m) return null;
4795
+ const c1 = columnLetterToIndex(m[1].toUpperCase());
4796
+ const r1 = parseInt(m[2], 10);
4797
+ const c2 = m[3] ? columnLetterToIndex(m[3].toUpperCase()) : c1;
4798
+ const r2 = m[4] ? parseInt(m[4], 10) : r1;
4799
+ if (!Number.isFinite(c1) || !Number.isFinite(r1) || !Number.isFinite(c2) || !Number.isFinite(r2)) {
4800
+ return null;
4801
+ }
4802
+ return {
4803
+ c1: Math.min(c1, c2),
4804
+ r1: Math.min(r1, r2),
4805
+ c2: Math.max(c1, c2),
4806
+ r2: Math.max(r1, r2)
4807
+ };
4808
+ }
4198
4809
  var XlsxUpdater = class _XlsxUpdater {
4199
4810
  /**
4200
4811
  * @param path Path to an existing `.xlsx` file.
@@ -4281,6 +4892,8 @@ var XlsxUpdater = class _XlsxUpdater {
4281
4892
  const dimRef = totalRows > 0 && lastCol >= 0 ? `A1:${columnIndexToLetter(lastCol)}${totalRows}` : "A1";
4282
4893
  this._updatePivotCaches(sheetName, dimRef, rows.length);
4283
4894
  this._addRefreshOnLoadToPivotTables();
4895
+ this._removeCalcChain();
4896
+ this._updateTableRefs(sheetName, dimRef);
4284
4897
  }
4285
4898
  /**
4286
4899
  * Replace worksheet rows from a one-pass source without materialising the
@@ -4353,10 +4966,10 @@ var XlsxUpdater = class _XlsxUpdater {
4353
4966
  if (outputError) throw outputError;
4354
4967
  writtenBytes += data.length;
4355
4968
  if (rowOutput.write(data)) return;
4356
- await new Promise((resolve4, reject) => {
4969
+ await new Promise((resolve6, reject) => {
4357
4970
  const onDrain = () => {
4358
4971
  cleanup();
4359
- resolve4();
4972
+ resolve6();
4360
4973
  };
4361
4974
  const onError = (error) => {
4362
4975
  cleanup();
@@ -4396,8 +5009,8 @@ var XlsxUpdater = class _XlsxUpdater {
4396
5009
  lastKeptEnd = writtenBytes;
4397
5010
  }
4398
5011
  }
4399
- await new Promise((resolve4, reject) => {
4400
- rowOutput.once("close", resolve4);
5012
+ await new Promise((resolve6, reject) => {
5013
+ rowOutput.once("close", resolve6);
4401
5014
  rowOutput.once("error", reject);
4402
5015
  rowOutput.end();
4403
5016
  });
@@ -4416,6 +5029,8 @@ var XlsxUpdater = class _XlsxUpdater {
4416
5029
  this._commitSharedStrings();
4417
5030
  this._updatePivotCaches(sheetName, dimRef, keptDataRows);
4418
5031
  this._addRefreshOnLoadToPivotTables();
5032
+ this._removeCalcChain();
5033
+ this._updateTableRefs(sheetName, dimRef);
4419
5034
  if (oldStage && oldStage !== outputPath) {
4420
5035
  this._removeTemporaryFile(oldStage);
4421
5036
  }
@@ -4489,7 +5104,7 @@ var XlsxUpdater = class _XlsxUpdater {
4489
5104
  }
4490
5105
  _ensureTemporaryDirectory() {
4491
5106
  if (this.temporaryDirectory === null) {
4492
- this.temporaryDirectory = fs5.mkdtempSync(path4.join(os.tmpdir(), "spreadsheet-updater-"));
5107
+ this.temporaryDirectory = fs5.mkdtempSync(path6.join(os.tmpdir(), "spreadsheet-updater-"));
4493
5108
  } else {
4494
5109
  try {
4495
5110
  fs5.mkdirSync(this.temporaryDirectory, { recursive: true });
@@ -4499,7 +5114,7 @@ var XlsxUpdater = class _XlsxUpdater {
4499
5114
  return this.temporaryDirectory;
4500
5115
  }
4501
5116
  _temporaryPath(suffix) {
4502
- return path4.join(this._ensureTemporaryDirectory(), `part-${Date.now()}-${Math.random().toString(16).slice(2)}${suffix}`);
5117
+ return path6.join(this._ensureTemporaryDirectory(), `part-${Date.now()}-${Math.random().toString(16).slice(2)}${suffix}`);
4503
5118
  }
4504
5119
  _removeTemporaryFile(filePath) {
4505
5120
  try {
@@ -4539,10 +5154,15 @@ var XlsxUpdater = class _XlsxUpdater {
4539
5154
  const rIdToTarget = {};
4540
5155
  if (relsEntry) {
4541
5156
  const rels = relsEntry.getData().toString("utf8");
4542
- const relRegex = /<Relationship[^>]*Id="([^"]*)"[^>]*Target="([^"]*)"/g;
4543
- let match2;
4544
- while ((match2 = relRegex.exec(rels)) !== null) {
4545
- rIdToTarget[match2[1]] = match2[2];
5157
+ const relTagRe = /<Relationship\b[^>]*>/g;
5158
+ let tagMatch;
5159
+ while ((tagMatch = relTagRe.exec(rels)) !== null) {
5160
+ const attrs = parseTagAttributes(tagMatch[0]);
5161
+ const id = attrs["Id"] ?? attrs["id"];
5162
+ const target = attrs["Target"] ?? attrs["target"];
5163
+ if (id !== void 0 && target !== void 0) {
5164
+ rIdToTarget[id] = target;
5165
+ }
4546
5166
  }
4547
5167
  }
4548
5168
  const wbEntry = this.zip.getEntry("xl/workbook.xml");
@@ -4551,21 +5171,23 @@ var XlsxUpdater = class _XlsxUpdater {
4551
5171
  let match;
4552
5172
  while ((match = sheetRe.exec(wbXml)) !== null) {
4553
5173
  const tag = match[0];
4554
- const nameMatch = /name="([^"]*)"/.exec(tag);
4555
- const rIdMatch = /r:id="([^"]*)"/.exec(tag);
4556
- if (!nameMatch || !rIdMatch) continue;
4557
- const name = nameMatch[1].replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'");
4558
- const target = rIdToTarget[rIdMatch[1]] ?? "";
4559
- let fullPath = target;
4560
- if (fullPath.startsWith("/")) {
4561
- fullPath = fullPath.substring(1);
4562
- } else if (!fullPath.startsWith("xl/")) {
4563
- fullPath = "xl/" + fullPath;
4564
- }
5174
+ const attrs = parseTagAttributes(tag);
5175
+ const rawName = attrs["name"];
5176
+ const rId = attrs["r:id"] ?? attrs["id"] ?? attrs["rId"];
5177
+ if (rawName === void 0 || rId === void 0) continue;
5178
+ const name = unescapeXml(rawName);
5179
+ const target = rIdToTarget[rId] ?? "";
5180
+ const fullPath = resolveRelTarget(target);
4565
5181
  if (fullPath) {
4566
5182
  this.sheetNameToPath.set(name, fullPath);
4567
5183
  }
4568
5184
  }
5185
+ const wbPrMatch = /<workbookPr\b[^>]*>/i.exec(wbXml);
5186
+ if (wbPrMatch) {
5187
+ const wbPrAttrs = parseTagAttributes(wbPrMatch[0]);
5188
+ const v = (wbPrAttrs["date1904"] ?? "").trim().toLowerCase();
5189
+ this._oaEpoch = v === "1" || v === "true" ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, 30);
5190
+ }
4569
5191
  for (const entry of this.zip.getEntries()) {
4570
5192
  const name = entry.entryName;
4571
5193
  if (/^xl\/pivotCache\/pivotCacheDefinition\d*\.xml$/.test(name)) {
@@ -4760,7 +5382,7 @@ var XlsxUpdater = class _XlsxUpdater {
4760
5382
  return `<c r="${colRef}${rowNum}" t="b"${colStyle > 0 ? ` s="${colStyle}"` : ""}><v>${val ? 1 : 0}</v></c>`;
4761
5383
  }
4762
5384
  if (val instanceof Date) {
4763
- const oaDate = (val.getTime() - this._oaEpoch) / 864e5;
5385
+ const oaDate = timeToOaDate(val.getTime(), this._oaEpoch);
4764
5386
  if (Number.isFinite(oaDate)) {
4765
5387
  const style = colStyle > 0 ? colStyle : dateStyle !== null ? dateStyle : 0;
4766
5388
  return `<c r="${colRef}${rowNum}"${style > 0 ? ` s="${style}"` : ""}><v>${oaDate}</v></c>`;
@@ -4977,8 +5599,8 @@ var XlsxUpdater = class _XlsxUpdater {
4977
5599
  }
4978
5600
  }
4979
5601
  _addRefreshOnLoadToPivotTables() {
4980
- for (const path7 of this.pivotTableDefPaths) {
4981
- const entry = this.zip.getEntry(path7);
5602
+ for (const path9 of this.pivotTableDefPaths) {
5603
+ const entry = this.zip.getEntry(path9);
4982
5604
  if (!entry) continue;
4983
5605
  let xml = entry.getData().toString("utf8");
4984
5606
  const rootRe = /<pivotTableDefinition\b[^>]*>/;
@@ -4986,7 +5608,233 @@ var XlsxUpdater = class _XlsxUpdater {
4986
5608
  if (!rootMatch || rootMatch[0].includes("refreshOnLoad")) continue;
4987
5609
  const newTag = rootMatch[0].replace(/(\/?>)$/, ' refreshOnLoad="1"$1');
4988
5610
  xml = xml.substring(0, rootMatch.index) + newTag + xml.substring(rootMatch.index + rootMatch[0].length);
4989
- this.zip.updateFile(path7, Buffer.from(xml, "utf8"));
5611
+ this.zip.updateFile(path9, Buffer.from(xml, "utf8"));
5612
+ }
5613
+ }
5614
+ /**
5615
+ * Remove the stale calculation chain (xl/calcChain.xml). Excel rebuilds it
5616
+ * on open; keeping stale <c> entries for the replaced sheet would force a
5617
+ * repair prompt. Removes the part, its Content_Types override and its
5618
+ * workbook rels entry (xlspy parity).
5619
+ */
5620
+ _removeCalcChain() {
5621
+ const calcPath = "xl/calcChain.xml";
5622
+ if (!this.zip.getEntry(calcPath) && !this.stagedParts.has(calcPath)) {
5623
+ this._ensureCalcPrFullCalc();
5624
+ return;
5625
+ }
5626
+ try {
5627
+ this.zip.deleteFile(calcPath);
5628
+ } catch {
5629
+ }
5630
+ const stagedCalc = this.stagedParts.get(calcPath);
5631
+ if (stagedCalc) {
5632
+ this.stagedParts.delete(calcPath);
5633
+ try {
5634
+ fs5.rmSync(stagedCalc, { force: true });
5635
+ } catch {
5636
+ }
5637
+ }
5638
+ const ctEntry = this.zip.getEntry("[Content_Types].xml");
5639
+ if (ctEntry || this.stagedParts.has("[Content_Types].xml")) {
5640
+ try {
5641
+ let ct = this._entryData("[Content_Types].xml").toString("utf8");
5642
+ const before = ct;
5643
+ ct = ct.replace(/<Override\b[^>]*PartName="\/xl\/calcChain\.xml"[^>]*\/?>/gi, "");
5644
+ if (ct !== before) {
5645
+ this._writePartText("[Content_Types].xml", ct);
5646
+ }
5647
+ } catch {
5648
+ }
5649
+ }
5650
+ const relsPath = "xl/_rels/workbook.xml.rels";
5651
+ if (this.zip.getEntry(relsPath) || this.stagedParts.has(relsPath)) {
5652
+ try {
5653
+ const rels = this._entryData(relsPath).toString("utf8");
5654
+ const relTagRe = /<Relationship\b[^>]*>/g;
5655
+ let m;
5656
+ let out = "";
5657
+ let last = 0;
5658
+ let changed = false;
5659
+ while ((m = relTagRe.exec(rels)) !== null) {
5660
+ const attrs = parseTagAttributes(m[0]);
5661
+ const type = attrs["Type"] ?? attrs["type"] ?? "";
5662
+ const target = attrs["Target"] ?? attrs["target"] ?? "";
5663
+ const isCalcChain = type.endsWith("/calcChain") && resolveRelTarget(target) === "xl/calcChain.xml";
5664
+ if (isCalcChain) {
5665
+ out += rels.substring(last, m.index);
5666
+ last = m.index + m[0].length;
5667
+ changed = true;
5668
+ }
5669
+ }
5670
+ if (changed) {
5671
+ out += rels.substring(last);
5672
+ this._writePartText(relsPath, out);
5673
+ }
5674
+ } catch {
5675
+ }
5676
+ }
5677
+ this._ensureCalcPrFullCalc();
5678
+ }
5679
+ _writePartText(name, text) {
5680
+ if (this.stagedParts.has(name)) {
5681
+ fs5.writeFileSync(this.stagedParts.get(name), text, "utf8");
5682
+ } else {
5683
+ this.zip.updateFile(name, Buffer.from(text, "utf8"));
5684
+ }
5685
+ }
5686
+ _ensureCalcPrFullCalc() {
5687
+ try {
5688
+ const wbPath = "xl/workbook.xml";
5689
+ if (!this.zip.getEntry(wbPath) && !this.stagedParts.has(wbPath)) return;
5690
+ let xml = this._entryData(wbPath).toString("utf8");
5691
+ const calcPrRe = /<(?:[A-Za-z_][\w.-]*:)?calcPr\b[^>]*>/i;
5692
+ const match = calcPrRe.exec(xml);
5693
+ if (match && match.index !== void 0) {
5694
+ const newTag = _XlsxUpdater._replaceOrAddXmlAttribute(match[0], "fullCalcOnLoad", "1");
5695
+ xml = xml.substring(0, match.index) + newTag + xml.substring(match.index + match[0].length);
5696
+ } else {
5697
+ const insertAt = _XlsxUpdater._calcPrInsertPosition(xml);
5698
+ if (insertAt < 0) return;
5699
+ xml = xml.substring(0, insertAt) + '<calcPr fullCalcOnLoad="1"/>' + xml.substring(insertAt);
5700
+ }
5701
+ this._writePartText(wbPath, xml);
5702
+ } catch {
5703
+ }
5704
+ }
5705
+ /**
5706
+ * Insertion offset for a missing `<calcPr>`. The element follows
5707
+ * sheets/externalReferences/definedNames in the workbook schema, so insert
5708
+ * after the last of those that exists instead of right after `<workbook>`.
5709
+ */
5710
+ static _calcPrInsertPosition(xml) {
5711
+ const prefixed = "(?:[A-Za-z_][\\w.-]*:)?";
5712
+ const candidates = [
5713
+ new RegExp(`</${prefixed}sheets\\s*>`, "i"),
5714
+ new RegExp(`<${prefixed}externalReferences\\b[^>]*/>`, "i"),
5715
+ new RegExp(`<${prefixed}externalReferences\\b[^>]*>[\\s\\S]*?</${prefixed}externalReferences\\s*>`, "i"),
5716
+ new RegExp(`<${prefixed}definedNames\\b[^>]*/>`, "i"),
5717
+ new RegExp(`<${prefixed}definedNames\\b[^>]*>[\\s\\S]*?</${prefixed}definedNames\\s*>`, "i")
5718
+ ];
5719
+ let insertAt = -1;
5720
+ for (const re of candidates) {
5721
+ const m = re.exec(xml);
5722
+ if (m && m.index !== void 0) {
5723
+ insertAt = Math.max(insertAt, m.index + m[0].length);
5724
+ }
5725
+ }
5726
+ if (insertAt >= 0) return insertAt;
5727
+ const close = new RegExp(`</${prefixed}workbook\\s*>`, "i").exec(xml);
5728
+ if (close && close.index !== void 0) return close.index;
5729
+ const root = new RegExp(`<${prefixed}workbook\\b[^>]*>`, "i").exec(xml);
5730
+ if (!root || root.index === void 0) return -1;
5731
+ return root.index + root[0].length;
5732
+ }
5733
+ /**
5734
+ * Update ListObject table ranges (xl/tables/*.xml) for the replaced sheet.
5735
+ * Only tables anchored at A1 are updated to the new dimension; tables
5736
+ * elsewhere are left untouched (moving them would corrupt the sheet).
5737
+ * Empty replacements (dimRef "A1") do not shrink multi-column tables.
5738
+ */
5739
+ _updateTableRefs(sheetName, dimRef) {
5740
+ const sheetPath = this.sheetNameToPath.get(sheetName);
5741
+ if (!sheetPath) return;
5742
+ const slash = sheetPath.lastIndexOf("/");
5743
+ const dir = slash >= 0 ? sheetPath.substring(0, slash + 1) : "";
5744
+ const base = slash >= 0 ? sheetPath.substring(slash + 1) : sheetPath;
5745
+ const sheetRelsPath = `${dir}_rels/${base}.rels`;
5746
+ const sheetRelsEntry = this.zip.getEntry(sheetRelsPath);
5747
+ const hasStagedRels = this.stagedParts.has(sheetRelsPath);
5748
+ if (!sheetRelsEntry && !hasStagedRels) return;
5749
+ const tableTargets = [];
5750
+ try {
5751
+ const relsXml = this._entryData(sheetRelsPath).toString("utf8");
5752
+ const relTagRe = /<Relationship\b[^>]*>/g;
5753
+ let m;
5754
+ while ((m = relTagRe.exec(relsXml)) !== null) {
5755
+ const attrs = parseTagAttributes(m[0]);
5756
+ const type = attrs["Type"] ?? attrs["type"] ?? "";
5757
+ const target = attrs["Target"] ?? attrs["target"] ?? "";
5758
+ if (!type.includes("/table") || !target) continue;
5759
+ let tablePath;
5760
+ if (target.startsWith("/")) {
5761
+ tablePath = resolveRelTarget(target);
5762
+ } else {
5763
+ const combined = dir + target;
5764
+ const parts = [];
5765
+ for (const seg of combined.split("/")) {
5766
+ if (seg === "..") parts.pop();
5767
+ else if (seg !== "." && seg !== "") parts.push(seg);
5768
+ }
5769
+ tablePath = parts.join("/");
5770
+ }
5771
+ tableTargets.push(tablePath);
5772
+ }
5773
+ } catch {
5774
+ return;
5775
+ }
5776
+ if (tableTargets.length === 0) return;
5777
+ const tables = [];
5778
+ for (const tablePath of tableTargets) {
5779
+ try {
5780
+ const hasEntry = !!this.zip.getEntry(tablePath);
5781
+ const hasStaged = this.stagedParts.has(tablePath);
5782
+ if (!hasEntry && !hasStaged) continue;
5783
+ const xml = this._entryData(tablePath).toString("utf8");
5784
+ const tableTagRe = /<(?:[A-Za-z_][\w.-]*:)?table\b[^>]*>/i;
5785
+ const tableMatch = tableTagRe.exec(xml);
5786
+ if (!tableMatch || tableMatch.index === void 0) continue;
5787
+ const refMatch = /\bref\s*=\s*("([^"]*)"|'([^']*)')/i.exec(tableMatch[0]);
5788
+ const ref = refMatch ? refMatch[2] ?? refMatch[3] ?? "" : "";
5789
+ tables.push({
5790
+ path: tablePath,
5791
+ xml,
5792
+ tag: tableMatch[0],
5793
+ tagIndex: tableMatch.index,
5794
+ ref,
5795
+ range: parseCellRange(ref),
5796
+ staged: hasStaged
5797
+ });
5798
+ } catch {
5799
+ }
5800
+ }
5801
+ if (tables.length === 0) return;
5802
+ const dimRange = parseCellRange(dimRef);
5803
+ if (!dimRange) return;
5804
+ for (const table of tables) {
5805
+ try {
5806
+ const origRange = table.range;
5807
+ if (!origRange) continue;
5808
+ if (origRange.r1 !== 1 || origRange.c1 !== 0) continue;
5809
+ if (dimRef === "A1" && !/^A1$/i.test(table.ref)) continue;
5810
+ const origCols = origRange.c2 - origRange.c1 + 1;
5811
+ const newCols = dimRange.c2 - dimRange.c1 + 1;
5812
+ if (newCols !== origCols) continue;
5813
+ let lastRow = dimRange.r2;
5814
+ for (const other of tables) {
5815
+ if (other === table || !other.range) continue;
5816
+ if (other.range.r1 <= 1) continue;
5817
+ if (other.range.c1 > origRange.c2 || other.range.c2 < origRange.c1) continue;
5818
+ lastRow = Math.min(lastRow, other.range.r1 - 1);
5819
+ }
5820
+ if (lastRow < 1) continue;
5821
+ const newRef = origRange.c2 === 0 && lastRow === 1 ? "A1" : `A1:${columnIndexToLetter(origRange.c2)}${lastRow}`;
5822
+ let xml = table.xml;
5823
+ const newTag = _XlsxUpdater._replaceOrAddXmlAttribute(table.tag, "ref", newRef);
5824
+ xml = xml.substring(0, table.tagIndex) + newTag + xml.substring(table.tagIndex + table.tag.length);
5825
+ const afRe = /<(?:[A-Za-z_][\w.-]*:)?autoFilter\b[^>]*>/i;
5826
+ const afMatch = afRe.exec(xml);
5827
+ if (afMatch && afMatch.index !== void 0) {
5828
+ const newAf = _XlsxUpdater._replaceOrAddXmlAttribute(afMatch[0], "ref", newRef);
5829
+ xml = xml.substring(0, afMatch.index) + newAf + xml.substring(afMatch.index + afMatch[0].length);
5830
+ }
5831
+ if (table.staged) {
5832
+ fs5.writeFileSync(this.stagedParts.get(table.path), xml, "utf8");
5833
+ } else {
5834
+ this.zip.updateFile(table.path, Buffer.from(xml, "utf8"));
5835
+ }
5836
+ } catch {
5837
+ }
4990
5838
  }
4991
5839
  }
4992
5840
  };
@@ -4994,78 +5842,8 @@ var XlsxUpdater = class _XlsxUpdater {
4994
5842
  // src/XlsbUpdater.ts
4995
5843
  var fs6 = __toESM(require("fs"));
4996
5844
  var os2 = __toESM(require("os"));
4997
- var path5 = __toESM(require("path"));
5845
+ var path7 = __toESM(require("path"));
4998
5846
  var import_adm_zip3 = __toESM(require("adm-zip"));
4999
-
5000
- // src/biff12Utils.ts
5001
- function readVlq(buf, pos) {
5002
- let value = 0;
5003
- let shift = 0;
5004
- let byte;
5005
- do {
5006
- byte = buf[pos++];
5007
- value |= (byte & 127) << shift;
5008
- shift += 7;
5009
- } while ((byte & 128) !== 0);
5010
- return { value, nextPos: pos };
5011
- }
5012
- function vlqBytes(value) {
5013
- const out = [];
5014
- while (value >= 128) {
5015
- out.push(value & 127 | 128);
5016
- value >>>= 7;
5017
- }
5018
- out.push(value & 127);
5019
- return out;
5020
- }
5021
- function readRecord(buf, pos, rec) {
5022
- const idRes = readVlq(buf, pos);
5023
- if (idRes.nextPos > buf.length) return false;
5024
- const lenRes = readVlq(buf, idRes.nextPos);
5025
- if (lenRes.nextPos + lenRes.value > buf.length) return false;
5026
- rec.headerStart = pos;
5027
- rec.dataStart = lenRes.nextPos;
5028
- rec.dataEnd = lenRes.nextPos + lenRes.value;
5029
- rec.id = idRes.value;
5030
- rec.len = lenRes.value;
5031
- return true;
5032
- }
5033
- function buildRecord(id, payload) {
5034
- const idBytes = vlqBytes(id);
5035
- const lenBytes = vlqBytes(payload.length);
5036
- const header = Buffer.alloc(idBytes.length + lenBytes.length);
5037
- idBytes.forEach((b, i) => header[i] = b);
5038
- lenBytes.forEach((b, i) => header[idBytes.length + i] = b);
5039
- return Buffer.concat([header, payload]);
5040
- }
5041
- function readUtf16(buf, start, charCount) {
5042
- const end = start + charCount * 2;
5043
- if (end > buf.length) return "";
5044
- return buf.toString("utf16le", start, end);
5045
- }
5046
- function parseSharedStringsBin(buf) {
5047
- const values = [];
5048
- let total = 0;
5049
- let unique = 0;
5050
- let endSstOffset = buf.length;
5051
- const rec = { headerStart: 0, dataStart: 0, dataEnd: 0, id: 0, len: 0 };
5052
- let pos = 0;
5053
- while (readRecord(buf, pos, rec)) {
5054
- pos = rec.dataEnd;
5055
- if (rec.id === 159) {
5056
- total = buf.readUInt32LE(rec.dataStart);
5057
- unique = buf.readUInt32LE(rec.dataStart + 4);
5058
- } else if (rec.id === 19) {
5059
- const cch = buf.readUInt32LE(rec.dataStart + 1);
5060
- values.push(readUtf16(buf, rec.dataStart + 5, cch));
5061
- } else if (rec.id === 160) {
5062
- endSstOffset = rec.headerStart;
5063
- }
5064
- }
5065
- return { values, total, unique, endSstOffset };
5066
- }
5067
-
5068
- // src/XlsbUpdater.ts
5069
5847
  var CELL_RECORDS = /* @__PURE__ */ new Set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
5070
5848
  var RK_INT_LOWER = -1 << 29;
5071
5849
  var RK_INT_UPPER = (1 << 29) - 1;
@@ -5169,6 +5947,7 @@ var XlsbUpdater = class {
5169
5947
  const rwLast = Math.max(0, rows.length + (headers ? 1 : 0) - 1);
5170
5948
  const colLast = lastCol;
5171
5949
  this._patchPivotCaches(sheetName, rwLast, colLast);
5950
+ this._removeCalcChain();
5172
5951
  }
5173
5952
  /** Replace worksheet rows from a one-pass source. */
5174
5953
  async replaceSheetDataStream(sheetName, rows, options = {}) {
@@ -5236,10 +6015,10 @@ var XlsbUpdater = class {
5236
6015
  if (outputError) throw outputError;
5237
6016
  writtenBytes += data.length;
5238
6017
  if (rowOutput.write(data)) return;
5239
- await new Promise((resolve4, reject) => {
6018
+ await new Promise((resolve6, reject) => {
5240
6019
  const onDrain = () => {
5241
6020
  cleanup();
5242
- resolve4();
6021
+ resolve6();
5243
6022
  };
5244
6023
  const onError = (error) => {
5245
6024
  cleanup();
@@ -5290,8 +6069,8 @@ var XlsbUpdater = class {
5290
6069
  lastKeptEnd = writtenBytes;
5291
6070
  }
5292
6071
  }
5293
- await new Promise((resolve4, reject) => {
5294
- rowOutput.once("close", resolve4);
6072
+ await new Promise((resolve6, reject) => {
6073
+ rowOutput.once("close", resolve6);
5295
6074
  rowOutput.once("error", reject);
5296
6075
  rowOutput.end();
5297
6076
  });
@@ -5354,6 +6133,7 @@ var XlsbUpdater = class {
5354
6133
  Math.max(0, keptDataRows + (headers !== void 0 ? 1 : 0) - 1),
5355
6134
  lastCol
5356
6135
  );
6136
+ this._removeCalcChain();
5357
6137
  if (oldStage && oldStage !== outputPath) this._removeTemporaryFile(oldStage);
5358
6138
  createdParts.splice(createdParts.indexOf(outputPath), 1);
5359
6139
  } catch (error) {
@@ -5424,7 +6204,7 @@ var XlsbUpdater = class {
5424
6204
  }
5425
6205
  _ensureTemporaryDirectory() {
5426
6206
  if (this.temporaryDirectory === null) {
5427
- this.temporaryDirectory = fs6.mkdtempSync(path5.join(os2.tmpdir(), "spreadsheet-updater-"));
6207
+ this.temporaryDirectory = fs6.mkdtempSync(path7.join(os2.tmpdir(), "spreadsheet-updater-"));
5428
6208
  } else {
5429
6209
  try {
5430
6210
  fs6.mkdirSync(this.temporaryDirectory, { recursive: true });
@@ -5434,7 +6214,7 @@ var XlsbUpdater = class {
5434
6214
  return this.temporaryDirectory;
5435
6215
  }
5436
6216
  _temporaryPath(suffix) {
5437
- return path5.join(this._ensureTemporaryDirectory(), `part-${Date.now()}-${Math.random().toString(16).slice(2)}${suffix}`);
6217
+ return path7.join(this._ensureTemporaryDirectory(), `part-${Date.now()}-${Math.random().toString(16).slice(2)}${suffix}`);
5438
6218
  }
5439
6219
  _removeTemporaryFile(filePath) {
5440
6220
  try {
@@ -5474,10 +6254,15 @@ var XlsbUpdater = class {
5474
6254
  const rIdToTarget = {};
5475
6255
  if (relsEntry) {
5476
6256
  const rels = relsEntry.getData().toString("utf8");
5477
- const relRegex = /<Relationship[^>]*Id="([^"]*)"[^>]*Target="([^"]*)"/g;
5478
- let match;
5479
- while ((match = relRegex.exec(rels)) !== null) {
5480
- rIdToTarget[match[1]] = match[2];
6257
+ const relTagRe = /<Relationship\b[^>]*>/g;
6258
+ let tagMatch;
6259
+ while ((tagMatch = relTagRe.exec(rels)) !== null) {
6260
+ const attrs = parseTagAttributes(tagMatch[0]);
6261
+ const id = attrs["Id"] ?? attrs["id"];
6262
+ const target = attrs["Target"] ?? attrs["target"];
6263
+ if (id !== void 0 && target !== void 0) {
6264
+ rIdToTarget[id] = target;
6265
+ }
5481
6266
  }
5482
6267
  }
5483
6268
  const wbEntry = this.zip.getEntry("xl/workbook.bin");
@@ -5497,12 +6282,24 @@ var XlsbUpdater = class {
5497
6282
  o += 4;
5498
6283
  const name = readUtf16(wbBuf, o, nameLen);
5499
6284
  let target = rIdToTarget[rId] ?? "";
5500
- if (target.startsWith("/")) target = target.substring(1);
5501
- else if (!target.startsWith("xl/")) target = "xl/" + target;
6285
+ target = resolveRelTarget(target);
5502
6286
  if (target) {
5503
6287
  this.sheetNameToPath.set(name, target);
5504
6288
  }
5505
6289
  }
6290
+ try {
6291
+ const rec1904 = { headerStart: 0, dataStart: 0, dataEnd: 0, id: 0, len: 0 };
6292
+ let p1904 = 0;
6293
+ while (readRecord(wbBuf, p1904, rec1904)) {
6294
+ if (rec1904.id === 153 && rec1904.len >= 4) {
6295
+ const is1904 = (wbBuf[rec1904.dataStart] & 1) !== 0;
6296
+ this._oaEpoch = is1904 ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, 30);
6297
+ break;
6298
+ }
6299
+ p1904 = rec1904.dataEnd;
6300
+ }
6301
+ } catch {
6302
+ }
5506
6303
  }
5507
6304
  for (const e of this.zip.getEntries()) {
5508
6305
  if (/^xl\/pivotCache\/pivotCacheDefinition\d*\.bin$/.test(e.entryName)) {
@@ -5611,27 +6408,15 @@ var XlsbUpdater = class {
5611
6408
  _findDateXf() {
5612
6409
  const entry = this.zip.getEntry("xl/styles.bin");
5613
6410
  if (!entry) return null;
5614
- const stylesBuf = entry.getData();
5615
- const rec = { headerStart: 0, dataStart: 0, dataEnd: 0, id: 0, len: 0 };
5616
- let pos = 0;
5617
- let inCellXfs = false;
5618
- let xfIndex = 0;
5619
- while (readRecord(stylesBuf, pos, rec)) {
5620
- pos = rec.dataEnd;
5621
- if (rec.id === 617) {
5622
- inCellXfs = true;
5623
- xfIndex = 0;
5624
- continue;
5625
- }
5626
- if (rec.id === 618) {
5627
- inCellXfs = false;
5628
- continue;
5629
- }
5630
- if (inCellXfs && rec.id === 47 && rec.len >= 4) {
5631
- const numFmtId = stylesBuf.readUInt16LE(rec.dataStart + 2);
5632
- const isDate = numFmtId >= 14 && numFmtId <= 22 || numFmtId >= 45 && numFmtId <= 47;
5633
- if (isDate) return xfIndex;
5634
- xfIndex++;
6411
+ const reader = new BiffReaderWriter(entry.getData());
6412
+ while (reader.readStyles()) {
6413
+ }
6414
+ const numFmtIds = reader._xfIndexToNumFmtId;
6415
+ const customDates = reader._customNumFmts;
6416
+ for (let i = 0; i < numFmtIds.length; i++) {
6417
+ const numFmtId = numFmtIds[i];
6418
+ if (numFmtId >= 14 && numFmtId <= 22 || numFmtId >= 45 && numFmtId <= 47 || customDates.has(numFmtId)) {
6419
+ return i;
5635
6420
  }
5636
6421
  }
5637
6422
  return null;
@@ -5711,7 +6496,7 @@ var XlsbUpdater = class {
5711
6496
  return buildRecord(4, payload);
5712
6497
  }
5713
6498
  if (val instanceof Date) {
5714
- const oaDate = (val.getTime() - this._oaEpoch) / 864e5;
6499
+ const oaDate = timeToOaDate(val.getTime(), this._oaEpoch);
5715
6500
  if (Number.isFinite(oaDate)) {
5716
6501
  const style = colStyle > 0 ? colStyle : dateXf !== null ? dateXf : 0;
5717
6502
  const payload = Buffer.alloc(16);
@@ -5778,10 +6563,10 @@ var XlsbUpdater = class {
5778
6563
  const rec = { headerStart: 0, dataStart: 0, dataEnd: 0, id: 0, len: 0 };
5779
6564
  let pos = 0;
5780
6565
  while (readRecord(originalSheet, pos, rec)) {
5781
- if (rec.id === 152 && rec.len >= 36) {
6566
+ if (rec.id === 148 && rec.len >= 16) {
5782
6567
  const shift = rec.dataStart >= rowsEnd ? delta : 0;
5783
- patchInt32(rec.dataStart + shift + 24, lastRowIdx);
5784
- patchInt32(rec.dataStart + shift + 32, lastCol);
6568
+ patchInt32(rec.dataStart + shift + 4, lastRowIdx);
6569
+ patchInt32(rec.dataStart + shift + 12, lastCol);
5785
6570
  break;
5786
6571
  }
5787
6572
  pos = rec.dataEnd;
@@ -5820,8 +6605,8 @@ var XlsbUpdater = class {
5820
6605
  return { rowsStart, rowsEnd, autoFilterRanges };
5821
6606
  }
5822
6607
  /**
5823
- * Keep the sheet dimension record (0x98) in sync with the new data.
5824
- * Excel uses its rwLast (payload offset 24) and colLast (payload offset 32)
6608
+ * Keep the sheet dimension record (0x94) in sync with the new data.
6609
+ * Excel uses its rwLast (payload offset 4) and colLast (payload offset 12)
5825
6610
  * fields to read the full row range; stale values make the last written row
5826
6611
  * invisible to Excel (and drop it from pivot refreshes).
5827
6612
  */
@@ -5829,9 +6614,9 @@ var XlsbUpdater = class {
5829
6614
  const rec = { headerStart: 0, dataStart: 0, dataEnd: 0, id: 0, len: 0 };
5830
6615
  let pos = 0;
5831
6616
  while (readRecord(sheetBuf, pos, rec)) {
5832
- if (rec.id === 152 && rec.len >= 36) {
5833
- sheetBuf.writeInt32LE(lastRowIdx, rec.dataStart + 24);
5834
- sheetBuf.writeInt32LE(lastCol, rec.dataStart + 32);
6617
+ if (rec.id === 148 && rec.len >= 16) {
6618
+ sheetBuf.writeInt32LE(lastRowIdx, rec.dataStart + 4);
6619
+ sheetBuf.writeInt32LE(lastCol, rec.dataStart + 12);
5835
6620
  return;
5836
6621
  }
5837
6622
  pos = rec.dataEnd;
@@ -5841,8 +6626,8 @@ var XlsbUpdater = class {
5841
6626
  // Pivot cache integration
5842
6627
  // ------------------------------------------------------------------
5843
6628
  _patchPivotCaches(sheetName, rwLast, colLast) {
5844
- for (const path7 of this.pivotCacheDefPaths) {
5845
- const entry = this.zip.getEntry(path7);
6629
+ for (const path9 of this.pivotCacheDefPaths) {
6630
+ const entry = this.zip.getEntry(path9);
5846
6631
  if (!entry) continue;
5847
6632
  const buf = Buffer.from(entry.getData());
5848
6633
  const rec = { headerStart: 0, dataStart: 0, dataEnd: 0, id: 0, len: 0 };
@@ -5874,16 +6659,84 @@ var XlsbUpdater = class {
5874
6659
  }
5875
6660
  }
5876
6661
  if (patched) {
5877
- this.zip.updateFile(path7, buf);
6662
+ this.zip.updateFile(path9, buf);
6663
+ }
6664
+ }
6665
+ }
6666
+ /**
6667
+ * Remove the stale calculation chain (xl/calcChain.bin). Excel rebuilds it
6668
+ * on open. Removes the part, its Content_Types override and its workbook
6669
+ * rels entry. XLSB tables are not patched (documented limitation).
6670
+ */
6671
+ _removeCalcChain() {
6672
+ const calcPath = "xl/calcChain.bin";
6673
+ if (!this.zip.getEntry(calcPath) && !this.stagedParts.has(calcPath)) return;
6674
+ try {
6675
+ this.zip.deleteFile(calcPath);
6676
+ } catch {
6677
+ }
6678
+ const stagedCalc = this.stagedParts.get(calcPath);
6679
+ if (stagedCalc) {
6680
+ this.stagedParts.delete(calcPath);
6681
+ try {
6682
+ fs6.rmSync(stagedCalc, { force: true });
6683
+ } catch {
6684
+ }
6685
+ }
6686
+ const ctPath = "[Content_Types].xml";
6687
+ if (this.zip.getEntry(ctPath) || this.stagedParts.has(ctPath)) {
6688
+ try {
6689
+ const ct = this._entryData(ctPath).toString("utf8");
6690
+ const updated = ct.replace(
6691
+ /<Override\b[^>]*PartName="\/xl\/calcChain\.bin"[^>]*\/?>/gi,
6692
+ ""
6693
+ );
6694
+ if (updated !== ct) this._writePartText(ctPath, updated);
6695
+ } catch {
6696
+ }
6697
+ }
6698
+ const relsPath = "xl/_rels/workbook.bin.rels";
6699
+ if (this.zip.getEntry(relsPath) || this.stagedParts.has(relsPath)) {
6700
+ try {
6701
+ const rels = this._entryData(relsPath).toString("utf8");
6702
+ const relTagRe = /<Relationship\b[^>]*>/g;
6703
+ let m;
6704
+ let out = "";
6705
+ let last = 0;
6706
+ let changed = false;
6707
+ while ((m = relTagRe.exec(rels)) !== null) {
6708
+ const attrs = parseTagAttributes(m[0]);
6709
+ const type = attrs["Type"] ?? attrs["type"] ?? "";
6710
+ const target = attrs["Target"] ?? attrs["target"] ?? "";
6711
+ if (type.endsWith("/calcChain") && resolveRelTarget(target) === "xl/calcChain.bin") {
6712
+ out += rels.substring(last, m.index);
6713
+ last = m.index + m[0].length;
6714
+ changed = true;
6715
+ }
6716
+ }
6717
+ if (changed) {
6718
+ out += rels.substring(last);
6719
+ this._writePartText(relsPath, out);
6720
+ }
6721
+ } catch {
5878
6722
  }
5879
6723
  }
5880
6724
  }
6725
+ /** Write an XML/text part to its staged file when present, else into the ZIP. */
6726
+ _writePartText(name, text) {
6727
+ const stagedPath = this.stagedParts.get(name);
6728
+ if (stagedPath) {
6729
+ fs6.writeFileSync(stagedPath, text, "utf8");
6730
+ } else {
6731
+ this.zip.updateFile(name, Buffer.from(text, "utf8"));
6732
+ }
6733
+ }
5881
6734
  };
5882
6735
 
5883
6736
  // src/ExcelConverter.ts
5884
6737
  var fs7 = __toESM(require("fs"));
5885
- var path6 = __toESM(require("path"));
5886
- var import_crypto3 = require("crypto");
6738
+ var path8 = __toESM(require("path"));
6739
+ var import_crypto5 = require("crypto");
5887
6740
  var import_child_process = require("child_process");
5888
6741
  var POWERSHELL_CONVERSION_SCRIPT = `
5889
6742
  $ErrorActionPreference = 'Stop'
@@ -5929,14 +6782,14 @@ function errorMessage2(error) {
5929
6782
  return error instanceof Error ? error.message : String(error);
5930
6783
  }
5931
6784
  function validateConversionPaths(inputPath, outputPath, inputExtension, outputExtension, overwrite) {
5932
- const input = path6.resolve(inputPath);
5933
- const output = path6.resolve(outputPath);
5934
- if (path6.extname(input).toLowerCase() !== inputExtension) {
6785
+ const input = path8.resolve(inputPath);
6786
+ const output = path8.resolve(outputPath);
6787
+ if (path8.extname(input).toLowerCase() !== inputExtension) {
5935
6788
  throw new Error(
5936
6789
  `Excel conversion: source must have the ${inputExtension} extension: ${inputPath}`
5937
6790
  );
5938
6791
  }
5939
- if (path6.extname(output).toLowerCase() !== outputExtension) {
6792
+ if (path8.extname(output).toLowerCase() !== outputExtension) {
5940
6793
  throw new Error(
5941
6794
  `Excel conversion: destination must have the ${outputExtension} extension: ${outputPath}`
5942
6795
  );
@@ -5947,8 +6800,8 @@ function validateConversionPaths(inputPath, outputPath, inputExtension, outputEx
5947
6800
  if (!fs7.statSync(input).isFile()) {
5948
6801
  throw new Error(`Excel conversion: source path is not a file: ${inputPath}`);
5949
6802
  }
5950
- if (!fs7.existsSync(path6.dirname(output))) {
5951
- throw new Error(`Excel conversion: destination directory not found: ${path6.dirname(output)}`);
6803
+ if (!fs7.existsSync(path8.dirname(output))) {
6804
+ throw new Error(`Excel conversion: destination directory not found: ${path8.dirname(output)}`);
5952
6805
  }
5953
6806
  if (fs7.existsSync(output)) {
5954
6807
  if (fs7.statSync(output).isDirectory()) {
@@ -5973,7 +6826,7 @@ function runPowerShellConversion(inputPath, outputPath, fileFormat) {
5973
6826
  JUSTYBASE_EXCEL_OUTPUT: outputPath,
5974
6827
  JUSTYBASE_EXCEL_FORMAT: String(fileFormat)
5975
6828
  };
5976
- return new Promise((resolve4, reject) => {
6829
+ return new Promise((resolve6, reject) => {
5977
6830
  var _a, _b, _c, _d;
5978
6831
  let stdout = "";
5979
6832
  let stderr = "";
@@ -6008,7 +6861,7 @@ function runPowerShellConversion(inputPath, outputPath, fileFormat) {
6008
6861
  if (settled) return;
6009
6862
  settled = true;
6010
6863
  if (code === 0) {
6011
- resolve4();
6864
+ resolve6();
6012
6865
  return;
6013
6866
  }
6014
6867
  const details = (stderr || stdout).replace(/\s+/g, " ").trim();
@@ -6029,9 +6882,9 @@ async function convertExcelFile(inputPath, outputPath, inputExtension, outputExt
6029
6882
  if (process.platform !== "win32") {
6030
6883
  throw new Error("Excel conversion requires Windows with desktop Microsoft Excel and COM automation.");
6031
6884
  }
6032
- const temporaryOutput = path6.join(
6033
- path6.dirname(output),
6034
- `.${path6.basename(output, outputExtension)}.${(0, import_crypto3.randomUUID)()}.conversion${outputExtension}`
6885
+ const temporaryOutput = path8.join(
6886
+ path8.dirname(output),
6887
+ `.${path8.basename(output, outputExtension)}.${(0, import_crypto5.randomUUID)()}.conversion${outputExtension}`
6035
6888
  );
6036
6889
  try {
6037
6890
  await runPowerShellConversion(input, temporaryOutput, fileFormat);
@@ -6063,6 +6916,9 @@ function convertXlsxToXlsb(inputPath, outputPath, options) {
6063
6916
  ExcelReaderAbstract,
6064
6917
  F,
6065
6918
  INVALID_SHEET_NAME_CHARS,
6919
+ MAX_CELL_CHARS,
6920
+ MAX_COLS,
6921
+ MAX_ROWS,
6066
6922
  ReaderFactory,
6067
6923
  StreamingSheetState,
6068
6924
  XlsbReader,
@@ -6073,13 +6929,25 @@ function convertXlsxToXlsb(inputPath, outputPath, options) {
6073
6929
  XlsxUpdater,
6074
6930
  XlsxWriter,
6075
6931
  applyHeaderWidths,
6932
+ assertCellTextLength,
6933
+ assertColumnCount,
6934
+ assertRowCount,
6935
+ assertRowFitsColumns,
6936
+ columnIndexToLetter,
6937
+ columnLetterToIndex,
6076
6938
  convertXlsbToXlsx,
6077
6939
  convertXlsxToXlsb,
6078
6940
  defaultColWidth,
6941
+ escapeXmlText,
6079
6942
  getFormat,
6080
6943
  initColWidths,
6081
6944
  isFormattedCell,
6945
+ parseSharedStringsXml,
6946
+ parseTagAttributes,
6947
+ resolveRelTarget,
6082
6948
  sanitizeSheetName,
6949
+ trimTrailingEmptyRows,
6950
+ unescapeXml,
6083
6951
  unwrapCell,
6084
6952
  updateColWidthsFromRows
6085
6953
  });