-
Notifications
You must be signed in to change notification settings - Fork 1
Changelog
Critical bug fixes found during comprehensive codebase audit.
-
Image embedding broken —
generateDrawingXmlrId off-by-one causing images to silently fail -
Frozen panes: wrong
activePane— column-only freeze wrote"bottomLeft"instead of"topRight" -
Invalid JSON for NaN/Infinity —
write_f64_jsonnow writesnullinstead of crashing JSON.parse -
Custom numFmt ID collision —
resolveNumFmtIdnow always assigns IDs >= 164 per ECMA-376
-
HashMap::with_capacityin ZIP reader -
col_index_to_letterdelegates to optimizedcol_to_letters -
TextEncoderhoisted to module-level constant
Closed 7 SheetJS advantage categories + added native Excel Tables, headers/footers, row/column grouping, and print layout. 704 tests (217 Rust + 487 TypeScript).
-
encodeRow()— convert 0-based row index to 1-based string -
decodeRow()— convert 1-based row string to 0-based index -
splitCellRef()— decompose$A$1into{ col, row, absCol, absRow }
-
appVersion— roundtrip<AppVersion>from app.xml -
hyperlinkBase— roundtrip<HyperlinkBase>from app.xml -
revision— roundtrip<cp:revision>from core.xml -
application,company,manager— now fully parsed and written
-
sheetToTxt()— tab-separated text output (reuses CSV engine with\tdelimiter) -
sheetToFormulae()— extract all cell values and formulas as["A1=100", "A3='SUM(A1:A2)"]
-
Conditional sections — parse
[>100]#,##0;[<=100]0.00with condition evaluation -
Bracket color codes — extract
[Red],[Blue],[Color3]–[Color56]from format strings -
formatCellRich()— returns{ text, color }with color metadata -
loadFormat()— register custom format code at runtime -
loadFormatTable()— bulk-register format codes by ID
-
ws.usedRange— computed getter returning cell extent (e.g.,"B2:D5") ornull -
ws.tabColor— getter/setter for sheet tab RGB hex color, roundtrips through WASM
-
cell.numberFormat— resolves style index → numFmtId → format code string -
cell.dateValue— returnsDateif cell contains a date-formatted number -
Stub cell type —
'stub'inCellTypeunion for explicitly empty cells (SheetJS type"z")
-
dynamicArray— roundtripcm="1"attribute on<f>element for SPILL/dynamic array formulas
| Category | v0.4.0 | v0.5.0 |
|---|---|---|
| Worksheet operations | Tie | modern-xlsx wins |
| Cell operations | Tie | modern-xlsx wins |
| Formulas | Tie | modern-xlsx wins |
| Document properties | SheetJS wins | modern-xlsx wins |
| Cell ref utilities | SheetJS wins | Tie |
| Number formatting | SheetJS wins | modern-xlsx wins |
| Sheet conversion | SheetJS wins | SheetJS (gap narrowed) |
-
Full OOXML Table read/write — native
xl/tables/table{n}.xmlsupport with SAX parser and XML writer -
ws.tables— getter returning all tables on a worksheet -
ws.getTable(name)— find table by name -
ws.addTable(opts)— create table with name, ref, columns, style, totalsRow, autoFilter -
ws.removeTable(name)— delete table by name -
60 built-in table styles —
TABLE_STYLES.light(1-21),.medium(1-28),.dark(1-11) -
VALID_TABLE_STYLES— ReadonlySet for style name validation -
TotalsRowFunction— type for totals row calculations (sum, count, average, etc.)
-
ws.headerFooter— getter/setter forHeaderFooterDatawith odd/even/first header/footer -
HeaderFooterBuilder— fluent builder withleft(),center(),right(),build() -
Static formatting helpers —
pageNumber(),totalPages(),date(),time(),fileName(),sheetName(),filePath() -
Text formatting —
bold(),italic(),underline(),strikethrough(),fontSize(),fontName(),color()
-
ws.groupRows(start, end, level?)— set outline level (0-7) on row range -
ws.ungroupRows(start, end)— remove outline level from rows -
ws.collapseRows(start, end)— collapse grouped rows -
ws.expandRows(start, end)— expand collapsed rows -
ws.groupColumns(start, end, level?)— set outline level on column range -
ws.ungroupColumns(start, end)— remove outline level from columns -
ws.outlineProperties— getter/setter for summary row/column position
-
wb.setPrintTitles(sheet, opts)— set repeating rows/columns via_xlnm.Print_Titlesdefined name -
wb.getPrintTitles(sheet)— get current print title configuration -
wb.setPrintArea(sheet, area)— set print area via_xlnm.Print_Areadefined name -
wb.getPrintArea(sheet)— get current print area
Declarative table generation API with styled headers, zebra striping, auto-width, merge cells, and multi-table composition. Critical bug fixes across WASM init, writer performance, and sheet conversion utilities.
-
drawTable(wb, ws, opts)— generate styled XLSX tables from declarative options, no manual cell coordinate math -
drawTableFromData(wb, ws, data, opts?)— create tables from JSON arrays with auto-extracted headers andheaderMapdisplay names -
Header styling — customizable font, background color, and alignment with sensible defaults (bold white on
#4472C4) -
Body styling — zebra striping via
alternateRowColor, configurable borders, font, and alignment - Auto-width — content-aware column width calculation with CJK double-width character support
-
Per-cell style overrides —
cellStylesmap with"row,col"keys for targeted formatting on top of base styles -
Merge cells — row and column spanning via
mergesarray (0-based, relative to data area) -
Column definitions —
TableColumnwith per-column width, alignment, and number format (e.g.'$#,##0.00') -
Freeze header —
freezeHeader: truefreezes the header row for scrolling -
Auto-filter —
autoFilter: trueadds filter dropdown arrows to header cells -
Nested composition — use
TableResult.lastDataRowto stack tables vertically with gap rows -
Side-by-side composition — use
origincolumn offsets to place tables horizontally
-
jsonToSheetstartCol —writeDataRownow respects thestartColparameter instead of ignoring it -
resolveNumFmtIdsort assumption — no longer assumes thenumFmtarray is sorted, uses correct lookup -
initWasmSyncrace condition — concurrentinitWasmcalls no longer conflict with synchronous initialization -
frozenPanefield names — table engine uses correctrows/colsfield names for frozen pane data -
WASM reader HashSet rebuild — eliminated unnecessary
HashSetreconstruction on every read operation -
Comments clone — removed avoidable
.clone()in comments path handling -
Writer insert shift — replaced
Vec::insert(0, ...)O(n) shift with efficient prepend pattern
-
columnToLetter/letterToColumn— corrected examples that used wrong indices -
serialToDate— fixed example showing wrong return type -
addValidation— corrected example using wrong field name - Rich text — fixed example that accessed private fields
Pure TypeScript barcode/QR generation with 9 formats, PNG renderer, and XLSX embedding. Full codebase audit with critical bug fixes. 437 tests (157 Rust + 280 TypeScript).
- 9 barcode formats — Code 39, Code 128, EAN-13, UPC-A, ITF-14, GS1-128, QR Code, Data Matrix, PDF417
-
renderBarcodePNG()— pure TypeScript PNG renderer (no external dependencies) -
generateBarcode()— one-call XLSX embedding with drawing XML and relationships -
generateDrawingXml()/generateDrawingRels()— low-level drawing XML generation - Multi-image accumulation — multiple images per sheet without data loss
-
Unicode panic —
validate.rsbyte-indexing multi-byte characters →chars().take(n).collect() -
Multi-image data loss —
addImage()now accumulates via Maps instead of overwriting drawing XML -
SST insert performance — Entry API replaces double hash lookup in
shared_strings.rs -
Comments author dedup — Entry::Vacant pattern eliminates double lookup in
comments.rs -
DXF diagonal attrs — eliminated redundant UTF-8 decoding in
styles.rs
- GF(256) lookup tables hoisted to module-level constants (Data Matrix encoder)
-
Array.prototype.at(-1)for O(1) sorted-array access (utils.ts,style-builder.ts) -
split_once(':')replacessplit(':').collect::<Vec<>>()in validators - Single
TextEncoderinstance in QR encoder (was creating two)
- All docs updated for v0.3.0 accuracy
- Barcode generation examples in playground
- Migration guides updated with barcode comparison
Browser-first release with IIFE bundle, CDN distribution, Web Worker support, and framework examples. 419 tests (171 Rust + 248 TypeScript).
-
IIFE build — self-contained
modern-xlsx.min.js(~29 KB) exposingwindow.ModernXlsx - CDN distribution — available on jsDelivr and unpkg, no bundler required
-
detectWasmUrl()— auto-detection of WASM binary URL fromdocument.currentScript.src -
initWasmSync(module)— synchronous WASM initialization from pre-loaded buffer -
ensureReady()— lazy auto-initialization on first use (cached Promise pattern) -
Source maps —
.mapfiles generated for all build outputs (ESM, IIFE, Worker)
-
createXlsxWorker()— off-thread XLSX read/write via Web Worker message passing -
modern-xlsx.worker.js— dedicated worker script with auto WASM init -
Transferable buffers — zero-copy transfer of
Uint8Arrayresults back to main thread
- tsdown 3-build config — ESM (primary), IIFE (browser), Worker (off-thread)
-
Package exports —
"."(ESM),"./browser"(IIFE),"./worker"(Worker script) -
browser/unpkg/jsdelivrfields in package.json for CDN auto-resolution
-
Interactive browser playground at
docs/site/playground.html - 6 built-in examples: Hello World, Styled Workbook, Read & Inspect, Batch Data, JSON to Sheet, Formulas & Dates
- Live WASM status indicator, Ctrl+Enter execution, download integration
-
React — hooks-based integration with
useEffectWASM init -
Vue 3 — Composition API with
onMountedWASM init -
Svelte 5 —
$effectrune-based WASM init - Angular — service-based WASM init with standalone components
- Cloudflare Workers — XLSX generation at the edge
- Deno Deploy — server-side XLSX with Deno-native imports
- Service Worker — offline XLSX generation with custom WASM URL
Complete 0.1.x hardening series. 419 tests (171 Rust + 248 TypeScript).
- Style roundtrip: gradient fills, diagonal borders, DXF styles, cell named styles
- Formula metadata: array formulas, shared formulas, formulaRef, sharedIndex
- Feature roundtrip: hyperlinks, comments, data validation, conditional formatting, sheet protection, page setup
- Edge cases: empty workbooks, malformed XML, boundary values
- Error handling: corrupted files, invalid inputs, graceful degradation
- Streaming & benchmarks: 100K row read/write, parallel parsing, buffer scaling
- Utilities: cell refs, dates, format codes, CSV/HTML/JSON conversion
-
push_entity()— zero-allocation XML entity resolution -
Vec::with_capacity()on all XML parse buffers (11 sites) -
from_utf8().unwrap_or_default()replacesfrom_utf8_lossy()(6 sites) -
entries.remove()in StreamingReader — moves data instead of cloning -
drain()incollect_preserved()— moves preserved entries -
#[non_exhaustive]on error enum
- Module-scoped
CELL_REF_REregex (hoisted from hot loop) -
isolatedDeclarations: truein tsconfig - Shared WASM init via
__tests__/setup.ts
- Migration guide: SheetJS
- Migration guide: ExcelJS
- Usage examples cookbook
- Release roadmap
- GitHub Actions pinned to stable versions
- Rust toolchain:
@stable - Node.js engine:
>=24.0.0
First public release.
- Full XLSX read/write with Rust WASM core
- Cell styling — fonts, fills, borders, alignment, number formats via StyleBuilder
- Data validation — list, number, date, text length, custom formula
- Conditional formatting — color scales, data bars, icon sets, formula-based rules
- Frozen panes, hyperlinks, comments, sheet protection, page setup
- Rich text with RichTextBuilder
- Named ranges, document properties, workbook views, calc chain
- Streaming reader/writer for large files
- Parallel sheet parsing (rayon)
- Cell reference utilities, date utilities, format utilities
- Sheet conversion utilities (JSON, CSV, HTML, array-of-arrays)
- Browser Blob download support
- 342 tests (170 Rust + 172 TypeScript)
| Operation | modern-xlsx | SheetJS CE | Factor |
|---|---|---|---|
| Read 100K | 1,155 ms | 4,927 ms | 4.3x faster |
| Write 100K | 5,048 ms | 5,048 ms | 1.0x |
| sheetToJson 10K | 54 ms | 103 ms | 1.9x faster |
modern-xlsx v1.0.0
Getting Started
Guides
- Charts & Visualizations
- Formula Engine
- Table Layout Engine
- Tables & Print Layout
- Encryption
- Feature Comparison
Reference
Migration
Project