github cjnoname/excelts v9.0.0

latest release: v9.1.0
14 hours ago

9.0.0 (2026-04-08)

⚠ BREAKING CHANGES

  • pdf(), readPdf(), and excelToPdf() now return Promise instead of synchronous results. All call sites must use await.
  • pdfAsync(), readPdfAsync(), and excelToPdfAsync() have been removed — the base names are now async.

Features

  • Make PDF APIs async to avoid blocking the event loop (2f521cd)

Bug Fixes

  • Improve Excel-to-PDF style fidelity and fix cell style mutation leaks (0448604)

PDF Rendering

  • Type-based default alignment: numbers/dates right-align, booleans/errors center, formulas align by result type — matching Excel behavior when no explicit alignment is set
  • Merged cell border propagation: borders set on boundary cells (right column, bottom row) are now correctly rendered on the merged region
  • Text overflow: non-wrapped text overflows into adjacent empty cells, stopped by cells with content (not just fill)
  • Double border: renders as two parallel thin lines with a gap, instead of a single line
  • Vertical stacked text: textRotation: 255 now renders characters top-to-bottom instead of at a skewed angle
  • Rotated text rewrite: dedicated rendering paths for 90°, −90°, and arbitrary angles with correct anchoring, multi-line support, and wrap
  • Column width: uses Excel's actual formula (excelWidth × maxDigitWidth + columnPadding) × px-to-pt instead of the rough width × 7 approximation
  • Row height: auto-sizing now uses actual font metrics and wrapTextLines() to match rendered output exactly
  • fitToPage: no longer double-applies pageSetup.scale on top of fit-to-page calculation
  • Image scaling: EMU offsets and extents are now multiplied by scaleFactor
  • Theme colors: updated to Office 2019+ default palette (e.g. accent1 = #4472C4)
  • Border widths: tuned to closer match Excel's visual rendering (hair 0.1pt, thin 0.25pt, medium 0.5pt, thick 1.0pt)
  • Shared constants: CELL_PADDING_H/V, LINE_HEIGHT_FACTOR, INDENT_WIDTH extracted to constants.ts to prevent layout/render drift
  • Bordered empty cells: cells with borders/fill/font but no value are now included in PDF output
  • Explicit newlines: non-wrapped text now splits on \n to produce multiple lines
  • Rich text type guard: replaced unsafe cast with proper "richText" in value check
  • Scale-aware rendering: cell padding, indent, and clip regions all respect page scaleFactor

Number Formatting (cell-format.ts)

  • ? placeholder: pads integer part with leading spaces and decimal part with trailing spaces
  • # placeholder: suppresses leading zeros in integer part and strips trailing zeros in decimal part
  • #.## with zero: produces empty string instead of a bare .
  • Zero-value sections: accounting formats like "-"?? correctly produce dash + spaces

Cell Style Isolation

  • Cell.merge(): deep-copies master style so each cell in a merge range has an independent style object — setting border on one cell no longer mutates all others
  • Cell.set model: clones shared cached style from XLSX deserialization, preventing cross-cell mutation when modifying style after loading a file
  • Row._applyStyle(): clones object values before broadcasting to cells
  • Column style setters: clone values before broadcasting to cells
  • Column.set defn: clones style from model during XLSX load and spliceColumns
  • Cell._mergeStyle(): clones sub-properties inherited from row/column styles at construction time
  • WorksheetReader (streaming): clones cached styles for both rows and cells

Tests

  • 40 new tests across 7 files (6623 total, all passing)
  • New integration test file: pdf-edge-cases.test.ts with 20 tests covering alignment, merge borders, overflow, double borders, zero formats, fitToPage, row heights, newlines, error values, rich text, hyperlinks, and vertical text
  • New example: pdf-edge-cases.ts demonstrating all advanced rendering scenarios

Don't miss a new excelts release

NewReleases is sending notifications on new releases.