@nazarkalytiuk/rusc-xlsx 2.0.0 → 2.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/README.md +68 -5
- package/index.d.ts +117 -22
- package/index.js +217 -82
- package/package.json +44 -17
- package/wrapper.d.ts +149 -532
- package/wrapper.js +1227 -1423
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ npm install @nazarkalytiuk/rusc-xlsx
|
|
|
68
68
|
### Requirements
|
|
69
69
|
|
|
70
70
|
- Node.js >= 22.13
|
|
71
|
-
- Rust >= 1.
|
|
71
|
+
- Rust >= 1.95 (only when building from source)
|
|
72
72
|
|
|
73
73
|
## Quick Start
|
|
74
74
|
|
|
@@ -171,6 +171,9 @@ workbook.save('output.xlsx');
|
|
|
171
171
|
- `setTempdir(path)` - Set temp directory for memory modes
|
|
172
172
|
- `setDefaultFormat(format, rowHeight, columnWidth)` - Set workbook-wide default formatting before adding worksheets
|
|
173
173
|
- `useExcel2023Theme()` / `useCustomTheme(path)` - Select the workbook theme before adding worksheets
|
|
174
|
+
- `setCalculationMode(mode)` - Formula recalculation: `'automatic'`, `'manual'` or `'partial'`
|
|
175
|
+
- `setZipCompressionLevel(level)` - Trade file size for speed (1-9, default 6)
|
|
176
|
+
- `setTabRatio(ratio)` - Width of the sheet tab bar vs. the horizontal scroll bar (0-100)
|
|
174
177
|
- `save(filename)` - Save to file
|
|
175
178
|
- `saveToBuffer()` - Save to Buffer
|
|
176
179
|
- `saveToStream(writable)` - Save through a temp file and await stream completion
|
|
@@ -187,7 +190,7 @@ workbook.save('output.xlsx');
|
|
|
187
190
|
- **Features**: `insertNote()`, `addDataValidation()`, `insertChart()`, `insertImage()`, `insertImageFitToCellCentered()`, `addTable()`, `insertButton()`, `insertShape()`
|
|
188
191
|
- **Conditional Formatting**: 14 methods for all rule types
|
|
189
192
|
- **Page Setup**: 26 methods for printing, margins, headers, etc.
|
|
190
|
-
- **View**: `autofilter()`, `setFreezePanes()`, `setZoom()`, `setTabColor()`, `
|
|
193
|
+
- **View**: `autofilter()`, `setFreezePanes()`, `setZoom()`, `setTabColor()`, `setHiddenZeroes()`, `setHidden()`
|
|
191
194
|
- **Hyperlinks**: `writeUrl()`
|
|
192
195
|
- **Protection**: `protect()`, `protectWithPassword()`
|
|
193
196
|
- **Rich Text**: `writeRichString()`
|
|
@@ -247,14 +250,31 @@ See the `examples/` directory for complete examples:
|
|
|
247
250
|
git clone https://github.com/NazarKalytiuk/napi_rust_xlsxwrighter.git
|
|
248
251
|
cd napi_rust_xlsxwrighter
|
|
249
252
|
|
|
250
|
-
# Install dependencies
|
|
253
|
+
# Install dependencies (also builds wrapper.js + wrapper.d.ts from wrapper.ts via tsdown)
|
|
251
254
|
npm install
|
|
252
255
|
|
|
253
256
|
# Build native module
|
|
254
257
|
npm run build
|
|
255
258
|
|
|
256
|
-
#
|
|
259
|
+
# Rebuild the JavaScript wrapper after editing wrapper.ts
|
|
260
|
+
npm run build:wrapper
|
|
261
|
+
|
|
262
|
+
# Run tests (Vitest)
|
|
257
263
|
npm test
|
|
264
|
+
npm run test:watch # re-run on change
|
|
265
|
+
npm run test:coverage # V8 coverage report for wrapper.ts
|
|
266
|
+
npm run test:coverage:rust # line coverage of src/*.rs via an instrumented addon;
|
|
267
|
+
# needs cargo-llvm-cov and `rustup component add llvm-tools`
|
|
268
|
+
|
|
269
|
+
# Format, lint (oxfmt, oxlint, rustfmt, clippy) and typecheck — same as CI
|
|
270
|
+
npm run check
|
|
271
|
+
npm run fmt # apply oxfmt + rustfmt
|
|
272
|
+
|
|
273
|
+
# rust_xlsxwriter coverage checklist (rust-xlsxwriter-coverage-checklist.md)
|
|
274
|
+
npm run coverage:check # verify test call sites, counts and the pinned version
|
|
275
|
+
npm run coverage:sync # refresh them after editing tests or row statuses; after a
|
|
276
|
+
# rust_xlsxwriter upgrade it documents the new release with
|
|
277
|
+
# rustdoc JSON (`rustup toolchain install nightly-2026-11-13`)
|
|
258
278
|
|
|
259
279
|
# Run examples
|
|
260
280
|
node examples/basic.js
|
|
@@ -267,7 +287,7 @@ node examples/basic.js
|
|
|
267
287
|
Built with Rust and NAPI-RS for native-level performance:
|
|
268
288
|
- **Fast execution**: Native Rust performance via NAPI bindings
|
|
269
289
|
- **Low memory usage**: Optimized memory footprint across all modes
|
|
270
|
-
- **Test performance**: All
|
|
290
|
+
- **Test performance**: All 601 tests complete in < 1 second
|
|
271
291
|
|
|
272
292
|
### Memory Modes
|
|
273
293
|
|
|
@@ -337,6 +357,49 @@ for await (const item of cursor) {
|
|
|
337
357
|
This keeps memory bounded to the current cursor item while retaining
|
|
338
358
|
constant-memory worksheet generation.
|
|
339
359
|
|
|
360
|
+
### Node.js vs Bun Benchmarks
|
|
361
|
+
|
|
362
|
+
The runtime benchmark executes the same package workload through the same
|
|
363
|
+
release N-API binary on Node.js and Bun:
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
npm run benchmark:runtimes
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Bun must be installed and available in `PATH`. The default workload generates
|
|
370
|
+
200,000 rows × 20 columns through `writeRow()` in constant-memory mode. The
|
|
371
|
+
runner alternates runtime order across three runs, reports both in-process
|
|
372
|
+
generation time and end-to-end process wall time, and verifies identical
|
|
373
|
+
worksheet XML size and CRC for every Node.js/Bun pair.
|
|
374
|
+
|
|
375
|
+
Override the workload or package API, or reuse the existing release build:
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
npm run benchmark:runtimes -- --rows 100000 --columns 20 --runs 5
|
|
379
|
+
npm run benchmark:runtimes -- --write-mode cell
|
|
380
|
+
npm run benchmark:runtimes -- --write-mode batch --batch-rows 1000
|
|
381
|
+
npm run benchmark:runtimes -- --skip-build
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
#### ExcelJS runtime comparison
|
|
385
|
+
|
|
386
|
+
To isolate the runtime difference for a JavaScript XLSX implementation, run the
|
|
387
|
+
same dataset through the ExcelJS streaming writer:
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
npm run benchmark:runtimes:exceljs
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
This profile uses ExcelJS `stream.xlsx.WorkbookWriter`, disables styles and
|
|
394
|
+
shared strings, fixes ZIP DEFLATE compression at level 6, and commits every
|
|
395
|
+
row. It uses the same alternating order, timing and memory metrics, and
|
|
396
|
+
worksheet-equivalence checks as the native-package profile. Override the
|
|
397
|
+
default workload when needed:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
npm run benchmark:runtimes:exceljs -- --rows 100000 --columns 20 --runs 5
|
|
401
|
+
```
|
|
402
|
+
|
|
340
403
|
### Node.js vs Go, C#, and Python Benchmark
|
|
341
404
|
|
|
342
405
|
The cross-language benchmark compares concrete streaming XLSX libraries, not
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
/* auto-generated by NAPI-RS */
|
|
2
2
|
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Which binding artifact the generated loader actually loaded: `'native'` for
|
|
6
|
+
* a native addon, otherwise the `platformArchABI` of the WASI flavor. Every
|
|
7
|
+
* flavor napi-rs can build is listed, because `NAPI_RS_NATIVE_LIBRARY_PATH`
|
|
8
|
+
* can point the loader at a WASI artifact this package does not build itself.
|
|
9
|
+
*/
|
|
10
|
+
export declare const __napiBindingTarget: 'native' | 'wasm32-wasi' | 'wasm32-wasip1'
|
|
11
|
+
|
|
3
12
|
export declare class RuscButton {
|
|
4
13
|
/** Create a new Button */
|
|
5
14
|
static new(): RuscButton
|
|
@@ -178,6 +187,13 @@ export declare class RuscFormat {
|
|
|
178
187
|
setQuotePrefix(): void
|
|
179
188
|
}
|
|
180
189
|
|
|
190
|
+
/**
|
|
191
|
+
* A formula for the native formula writers.
|
|
192
|
+
*
|
|
193
|
+
* @deprecated Pass a `RuscFormulaData` object instead. An instance keeps its Rust
|
|
194
|
+
* memory until its finalizer runs after the event loop turns, so instances
|
|
195
|
+
* created in a synchronous loop accumulate.
|
|
196
|
+
*/
|
|
181
197
|
export declare class RuscFormula {
|
|
182
198
|
/** Create a new formula */
|
|
183
199
|
constructor(formula: string)
|
|
@@ -272,15 +288,21 @@ export declare class RuscProtectionOptions {
|
|
|
272
288
|
setContents(allow: boolean): this
|
|
273
289
|
}
|
|
274
290
|
|
|
275
|
-
/**
|
|
291
|
+
/**
|
|
292
|
+
* Wrapper for rich text strings (multi-format text in a single cell)
|
|
293
|
+
*
|
|
294
|
+
* @deprecated Pass `[text, format]` segments to `RuscWorksheet.writeRichString`
|
|
295
|
+
* instead. An instance keeps its Rust memory until its finalizer runs after the
|
|
296
|
+
* event loop turns, so instances created in a synchronous loop accumulate.
|
|
297
|
+
*/
|
|
276
298
|
export declare class RuscRichText {
|
|
277
299
|
/** Create a new empty rich text string */
|
|
278
300
|
constructor()
|
|
279
301
|
/**
|
|
280
|
-
* Add a text segment
|
|
281
|
-
* The format is cloned internally for storage
|
|
302
|
+
* Add a text segment, optionally formatted; without a format the segment uses
|
|
303
|
+
* the default cell font. The format is cloned internally for storage.
|
|
282
304
|
*/
|
|
283
|
-
addSegment(text: string, format
|
|
305
|
+
addSegment(text: string, format?: RuscFormat | undefined | null): this
|
|
284
306
|
}
|
|
285
307
|
|
|
286
308
|
export declare class RuscShape {
|
|
@@ -301,7 +323,10 @@ export declare class RuscShape {
|
|
|
301
323
|
export declare class RuscSparkline {
|
|
302
324
|
/** Create a new Sparkline */
|
|
303
325
|
static new(): RuscSparkline
|
|
304
|
-
/**
|
|
326
|
+
/**
|
|
327
|
+
* Set the data range for the sparkline, e.g. "Sheet1!A1:E1", or "A1:E1"
|
|
328
|
+
* for a range on the worksheet the sparkline is added to
|
|
329
|
+
*/
|
|
305
330
|
setRange(range: string): this
|
|
306
331
|
/** Set the type of sparkline: 'line', 'column', or 'winLose' */
|
|
307
332
|
setType(sparklineType: string): this
|
|
@@ -374,7 +399,10 @@ export declare class RuscTable {
|
|
|
374
399
|
setAltText(altText: string): this
|
|
375
400
|
/** Set the alternative text title for screen readers. */
|
|
376
401
|
setAltTextTitle(title: string): this
|
|
377
|
-
/**
|
|
402
|
+
/**
|
|
403
|
+
* Set the style of the table: 0 for no style, 1-21 for light styles,
|
|
404
|
+
* 22-49 for medium styles and 50-60 for dark styles
|
|
405
|
+
*/
|
|
378
406
|
setStyle(styleId: number): this
|
|
379
407
|
/** Add columns to the table */
|
|
380
408
|
setColumns(columns: Array<RuscTableColumn>): this
|
|
@@ -410,6 +438,21 @@ export declare class RuscWorkbook {
|
|
|
410
438
|
* Must be called before adding worksheets.
|
|
411
439
|
*/
|
|
412
440
|
setDefaultFormat(format: RuscFormat, rowHeight: number, columnWidth: number): void
|
|
441
|
+
/**
|
|
442
|
+
* Set the zip compression level of the xlsx container (1-9, default 6).
|
|
443
|
+
* Lower levels are faster, higher levels produce smaller files.
|
|
444
|
+
*/
|
|
445
|
+
setZipCompressionLevel(level: number): void
|
|
446
|
+
/**
|
|
447
|
+
* Set when Excel recalculates formulas: "automatic" (default), "manual",
|
|
448
|
+
* or "partial" (automatic except for data tables).
|
|
449
|
+
*/
|
|
450
|
+
setCalculationMode(mode: string): void
|
|
451
|
+
/**
|
|
452
|
+
* Set the width of the worksheet tab bar as a percentage (0-100, default
|
|
453
|
+
* 60) of the space it shares with the horizontal scroll bar.
|
|
454
|
+
*/
|
|
455
|
+
setTabRatio(ratio: number): void
|
|
413
456
|
/**
|
|
414
457
|
* Use the Excel 2023 Office theme with the Aptos default font.
|
|
415
458
|
* Must be called before adding worksheets.
|
|
@@ -452,20 +495,25 @@ export declare class RuscWorkbook {
|
|
|
452
495
|
|
|
453
496
|
/** Worksheet wrapper for Excel sheet manipulation */
|
|
454
497
|
export declare class RuscWorksheet {
|
|
455
|
-
/**
|
|
456
|
-
|
|
498
|
+
/**
|
|
499
|
+
* Write a value to a cell (auto-detects type). `null` or `undefined`
|
|
500
|
+
* writes nothing, or a blank cell with the format when one is given.
|
|
501
|
+
*/
|
|
502
|
+
write(row: number, col: number, value: string | number | boolean | null | undefined, format?: RuscFormat | undefined | null): void
|
|
457
503
|
/**
|
|
458
504
|
* Write an array of values as a row starting at the given column.
|
|
459
505
|
* Uses lazy Array iteration — reads one cell at a time from the JS array
|
|
460
506
|
* instead of deserializing the entire row into Rust memory.
|
|
461
|
-
*
|
|
507
|
+
* Values are written as `write` writes them: `null`, `undefined` and
|
|
508
|
+
* holes leave the cell empty, or write a blank cell with the format.
|
|
462
509
|
*/
|
|
463
510
|
writeRow(row: number, startCol: number, values: unknown[], format?: RuscFormat | undefined | null): void
|
|
464
511
|
/**
|
|
465
512
|
* Write a 2D array of values starting at the given position.
|
|
466
513
|
* Uses lazy Array iteration — reads one row/cell at a time from JS,
|
|
467
514
|
* never materializing the entire grid in Rust memory.
|
|
468
|
-
*
|
|
515
|
+
* Values are written as `write` writes them: `null`, `undefined` and
|
|
516
|
+
* holes leave the cell empty, or write a blank cell with the format.
|
|
469
517
|
*/
|
|
470
518
|
writeRows(startRow: number, startCol: number, rows: unknown[], format?: RuscFormat | undefined | null): void
|
|
471
519
|
/** Write a string to a cell */
|
|
@@ -476,10 +524,22 @@ export declare class RuscWorksheet {
|
|
|
476
524
|
writeBoolean(row: number, col: number, value: boolean): void
|
|
477
525
|
/** Write a blank cell with formatting */
|
|
478
526
|
writeBlank(row: number, col: number, format: RuscFormat): void
|
|
479
|
-
/**
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
527
|
+
/**
|
|
528
|
+
* Write a rich text string (multi-format text) to a cell.
|
|
529
|
+
*
|
|
530
|
+
* `richText` is `[text, format]` segments, or a deprecated `RuscRichText`; a
|
|
531
|
+
* segment without a format uses the default cell font. Segments are plain data,
|
|
532
|
+
* so nothing outlives the call. Empty segments are skipped, and a rich string
|
|
533
|
+
* whose segments are all empty leaves the cell untouched.
|
|
534
|
+
*/
|
|
535
|
+
writeRichString(row: number, col: number, richText: RuscRichText | Array<[string, RuscFormat | undefined | null]>): void
|
|
536
|
+
/**
|
|
537
|
+
* Write a rich text string with an additional cell format.
|
|
538
|
+
*
|
|
539
|
+
* `richText` is as for `writeRichString`. A rich string whose segments are all
|
|
540
|
+
* empty writes a blank cell with the cell format.
|
|
541
|
+
*/
|
|
542
|
+
writeRichStringWithFormat(row: number, col: number, richText: RuscRichText | Array<[string, RuscFormat | undefined | null]>, cellFormat: RuscFormat): void
|
|
483
543
|
/** Write a datetime from a Unix timestamp (seconds since 1970-01-01 UTC) */
|
|
484
544
|
writeDatetimeFromTimestamp(row: number, col: number, timestamp: number, format?: RuscFormat | undefined | null): void
|
|
485
545
|
/** Write a datetime from year, month, day components */
|
|
@@ -488,8 +548,11 @@ export declare class RuscWorksheet {
|
|
|
488
548
|
writeDatetimeFromYmdHms(row: number, col: number, year: number, month: number, day: number, hour: number, min: number, sec: number, format?: RuscFormat | undefined | null): void
|
|
489
549
|
/** Write a datetime from an ISO 8601 string (e.g., "2023-01-25T12:30:00") */
|
|
490
550
|
writeDatetimeFromString(row: number, col: number, datetimeStr: string, format?: RuscFormat | undefined | null): void
|
|
491
|
-
/**
|
|
492
|
-
|
|
551
|
+
/**
|
|
552
|
+
* Write a value with formatting to a cell; `null` or `undefined` writes
|
|
553
|
+
* a blank cell with the format
|
|
554
|
+
*/
|
|
555
|
+
writeWithFormat(row: number, col: number, value: string | number | boolean | null | undefined, format: RuscFormat): void
|
|
493
556
|
/** Set the width of a column */
|
|
494
557
|
setColumnWidth(col: number, width: number): void
|
|
495
558
|
/** Set the height of a row */
|
|
@@ -513,11 +576,11 @@ export declare class RuscWorksheet {
|
|
|
513
576
|
/** Set the default author name for all notes in the worksheet */
|
|
514
577
|
setDefaultNoteAuthor(name: string): void
|
|
515
578
|
/** Write a formula to a cell */
|
|
516
|
-
writeFormula(row: number, col: number, formula: RuscFormula, format?: RuscFormat | undefined | null): void
|
|
579
|
+
writeFormula(row: number, col: number, formula: RuscFormula | RuscFormulaData, format?: RuscFormat | undefined | null): void
|
|
517
580
|
/** Write a dynamic array formula to a cell (Excel 365) */
|
|
518
|
-
writeDynamicFormula(row: number, col: number, formula: RuscFormula, format?: RuscFormat | undefined | null): void
|
|
581
|
+
writeDynamicFormula(row: number, col: number, formula: RuscFormula | RuscFormulaData, format?: RuscFormat | undefined | null): void
|
|
519
582
|
/** Write an array formula to a range of cells */
|
|
520
|
-
writeArrayFormula(firstRow: number, firstCol: number, lastRow: number, lastCol: number, formula: RuscFormula, format?: RuscFormat | undefined | null): void
|
|
583
|
+
writeArrayFormula(firstRow: number, firstCol: number, lastRow: number, lastCol: number, formula: RuscFormula | RuscFormulaData, format?: RuscFormat | undefined | null): void
|
|
521
584
|
/** Add data validation to a cell or range */
|
|
522
585
|
addDataValidation(firstRow: number, firstCol: number, lastRow: number, lastCol: number, validation: RuscDataValidation): void
|
|
523
586
|
/** Write a URL to a cell */
|
|
@@ -600,6 +663,11 @@ export declare class RuscWorksheet {
|
|
|
600
663
|
setHidden(enable: boolean): void
|
|
601
664
|
/** Set the worksheet zoom level (10-400) */
|
|
602
665
|
setZoom(zoom: number): void
|
|
666
|
+
/**
|
|
667
|
+
* Hide zero values in worksheet cells, the equivalent of turning off the
|
|
668
|
+
* Excel option "Show a zero in cells that have zero value"
|
|
669
|
+
*/
|
|
670
|
+
setHiddenZeroes(enable: boolean): void
|
|
603
671
|
/** Set the default cell selection when opening the worksheet */
|
|
604
672
|
setSelection(firstRow: number, firstCol: number, lastRow: number, lastCol: number): void
|
|
605
673
|
/** Set which cell appears in the top-left corner when opening the worksheet */
|
|
@@ -640,8 +708,35 @@ export declare class RuscWorksheet {
|
|
|
640
708
|
insertShapeWithOffset(row: number, col: number, shape: RuscShape, xOffset: number, yOffset: number): void
|
|
641
709
|
}
|
|
642
710
|
|
|
643
|
-
/**
|
|
711
|
+
/**
|
|
712
|
+
* The data of a JavaScript `Formula`: the formula text and, for applications
|
|
713
|
+
* that don't recalculate, its cached result.
|
|
714
|
+
*
|
|
715
|
+
* It is plain data rather than a class so that a formula written per row owns no
|
|
716
|
+
* Rust memory between writes.
|
|
717
|
+
*/
|
|
718
|
+
export interface RuscFormulaData {
|
|
719
|
+
formula: string
|
|
720
|
+
result?: string
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Resets peak memory tracking to the current allocation level.
|
|
725
|
+
* Call before a section you want to measure.
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* rustMemoryResetPeak();
|
|
729
|
+
* // ... do work ...
|
|
730
|
+
* const [current, peak] = rustMemoryStats();
|
|
731
|
+
*/
|
|
644
732
|
export declare function rustMemoryResetPeak(): void
|
|
645
733
|
|
|
646
|
-
/**
|
|
647
|
-
|
|
734
|
+
/**
|
|
735
|
+
* Returns [currentBytes, peakBytes] of Rust allocator usage.
|
|
736
|
+
* Useful for profiling memory consumption of the native layer.
|
|
737
|
+
*
|
|
738
|
+
* @example
|
|
739
|
+
* const [current, peak] = rustMemoryStats();
|
|
740
|
+
* console.log(`Rust heap: ${(current / 1024 / 1024).toFixed(2)} MB (peak: ${(peak / 1024 / 1024).toFixed(2)} MB)`);
|
|
741
|
+
*/
|
|
742
|
+
export declare function rustMemoryStats(): [number, number]
|