Skip to content

Changelog

ABCrimson edited this page Mar 7, 2026 · 18 revisions

Changelog

v1.0.0 — Stable Release (2026-03-06)

First stable release — API frozen, production-ready feature set. 1,711 tests (424 Rust + 1,287 TypeScript).

New Features

  • PivotTableBuilder — fluent builder API for pivot tables
  • Auto-Filter Custom FiltersCustomFilterData/CustomFiltersData with full roundtrip
  • Page BreaksPageBreaksData with row/column break parsing and writing
  • Rich Text CellsCell.richText getter/setter, RichTextBuilder fluent API
  • Error SystemModernXlsxError with 18 machine-readable error codes
  • Image Embedding — PNG/JPEG support in worksheets

Since 0.5.0

  • v0.6.0 — Full ECMA-376 encryption (read + write), OLE2 support
  • v0.7.0 — Formula engine with 54 built-in functions
  • v0.8.0 — 10 chart types with ChartBuilder API, trendlines, error bars, 3D
  • v0.9.0 — Pivot tables, threaded comments, slicers, timelines, CLI tool
  • v0.9.2 — Streaming writer, pivot/slicer/timeline write APIs, security audit

See the full changelog in packages/modern-xlsx/CHANGELOG.md.


v0.9.1 — Performance, Quality & Maintainability Overhaul

Rust Performance:

  • ryu crate for 2-6x faster f64 formatting in hot paths
  • Byte-level JSON escaping (batch-copies vs char-by-char)
  • make_rid() helper with itoa::Buffer — 21 format!() allocations eliminated
  • Cow<'static, str> on Relationship fields — zero-alloc for static constants
  • From<serde_json::Error> — 16 .map_err() calls → ?
  • if-let chains (Rust 2024 edition)

Code Organization:

  • Split worksheet.rs (7,173 lines) → worksheet/{mod,parser,writer,json}.rs
  • Split charts.rs (4,862 lines) → charts/{mod,types,parser,writer}.rs
  • Split barcode.ts (1,828 lines) → 11 tree-shakeable modules
  • Removed unused serde-wasm-bindgen dependency

TypeScript Improvements:

  • O(1) sheet name cache via Map in Workbook
  • Discriminated union types for Worker messages
  • Replaced custom at() helpers with native methods
  • Vitest pool: forksthreads

CI/CD:

  • cargo-audit + npm audit security scanning
  • WASM binary size tracking (>2MB warning)
  • Matrix testing: Node 24+25 × ubuntu+windows
  • WASM artifact caching
  • dependabot.yml, CODEOWNERS, FUNDING.yml

Docs: Fixed test counts, Rust version, SECURITY.md; added pivot table/threaded comment/slicer/timeline/CLI examples.

v0.9.0 — Pivot Tables, Threaded Comments, Slicers & Timelines (2026-03-06)

Major feature release adding advanced Excel features, CLI tool, performance optimizations, and feature-gated WASM.

Pivot Tables (read-only)

  • Full OOXML pivot table definition parsing — PivotTableData, PivotFieldData, PivotDataFieldData, PivotPageFieldData
  • Pivot field axes (axisRow/axisCol/axisPage/axisValues) and 11 subtotal functions
  • Pivot cache definition and records parsing/writing (CacheSource, CacheFieldData, CacheValue)
  • ws.pivotTables read-only API for pivot table metadata
  • OOXML parts: xl/pivotTables/, xl/pivotCache/

Threaded Comments (read + write)

  • Modern threaded comment parsing/writing (xl/threadedComments/)
  • Person management with xl/persons/person.xml
  • ws.addThreadedComment(cell, text, author) — create new comment thread
  • ws.replyToComment(commentId, text, author) — reply to existing thread
  • Auto-generates GUIDs and ISO 8601 timestamps
  • Coexists with legacy xl/comments*.xml

Slicers (read-only)

  • Slicer definition and cache parsing/writing
  • SlicerData, SlicerCacheData, SlicerItem types
  • ws.slicers read-only API
  • OOXML parts: xl/slicers/, xl/slicerCaches/

Timelines (read-only)

  • Timeline definition and cache parsing/writing
  • TimelineData, TimelineCacheData, TimelineLevel enum (Years/Quarters/Months/Days)
  • ws.timelines read-only API
  • OOXML parts: xl/timelines/, xl/timelineCache/

