sheets-diff 2.0.0

Structured diff engine for Microsoft Excel .xlsx workbooks
Documentation

sheets-diff

crates.io docs.rs deps.rs License

Structured diff engine for Microsoft Excel .xlsx workbooks.

Compares two workbooks and returns a typed, deterministic result — not just a text diff. Application developers get the data; they decide the presentation.

Overview

sheets-diff compares .xlsx workbooks at the cell level and returns a WorkbookDiff carrying:

  • per-sheet change classification (added, removed, renamed, moved, modified);
  • per-cell typed value changes (Integer, Number, Bool, DateTime, …);
  • per-cell formula text changes;
  • structured diagnostics and per-level summary counts;
  • deterministic ordering by sheet index, then (row, col).

Supported format: .xlsx only. .xls, .ods, .xlsm, CSV, and other formats are out of scope for v2. Passing a non-xlsx file returns a structured error, never a panic.

Why / When

Use sheets-diff when you need:

  • a library that returns structured data rather than printing a diff;
  • typed valuesText("100") and Integer(100) are distinct;
  • GUI or batch integration: bytes/reader inputs, progress events, cancellation;
  • no hidden side effects — the library never writes to stdout/stderr or accesses the network.

It is intentionally not a spreadsheet editor, merge engine, or formula engine.

Quick Start

use sheets_diff::compare_paths;

let diff = compare_paths("old.xlsx", "new.xlsx")?;
println!("{} cell(s) changed", diff.summary.cells_changed);

for sheet in &diff.sheets {
    for cell in &sheet.cell_diffs {
        if let Some(vc) = &cell.value {
            println!("{}: {}{}", cell.address.a1,
                vc.old.display_string(), vc.new.display_string());
        }
    }
}

Features

Cargo feature What it enables
(none) Core library — no extra deps
serde Serialize on all public model types; output::json helpers
chrono ISO-8601 string synthesis for DateTime values
cli Builds the sheets-diff binary (requires clap)

Design Notes

  • One CellDiff per address. Value and formula changes are independent sub-fields; no duplicate-address entries.
  • #[non_exhaustive] everywhere. Adding fields or variants in v2.x is additive — no forced semver bump for struct consumers.
  • Conservative by default. Sheet rename detection only fires when exactly one old and one new sheet are unmatched. Ambiguous matches surface as Added/Removed plus a diagnostic.
  • calamine 0.35 pinned. The Data enum variant set is the grounding for all CellValue conversions.

More Detail