@justybase/spreadsheet-tasks 2.0.0 → 2.1.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 +25 -0
- package/README.md +128 -40
- package/browser/browser-spreadsheet.js +10 -3
- package/browser/justybase-spreadsheet.min.js +11 -11
- package/dist/cjs/index.d.ts +163 -3
- package/dist/cjs/index.js +1064 -37
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +1062 -37
- package/dist/esm/index.js.map +1 -1
- package/docs/API.md +158 -0
- package/examples/basic-read.ts +1 -1
- package/examples/basic-write.ts +1 -1
- package/examples/datetime-widths.ts +1 -1
- package/examples/large-dataset.ts +1 -1
- package/examples/multiple-sheets.ts +1 -1
- package/examples/streaming-example.ts +3 -1
- package/examples/update-existing.ts +53 -0
- package/package.json +4 -4
package/docs/API.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
- [XlsxWriter](#xlsxwriter)
|
|
7
7
|
- [XlsbReader](#xlsbreader)
|
|
8
8
|
- [XlsxReader](#xlsxreader)
|
|
9
|
+
- [XlsxUpdater](#xlsxupdater)
|
|
10
|
+
- [XlsbUpdater](#xlsbupdater)
|
|
9
11
|
- [ReaderFactory](#readerfactory)
|
|
10
12
|
- [Types](#types)
|
|
11
13
|
|
|
@@ -224,6 +226,162 @@ Gets value at the specified column index.
|
|
|
224
226
|
|
|
225
227
|
---
|
|
226
228
|
|
|
229
|
+
## XlsxUpdater
|
|
230
|
+
|
|
231
|
+
Updates the data of a worksheet inside an existing `.xlsx` file without rebuilding
|
|
232
|
+
the workbook. Everything outside the target sheet's cell data — pivot tables and
|
|
233
|
+
their caches, other sheets, styles, themes, defined names — is preserved, which
|
|
234
|
+
makes it possible to refresh a data sheet that pivot tables / charts / formulas
|
|
235
|
+
are wired to.
|
|
236
|
+
|
|
237
|
+
### Constructor
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
new XlsxUpdater(filePath: string)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Parameters:**
|
|
244
|
+
- `filePath` - Path to an existing `.xlsx` file
|
|
245
|
+
|
|
246
|
+
Throws if the file does not exist, is not a valid XLSX, or is an XLSB
|
|
247
|
+
(XLSB updates are not supported yet).
|
|
248
|
+
|
|
249
|
+
**Example:**
|
|
250
|
+
```typescript
|
|
251
|
+
const updater = new XlsxUpdater('report.xlsx');
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Methods
|
|
255
|
+
|
|
256
|
+
#### `getSheetNames(): string[]`
|
|
257
|
+
|
|
258
|
+
Returns the worksheet names in workbook order.
|
|
259
|
+
|
|
260
|
+
#### `replaceSheetData(sheetName: string, rows: CellValue[][], options?: ReplaceSheetDataOptions): void`
|
|
261
|
+
|
|
262
|
+
Clears the entire cell data of the target sheet and writes new rows in its place.
|
|
263
|
+
|
|
264
|
+
**Parameters:**
|
|
265
|
+
- `sheetName` - Name of the worksheet to replace. Throws if not found.
|
|
266
|
+
- `rows` - 2D array of new data (`null` / `undefined` cells stay empty).
|
|
267
|
+
Trailing rows that contain no non-empty cells are trimmed so the written
|
|
268
|
+
range matches the actual data (pivot tables won't pick up "(blank)" items
|
|
269
|
+
from padding rows).
|
|
270
|
+
- `options` - Optional object:
|
|
271
|
+
- `headers?: string[]` - Optional header row written into row 1
|
|
272
|
+
- `styleFallback?: 'inherit' | 'general'` - Style strategy for new cells
|
|
273
|
+
(default `'inherit'`)
|
|
274
|
+
|
|
275
|
+
**Behavior:**
|
|
276
|
+
- The sheet's `<dimension>` and `<autoFilter>` ranges are recalculated and end
|
|
277
|
+
exactly at the last data row.
|
|
278
|
+
- When `headers` are omitted, the first data row lands in row 1 and becomes the
|
|
279
|
+
pivot's field names — always pass `headers` matching the original columns.
|
|
280
|
+
- New strings are appended to `xl/sharedStrings.xml` (existing entries and their
|
|
281
|
+
indices are never modified); files without a shared string table use inline strings.
|
|
282
|
+
- With `styleFallback: 'inherit'` (default), new cells reuse the dominant style
|
|
283
|
+
of their column from the existing data, and `Date` cells fall back to a date
|
|
284
|
+
style found in `styles.xml` when the column has none.
|
|
285
|
+
- Pivot tables whose `worksheetSource` references the updated sheet get their
|
|
286
|
+
`ref` and `recordCount` adjusted, and `refreshOnLoad="1"` is added to the
|
|
287
|
+
pivot table definitions so Excel refreshes them on open.
|
|
288
|
+
|
|
289
|
+
**Example:**
|
|
290
|
+
```typescript
|
|
291
|
+
const updater = new XlsxUpdater('report.xlsx');
|
|
292
|
+
updater.replaceSheetData('data1', rows, { headers: ['ID', 'NAME'] });
|
|
293
|
+
updater.save('report_new.xlsx');
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### `save(outputPath?: string): void`
|
|
297
|
+
|
|
298
|
+
Writes the updated workbook to disk. When `outputPath` is omitted, the source
|
|
299
|
+
file is overwritten in place.
|
|
300
|
+
|
|
301
|
+
#### `toBuffer(): Buffer`
|
|
302
|
+
|
|
303
|
+
Returns the updated workbook as an in-memory ZIP buffer.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## XlsbUpdater
|
|
308
|
+
|
|
309
|
+
Updates the data of a worksheet inside an existing `.xlsb` file without
|
|
310
|
+
rebuilding the workbook. Everything outside the target sheet's rows — pivot
|
|
311
|
+
tables and their caches, other sheets, styles, column widths, views — is
|
|
312
|
+
preserved byte-for-byte.
|
|
313
|
+
|
|
314
|
+
The API is identical to [XlsxUpdater](#xlsxupdater); see that section for the
|
|
315
|
+
behavior of `replaceSheetData` (inherited column styles, shared-strings
|
|
316
|
+
appending, pivot cache range + `refreshOnLoad`).
|
|
317
|
+
|
|
318
|
+
### Constructor
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
new XlsbUpdater(filePath: string)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**Parameters:**
|
|
325
|
+
- `filePath` - Path to an existing `.xlsb` file
|
|
326
|
+
|
|
327
|
+
Throws if the file does not exist, is not a valid XLSB, or is an XLSX
|
|
328
|
+
(XLSB-only updater).
|
|
329
|
+
|
|
330
|
+
### Methods
|
|
331
|
+
|
|
332
|
+
#### `getSheetNames(): string[]`
|
|
333
|
+
|
|
334
|
+
Returns the worksheet names in workbook order.
|
|
335
|
+
|
|
336
|
+
#### `replaceSheetData(sheetName: string, rows: CellValue[][], options?: ReplaceSheetDataOptions): void`
|
|
337
|
+
|
|
338
|
+
Clears the entire cell data of the target sheet and writes new rows in its place.
|
|
339
|
+
|
|
340
|
+
**Parameters:**
|
|
341
|
+
- `sheetName` - Name of the worksheet to replace. Throws if not found.
|
|
342
|
+
- `rows` - 2D array of new data (`null` / `undefined` cells stay empty).
|
|
343
|
+
Trailing rows that contain no non-empty cells are trimmed so the written
|
|
344
|
+
range matches the actual data (pivot tables won't pick up "(blank)" items
|
|
345
|
+
from padding rows).
|
|
346
|
+
- `options` - Optional object:
|
|
347
|
+
- `headers?: string[]` - Optional header row written into row 1
|
|
348
|
+
- `styleFallback?: 'inherit' | 'general'` - Style strategy for new cells
|
|
349
|
+
(default `'inherit'`)
|
|
350
|
+
|
|
351
|
+
**Behavior:**
|
|
352
|
+
- Only the worksheet's row records are replaced; column widths, views, and all
|
|
353
|
+
other sheet records are preserved. Auto-filter ranges are recalculated.
|
|
354
|
+
- The sheet's dimension record and the pivot cache source range end exactly at
|
|
355
|
+
the last data row.
|
|
356
|
+
- When `headers` are omitted, the first data row lands in row 1 and becomes the
|
|
357
|
+
pivot's field names — always pass `headers` matching the original columns.
|
|
358
|
+
- New strings are appended to `xl/sharedStrings.bin` (existing entries and their
|
|
359
|
+
indices are never modified).
|
|
360
|
+
- With `styleFallback: 'inherit'` (default), new cells reuse the dominant cell
|
|
361
|
+
style (xf) of their column from the existing data, and `Date` cells fall back
|
|
362
|
+
to a date style found in `styles.bin` when the column has none.
|
|
363
|
+
- Pivot caches whose `worksheetSource` references the updated sheet get their
|
|
364
|
+
range and record count adjusted, and the `refreshOnLoad` flag is set so Excel
|
|
365
|
+
refreshes them on open.
|
|
366
|
+
|
|
367
|
+
**Example:**
|
|
368
|
+
```typescript
|
|
369
|
+
const updater = new XlsbUpdater('report.xlsb');
|
|
370
|
+
updater.replaceSheetData('data1', rows, { headers: ['ID', 'NAME'] });
|
|
371
|
+
updater.save('report_new.xlsb');
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### `save(outputPath?: string): void`
|
|
375
|
+
|
|
376
|
+
Writes the updated workbook to disk. When `outputPath` is omitted, the source
|
|
377
|
+
file is overwritten in place.
|
|
378
|
+
|
|
379
|
+
#### `toBuffer(): Buffer`
|
|
380
|
+
|
|
381
|
+
Returns the updated workbook as an in-memory ZIP buffer.
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
227
385
|
## ReaderFactory
|
|
228
386
|
|
|
229
387
|
Factory class for creating appropriate reader based on file extension.
|
package/examples/basic-read.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Run with: npx ts-node examples/basic-read.ts
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { XlsbReader, XlsxReader, ReaderFactory } from '../dist';
|
|
10
|
+
import { XlsbReader, XlsxReader, ReaderFactory } from '../dist/cjs';
|
|
11
11
|
import * as path from 'path';
|
|
12
12
|
|
|
13
13
|
async function readXlsbExample() {
|
package/examples/basic-write.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Run with: npx ts-node examples/large-dataset.ts
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { XlsbWriter, XlsxWriter, XlsbReader, XlsxReader } from '../dist';
|
|
10
|
+
import { XlsbWriter, XlsxWriter, XlsbReader, XlsxReader } from '../dist/cjs';
|
|
11
11
|
import * as path from 'path';
|
|
12
12
|
import * as fs from 'fs';
|
|
13
13
|
|
|
@@ -7,13 +7,15 @@
|
|
|
7
7
|
* Run with: npx ts-node examples/streaming-example.ts
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { XlsbWriter } from '../dist/
|
|
10
|
+
import { XlsbWriter } from '../dist/cjs';
|
|
11
11
|
import * as path from 'path';
|
|
12
|
+
import * as fs from 'fs';
|
|
12
13
|
|
|
13
14
|
async function streamingExample() {
|
|
14
15
|
console.log('=== XlsbWriter Streaming Example ===\n');
|
|
15
16
|
|
|
16
17
|
const outputPath = path.join(__dirname, '..', 'output', 'streaming-example.xlsb');
|
|
18
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
17
19
|
console.log(`Output file: ${outputPath}\n`);
|
|
18
20
|
|
|
19
21
|
const writer = new XlsbWriter(outputPath);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update Existing Workbook Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates how to replace the data of a worksheet inside an
|
|
5
|
+
* existing Excel file (e.g. a report whose pivot tables are wired to a "data1"
|
|
6
|
+
* sheet) without rebuilding the workbook. The same API works for XLSX and XLSB.
|
|
7
|
+
*
|
|
8
|
+
* Run with: npx ts-node examples/update-existing.ts
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { XlsxUpdater, XlsbUpdater } from '../dist/cjs';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
|
|
15
|
+
const outputDir = path.join(__dirname, 'output');
|
|
16
|
+
if (!fs.existsSync(outputDir)) {
|
|
17
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function updateExistingWorkbook() {
|
|
21
|
+
// New data for the "data1" sheet (same columns as before)
|
|
22
|
+
const rows = [
|
|
23
|
+
[new Date('2026-01-01'), 'PL', 'Warsaw', 1200.5, true],
|
|
24
|
+
[new Date('2026-01-02'), 'DE', 'Berlin', 980.25, true],
|
|
25
|
+
[new Date('2026-01-03'), 'PL', 'Krakow', 1530.0, false],
|
|
26
|
+
];
|
|
27
|
+
const headers = ['DATEKEY', 'COUNTRY', 'CITY', 'AMOUNT', 'ACTIVE'];
|
|
28
|
+
|
|
29
|
+
for (const ext of ['xlsx', 'xlsb']) {
|
|
30
|
+
const input = path.join(__dirname, '..', `report.${ext}`);
|
|
31
|
+
const output = path.join(outputDir, `report_updated.${ext}`);
|
|
32
|
+
|
|
33
|
+
if (!fs.existsSync(input)) {
|
|
34
|
+
console.log(`Template workbook not found: ${input} (skipping)`);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Open the existing workbook (everything outside the replaced sheet
|
|
39
|
+
// — pivot tables, other sheets, styles — is preserved)
|
|
40
|
+
const updater = ext === 'xlsb' ? new XlsbUpdater(input) : new XlsxUpdater(input);
|
|
41
|
+
console.log(`[${ext}] Sheets:`, updater.getSheetNames());
|
|
42
|
+
|
|
43
|
+
updater.replaceSheetData('data1', rows, { headers });
|
|
44
|
+
|
|
45
|
+
// Write the updated workbook to a new file (or omit the path to
|
|
46
|
+
// overwrite the source in place)
|
|
47
|
+
updater.save(output);
|
|
48
|
+
console.log(`[${ext}] Workbook updated: ${output}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
updateExistingWorkbook();
|
|
53
|
+
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justybase/spreadsheet-tasks",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "High-performance TypeScript library for reading and writing Excel files in XLSB and XLSX formats. XLSB is 3.3x faster to write and 2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "High-performance TypeScript library for reading and writing Excel files in XLSB and XLSX formats. XLSB is 3.3x faster to write and 2.3x faster to read than XLSX.",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
7
7
|
"types": "./dist/cjs/index.d.ts",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"test": "npm run typecheck && npm run test:smoke && npm run test:unit && npm run test:integration && npm run test:dist",
|
|
31
31
|
"test:smoke": "npx ts-node tests/smoke.test.ts",
|
|
32
32
|
"test:unit": "npx ts-node tests/unit/bigbuffer.test.ts && npx ts-node tests/unit/biff-reader-writer.test.ts && npx ts-node tests/unit/xlsb-writer.test.ts",
|
|
33
|
-
"test:integration": "npx ts-node tests/integration/xlsb-writer.test.ts && npx ts-node tests/integration/xlsx-writer.test.ts",
|
|
33
|
+
"test:integration": "npx ts-node tests/integration/xlsb-writer.test.ts && npx ts-node tests/integration/xlsx-writer.test.ts && npx ts-node tests/integration/xlsx-updater.test.ts && npx ts-node tests/integration/xlsb-updater.test.ts",
|
|
34
34
|
"test:dist": "npm run build && npx ts-node tests/dist-surface.test.ts",
|
|
35
|
-
"test:xlsb": "npx ts-node tests/integration/xlsb-writer.test.ts",
|
|
35
|
+
"test:xlsb": "npx ts-node tests/integration/xlsb-writer.test.ts && npx ts-node tests/integration/xlsb-updater.test.ts",
|
|
36
36
|
"test:xlsx": "npx ts-node tests/integration/xlsx-writer.test.ts",
|
|
37
37
|
"benchmark": "npm run build && npx ts-node benchmarks/performance.bench.ts",
|
|
38
38
|
"benchmark:comparison": "npm run build && npx ts-node benchmarks/comparison.bench.ts",
|