CLI Tool

  • modern-xlsx info <file> — sheet names, dimensions, row counts
  • modern-xlsx convert <file> <output> — XLSX to JSON
  • modern-xlsx convert <file> <output> --sheet N --format csv — single sheet to CSV
  • Installed via npx modern-xlsx or global install

Performance Optimization

  • XML writer buffer pre-allocation based on data size estimates
  • 4-8x faster than SheetJS for bulk read/write operations
  • Benchmark integration tests for 10K and 100K row workloads

Feature-Gated WASM

  • Cargo features: encryption and charts (both on by default)
  • 9 crypto dependencies made optional via #[cfg(feature = "encryption")]
  • Smaller WASM bundles possible by disabling unused features

API Improvements

  • ModernXlsxError class with .code property (INVALID_CELL_REF, WASM_INIT_FAILED, SHEET_NOT_FOUND, COMMENT_NOT_FOUND, INVALID_ARGUMENT)
  • Readonly arrays throughout the public API surface
  • ws.dimension and ws.rowCount getters
  • Null consistency across all optional properties

Comprehensive Codebase Audit

  • Full Rust 1.95 modernization (cold_path, .find(), #[inline], match guards)
  • TypeScript 6.0 patterns (satisfies, type guards, no as casts)
  • Zero clippy warnings (collapsible_match, derivable_impls, unnecessary_sort_by fixed)
  • Removed obsolete #![allow(clippy::...)] directives

Verification

  • 389 Rust tests pass (368 unit + 4 benchmark + 12 golden + 5 security)
  • 1230 TypeScript tests pass across 55 test files
  • Zero clippy warnings, zero TypeScript type errors

v0.8.6 — Rust 1.95 Modernization (2026-03-05)

Deep Rust modernization targeting Rust 1.95-beta features and idiomatic patterns across all 34 Rust source files (~30,760 lines).

Rust 1.95 Features

  • core::hint::cold_path() on all error/panic branches (23 files) — compiler branch layout optimization
  • rust-version bumped to 1.95.0 in workspace Cargo.toml

Iterator Modernization

  • 58 single-attribute for loops replaced with .find() iterator pattern across all OOXML parsers
  • 3 index-based loops replaced with zip() iteration in reader.rs
  • next_r_id() extracted as method on Relationships — deduplicates closure + inline expression in writer.rs

Performance Annotations

  • #[inline] on 3 hot-path streaming JSON helpers (worksheet.rs)
  • #[inline] on 12 chart enum xml_val() methods (charts.rs)

Code Quality

  • Shared serde helpers (is_false, is_true, default_true) extracted to ooxml/mod.rs — removes 22 lines of duplication across 5 files
  • WASM bridge: parse_workbook() + to_js_err() helpers deduplicate 6 JSON parse patterns

Verification

  • 357 Rust tests pass (340 unit + 12 golden + 5 security)
  • 1210 TypeScript tests pass across 50 test files
  • Zero clippy warnings

v0.8.5 — Comprehensive Audit & Modernization (2026-03-05)

Deep audit across entire codebase: bug fixes, lint cleanup, Rust & TypeScript modernization, expanded test coverage.

Bug Fixes

  • CRITICAL: Merge image + chart drawing XML to prevent silent data loss
  • Restore ChartAxis.fontSize with proper c:txPr writer/parser
  • Parse oneCellAnchor charts from drawing XML
  • Combo chart roundtrip — parse secondary_chart correctly
  • WASM boundary validation for chart data

Rust Modernization

  • Eliminated all panic!() calls in encryption
  • Iterator combinators replace manual loops across charts, styles, tables, theme
  • #[derive(Default)] on 7 builder structs
  • Let-else patterns, Option::take() for zero-clone operations
  • Zero clippy warnings

TypeScript 6.0 Modernization

  • satisfies operator for compile-time validation of constant maps
  • readonly on 16 interface array fields
  • Cached Intl.NumberFormat — 10x faster numeric formatting
  • Single-pass escapeHtml — replaces 4 chained .replaceAll()
  • Worker crash memory leak fix
  • Eliminated all 19 noNonNullAssertion lint errors

Test Coverage

  • Rust: 357 tests (expanded golden tests from 2 to 12 scenarios)
  • TypeScript: 1210 tests (added chart API and roundtrip tests)

v0.8.1 — Audit Patch (2026-03-04)

Bug fixes from comprehensive v0.8.0 charts audit.

Rust Fixes

  • CRITICAL: <drawing> now emitted before <tableParts> per ECMA-376 CT_Worksheet schema
  • CRITICAL: <c:style> now emitted before <c:chart> per CT_ChartSpace schema
  • write_f64_element skips NaN/Infinity values
  • Remove dead ChartAxis.font_size field
  • DataLabelsBuilder::build_and_reset() uses Option::take() (zero-clone)

TypeScript Fixes

  • buildAxisTitle uses == null instead of !title (preserves empty string titles)
  • Remove ChartAxisData.fontSize (dead field, matches Rust removal)

v0.8.0 — Charts & Visualizations (2026-03-04)

Full chart creation, reading, and roundtrip for 10 chart types. ChartBuilder fluent API, chart style presets, trendlines, error bars, 3D rotation, combo charts, and data tables. 337 Rust tests + 1171 TypeScript tests.

Chart Types (10)

  • Bar — horizontal bars with clustered/stacked/percentStacked grouping
  • Column — vertical bars with clustered/stacked/percentStacked grouping
  • Line — line charts with standard/stacked/percentStacked grouping
  • Pie — single-series pie charts
  • Doughnut — pie with configurable hole size
  • Scatter — XY scatter with lineMarker/smoothMarker/line/smooth styles
  • Area — area charts with standard/stacked/percentStacked grouping
  • Radar — radar/spider charts with radar/filled styles
  • Bubble — bubble charts with bubble size series
  • Stock — OHLC stock charts (open-high-low-close)

ChartBuilder API

import { ChartBuilder } from 'modern-xlsx';

const chart = new ChartBuilder('bar')
  .title('Q1 Sales')
  .addSeries({
    name: 'Revenue',
    categories: 'Sheet1!$A$2:$A$5',
    values: 'Sheet1!$B$2:$B$5',
  })
  .catAxis({ title: 'Product' })
  .valAxis({ title: 'Revenue ($)' })
  .legend('bottom')
  .build();

ws.addChartData(chart);

Callback-Based Chart Creation

ws.addChart('line', (b) => {
  b.title('Monthly Trend')
   .addSeries({ name: 'Sales', values: 'Sheet1!$B$2:$B$13' })
   .legend('right');
});

Advanced Features

  • Trendlines — linear, exponential, logarithmic, polynomial, power, movingAverage
  • Error bars — fixed, percentage, stdDev, stdErr, custom with plus/minus values
  • 3D rotationrotX, rotY, perspective, rAngAx via view3d() builder
  • Combo charts — secondary chart type + secondary value axis
  • Data tables — show data table below chart with showDataTable()
  • Style presets — 8 color palettes via getChartStylePalette()

Roundtrip

Charts written by modern-xlsx can be read back with full fidelity — all chart data, series, axes, labels, trendlines, and styling are preserved through write → read roundtrip.

Rust Core

  • ChartData, ChartSeries, ChartAxis, ChartLegend structs with serde
  • ChartData::to_xml() — ECMA-376 DrawingML chart XML generator
  • ChartData::parse() — SAX parser with state machine (25 parse states)
  • ChartAnchor::generate_drawing_xml() — two-cell anchor drawing XML
  • parse_drawing_anchors() — extracts chart rIds from drawing XML
  • resolve_charts() — two-step resolution (sheet.rels → drawing → chart)
  • 33+ chart-specific tests

v0.7.1 — Audit Patch (2026-03-04)

Bug fixes, security hardening, and precision improvements from comprehensive codebase audit.

Rust Fixes

  • JSON injection prevention in streaming path (cell refs now escaped)
  • xml:space="preserve" on SST <t> elements (whitespace-padded strings)
  • Path traversal defense in resolve_relative_path
  • Saturating add for frozen pane topLeftCell
  • Writer entries Vec capacity improvement

TypeScript Fixes

  • ROUND precision (epsilon adjustment for 1.005-style edge cases)
  • ROUND/ROUNDUP/ROUNDDOWN use Math.trunc for negative digit args
  • Cross-sheet range resolver propagation
  • Tokenizer backtrack on invalid exponents (e.g., 1e+)
  • sheetToJson off-by-one fix in collectRows
  • SUMIF/COUNTIF localeCompare consistency

v0.7.0 — Formula Engine (2026-03-04)

Complete formula tokenizer, parser, evaluator, and 54 built-in Excel functions — enabling modern-xlsx to compute cell values without Excel. 1142 TypeScript tests.

Formula Pipeline

  • Tokenizer — single-pass lexer producing typed tokens (24 token types)
  • Parser — recursive descent with operator precedence (12 AST node types)
  • Serializer — AST to formula string with precedence-aware parenthesization
  • Reference Resolver — resolves A1 refs and ranges to cell values via EvalContext
  • Reference Rewriter — adjusts refs on row/column insert/delete, generates #REF! for deleted
  • Shared Formula Expansion — derives child formulas from master + row/col offset
  • Evaluator — tree-walk interpreter with Excel-compatible type coercion and error propagation

Built-in Functions (54)

String & Logical (20): IF, AND, OR, NOT, IFERROR, CONCATENATE, LEFT, RIGHT, MID, LEN, TRIM, UPPER, LOWER, TEXT, VALUE, EXACT, SUBSTITUTE, REPT, FIND, SEARCH

Math & Statistical (25): SUM, AVERAGE, MIN, MAX, COUNT, COUNTA, COUNTBLANK, ROUND, ROUNDUP, ROUNDDOWN, ABS, SQRT, MOD, INT, CEILING, FLOOR, POWER, LOG, LN, PI, RAND, SUMIF, COUNTIF, AVERAGEIF, SUMPRODUCT

Lookup (9): VLOOKUP, HLOOKUP, INDEX, MATCH, CHOOSE, ROW, COLUMN, ROWS, COLUMNS

API

import { evaluateFormula, createDefaultFunctions } from 'modern-xlsx';

const functions = createDefaultFunctions();
const result = evaluateFormula('SUM(A1:A3)*2', {
  currentSheet: 'Sheet1',
  functions,
  getCell: (sheet, col, row) => { /* return cell value */ },
});

v0.6.0 — Security & Encryption (2026-03-04)

Full ECMA-376 encryption support — read and write password-protected XLSX files. Agile Encryption (AES-256-CBC, SHA-512) for modern files, Standard Encryption (AES-128-ECB, SHA-1) for legacy compatibility. OLE2 compound document read/write. 299 Rust tests + 583 TypeScript tests.

Encryption: Read Path

  • OLE2 compound document detection — magic byte analysis distinguishes encrypted XLSX, legacy XLS, and normal ZIP
  • EncryptionInfo parser — Agile (v4.4) and Standard (v2.2/3.2/4.2) encryption method identification
  • SHA-512/SHA-256/SHA-1 key derivation — per ECMA-376 SS2.3.6.2 with configurable spin count (100K default)
  • AES-256-CBC segment decryption — 4096-byte segment-based decryption with per-segment IV derivation
  • AES-128-ECB decryption — Standard Encryption verifier decryption using raw block cipher
  • HMAC-SHA-512 integrity — tamper detection via encrypt-then-MAC verification
  • Password verification — constant-time comparison for Agile and Standard encryption
  • readBuffer(data, { password }) — simple API to read encrypted files
  • readFile(path, { password }) — file-based encrypted read (Node.js/Bun/Deno)

Encryption: Write Path

  • OLE2 compound document writer — v3 format (512-byte sectors), FAT chains, directory entries
  • Agile Encryption pipeline — random salt/key generation, segment-based AES-256-CBC encryption
  • HMAC integrity embedding — compute-and-encrypt HMAC for post-write tamper detection
  • EncryptionInfo XML generation — produces spec-compliant Agile encryption descriptor
  • wb.toBuffer({ password }) — simple API to write encrypted files
  • wb.toFile(path, { password }) — file-based encrypted write (Node.js/Bun/Deno)

Security Hardening

  • SensitiveKey RAII wrapper#[derive(Zeroize, ZeroizeOnDrop)] for automatic key material cleanup
  • No key leaks on error paths — all derived keys wrapped in SensitiveKey (immune to ? operator bypass)
  • Constant-time comparisonsconstant_time_eq at all 3 secret comparison sites
  • Error message safety — no key material, hash values, or intermediate state in error strings
  • Cryptographically secure randomgetrandom with wasm_js feature for WASM targets

New Dependencies (Rust)

  • sha1 0.10 — SHA-1 hash for Standard Encryption
  • getrandom 0.3 — CSPRNG for salt/key generation (WASM-compatible)

Test Coverage

  • 42 new Rust tests (OLE2 detection, encryption info, key derivation, AES, HMAC, OLE2 writer, security)
  • 30+ new TypeScript tests (encryption read/write, roundtrip, edge cases, 10K-row performance)

v0.6.1 — Worker Encryption & DRY (2026-03-04)

Encryption support for the Worker API, OLE2 code deduplication, and crypto helper consolidation.

Worker API Encryption

  • worker.readBuffer(data, { password }) — read encrypted files in Web Worker thread
  • worker.writeBuffer(data, { password }) — write encrypted files in Web Worker thread
  • Backward compatible — password parameter is optional, existing code unchanged

DRY Improvements (Rust)

  • OLE2_MAGIC consolidation — deduplicated constant from detect.rs and writer.rs into ole2/mod.rs
  • Generic hash dispatcherwith_hash_alg eliminates triplicated SHA-512/SHA-256/SHA-1 match blocks
  • HMAC computation helpercompute_hmac deduplicates HMAC dispatch between verify and encrypt paths
  • DIFAT documentation — enhanced write_ole2 doc comments explaining 109-entry DIFAT limitation

New Dependencies (Rust)

  • digest 0.10 (with alloc feature) — DynDigest trait for generic hash dispatch

v0.5.1 — Audit Patch (2026-03-03)

Critical bug fixes found during comprehensive codebase audit.

Bug Fixes

  • Image embedding brokengenerateDrawingXml rId off-by-one causing images to silently fail
  • Frozen panes: wrong activePane — column-only freeze wrote "bottomLeft" instead of "topRight"
  • Invalid JSON for NaN/Infinitywrite_f64_json now writes null instead of crashing JSON.parse
  • Custom numFmt ID collisionresolveNumFmtId now always assigns IDs >= 164 per ECMA-376

Performance

  • HashMap::with_capacity in ZIP reader
  • col_index_to_letter delegates to optimized col_to_letters
  • TextEncoder hoisted to module-level constant

v0.5.0 — Tables, Print Layout & Parity Sprint (2026-03-03)

Closed 7 SheetJS advantage categories + added native Excel Tables, headers/footers, row/column grouping, and print layout. 704 tests (217 Rust + 487 TypeScript).

Cell Reference Utilities

  • encodeRow() — convert 0-based row index to 1-based string
  • decodeRow() — convert 1-based row string to 0-based index
  • splitCellRef() — decompose $A$1 into { col, row, absCol, absRow }

Document Properties

  • 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

Sheet Conversion Utilities

  • sheetToTxt() — tab-separated text output (reuses CSV engine with \t delimiter)
  • sheetToFormulae() — extract all cell values and formulas as ["A1=100", "A3='SUM(A1:A2)"]

Number Formatting

  • Conditional sections — parse [>100]#,##0;[<=100]0.00 with 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

Worksheet Operations

  • ws.usedRange — computed getter returning cell extent (e.g., "B2:D5") or null
  • ws.tabColor — getter/setter for sheet tab RGB hex color, roundtrips through WASM

Cell Operations

  • cell.numberFormat — resolves style index → numFmtId → format code string
  • cell.dateValue — returns Date if cell contains a date-formatted number
  • Stub cell type'stub' in CellType union for explicitly empty cells (SheetJS type "z")

Formulas

  • dynamicArray — roundtrip cm="1" attribute on <f> element for SPILL/dynamic array formulas

Scorecard Changes (v0.4.0 → v0.5.0)

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)

