9.3.0 (2026-04-18)
⚠️ Breaking Changes
Three runtime-observable breaks since v9.2.1. Full migration notes in MIGRATION.md.
1. Empty <border> now parses to undefined instead of {} (59f24cf)
Cells referencing borderId=0 (the default empty border) used to populate cell.border with {} (truthy). It now correctly parses to undefined, matching the declared type.
Impact: Truthy-check patterns break.
// Before — accidentally ran for every cell
if (cell.border) { ... }
// After — use optional chaining
if (cell.border?.top || cell.border?.left || ...) { ... }2. Worksheet.addTable() enforces workbook-wide unique table names (59f24cf)
Duplicate table names (case-insensitive) across the workbook are now rejected at addTable() time. Previously silently accepted, producing XLSX files Excel itself refused to open.
Impact: Code that added same-named tables to different worksheets now throws.
ws1.addTable({ name: "Data", ... });
ws2.addTable({ name: "Data", ... }); // throws — use distinct names3. { richText: [] } no longer classifies as RichText (fa350f7)
Cell.Value.getType now requires richText.length > 0. Assigning { richText: [] } used to produce a RichText cell (empty-array was truthy); it now falls through to JSON type.
Impact: Serialization and cell.type change for anyone using empty-runs arrays as "empty rich text".
// Before
cell.value = { richText: [] }; // classified as RichText
// After — use one of:
cell.value = null; // empty cell
cell.value = ""; // empty string
cell.value = { richText: [{ text: "" }] }; // zero-length runNon-breaking but noteworthy
The following changed but remain backward-compatible at runtime:
CellModel.richTextunion widened toCellRichTextValue | RichText[] | undefinedfor Hyperlink cells with formatted display runs (fa350f7). Readers ofcell.model.richTexton Hyperlink cells should branch onArray.isArray().HyperlinkValue.textsetter now enforcestext === flatten(richText)(fa350f7). Setting.texton a hyperlink cell clears stalerichText.TableProperties.rowstightened fromany[][]toArray<Array<CellValue | CellFormulaValue>>(fa350f7). TypeScript-only; runtime unchanged.
Major Additions (Non-Breaking)
Formula Calculation Engine — new /formula subpath
Standalone 433-function Excel-compatible calculation engine with tokenizer, parser, compiler, evaluator, dependency graph, dynamic-array spill, and LAMBDA/LET/MAP/REDUCE. Zero runtime dependencies.
Two usage modes:
// Mode A: paired with Workbook
import { Workbook } from "@cj-tech-master/excelts";
import { installFormulaEngine } from "@cj-tech-master/excelts/formula";
installFormulaEngine(); // once at startup
wb.calculateFormulas();
// Mode B: standalone — zero excel runtime, any WorkbookLike
import { calculateFormulas } from "@cj-tech-master/excelts/formula";
calculateFormulas(anyWorkbookLikeObject);Engine is kept out of bundles that don't import it. Tree-shake-verified across esbuild / rolldown / rspack.
Dynamic Array Formulas (Excel 365)
FILTER, SORT, UNIQUE, XLOOKUP, SEQUENCE, spill-error detection, ghost-cell cleanup.
External Workbook Links
[Book.xlsx]Sheet!A1 references now round-trip through load/save.
Workbook Structure Protection + Public APIs
Workbook.protection— structure/windows/revision lockWorkbook.defaultFont— now public, for round-trip fidelityImage.absoluteAnchor— absolute image positioningCell.ignoredErrors— suppress Excel's green triangles per cell
Features
- excel: Add COUP family + BINOM.DIST.RANGE (a7e3e54)
- excel: Add Excel 365 dynamic array formula support (FILTER/SORT/UNIQUE/XLOOKUP/SEQUENCE) (17e6c22)
- excel: Add external workbook link support ([Book]Sheet!Ref) (8d0d046)
- excel: Add formula calculation engine with tokenizer, parser, evaluator, dependency graph, and 220+ Excel functions (6b6c9a8)
- excel: Add ignoredErrors support, absoluteAnchor images, and reconcilePicture null guard (da34761)
- excel: Add matrix + series math functions (MMULT, MDETERM, MINVERSE, MUNIT, SERIESSUM) (ee6a094)
- excel: Add REGEX, VALUETOTEXT, ARRAYTOTEXT, PERCENTRANK, PROB functions (03913e5)
- excel: Add SQRTPI, ENCODEURL, ACCRINTM, TBILL*, PRICEMAT, YIELDMAT (96813b8)
- excel: Add workbook structure protection and public defaultFont API (7f15a58)
- excel: Cast-free hyperlink + formula+hyperlink cell input (86340a0)
- excel: Harden formula engine — +5000 tests, 30+ bug fixes, 34 new functions, 3D ref + dynamic-array dependency fixes (06b0cf4)
Bug Fixes
- excel: Fix 21 formula engine bugs, add 13 functions, 2 language features (487079a)
- excel: Fix data validation sort, empty border truthy, and table name uniqueness (59f24cf)
- excel: Preserve formula+hyperlink and rich-text on round-trip (#142) (fa350f7)
- excel: SUBTOTAL/AGGREGATE full Excel semantics, totals-row SUBTOTAL codes, multi-area mask merging (128c54c)
- excel: Support range operator ':' with dynamic refs, add 50+ functions, fix SUBTOTAL/AGGREGATE semantics (f912857)
- Update TypeScript linting rules — add no-misused-spread and no-useless-default-assignment (480b7c0)