npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rosperitus/excelerate-reader

v0.13.0

Published

Read spreadsheets in the browser or Node: xlsx, xls, ods, csv, html, SYLK, Gnumeric and SpreadsheetML, with cell styles. Reading only.

Downloads

672

Readme

excelerate-reader

Read spreadsheets in Node or the browser - xlsx, xls, ods, csv, html, SYLK, Gnumeric and SpreadsheetML 2003 - and read how their cells are painted. Rust compiled to WebAssembly, no native module to build and nothing to install alongside it.

This is the reading half of excelerate. The full package also writes files back out and carries a 518-function formula engine; if you need either, use that one. Here they are not compiled in at all, which is the point: a reader that cannot write cannot be made to write, and the binary is the smaller for it.

const { readFileSync } = require("node:fs");
const { Book } = require("@rosperitus/excelerate-reader");

// The format is worked out from the bytes; the name only settles what they
// cannot say themselves.
const book = Book.read(readFileSync("report.xlsx"), "report.xlsx");

for (const name of book.sheetNames()) {
  const sheet = book.sheetIndex(name);
  console.log(name, book.usedRange(sheet));
}

// A cell's value, the text Excel shows for it, and the formula behind it.
book.get(0, "B2");           // 1234.5
book.getFormatted(0, "B2");  // "1 234,50 ₽"
book.getFormula(0, "B2");    // "SUM(B3:B9)" - the text, not its answer

// A whole rectangle in one crossing of the wasm boundary.
book.getRange(0, "A1:D20");

// Or a whole row with its styling, which is one crossing instead of a dozen.
book.getRowAt(0, 3);          // { values, formatted, bold, indent, hidden }
book.getRowAt(0, 3, false);   // the same without the displayed text, which is
                              // a string per cell nobody asked for

Layout

Reading a sheet usually means asking the same few things of every row, so each has an answer that does not build a whole style to get at one flag:

book.cellBoldAt(0, 3, 1);   // true - the font flag on its own
book.rowHidden(0, 3);       // false
book.mergedRanges(0);       // ["A1:H1", "A2:H2", ...] - what the header spans
book.mergedRangesAt(0);     // the same as numbers: [r1, c1, r2, c2] per area,
                            // one Uint32Array where a big sheet has 300k areas
book.sheetVisibility(0);    // "visible" | "hidden" | "veryHidden"

sheetNames lists every sheet, hidden ones included: the index every other call takes is the sheet's position in the workbook, and skipping the hidden ones would shift it.

usedRangeHint answers the same question as usedRange without ever walking the rows (usedRange walks them only after a cell in an edge column was removed, and the hint may then be wider), and columnWidth and rowHeight come back undefined where the sheet leaves them to the default.

What is on a sheet besides cells

book.comments(0);    // [{ address: "B2", author: "Иванов", text: "сверить" }]
book.hyperlinks(0);  // [{ range, target, external, display, tooltip }]
book.tables(0);      // [{ name, displayName, range, columns, ... }]
book.charts(0);      // [{ name, title, kinds: ["barChart"], seriesCount, anchor }]
book.images(0);      // [{ name, format, byteLength, anchor }] - no bytes
book.imageData(0, 0); // Uint8Array, the picture itself
book.shapes(0);      // [{ name, geometry, text, anchor }]

An anchor is where the object sits, in the numbers a user sees: { kind: "twoCell", row: 3, column: 2 }. An absolute anchor is at a point on the sheet rather than at a cell, so its row and column are null.

Beyond the cells, a file states rules and names, and those are here too: definedNames(), dataValidations(sheet), conditionalFormats(sheet), autoFilter(sheet), pivotTables(sheet), arrayFormulas(sheet), externalBooks(), sheetView(sheet) (frozen rows and columns, zoom, grid lines) and sheetProtection(sheet) with verifySheetPassword. Book.readCsv reads CSV with the delimiter stated rather than guessed.

Styles

cellStyle answers with the number format, font, fill, borders and text placement, as the file states them. A cell the file says nothing about answers with Excel's own defaults, which is what Excel shows for it.

const style = book.cellStyle(0, "A1");
style.font.bold;          // true
style.font.size;          // 14 - points, not the hundredths the file stores
style.fill.foreground;    // "#FFFFE699"
style.borders.bottom;     // { style: "thin", color: "#FF000000" }
style.alignment.wrapText; // true
style.numberFormat;       // "#,##0.00"

Colours come as text: #AARRGGBB when the file names one outright, null where it leaves the choice to the reader, and indexed:N or theme:N when it points into the legacy palette or the workbook theme instead. A theme colour carries its tint as theme:[email protected]. The two indirect forms are not resolved for you - an indexed colour needs the palette of the file it came from, and a theme colour needs the workbook theme, which the reader keeps but does not interpret.

For a block of cells, getRangeStyles(sheet, "A1:H40") answers { styles, grid }: each distinct style once and a grid of indexes into them, which is one crossing instead of a cellStyle per cell. cellStyleAt and getRangeStylesAt take 1-based numbers instead of an address.

Formulas

A formula's text is here (getFormula), and so is the value the file was saved with - get on a formula cell answers with the cached result. What is not here is the engine that would recompute it: evaluate, recalculate and recalculateFrom exist only in the full package.

That cached value is worth exactly what the application that wrote the file is worth. A package with no xl/calcChain.xml was not last saved by Excel, and its cached values may be stale.

Reading a package that expands a long way

Book.read(bytes, name, maxExpanded) takes a ceiling on how far a zipped package may unpack, which is what stops a zip bomb. It defaults to 512 MB; a real workbook can outgrow that - a 100 MB package unpacking to 560 MB is not unusual - so raise it when you know where the file came from.

A callback as the fourth argument hears about each sheet as it is read: { stage, done, total, what, fraction }, with total null until the workbook part says how many sheets there are.

What is not here

Writing, in any format - including painting a cell, writing a note, a link or a table. Recalculation. Editing the grid - inserting and removing rows, columns and sheets - which only makes sense when the result can be saved. Everything else the full package can do with a workbook once it is open - the reading side of it - is.

MIT.