Excel Tables (ListObjects)

  • Full OOXML Table read/write — native xl/tables/table{n}.xml support 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 stylesTABLE_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.)

Headers & Footers

  • ws.headerFooter — getter/setter for HeaderFooterData with odd/even/first header/footer
  • HeaderFooterBuilder — fluent builder with left(), center(), right(), build()
  • Static formatting helperspageNumber(), totalPages(), date(), time(), fileName(), sheetName(), filePath()
  • Text formattingbold(), italic(), underline(), strikethrough(), fontSize(), fontName(), color()

Row & Column Grouping

  • 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

Print Titles & Print Areas

  • wb.setPrintTitles(sheet, opts) — set repeating rows/columns via _xlnm.Print_Titles defined name
  • wb.getPrintTitles(sheet) — get current print title configuration
  • wb.setPrintArea(sheet, area) — set print area via _xlnm.Print_Area defined name
  • wb.getPrintArea(sheet) — get current print area

v0.4.0 — Table Layout Engine (2026-03-02)

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.

Table Layout Engine

  • 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 and headerMap display 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 overridescellStyles map with "row,col" keys for targeted formatting on top of base styles
  • Merge cells — row and column spanning via merges array (0-based, relative to data area)
  • Column definitionsTableColumn with per-column width, alignment, and number format (e.g. '$#,##0.00')
  • Freeze headerfreezeHeader: true freezes the header row for scrolling
  • Auto-filterautoFilter: true adds filter dropdown arrows to header cells
  • Nested composition — use TableResult.lastDataRow to stack tables vertically with gap rows
  • Side-by-side composition — use origin column offsets to place tables horizontally

