@justybase/spreadsheet-tasks 1.2.0 → 1.3.1

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.
@@ -0,0 +1,34 @@
1
+ export interface FormattedCell {
2
+ value: any;
3
+ format: string;
4
+ }
5
+ export declare const F: {
6
+ THOUSANDS_SEP: string;
7
+ CURRENCY_PLN: string;
8
+ CURRENCY_EUR: string;
9
+ PERCENTAGE: string;
10
+ SCIENTIFIC: string;
11
+ TWO_DECIMALS: string;
12
+ TEXT: string;
13
+ LEADING_ZEROS: string;
14
+ DATE_SHORT: string;
15
+ DATE_LONG: string;
16
+ DATE_DAY_MONTH_YEAR: string;
17
+ DATE_ISO: string;
18
+ DATE_MONTH_YEAR: string;
19
+ DATE_WEEKDAY: string;
20
+ DATE_DAY_MONTH: string;
21
+ DATE_YEAR_ONLY: string;
22
+ DATETIME_SHORT: string;
23
+ DATETIME_LONG: string;
24
+ TIME_HH_MM: string;
25
+ TIME_HH_MM_SS: string;
26
+ TIME_12H: string;
27
+ DATETIME_24H: string;
28
+ DATETIME_ISO: string;
29
+ TIME_MS: string;
30
+ };
31
+ export declare function isFormattedCell(val: any): val is FormattedCell;
32
+ export declare function unwrapCell(val: any): any;
33
+ export declare function getFormat(val: any): string | null;
34
+ //# sourceMappingURL=Formats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Formats.d.ts","sourceRoot":"","sources":["../src/Formats.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,GAAG,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;CA2Bb,CAAC;AAEF,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,aAAa,CAE9D;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CAKxC;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAKjD"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.F = void 0;
4
+ exports.isFormattedCell = isFormattedCell;
5
+ exports.unwrapCell = unwrapCell;
6
+ exports.getFormat = getFormat;
7
+ exports.F = {
8
+ THOUSANDS_SEP: '#,##0',
9
+ CURRENCY_PLN: '#,##0.00 "z\u0142"',
10
+ CURRENCY_EUR: '#,##0.00 \u20AC',
11
+ PERCENTAGE: '0%',
12
+ SCIENTIFIC: '0.00E+00',
13
+ TWO_DECIMALS: '#,##0.00',
14
+ TEXT: '@',
15
+ LEADING_ZEROS: '000000000',
16
+ DATE_SHORT: 'dd.mm.yyyy',
17
+ DATE_LONG: 'd mmmm yyyy',
18
+ DATE_DAY_MONTH_YEAR: 'dd-mm-yyyy',
19
+ DATE_ISO: 'yyyy-mm-dd',
20
+ DATE_MONTH_YEAR: 'mmmm yyyy',
21
+ DATE_WEEKDAY: 'dddd, d mmmm yyyy',
22
+ DATE_DAY_MONTH: 'd mmmm',
23
+ DATE_YEAR_ONLY: 'yyyy',
24
+ DATETIME_SHORT: 'dd.mm.yyyy hh:mm',
25
+ DATETIME_LONG: 'd mmmm yyyy hh:mm:ss',
26
+ TIME_HH_MM: 'hh:mm',
27
+ TIME_HH_MM_SS: 'hh:mm:ss',
28
+ TIME_12H: 'h:mm AM/PM',
29
+ DATETIME_24H: 'dd.mm.yyyy hh:mm:ss',
30
+ DATETIME_ISO: 'yyyy-mm-dd"T"hh:mm:ss',
31
+ TIME_MS: 'hh:mm:ss.000',
32
+ };
33
+ function isFormattedCell(val) {
34
+ return val !== null && val !== undefined && typeof val === 'object' && 'format' in val && typeof val.format === 'string';
35
+ }
36
+ function unwrapCell(val) {
37
+ if (isFormattedCell(val)) {
38
+ return val.value;
39
+ }
40
+ return val;
41
+ }
42
+ function getFormat(val) {
43
+ if (isFormattedCell(val)) {
44
+ return val.format;
45
+ }
46
+ return null;
47
+ }
48
+ //# sourceMappingURL=Formats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Formats.js","sourceRoot":"","sources":["../src/Formats.ts"],"names":[],"mappings":";;;AAkCA,0CAEC;AAED,gCAKC;AAED,8BAKC;AA7CY,QAAA,CAAC,GAAG;IACb,aAAa,EAAE,OAAO;IACtB,YAAY,EAAE,oBAAoB;IAClC,YAAY,EAAE,iBAAiB;IAC/B,UAAU,EAAE,IAAI;IAChB,UAAU,EAAE,UAAU;IACtB,YAAY,EAAE,UAAU;IACxB,IAAI,EAAE,GAAG;IACT,aAAa,EAAE,WAAW;IAE1B,UAAU,EAAE,YAAY;IACxB,SAAS,EAAE,aAAa;IACxB,mBAAmB,EAAE,YAAY;IACjC,QAAQ,EAAE,YAAY;IACtB,eAAe,EAAE,WAAW;IAC5B,YAAY,EAAE,mBAAmB;IACjC,cAAc,EAAE,QAAQ;IACxB,cAAc,EAAE,MAAM;IAEtB,cAAc,EAAE,kBAAkB;IAClC,aAAa,EAAE,sBAAsB;IACrC,UAAU,EAAE,OAAO;IACnB,aAAa,EAAE,UAAU;IACzB,QAAQ,EAAE,YAAY;IACtB,YAAY,EAAE,qBAAqB;IACnC,YAAY,EAAE,uBAAuB;IACrC,OAAO,EAAE,cAAc;CAC1B,CAAC;AAEF,SAAgB,eAAe,CAAC,GAAQ;IACpC,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,QAAQ,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC;AAC7H,CAAC;AAED,SAAgB,UAAU,CAAC,GAAQ;IAC/B,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,KAAK,CAAC;IACrB,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED,SAAgB,SAAS,CAAC,GAAQ;IAC9B,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,MAAM,CAAC;IACtB,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
@@ -10,6 +10,9 @@ export declare class XlsbWriter {
10
10
  private colWidths;
11
11
  private _autofilterIsOn;
12
12
  private _oaEpoch;
13
+ private _nextFmtId;
14
+ private _nextXfIdx;
15
+ private _stFmtRecords;
13
16
  private _sheet1Bytes;
14
17
  private _workbookBinStart;
15
18
  private _workbookBinMiddle;
@@ -32,6 +35,12 @@ export declare class XlsbWriter {
32
35
  private isStreaming;
33
36
  constructor(filePath: string);
34
37
  private _sanitizeSheetName;
38
+ private _registerFormat;
39
+ private static _buildBrtRecord;
40
+ private static _encodeVlq;
41
+ private static _buildStFmtRecord;
42
+ private static _buildXfRecord;
43
+ private _buildStylesBin;
35
44
  addSheet(sheetName: string, hidden?: boolean): void;
36
45
  /**
37
46
  * Start a new sheet in streaming mode. Call writeRow() for each row, then endSheet() when done.
@@ -60,7 +69,7 @@ export declare class XlsbWriter {
60
69
  writeDouble(bigBuf: BigBuffer, val: number, colNum: number, styleNum?: number): void;
61
70
  writeBool(bigBuf: BigBuffer, val: boolean, colNum: number): void;
62
71
  writeDateTime(bigBuf: BigBuffer, date: Date, colNum: number): void;
63
- writeString(bigBuf: BigBuffer, val: string, colNum: number, bolded?: boolean): void;
72
+ writeString(bigBuf: BigBuffer, val: string, colNum: number, bolded?: boolean, styleOverride?: number): void;
64
73
  private saveSst;
65
74
  private _writeFilterDefinedName;
66
75
  finalize(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"XlsbWriter.d.ts","sourceRoot":"","sources":["../src/XlsbWriter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"XlsbWriter.d.ts","sourceRoot":"","sources":["../src/XlsbWriter.ts"],"names":[],"mappings":"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"}
@@ -41,6 +41,7 @@ const fs = __importStar(require("fs"));
41
41
  const archiver_1 = __importDefault(require("archiver"));
42
42
  const stream_1 = require("stream");
43
43
  const BigBuffer_1 = require("./BigBuffer");
44
+ const Formats_1 = require("./Formats");
44
45
  const INVALID_SHEET_NAME_CHARS = /[\\/*?[\]:]/g;
45
46
  class XlsbWriter {
46
47
  constructor(filePath) {
@@ -51,6 +52,9 @@ class XlsbWriter {
51
52
  this.sstCntAll = 0;
52
53
  this.colWidths = [];
53
54
  this._autofilterIsOn = false;
55
+ this._nextFmtId = 167;
56
+ this._nextXfIdx = 4;
57
+ this._stFmtRecords = new Map();
54
58
  // Streaming state
55
59
  this.currentSheetBuffer = null;
56
60
  this.currentSheetRowNum = 0;
@@ -229,6 +233,128 @@ class XlsbWriter {
229
233
  }
230
234
  return sanitized;
231
235
  }
236
+ _registerFormat(fmtString) {
237
+ if (this._stFmtRecords.has(fmtString)) {
238
+ return this._stFmtRecords.get(fmtString).xfIndex;
239
+ }
240
+ const numfmtId = this._nextFmtId++;
241
+ const xfIndex = this._nextXfIdx++;
242
+ this._stFmtRecords.set(fmtString, { numfmtId, xfIndex });
243
+ return xfIndex;
244
+ }
245
+ static _buildBrtRecord(type, data) {
246
+ const header = XlsbWriter._encodeVlq(type);
247
+ header.push(...XlsbWriter._encodeVlq(data.length));
248
+ return Buffer.concat([Buffer.from(header), data]);
249
+ }
250
+ static _encodeVlq(value) {
251
+ const result = [];
252
+ while (value >= 0x80) {
253
+ result.push((value & 0x7F) | 0x80);
254
+ value >>>= 7;
255
+ }
256
+ result.push(value & 0x7F);
257
+ return result;
258
+ }
259
+ static _buildStFmtRecord(ifmt, fmtString) {
260
+ const cch = fmtString.length;
261
+ const remaining = 2 + 4 + cch * 2;
262
+ const data = Buffer.alloc(2 + remaining);
263
+ data[0] = 0x2C;
264
+ data[1] = remaining;
265
+ data.writeUInt16LE(ifmt, 2);
266
+ data.writeUInt32LE(cch, 4);
267
+ data.write(fmtString, 8, cch * 2, 'utf16le');
268
+ return data;
269
+ }
270
+ static _buildXfRecord(fontId, ifmt, flags, byte6Extra = 0) {
271
+ const data = Buffer.alloc(18);
272
+ data[0] = 0x2F;
273
+ data[1] = 16;
274
+ data.writeUInt16LE(fontId, 2);
275
+ data.writeUInt16LE(ifmt, 4);
276
+ data[6] = byte6Extra;
277
+ data[14] = 0x10;
278
+ data[15] = 0x10;
279
+ data.writeUInt16LE(flags, 16);
280
+ return data;
281
+ }
282
+ _buildStylesBin() {
283
+ if (this._stFmtRecords.size === 0) {
284
+ return this._stylesBin;
285
+ }
286
+ const base = this._stylesBin;
287
+ // Find BrtEndFonts (0xE8, 0x04, 0x00)
288
+ let fontEndOff = -1;
289
+ for (let i = 3; i < base.length - 3; i++) {
290
+ if (base[i] === 0xE8 && base[i + 1] === 0x04 && base[i + 2] === 0x00) {
291
+ fontEndOff = i;
292
+ break;
293
+ }
294
+ }
295
+ // Find BrtBeginCellXFs (0xE9, 0x04)
296
+ let xfBeginOff = -1;
297
+ for (let i = fontEndOff + 3; i < base.length - 2; i++) {
298
+ if (base[i] === 0xE9 && base[i + 1] === 0x04) {
299
+ xfBeginOff = i;
300
+ break;
301
+ }
302
+ }
303
+ // Find BrtEndCellXFs (0xEA, 0x04, 0x00)
304
+ let xfEndOff = -1;
305
+ for (let i = xfBeginOff; i < base.length - 3; i++) {
306
+ if (base[i] === 0xEA && base[i + 1] === 0x04 && base[i + 2] === 0x00) {
307
+ xfEndOff = i;
308
+ break;
309
+ }
310
+ }
311
+ // Find BrtBeginFills (0xE3, 0x04) — start after BrtEndFonts
312
+ let fillBeginOff = -1;
313
+ for (let i = fontEndOff + 3; i < base.length - 2; i++) {
314
+ if (base[i] === 0xE3 && base[i + 1] === 0x04) {
315
+ fillBeginOff = i;
316
+ break;
317
+ }
318
+ }
319
+ const totalFmt = 2 + this._stFmtRecords.size;
320
+ const totalXf = 4 + this._stFmtRecords.size;
321
+ const parts = [];
322
+ // 1. BrtBeginStyleSheet
323
+ parts.push(base.subarray(0, 3));
324
+ // 2. NEW BrtFmt: VLQ(0x0267) + VLQ(4) + count(2 LE) + pad(2)
325
+ const fmtHeader = Buffer.alloc(4);
326
+ fmtHeader.writeUInt16LE(totalFmt, 0);
327
+ parts.push(XlsbWriter._buildBrtRecord(0x0267, fmtHeader));
328
+ // 3. BrtNumFmt records: 2 base + custom (ALWAYS add base formats)
329
+ parts.push(XlsbWriter._buildStFmtRecord(164, 'yyyy\\-mm\\-dd\\ hh:mm'));
330
+ parts.push(XlsbWriter._buildStFmtRecord(166, 'yyyy\\-mm\\-dd'));
331
+ for (const [fmtString, st] of this._stFmtRecords) {
332
+ parts.push(XlsbWriter._buildStFmtRecord(st.numfmtId, fmtString));
333
+ }
334
+ // 4. BrtEndFonts
335
+ parts.push(XlsbWriter._buildBrtRecord(0x0268, Buffer.alloc(0)));
336
+ // 5. Copy fills+borders+BrtFont+cellStyleXFs from template
337
+ parts.push(base.subarray(fillBeginOff, xfBeginOff));
338
+ // 7. NEW BrtBeginCellXFs
339
+ const xfHeader = Buffer.alloc(4);
340
+ xfHeader.writeUInt16LE(totalXf, 0);
341
+ parts.push(XlsbWriter._buildBrtRecord(0x0269, xfHeader));
342
+ // 8. Base XF records
343
+ parts.push(XlsbWriter._buildXfRecord(0, 0, 0x0000));
344
+ parts.push(XlsbWriter._buildXfRecord(0, 164, 0x0001));
345
+ parts.push(XlsbWriter._buildXfRecord(0, 166, 0x0001));
346
+ parts.push(XlsbWriter._buildXfRecord(1, 0, 0x0000, 1));
347
+ // 9. Custom XF records
348
+ const sortedXf = [...this._stFmtRecords.entries()].sort((a, b) => a[1].xfIndex - b[1].xfIndex);
349
+ for (const [, st] of sortedXf) {
350
+ parts.push(XlsbWriter._buildXfRecord(0, st.numfmtId, 0x0001));
351
+ }
352
+ // 10. BrtEndCellXFs
353
+ parts.push(XlsbWriter._buildBrtRecord(0x026A, Buffer.alloc(0)));
354
+ // 11. Copy remaining template
355
+ parts.push(base.subarray(xfEndOff + 3));
356
+ return Buffer.concat(parts);
357
+ }
232
358
  addSheet(sheetName, hidden = false) {
233
359
  const sanitizedName = this._sanitizeSheetName(sheetName);
234
360
  this.sheetCount++;
@@ -283,8 +409,8 @@ class XlsbWriter {
283
409
  sheetHeader[54] = 0x9C;
284
410
  }
285
411
  bigBuf.write(sheetHeader.subarray(0, 84));
286
- // Write sticky header if autofilter is on
287
- if (this.currentSheetDoAutofilter) {
412
+ // Write sticky header if headers are present
413
+ if (headers) {
288
414
  bigBuf.write(this._stickHeaderA1bytes);
289
415
  }
290
416
  bigBuf.write(sheetHeader.subarray(84, 159));
@@ -339,20 +465,23 @@ class XlsbWriter {
339
465
  this.createRowHeader(bigBuf, this.currentSheetRowNum, this.currentSheetStartCol, this.currentSheetEndCol);
340
466
  // Write each cell
341
467
  for (let c = 0; c < row.length; c++) {
342
- const val = row[c];
343
- if (val === null || val === undefined)
468
+ const raw = row[c];
469
+ if (raw === null || raw === undefined)
344
470
  continue;
471
+ const fmtString = (0, Formats_1.getFormat)(raw);
472
+ const val = fmtString !== null ? (0, Formats_1.unwrapCell)(raw) : raw;
473
+ const styleNum = fmtString !== null ? this._registerFormat(fmtString) : 0;
345
474
  if (typeof val === 'number') {
346
475
  if (Number.isInteger(val)) {
347
476
  if (val >= this._rRkIntegerLowerLimit && val <= this._rRkIntegerUpperLimit) {
348
- this.writeRkNumberInteger(bigBuf, val, c);
477
+ this.writeRkNumberInteger(bigBuf, val, c, styleNum);
349
478
  }
350
479
  else {
351
- this.writeDouble(bigBuf, val, c);
480
+ this.writeDouble(bigBuf, val, c, styleNum);
352
481
  }
353
482
  }
354
483
  else {
355
- this.writeDouble(bigBuf, val, c);
484
+ this.writeDouble(bigBuf, val, c, styleNum);
356
485
  }
357
486
  }
358
487
  else if (typeof val === 'bigint') {
@@ -362,10 +491,11 @@ class XlsbWriter {
362
491
  this.writeBool(bigBuf, val, c);
363
492
  }
364
493
  else if (val instanceof Date) {
365
- this.writeDateTime(bigBuf, val, c);
494
+ const oaDate = (val.getTime() - this._oaEpoch) / 86400000;
495
+ this.writeDouble(bigBuf, oaDate, c, fmtString !== null ? styleNum : 1);
366
496
  }
367
497
  else {
368
- this.writeString(bigBuf, val.toString(), c);
498
+ this.writeString(bigBuf, val.toString(), c, false, fmtString !== null ? styleNum : undefined);
369
499
  }
370
500
  }
371
501
  this.currentSheetRowNum++;
@@ -442,8 +572,11 @@ class XlsbWriter {
442
572
  for (let r = 0; r < Math.min(rows.length, 100); r++) {
443
573
  const row = rows[r];
444
574
  for (let c = 0; c < row.length; c++) {
445
- const val = row[c];
446
- const len = val ? val.toString().length : 0;
575
+ const raw = row[c];
576
+ if (raw === null || raw === undefined)
577
+ continue;
578
+ const val = (0, Formats_1.isFormattedCell)(raw) ? raw.value : raw;
579
+ const len = val instanceof Date ? 10 : val.toString().length;
447
580
  let width = 1.25 * len + 2;
448
581
  if (width > 80)
449
582
  width = 80;
@@ -460,7 +593,7 @@ class XlsbWriter {
460
593
  sheetHeader[54] = 0x9C;
461
594
  }
462
595
  bigBuf.write(sheetHeader.subarray(0, 84));
463
- if (doAutofilter && headers) {
596
+ if (headers) {
464
597
  bigBuf.write(this._stickHeaderA1bytes);
465
598
  }
466
599
  bigBuf.write(sheetHeader.subarray(84, 159));
@@ -501,20 +634,23 @@ class XlsbWriter {
501
634
  this.createRowHeader(bigBuf, rowNum, startCol, endCol);
502
635
  const row = rows[r];
503
636
  for (let c = 0; c < row.length; c++) {
504
- const val = row[c];
505
- if (val === null || val === undefined)
637
+ const raw = row[c];
638
+ if (raw === null || raw === undefined)
506
639
  continue;
640
+ const fmtString = (0, Formats_1.getFormat)(raw);
641
+ const val = fmtString !== null ? (0, Formats_1.unwrapCell)(raw) : raw;
642
+ const styleNum = fmtString !== null ? this._registerFormat(fmtString) : 0;
507
643
  if (typeof val === 'number') {
508
644
  if (Number.isInteger(val)) {
509
645
  if (val >= this._rRkIntegerLowerLimit && val <= this._rRkIntegerUpperLimit) {
510
- this.writeRkNumberInteger(bigBuf, val, c);
646
+ this.writeRkNumberInteger(bigBuf, val, c, styleNum);
511
647
  }
512
648
  else {
513
- this.writeDouble(bigBuf, val, c);
649
+ this.writeDouble(bigBuf, val, c, styleNum);
514
650
  }
515
651
  }
516
652
  else {
517
- this.writeDouble(bigBuf, val, c);
653
+ this.writeDouble(bigBuf, val, c, styleNum);
518
654
  }
519
655
  }
520
656
  else if (typeof val === 'bigint') {
@@ -524,10 +660,11 @@ class XlsbWriter {
524
660
  this.writeBool(bigBuf, val, c);
525
661
  }
526
662
  else if (val instanceof Date) {
527
- this.writeDateTime(bigBuf, val, c);
663
+ const oaDate = (val.getTime() - this._oaEpoch) / 86400000;
664
+ this.writeDouble(bigBuf, oaDate, c, fmtString !== null ? styleNum : 1);
528
665
  }
529
666
  else {
530
- this.writeString(bigBuf, val.toString(), c);
667
+ this.writeString(bigBuf, val.toString(), c, false, fmtString !== null ? styleNum : undefined);
531
668
  }
532
669
  }
533
670
  rowNum++;
@@ -611,7 +748,7 @@ class XlsbWriter {
611
748
  const oaDate = (date.getTime() - this._oaEpoch) / 86400000;
612
749
  this.writeDouble(bigBuf, oaDate, colNum, 1);
613
750
  }
614
- writeString(bigBuf, val, colNum, bolded = false) {
751
+ writeString(bigBuf, val, colNum, bolded = false, styleOverride) {
615
752
  let index;
616
753
  if (this.sstDic.has(val)) {
617
754
  index = this.sstDic.get(val);
@@ -622,11 +759,12 @@ class XlsbWriter {
622
759
  this.sstCntUnique++;
623
760
  }
624
761
  this.sstCntAll++;
762
+ const styleNum = styleOverride !== undefined ? styleOverride : (bolded ? 3 : 0);
625
763
  bigBuf.ensureCapacity(17);
626
764
  bigBuf.writeUnsafeByte(7);
627
765
  bigBuf.writeUnsafeByte(12);
628
766
  bigBuf.writeUnsafeInt32LE(colNum);
629
- bigBuf.writeUnsafeByte(bolded ? 3 : 0);
767
+ bigBuf.writeUnsafeByte(styleNum);
630
768
  bigBuf.writeUnsafeByte(0);
631
769
  bigBuf.writeUnsafeByte(0);
632
770
  bigBuf.writeUnsafeByte(0);
@@ -692,7 +830,7 @@ class XlsbWriter {
692
830
  return new Promise((resolve, reject) => {
693
831
  try {
694
832
  this.saveSst();
695
- this.archive.append(this._stylesBin, { name: 'xl/styles.bin' });
833
+ this.archive.append(this._buildStylesBin(), { name: 'xl/styles.bin' });
696
834
  const wbBuffers = [];
697
835
  wbBuffers.push(this._workbookBinStart);
698
836
  for (const sheet of this.sheetList) {
@@ -729,8 +867,12 @@ class XlsbWriter {
729
867
  const cnt = filteredSheets.length;
730
868
  if (cnt > 0) {
731
869
  wbBuffers.push(this._magicFilterExcel2016Fix0);
732
- const firstByte = 0x10 + (cnt - 1) * 0x0C;
733
- const countBuf = Buffer.from([firstByte, cnt, 0x00, 0x00, 0x00]);
870
+ const firstByte = cnt <= 20
871
+ ? 0x10 + (cnt - 1) * 0x0C
872
+ : 0x80 + (cnt - 21) * 0x0C;
873
+ const countBuf = cnt <= 10
874
+ ? Buffer.from([firstByte, cnt, 0x00, 0x00, 0x00])
875
+ : Buffer.from([firstByte, Math.floor((cnt - 1) / 10), cnt, 0x00, 0x00, 0x00]);
734
876
  wbBuffers.push(countBuf);
735
877
  for (let nm = 0; nm < cnt; nm++) {
736
878
  const sheetIndex = filteredSheets[nm].sheetId - 1;