@justybase/spreadsheet-tasks 3.1.1 → 3.2.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/CHANGELOG.md +78 -0
- package/README.md +124 -3
- package/browser/browser-spreadsheet.js +3659 -1784
- package/browser/justybase-spreadsheet.min.js +50 -23
- package/dist/cjs/index.d.ts +458 -59
- package/dist/cjs/index.js +5643 -2523
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +5623 -2523
- package/dist/esm/index.js.map +1 -1
- package/docs/API.md +130 -7
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,84 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.2.0] - 2026-11-08
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Shared writer core (`src/writers/core`) used by the Node and browser XLSX/XLSB
|
|
13
|
+
writers. The unpacked package parts are byte-identical between Node and browsers.
|
|
14
|
+
- `useSharedStrings: false` writer option for inline strings (four writers).
|
|
15
|
+
- `ExcelError` cell value and round-trip support for Excel error cells.
|
|
16
|
+
- `XlsxReader.openBuffer()` and `XlsbReader.openBuffer()` plus `readRow()`,
|
|
17
|
+
`readAll()` and `rows()` batch APIs.
|
|
18
|
+
- Isolated-process I/O benchmark (`npm run benchmark:io`) with a 3% regression
|
|
19
|
+
gate, and a self-contained Microsoft Excel COM conformance suite
|
|
20
|
+
(`EXCEL_COM=1 npm run test:excel-com`).
|
|
21
|
+
- Etap 2 cell formatting: `CellStyle`, `StyledCell`, `FormulaCell`, `RichText`
|
|
22
|
+
and style helpers. `FormattedCell` remains supported.
|
|
23
|
+
- XLSX styling: fonts, fills, borders, alignment, protection, custom number
|
|
24
|
+
formats and differential styles for conditional formatting.
|
|
25
|
+
- XLSX sheet features: formula cells with cached values, rich text, merged
|
|
26
|
+
cells, hyperlinks, data validation, conditional formatting and cell comments
|
|
27
|
+
(classic notes with VML).
|
|
28
|
+
- XLSB styling and formulas: a BIFF12 style registry and a curated formula
|
|
29
|
+
compiler with cached values; merged cells, hyperlinks and data validation.
|
|
30
|
+
- Conservative column autofit (header + up to 200 sample rows, capped at 200,
|
|
31
|
+
not narrower than xlspy/Excel AutoFit up to that cap) and explicit
|
|
32
|
+
`columnWidths` overrides in all four writers. Streaming writers delay the
|
|
33
|
+
sheet head until the first 200 data rows have been measured.
|
|
34
|
+
- `XlsxReader.getStyle()`, `getFormula()` and `getRichText()`; `XlsbReader.getStyle()`.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- `writeSheet` accepts a sheet-options object in place of the legacy
|
|
39
|
+
`doAutofilter` boolean while keeping the boolean overload backward compatible.
|
|
40
|
+
- `updateColWidthsFromRows` understands styled, formula and rich-text cells.
|
|
41
|
+
- Autofit is deliberately conservative so it is not narrower than
|
|
42
|
+
xlspy/Excel AutoFit up to the 200 cap: columns use the 8.43 minimum, calibrated
|
|
43
|
+
character costs (CJK/fullwidth, emoji, wide fonts, bold/italic and font
|
|
44
|
+
size), number/date-format display text, room for the autofilter button, the
|
|
45
|
+
5/7-character cell padding, and a 200-character cap on the stored width. The
|
|
46
|
+
default fallback width is 9.14.
|
|
47
|
+
- Autofit also measures alignment indent, the longest line of wrapped text,
|
|
48
|
+
negative number-format sections, and Excel's 11-character General rendering
|
|
49
|
+
instead of the full JavaScript decimal expansion.
|
|
50
|
+
- `options.autofitRows` controls how many rows are measured (default 200;
|
|
51
|
+
`0` disables row sampling).
|
|
52
|
+
- XLSB column widths are written as full 1/256-character units instead of
|
|
53
|
+
floored integers.
|
|
54
|
+
- Explicit `columnWidths` values are validated to 0.5-255 characters.
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
|
|
58
|
+
- XLSX reading no longer scans the rest of the sheet for every cell. The
|
|
59
|
+
formula lookup was unbounded, so a 20,000 x 10 sheet took minutes to read
|
|
60
|
+
instead of milliseconds; tag and value lookups are now bounded to the cell.
|
|
61
|
+
- XLSX numeric cells are parsed without allocating an intermediate string
|
|
62
|
+
(`parseFloat` is still used for exponents and long mantissas), restoring
|
|
63
|
+
read throughput close to the pre-Etap-2 reader.
|
|
64
|
+
- Dates with a time of day now use the datetime style (`numFmt` 22) in XLSX and
|
|
65
|
+
XLSB instead of the date-only style, so the time is no longer hidden.
|
|
66
|
+
- Streaming `writeRow()` now feeds autofit instead of leaving columns sized only
|
|
67
|
+
from the header and `sampleRows`.
|
|
68
|
+
- Long runs of accented Latin, Greek/Cyrillic and symbol characters are no
|
|
69
|
+
longer measured narrower than xlspy; a per-character exception table covers
|
|
70
|
+
the outliers.
|
|
71
|
+
- XLSB `BrtWsDim` now contains the real last row and an inclusive last column;
|
|
72
|
+
previously rows were always 0 and the column was one past the data.
|
|
73
|
+
- XLSB cells with an error value are read as `#DIV/0!`-style text instead of `null`.
|
|
74
|
+
- XLSX reader resolves optional `r`/`t`/`s` cell attributes from raw bytes
|
|
75
|
+
(previously attribute-less and typed cells could be misread).
|
|
76
|
+
- XLSB custom number formats no longer produce a corrupt styles part.
|
|
77
|
+
|
|
78
|
+
### Limitations
|
|
79
|
+
|
|
80
|
+
- XLSB rich text, comments and conditional formatting are not emitted yet; the
|
|
81
|
+
writers throw a clear error instead of silently dropping them.
|
|
82
|
+
- XLSB formula support is a subset (literals, A1 references/ranges, operators
|
|
83
|
+
and common worksheet functions); unsupported syntax throws.
|
|
84
|
+
- `XlsbReader` does not reconstruct formula text; it returns cached values.
|
|
85
|
+
|
|
8
86
|
## [3.1.1] - 2026-10-24
|
|
9
87
|
|
|
10
88
|
### Changed
|
package/README.md
CHANGED
|
@@ -28,7 +28,16 @@ High-performance TypeScript library for reading and writing Excel files in XLSB
|
|
|
28
28
|
- **TypeScript First** — Full TypeScript support with type definitions
|
|
29
29
|
- **Dual Format Support** — Read and write both XLSB and XLSX formats
|
|
30
30
|
- **Lightweight Node Dependencies** — Small ZIP-focused runtime deps (`adm-zip`, `archiver`, `yauzl`); no heavy Excel framework
|
|
31
|
-
- **Streaming Support**
|
|
31
|
+
- **Streaming Support** - Efficient memory usage for large files
|
|
32
|
+
- **Shared Writer Core** - Node and browser writers emit byte-identical package parts
|
|
33
|
+
- **Inline or Shared Strings** - Opt into inline strings for high-cardinality text
|
|
34
|
+
- **Buffer I/O** - `openBuffer()` reads a workbook from memory; `readAll()`/`rows()` batch APIs
|
|
35
|
+
- **Styles and Formats** - Fonts, fills, borders, alignment, protection and number formats (`CellStyle`)
|
|
36
|
+
- **Formulas** - Write formula cells with cached values (`FormulaCell`); XLSX and a curated XLSB formula subset
|
|
37
|
+
- **Sheet Features** - Merged cells, hyperlinks, data validation, comments and conditional formatting in XLSX; merges, hyperlinks and validation in XLSB
|
|
38
|
+
- **Rich Text** - Formatted text runs in XLSX shared and inline strings
|
|
39
|
+
- **Conservative Column Autofit** - Not narrower than xlspy/Excel AutoFit up to the 200 cap; explicit `columnWidths` override it
|
|
40
|
+
- **Excel Error Values** - Read and write `#DIV/0!`, `#N/A` and the other Excel errors
|
|
32
41
|
- **Multiple Sheets** — Support for multiple worksheets per workbook
|
|
33
42
|
- **Auto-filter** — Automatic filter headers support
|
|
34
43
|
- **Excel COM Conversion** — Convert XLSB and XLSX through desktop Microsoft Excel on Windows
|
|
@@ -190,6 +199,19 @@ const writer = new XlsxWriter('fast.xlsx', { compressionLevel: 1 });
|
|
|
190
199
|
|
|
191
200
|
Out-of-range values throw a `RangeError`.
|
|
192
201
|
|
|
202
|
+
### Inline Strings
|
|
203
|
+
|
|
204
|
+
Writers use a shared-string table by default, which is fastest when text repeats.
|
|
205
|
+
For high-cardinality text (IDs, messages) inline strings can reduce peak memory:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
const xlsx = new XlsxWriter('inline.xlsx', { useSharedStrings: false });
|
|
209
|
+
const xlsb = new XlsbWriter('inline.xlsb', { useSharedStrings: false });
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
The browser writers accept the same option:
|
|
213
|
+
`new BrowserXlsxWriter({ useSharedStrings: false })`.
|
|
214
|
+
|
|
193
215
|
### Reading Excel Files
|
|
194
216
|
|
|
195
217
|
```typescript
|
|
@@ -215,6 +237,101 @@ await xlsbReader.open('data.xlsb');
|
|
|
215
237
|
// ... same API as above
|
|
216
238
|
```
|
|
217
239
|
|
|
240
|
+
Batch and in-memory APIs avoid the per-row `await`/`getValue` loop:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
const reader = new XlsxReader();
|
|
244
|
+
await reader.openBuffer(buffer); // ZIP bytes, e.g. from fetch() or fs.readFileSync()
|
|
245
|
+
await reader.selectSheet(0); // or a sheet name
|
|
246
|
+
const rows = await reader.readAll(); // CellValue[][] (header row included)
|
|
247
|
+
|
|
248
|
+
for await (const row of reader.rows()) { // streaming without holding the sheet
|
|
249
|
+
consume(row);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Synchronous fast path after selectSheet(): the returned array is reused until the next call.
|
|
253
|
+
let row: CellValue[] | null;
|
|
254
|
+
while ((row = reader.readRow()) !== null) {
|
|
255
|
+
consume(row.slice()); // copy if you keep it
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Excel error cells are returned as their display text (`'#DIV/0!'`). To write an error,
|
|
260
|
+
wrap it in `ExcelError`:
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
import { ExcelError } from '@justybase/spreadsheet-tasks';
|
|
264
|
+
writer.writeSheet([[new ExcelError('#N/A'), 1, 2]]);
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Styles, Formulas and Sheet Features
|
|
268
|
+
|
|
269
|
+
Cells can carry a full style, a formula with a cached value, or rich text:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
import { XlsxWriter, RichText } from '@justybase/spreadsheet-tasks';
|
|
273
|
+
|
|
274
|
+
const writer = new XlsxWriter('report.xlsx');
|
|
275
|
+
writer.addSheet('Report');
|
|
276
|
+
writer.writeSheet(
|
|
277
|
+
[
|
|
278
|
+
[
|
|
279
|
+
{ value: 1234.5, style: { numFmt: '#,##0.00', font: { bold: true, color: 'FF0000' }, fill: { fgColor: 'FFFF00' } } },
|
|
280
|
+
{ formula: 'SUM(A2:A3)', value: 1234.5 },
|
|
281
|
+
new RichText([
|
|
282
|
+
{ text: 'red', style: { font: { color: 'FF0000' } } },
|
|
283
|
+
{ text: ' plain' },
|
|
284
|
+
]),
|
|
285
|
+
],
|
|
286
|
+
[200, { formula: 'A2*2', value: 400 }, 'x'],
|
|
287
|
+
],
|
|
288
|
+
['Amount', 'Total', 'Note'],
|
|
289
|
+
{
|
|
290
|
+
merges: ['A4:B4'],
|
|
291
|
+
hyperlinks: [{ ref: 'C1', target: 'https://example.com', tooltip: 'Example' }],
|
|
292
|
+
dataValidations: [{ sqref: 'C2:C5', type: 'list', values: ['x', 'y'] }],
|
|
293
|
+
conditionalFormats: [{
|
|
294
|
+
sqref: 'A2:A3',
|
|
295
|
+
rules: [{ type: 'cellIs', operator: 'greaterThan', formula: ['1000'], style: { font: { bold: true } } }],
|
|
296
|
+
}],
|
|
297
|
+
comments: [{ ref: 'A2', text: 'Reviewed', author: 'Analyst' }],
|
|
298
|
+
columnWidths: [18, 14], // optional; otherwise conservative autofit is used
|
|
299
|
+
},
|
|
300
|
+
);
|
|
301
|
+
await writer.finalize();
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
`columnWidths` wins over autofit. Autofit itself is deliberately conservative:
|
|
305
|
+
it looks at the header plus up to 200 sample rows (xlspy measures up to 1000) and
|
|
306
|
+
estimates widths from character costs calibrated against xlspy's widest font
|
|
307
|
+
metrics. The estimate includes CJK/fullwidth characters, emoji, bold/italic
|
|
308
|
+
text, font size, wide font families, common number/date formats, alignment
|
|
309
|
+
indent, the longest line of wrapped text and negative number-format sections.
|
|
310
|
+
It enforces Excel's 8.43 minimum, reserves room for the autofilter button, adds
|
|
311
|
+
the 5/7-character cell padding when writing, and caps the stored width at 200.
|
|
312
|
+
The estimate errs on the wide side so columns are not narrower than
|
|
313
|
+
xlspy/Excel AutoFit up to that cap. In streaming mode the sheet head is delayed
|
|
314
|
+
until the first 200 data rows have been measured. Explicit
|
|
315
|
+
`columnWidths` must be 0.5-255 characters and are written unchanged.
|
|
316
|
+
|
|
317
|
+
XLSB supports `CellStyle`, `FormulaCell` (a formula subset with cached values),
|
|
318
|
+
`merges`, `hyperlinks`, `dataValidations` and `columnWidths`. Rich text,
|
|
319
|
+
comments and conditional formatting are XLSX-only and throw a clear error when
|
|
320
|
+
passed to an XLSB writer.
|
|
321
|
+
|
|
322
|
+
XlsxReader exposes the style, formula and rich-text runs of the last read row:
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
const reader = new XlsxReader();
|
|
326
|
+
await reader.open('report.xlsx');
|
|
327
|
+
await reader.selectSheet('Report');
|
|
328
|
+
while (reader.readRow() !== null) {
|
|
329
|
+
const style = reader.getStyle(0); // CellStyle | null
|
|
330
|
+
const formula = reader.getFormula(1); // string | null (no leading '=')
|
|
331
|
+
const rich = reader.getRichText(2); // RichText | null
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
218
335
|
### Updating Data in an Existing Workbook
|
|
219
336
|
|
|
220
337
|
`XlsxUpdater` and `XlsbUpdater` replace the cell data of a worksheet inside an
|
|
@@ -343,8 +460,12 @@ npm test
|
|
|
343
460
|
Before opening a pull request:
|
|
344
461
|
|
|
345
462
|
1. Run `npm run lint` and `npm test`.
|
|
346
|
-
2.
|
|
347
|
-
|
|
463
|
+
2. Run `npm run benchmark:io:baseline` once, then `npm run benchmark:io:check` to
|
|
464
|
+
catch I/O regressions (the quick gate defaults to 5% on a quiet machine; pass
|
|
465
|
+
`-- --max-regression 3` for the strict full-run gate).
|
|
466
|
+
3. On Windows with desktop Excel, run `EXCEL_COM=1 npm run test:excel-com`.
|
|
467
|
+
4. Add or update tests if you change behavior.
|
|
468
|
+
5. Update [CHANGELOG.md](./CHANGELOG.md) for user-visible changes.
|
|
348
469
|
|
|
349
470
|
Please open an issue or pull request on [GitHub](https://github.com/justybase/justybase_spreadsheet_tasks).
|
|
350
471
|
|