Bug Fixes

  • jsonToSheet startColwriteDataRow now respects the startCol parameter instead of ignoring it
  • resolveNumFmtId sort assumption — no longer assumes the numFmt array is sorted, uses correct lookup
  • initWasmSync race condition — concurrent initWasm calls no longer conflict with synchronous initialization
  • frozenPane field names — table engine uses correct rows/cols field names for frozen pane data
  • WASM reader HashSet rebuild — eliminated unnecessary HashSet reconstruction 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

Documentation Fixes

  • 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

v0.3.0 — Barcode & QR Code Generation (2026-03-02)

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).

Barcode & QR Generation

  • 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

Critical Bug Fixes

  • Unicode panicvalidate.rs byte-indexing multi-byte characters → chars().take(n).collect()
  • Multi-image data lossaddImage() 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

Performance

  • 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(':') replaces split(':').collect::<Vec<>>() in validators
  • Single TextEncoder instance in QR encoder (was creating two)

Documentation

  • All docs updated for v0.3.0 accuracy
  • Barcode generation examples in playground
  • Migration guides updated with barcode comparison

v0.2.0 — Browser & CDN Distribution (2026-03-02)

Browser-first release with IIFE bundle, CDN distribution, Web Worker support, and framework examples. 419 tests (171 Rust + 248 TypeScript).

Browser Bundle

  • IIFE build — self-contained modern-xlsx.min.js (~29 KB) exposing window.ModernXlsx
  • CDN distribution — available on jsDelivr and unpkg, no bundler required
  • detectWasmUrl() — auto-detection of WASM binary URL from document.currentScript.src
  • initWasmSync(module) — synchronous WASM initialization from pre-loaded buffer
  • ensureReady() — lazy auto-initialization on first use (cached Promise pattern)
  • Source maps.map files generated for all build outputs (ESM, IIFE, Worker)

Web 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 Uint8Array results back to main thread

Build Pipeline

  • tsdown 3-build config — ESM (primary), IIFE (browser), Worker (off-thread)
  • Package exports"." (ESM), "./browser" (IIFE), "./worker" (Worker script)
  • browser / unpkg / jsdelivr fields in package.json for CDN auto-resolution

Playground

  • 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

Framework Examples

  • React — hooks-based integration with useEffect WASM init
  • Vue 3 — Composition API with onMounted WASM init
  • Svelte 5$effect rune-based WASM init
  • Angular — service-based WASM init with standalone components

Edge Runtime Examples

  • 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

v0.1.9 — Hardening & Performance Audit (2026-03-02)

Complete 0.1.x hardening series. 419 tests (171 Rust + 248 TypeScript).

Tests (+77 new)

  • 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

Performance (Rust Core)

  • push_entity() — zero-allocation XML entity resolution
  • Vec::with_capacity() on all XML parse buffers (11 sites)
  • from_utf8().unwrap_or_default() replaces from_utf8_lossy() (6 sites)
  • entries.remove() in StreamingReader — moves data instead of cloning
  • drain() in collect_preserved() — moves preserved entries
  • #[non_exhaustive] on error enum

TypeScript

  • Module-scoped CELL_REF_RE regex (hoisted from hot loop)
  • isolatedDeclarations: true in tsconfig
  • Shared WASM init via __tests__/setup.ts

Documentation

  • Migration guide: SheetJS
  • Migration guide: ExcelJS
  • Usage examples cookbook
  • Release roadmap

CI

  • GitHub Actions pinned to stable versions
  • Rust toolchain: @stable
  • Node.js engine: >=24.0.0

v0.1.0 — Initial Release (2026-03-02)

First public release.

Features

  • 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)

Performance

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

Clone this wiki locally