xlvane 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,11 +31,11 @@ From a shell: `npx xlvane inspect orders.xlsx`, then `npx xlvane read orders.xls
31
31
  - [Large files: streaming](#large-files-streaming)
32
32
  - [Inspecting a workbook](#inspecting-a-workbook) · [Errors and warnings](#errors-and-warnings) · [Untrusted input and limits](#untrusted-input-and-limits)
33
33
  - [Limitations](#limitations) · [Package size](#package-size) · [Links](#links)
34
- - exceljs users: [`@xlvane/compat`](https://www.npmjs.com/package/@xlvane/compat) and `xlvane migrate`
34
+ - exceljs users: [`@xlvane/exceljs`](https://www.npmjs.com/package/@xlvane/exceljs) and `xlvane migrate`
35
35
 
36
36
  ## Tested environments
37
37
 
38
- The core API (reading, writing, inspect, tables, CSV, editing, diff, streaming with Web Streams) and `@xlvane/compat` are tested in Node.js 22, 24 and 26, Bun, Deno, Chromium (Playwright) and the Cloudflare Workers runtime (workerd), with the same test bundle (`npm run test:runtimes`). In Deno, import from `npm:xlvane`; in browsers and Workers, through a bundler such as Vite, esbuild or webpack. `xlvane/node` and the command line need Node.js. Reading is tested on 340 files of the Apache POI test corpus (written by Excel for Windows, Mac and the web, LibreOffice, ONLYOFFICE and others, and damaged files) and on files saved by LibreOffice; see `tests/corpus/`.
38
+ The core API (reading, writing, inspect, tables, CSV, editing, diff, streaming with Web Streams) and `@xlvane/exceljs` are tested in Node.js 22, 24 and 26, Bun, Deno, Chromium (Playwright) and the Cloudflare Workers runtime (workerd), with the same test bundle (`npm run test:runtimes`). In Deno, import from `npm:xlvane`; in browsers and Workers, through a bundler such as Vite, esbuild or webpack. `xlvane/node` and the command line need Node.js. Reading is tested on 340 files of the Apache POI test corpus (written by Excel for Windows, Mac and the web, LibreOffice, ONLYOFFICE and others, and damaged files) and on files saved by LibreOffice; see `tests/corpus/`.
39
39
 
40
40
  ## Command line in 5 minutes
41
41
 
@@ -58,7 +58,7 @@ xlvane help edit # usage and examples of one command
58
58
  - `--json` prints one JSON document per command with a documented schema ([docs/cli-json.md](https://github.com/DevXord/xlvane/blob/main/docs/cli-json.md)). Exit codes: 0 success, 1 a check found something (`diff`, `validate`), 2 usage error, 3 input or file error.
59
59
  - Colour (red errors, yellow warnings, green results, bold headings) is used only on a terminal and never carries information alone; `NO_COLOR` or `TERM=dumb` turn it off, `FORCE_COLOR=1` turns it on. Control characters from files, such as an escape character in a cell, are shown as `\x1b` and never reach the terminal.
60
60
  - Tables and summaries go to separate streams: `xlvane read report.xlsx > out.txt` writes only the table; the row count and warnings notes go to stderr.
61
- - `xlvane migrate` prepares a project for `@xlvane/compat`, and `xlvane mcp` starts the MCP server from `@xlvane/mcp` (a separate package; [its README](https://github.com/DevXord/xlvane/blob/main/packages/mcp/README.md)).
61
+ - `xlvane migrate` prepares a project for `@xlvane/exceljs`, and `xlvane mcp` starts the MCP server from `@xlvane/mcp` (a separate package; [its README](https://github.com/DevXord/xlvane/blob/main/packages/mcp/README.md)).
62
62
 
63
63
  ## Reading a workbook
64
64
 
package/dist/cli.js CHANGED
@@ -1977,8 +1977,8 @@ const mcpCommand = {
1977
1977
  }
1978
1978
  };
1979
1979
  // src/cli/commands/migrate.ts
1980
- /** The dependency value that installs @xlvane/compat under the name exceljs (npm alias). */
1981
- const ALIAS = "npm:@xlvane/compat@^1";
1980
+ /** The dependency value that installs @xlvane/exceljs under the name exceljs (npm alias). */
1981
+ const ALIAS = "npm:@xlvane/exceljs@^1";
1982
1982
  const SECTIONS = [
1983
1983
  "dependencies",
1984
1984
  "devDependencies",
@@ -1989,7 +1989,7 @@ const SOURCE = /\.(?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$/;
1989
1989
  const MAX_FILES = 1e4;
1990
1990
  const MAX_FILE_BYTES = 2097152;
1991
1991
  /**
1992
- * exceljs API that @xlvane/compat does not support or supports only partly
1992
+ * exceljs API that @xlvane/exceljs does not support or supports only partly
1993
1993
  * (docs/exceljs-compat.md). Matching is textual, so a hit is a place to look at, not proof.
1994
1994
  */
1995
1995
  const PATTERNS = [{
@@ -2217,8 +2217,8 @@ async function run$1(ctx) {
2217
2217
  lines.push(`${out.bold("Change in")} ${pkgPath}:`);
2218
2218
  for (const c of changes) lines.push(` ${c.section}: ${out.red(`- "exceljs": "${escapeControls(c.from)}"`)}`, ` ${" ".repeat(c.section.length)} ${out.green(`+ "exceljs": "${escapeControls(c.to)}"`)}`);
2219
2219
  }
2220
- lines.push(`Node.js: require('exceljs') of @xlvane/compat needs Node.js 22.12 or later (package.json engines.node: ${typeof engines === "string" ? `"${escapeControls(engines)}"` : "not set"}).`);
2221
- lines.push("", `Scanned ${plural(files.length, "source file")}${limited ? ` (stopped at ${String(MAX_FILES)})` : ""} for exceljs API that @xlvane/compat does not fully support:`);
2220
+ lines.push(`Node.js: require('exceljs') of @xlvane/exceljs needs Node.js 22.12 or later (package.json engines.node: ${typeof engines === "string" ? `"${escapeControls(engines)}"` : "not set"}).`);
2221
+ lines.push("", `Scanned ${plural(files.length, "source file")}${limited ? ` (stopped at ${String(MAX_FILES)})` : ""} for exceljs API that @xlvane/exceljs does not fully support:`);
2222
2222
  if (findings.length === 0) lines.push(" none found.");
2223
2223
  for (const f of findings.slice(0, 200)) lines.push(` ${f.status === "partly" ? out.yellow("partly ") : out.red("not supported")} ${escapeControls(f.file)}:${String(f.line)}:${String(f.column)} ${escapeControls(f.api)}`);
2224
2224
  if (findings.length > 200) lines.push(out.dim(` … ${String(findings.length - 200)} more; use --json for all`));
@@ -2241,8 +2241,8 @@ async function run$1(ctx) {
2241
2241
  }
2242
2242
  const migrateCommand = {
2243
2243
  name: "migrate",
2244
- summary: "Switch a project from exceljs to @xlvane/compat",
2245
- description: "Prepares a project for @xlvane/compat, which offers the commonly used exceljs API. It shows the change to package.json (\"exceljs\": \"npm:@xlvane/compat@^1\", an npm alias, so the code keeps importing \"exceljs\") and lists places in the source code that use exceljs API outside the supported subset. Only files that mention exceljs are scanned (node_modules and dot folders are skipped), and matching is textual. package.json is changed only with --force; nothing else is changed.",
2244
+ summary: "Switch a project from exceljs to @xlvane/exceljs",
2245
+ description: "Prepares a project for @xlvane/exceljs, which offers the commonly used exceljs API. It shows the change to package.json (\"exceljs\": \"npm:@xlvane/exceljs@^1\", an npm alias, so the code keeps importing \"exceljs\") and lists places in the source code that use exceljs API outside the supported subset. Only files that mention exceljs are scanned (node_modules and dot folders are skipped), and matching is textual. package.json is changed only with --force; nothing else is changed.",
2246
2246
  usage: "[project-dir] [options]",
2247
2247
  positionals: {
2248
2248
  min: 0,
package/docs/errors.md CHANGED
@@ -14,7 +14,7 @@ Each code links to its section, which says what to do. The CLI prints the code a
14
14
  | --- | --- |
15
15
  | [`XLV_E_INVALID_INPUT`](#xlv_e_invalid_input) | The input is not what the function expects: `readWorkbook` and `inspect` accept a `Uint8Array`, an `ArrayBuffer` (or another typed-array … |
16
16
  | [`XLV_E_INVALID_OPTION`](#xlv_e_invalid_option) | An option is unknown, has the wrong type or is out of range. |
17
- | [`XLV_E_INVALID_ARGUMENT`](#xlv_e_invalid_argument) | An argument would lose or move data: a method of `@xlvane/compat` where exceljs 4.4.0 accepts it silently, or `appendRows` with array rows when the starting column is ambiguous. |
17
+ | [`XLV_E_INVALID_ARGUMENT`](#xlv_e_invalid_argument) | An argument would lose or move data: a method of `@xlvane/exceljs` where exceljs 4.4.0 accepts it silently, or `appendRows` with array rows when the starting column is ambiguous. |
18
18
  | [`XLV_E_LIMIT_EXCEEDED`](#xlv_e_limit_exceeded) | The file exceeds one of the resource limits (`ReadLimits`): input size, number of ZIP entries, decompressed size of one entry or of all … |
19
19
  | [`XLV_E_NOT_ZIP`](#xlv_e_not_zip) | The input is not a ZIP archive, so it cannot be an XLSX file. |
20
20
  | [`XLV_E_UNSUPPORTED_CONTAINER`](#xlv_e_unsupported_container) | The input is a Compound File Binary container (signature `D0 CF 11 E0 A1 B1 1A E1`). |
@@ -48,7 +48,7 @@ Each code links to its section, which says what to do. The CLI prints the code a
48
48
  | [`XLV_E_INVALID_ROWS`](#xlv_e_invalid_rows) | Rows given to `writeTable`, `fromJSON` or `appendRows` have the wrong shape: not an array, rows mixing objects and arrays, a value that … |
49
49
  | [`XLV_E_JSON_INVALID`](#xlv_e_json_invalid) | The text given to `fromJSON` is not valid JSON. |
50
50
  | [`XLV_E_CSV_MALFORMED`](#xlv_e_csv_malformed) | The CSV text given to `fromCSV` has a quoted field that is never closed, text right after a closing quote, or bytes that are not valid … |
51
- | [`XLV_E_NOT_SUPPORTED`](#xlv_e_not_supported) | `@xlvane/compat` was asked for an exceljs feature it does not implement, for example a rich-text or hyperlink value, images, tables, … |
51
+ | [`XLV_E_NOT_SUPPORTED`](#xlv_e_not_supported) | `@xlvane/exceljs` was asked for an exceljs feature it does not implement, for example a rich-text or hyperlink value, images, tables, … |
52
52
  | [`XLV_E_USAGE`](#xlv_e_usage) | The `xlvane` command line was used incorrectly: an unknown command or option, a missing or extra argument, an option without its value, … |
53
53
  | [`XLV_E_INTERNAL`](#xlv_e_internal) | The `xlvane` command line caught an error that is not an `XlvError`. |
54
54
  | [`XLV_E_NOT_INSTALLED`](#xlv_e_not_installed) | `xlvane mcp` needs the separate package `@xlvane/mcp`, which could not be loaded. |
@@ -89,7 +89,7 @@ The settings of a note box (`box` of a note: `margins` in millimetres from 0 to
89
89
  **Fix:** correct the option name or value.
90
90
 
91
91
  ### XLV_E_INVALID_ARGUMENT
92
- An argument of a method of `@xlvane/compat` is not valid, in a case where exceljs 4.4.0 accepts it and loses or moves data without an error: for example `insertRow(0, …)`, a row position given as a string, a negative count in `spliceRows` or `spliceColumns`, an outline level outside 0–7 set on a row or column (exceljs writes it), `duplicateRow` of a row that does not exist, `insertRows` without an array of values, or rows or columns pushed beyond the sheet (row 1048576, column XFD). `details.method`, `details.argument` and `details.value` name the method, the argument and its value (docs/exceljs-compat.md).
92
+ An argument of a method of `@xlvane/exceljs` is not valid, in a case where exceljs 4.4.0 accepts it and loses or moves data without an error: for example `insertRow(0, …)`, a row position given as a string, a negative count in `spliceRows` or `spliceColumns`, an outline level outside 0–7 set on a row or column (exceljs writes it), `duplicateRow` of a row that does not exist, `insertRows` without an array of values, or rows or columns pushed beyond the sheet (row 1048576, column XFD). `details.method`, `details.argument` and `details.value` name the method, the argument and its value (docs/exceljs-compat.md).
93
93
  `appendRows` throws it for array rows when tables that start in different columns reach the sheet's last used row, so the column where the rows start is ambiguous (D-K04); `details.tables` names the tables and `details.row` the row. Pass object rows keyed by header text.
94
94
  **Fix:** pass a whole number in the range the hint gives (rows from 1, columns from 1), or remove rows at the end of the sheet before inserting.
95
95
 
@@ -98,21 +98,21 @@ The file exceeds one of the resource limits (`ReadLimits`): input size, number o
98
98
 
99
99
  Some limits also bound work derived from a small file (1.1.1, D-H01):
100
100
 
101
- - `maxCells` (`details.limit` `maxCells`, `details.value` the budget): `toCSV`, `readTable`, `toJSON`, `readTableStream`, `xlvane read` and `xlvane convert` write at most `max(maxCells, 16 × cells read)` positions (rows × columns of the output), so a few cells far apart cannot make them produce a value for every position between; `@xlvane/compat`'s `xlsx.load` creates at most as many cells for merged ranges, tables and column definitions, and looks up at most 64 Mi rows (or 16 per cell read) for row settings up to the sheets' dimensions. Pass a smaller `range`, or raise `maxCells` for a trusted file.
101
+ - `maxCells` (`details.limit` `maxCells`, `details.value` the budget): `toCSV`, `readTable`, `toJSON`, `readTableStream`, `xlvane read` and `xlvane convert` write at most `max(maxCells, 16 × cells read)` positions (rows × columns of the output), so a few cells far apart cannot make them produce a value for every position between; `@xlvane/exceljs`'s `xlsx.load` creates at most as many cells for merged ranges, tables and column definitions, and looks up at most 64 Mi rows (or 16 per cell read) for row settings up to the sheets' dimensions. Pass a smaller `range`, or raise `maxCells` for a trusted file.
102
102
  - `maxXmlTextLength`: also the length of an XML comment or processing instruction.
103
103
  - `maxSharedStringChars`: also the text of shared formulas, counted apart from shared strings: the length of each sharing cell's formula, as moved to that cell. From 1.2.3 (D-J01) also the header names that `readTable`, `toJSON` and `readTableStream` repeat in every row object: the sum of the key lengths times the number of rows (a long header over many rows would otherwise make JSON text far larger than the file); `readTableStream` counts one row at a time.
104
104
 
105
105
  From 1.2.3 (D-J01):
106
106
 
107
- - `maxCells`: `fromCSV`, `fromJSON` and `writeTable` write at most `max(maxCells, 16 × cells written)` positions (rows × columns), so one very wide row followed by many short ones cannot make them visit every position; each takes a `maxCells` option (default 5 000 000). While streaming, one `<row>` element may hold at most 16 384 cells (`details.value` 16384), the most a row can have, because its cells are held until the element ends. `@xlvane/compat` `xlsx.load` also counts the cells of defined names against its budget, and its `xlsx.read`, `csv.read` and `stream.xlsx.WorkbookReader` stop collecting a stream after `maxInputBytes` (256 MiB; `details.limit` `maxInputBytes`).
107
+ - `maxCells`: `fromCSV`, `fromJSON` and `writeTable` write at most `max(maxCells, 16 × cells written)` positions (rows × columns), so one very wide row followed by many short ones cannot make them visit every position; each takes a `maxCells` option (default 5 000 000). While streaming, one `<row>` element may hold at most 16 384 cells (`details.value` 16384), the most a row can have, because its cells are held until the element ends. `@xlvane/exceljs` `xlsx.load` also counts the cells of defined names against its budget, and its `xlsx.read`, `csv.read` and `stream.xlsx.WorkbookReader` stop collecting a stream after `maxInputBytes` (256 MiB; `details.limit` `maxInputBytes`).
108
108
 
109
109
  From 1.3.0 (D-K04):
110
110
 
111
111
  - `maxCells`: `editCells` and `appendRows` check, before building any cell, that the cells of the workbook (with a value or only a style) plus the new cells stay within `maxCells`, so the result can be read with the same limits, and they write at most 1 000 000 cells per call unless `limits.maxCells` is given, then at most `maxCells` (`details.limit` `maxCells`, `details.value` the limit). Each cell written takes about 0.5 KB of memory while the file is rebuilt; split the edits into several calls, or pass a larger `maxCells` if there is enough memory.
112
112
  - `maxCells`: `insertRows` with `style: 'above'` or `'below'` (and `xlvane edit --insert-rows` with a style) counts the formatted cells copied into the new rows (the formatted cells of the copied row times the number of rows) plus the cells of the workbook against `maxCells`, before the rows are built. Insert fewer rows, use `style: 'none'`, or raise `maxCells`.
113
- - `sharedFormulaText`: `@xlvane/compat` `cell.formula` of a `{ sharedFormula }` dependent moves the master's formula once and keeps the result; the text moved per workbook (master text read plus moved text built) is limited to 512 Mi characters, the default `maxSharedStringChars` with which `readWorkbook` expands shared formulas, and for masters longer than 8192 characters (the longest formula Office writes, [MS-OI29500] §2.1.1085 a) to 32 Mi characters; also in `stream.xlsx.WorkbookReader` (per read). `location` names the dependent cell; its cached `cell.result` stays readable.
113
+ - `sharedFormulaText`: `@xlvane/exceljs` `cell.formula` of a `{ sharedFormula }` dependent moves the master's formula once and keeps the result; the text moved per workbook (master text read plus moved text built) is limited to 512 Mi characters, the default `maxSharedStringChars` with which `readWorkbook` expands shared formulas, and for masters longer than 8192 characters (the longest formula Office writes, [MS-OI29500] §2.1.1085 a) to 32 Mi characters; also in `stream.xlsx.WorkbookReader` (per read). `location` names the dependent cell; its cached `cell.result` stays readable.
114
114
 
115
- From 1.3.0 (D-K03): `@xlvane/compat` `xlsx.load` limits merged cells to `max(1 048 576, cells in the file)` (`details.limit` `mergedCells`; each merged position becomes a cell, which a row or column style gives a style, so a few bytes of `mergeCell` could ask for millions of styled cells), and `csv.read` stops at more than 1 048 576 rows (`details.limit` `maxRows`) 16 384 fields in a row (`details.limit` `maxColumns`, with `location.line`) or 5 000 000 fields in all (`details.limit` `maxCells`) while it parses.
115
+ From 1.3.0 (D-K03): `@xlvane/exceljs` `xlsx.load` limits merged cells to `max(1 048 576, cells in the file)` (`details.limit` `mergedCells`; each merged position becomes a cell, which a row or column style gives a style, so a few bytes of `mergeCell` could ask for millions of styled cells), and `csv.read` stops at more than 1 048 576 rows (`details.limit` `maxRows`) 16 384 fields in a row (`details.limit` `maxColumns`, with `location.line`) or 5 000 000 fields in all (`details.limit` `maxCells`) while it parses.
116
116
 
117
117
  The MCP server (`@xlvane/mcp`) returns it as a tool error for a file larger than `--max-file-size` (`details.limit` `maxFileBytes`; `convert` to JSON stops building the text at that size), for a workbook with more cells than `--max-cells` (`details.limit` `maxCells`) and for a result longer than `--max-response-chars` (`details.limit` `maxResponseChars`; `read_table` instead returns the rows that fit). `xlvane convert` to JSON returns it when the text would be longer than a JavaScript string can be.
118
118
 
@@ -283,12 +283,12 @@ The CSV text given to `fromCSV` has a quoted field that is never closed, text ri
283
283
  **Fix:** close the quoted field or double the quotes inside it (`""`), or convert the file to UTF-8.
284
284
 
285
285
  ### XLV_E_NOT_SUPPORTED
286
- `@xlvane/compat` was asked for an exceljs feature it does not implement, for example a rich-text or hyperlink value, images, tables, conditional formatting, data validation, notes, CSV, protection or `insertRow`. `details.feature` names it. The error is thrown where the feature is used, so nothing is dropped silently.
286
+ `@xlvane/exceljs` was asked for an exceljs feature it does not implement, for example a rich-text or hyperlink value, images, tables, conditional formatting, data validation, notes, CSV, protection or `insertRow`. `details.feature` names it. The error is thrown where the feature is used, so nothing is dropped silently.
287
287
  `hashPassword` and `verifyPassword` throw it for a hash algorithm other than SHA-1, SHA-256, SHA-384 and SHA-512, and `hashPassword` without a `salt` throws it in a runtime that has no `crypto.getRandomValues` (pass your own random salt there; SR-50, D-C08).
288
288
  `editCells` throws it for an array or shared formula in an edit (it writes plain formulas only), and for a cell inside an array formula's range or the master of a shared formula with other cells in its range (D-E02); `details.cell` names it.
289
289
  `appendRows` throws it when a table ends with a totals row on the sheet's last used row (the new rows would fall below the totals row; the hint gives the `insertRows` call that grows the table instead), or when growing a table for the new rows would overlap another table (D-R03).
290
290
  `insertRows` and `deleteRows` (and `xlvane edit --insert-rows` / `--delete-rows`) also throw it when the sheet has content whose cell references xlvane cannot move yet: tables, charts, shapes and other drawing objects (pictures alone are moved, and deleting rows that would cut a picture is refused), pivot tables, form controls, embedded objects, custom sheet views, threaded comments, extended content such as sparklines or slicers (the conditional formats and data validations of the [MS-XLSX] extension are moved, D-F04), a chart or pivot cache elsewhere that names the sheet (also when the XML escapes the name, such as `R&amp;D`, or quotes it, such as `'O''Brien'!`; pivot cache definitions are found by part name, content type or workbook relationship, D-K04), a drawing, chart or pivot cache relationship whose target is not a part of the package (for example a chart stored under a percent-encoded name; `details.type` and `details.target`), a data table, an array formula the change would split, or a formula or defined name that cannot be adjusted safely (for example a 3-D reference such as `Jan:Mar!A1` that includes the sheet, D-B01). The message names the part or the cell, and `details` gives the element, relationship type or formula.
291
- **Fix:** for `@xlvane/compat`, see docs/exceljs-compat.md for the supported subset; remove the call, or keep using exceljs for files that need the feature.
291
+ **Fix:** for `@xlvane/exceljs`, see docs/exceljs-compat.md for the supported subset; remove the call, or keep using exceljs for files that need the feature.
292
292
  For `insertRows`/`deleteRows`, insert or delete the rows in a spreadsheet application, or remove the named content first.
293
293
 
294
294
  ### XLV_E_USAGE
@@ -1,16 +1,16 @@
1
- # exceljs compatibility (`@xlvane/compat`)
1
+ # exceljs compatibility (`@xlvane/exceljs`)
2
2
 
3
- `@xlvane/compat` offers the commonly used part of the exceljs 4.4.0 API on top of xlvane, so that code written for exceljs keeps working after one change in `package.json`:
3
+ `@xlvane/exceljs` offers the commonly used part of the exceljs 4.4.0 API on top of xlvane, so that code written for exceljs keeps working after one change in `package.json`:
4
4
 
5
5
  ```json
6
6
  "dependencies": {
7
- "exceljs": "npm:@xlvane/compat@^1"
7
+ "exceljs": "npm:@xlvane/exceljs@^1"
8
8
  }
9
9
  ```
10
10
 
11
- npm installs an alias `<alias>@npm:<name>` under the alias name in `node_modules` (npm/cli `docs/lib/content/using-npm/package-spec.md`, "Aliases"), so `require('exceljs')` and `import ExcelJS from 'exceljs'` load `@xlvane/compat`.
11
+ npm installs an alias `<alias>@npm:<name>` under the alias name in `node_modules` (npm/cli `docs/lib/content/using-npm/package-spec.md`, "Aliases"), so `require('exceljs')` and `import ExcelJS from 'exceljs'` load `@xlvane/exceljs`.
12
12
 
13
- - **ESM:** `import ExcelJS from 'exceljs'` works as with exceljs. `@xlvane/compat` is an ES module, so named imports (`import { Workbook } from 'exceljs'`) work too; exceljs 4.4.0 rejects them because it is a CommonJS package.
13
+ - **ESM:** `import ExcelJS from 'exceljs'` works as with exceljs. `@xlvane/exceljs` is an ES module, so named imports (`import { Workbook } from 'exceljs'`) work too; exceljs 4.4.0 rejects them because it is a CommonJS package.
14
14
  - **CommonJS:** `const ExcelJS = require('exceljs')` needs **Node.js 22.12 or later**. The package is ESM-only and exports the `ExcelJS` object under the name `"module.exports"`, which `require()` of an ES module returns directly from Node.js 22.12 on (Node.js `doc/api/modules.md`, "Loading ECMAScript modules using `require()`"). `engines.node` is `>=22.12`.
15
15
  - **Unsupported API** throws an `XlvError` with code `XLV_E_NOT_SUPPORTED`, naming the method (docs/errors.md). Options and settings that are accepted but not handled as exceljs handles them are described with the API they belong to (for example `formatterOptions.objectMode` of `csv.write` has no effect); the [Known differences from the 1.3.0 review](#known-differences-from-the-130-review) lists further differences in values.
16
16
 
@@ -153,7 +153,7 @@ Status: **supported** means the same behaviour as exceljs for the cases covered
153
153
  | Other deep imports (`exceljs/lib/...`) | not supported | Internal files of exceljs; not offered. |
154
154
  | `ModelContainer` | not supported | exceljs exports it as a holder of a workbook model with an `xlsx` property (`lib/exceljs.nodejs.js` L3, `lib/doc/modelcontainer.js`). The class is on the module object so that code referring to it loads; constructing it throws `XLV_E_NOT_SUPPORTED`. `xlvane migrate` lists its uses. |
155
155
  | `RelationshipType`, `DocumentType`, `ReadingOrder` | supported | The enums of `lib/doc/enums.js`, on the module object and as named exports. |
156
- | `PaperSize` | supported | exceljs declares it as a `const enum` in index.d.ts (inlined by TypeScript, absent at run time); @xlvane/compat exports it as an object and on the default export. |
156
+ | `PaperSize` | supported | exceljs declares it as a `const enum` in index.d.ts (inlined by TypeScript, absent at run time); @xlvane/exceljs exports it as an object and on the default export. |
157
157
  | TypeScript types (`ExcelJS.Worksheet`, `ExcelJS.Fill`, `ExcelJS.stream.xlsx.WorkbookWriterOptions`, …) | supported | The type names of exceljs's index.d.ts are exported and usable through `import * as ExcelJS`, `import ExcelJS from`, and `import ExcelJS = require('exceljs')`, under `moduleResolution` bundler, nodenext (ESM and CommonJS) and `module: commonjs` (`tests/exceljs/types-compat.test.ts`, which type-checks code from the exceljs README). In a CommonJS project TypeScript refuses `import ExcelJS = require(...)` of an ES module under `module: node16` (TS1471, checked with TypeScript 5.9.3); `module: nodenext` and `module: commonjs` accept it. `Buffer` is `Uint8Array`. Enums (`ValueType`, `FormulaType`, `ErrorValue`, `PaperSize`) are also types. `WorkbookStreamReaderOptions` is an alias of `WorkbookReaderOptions`. As in exceljs's declarations, `getTable(name)` returns `Table`, `workbook.getImage(id)` returns `Image`, `getImages()[i].range` is required and `fillFormula`'s `results` is `(row, col) => value`, a flat or a 2-D array (index.d.ts L1327, L1342–1346, L1365, L1780); at run time an unknown table name or image id gives `undefined`, as in exceljs. The module object is frozen: adding or replacing its properties (monkey-patching) has no effect. |
158
158
  | Bundling for browsers and Cloudflare Workers | supported | The file helpers of `xlvane/node` are loaded only by `readFile`/`writeFile` and the `filename` forms of the streaming classes, through the package imports `#xlvane-node` and `#node-fs` (package.json `imports`), which resolve to `xlvane/node` and a re-export of `node:fs/promises` under the `node` condition (Node.js, Bun, Deno) and to a module that fails to load elsewhere, so bundlers such as esbuild, vite and wrangler leave out every `node:` import (D-R07); in browsers and Workers these methods throw `XLV_E_NOT_SUPPORTED`. `npm run test:runtimes` bundles the built packages for the browser and runs them in Chromium and workerd. |
159
159
 
@@ -168,7 +168,7 @@ A workbook loaded with `xlsx.load()` is written again by `xlsx.writeBuffer()` (`
168
168
  - Row heights above 409.5 points are read as 409.5; 409.5 itself, which Excel writes, is accepted.
169
169
  - A table whose style is a custom style of the file is written without a style name, because xlvane does not write the file's custom table styles; a style name set in code must still be one of the built-in names.
170
170
  - Totals-row formulas keep their cached results.
171
- - Charts are not kept. exceljs 4.4.0 has no chart API (`lib/` mentions charts only in a comment of `lib/xlsx/xform/book/workbook-xform.js` L174–178; docs/facts/charts.md CH-30) and drops the charts of a file it reads and writes again; `@xlvane/compat` does the same and offers no chart API. xlvane itself writes charts with `NewSheet.addChart` and reads them as `Sheet.charts`.
171
+ - Charts are not kept. exceljs 4.4.0 has no chart API (`lib/` mentions charts only in a comment of `lib/xlsx/xform/book/workbook-xform.js` L174–178; docs/facts/charts.md CH-30) and drops the charts of a file it reads and writes again; `@xlvane/exceljs` does the same and offers no chart API. xlvane itself writes charts with `NewSheet.addChart` and reads them as `Sheet.charts`.
172
172
  - `activeTab` and `firstSheet` count chart sheets in the file; chart sheets are not loaded, so the indexes are mapped to the worksheet they fall on, or the worksheet before a chart sheet.
173
173
  - Row height, visibility and outline level are also read for rows without cells, up to the sheet's `dimension` or its last cell; rows after both are not looked at.
174
174
 
@@ -184,13 +184,13 @@ A workbook loaded with `xlsx.load()` is written again by `xlsx.writeBuffer()` (`
184
184
 
185
185
  ## Known differences found by the cross-check
186
186
 
187
- `tests/exceljs/cross-check.test.ts` runs `tests/exceljs/sample-project` against exceljs 4.4.0 and stores its output in `expected-exceljs-4.4.0.json`. `tests/exceljs/alias.test.ts` requires @xlvane/compat to produce the same output, except for the entries of `KNOWN_DIFFERENCES` in `tests/exceljs/project-helper.ts`, which are listed here:
187
+ `tests/exceljs/cross-check.test.ts` runs `tests/exceljs/sample-project` against exceljs 4.4.0 and stores its output in `expected-exceljs-4.4.0.json`. `tests/exceljs/alias.test.ts` requires @xlvane/exceljs to produce the same output, except for the entries of `KNOWN_DIFFERENCES` in `tests/exceljs/project-helper.ts`, which are listed here:
188
188
 
189
189
  - None so far for what the sample reads back. The sample covers document properties (including `company` and `manager`), rich text, a column style, defined names (including `cell.name`), the built-in date format, a tab colour, a zoomed frozen view external, `mailto:` and `#` links (without tooltips, which exceljs does not read back), gradient fills, a diagonal border, alignment (`textRotation`, `shrinkToFit`, `readingOrder`) and protection, a shared formula from `fillFormula`, outline levels of rows and columns, workbook views, and `insertRow` with style `'i'`, `spliceRows`, `duplicateRow`, `spliceColumns`, `insertRows` and `row.splice` on plain values (no formulas, merges, notes or names, which exceljs does not move); CSV written with the default and with custom options and read back (no formula-like text, no formula result 0, no gap before the first row); `cross-check.test.ts` and `alias.test.ts` also run the documented deep imports (`deep-imports.cjs`); `alias.test.ts` also checks that LibreOffice shows the dates as exceljs's files do (`1/31/2024`).
190
190
 
191
191
  ## Known differences from the 1.3.0 review
192
192
 
193
- Found by a review of 1.3.0 and checked by running exceljs 4.4.0 and `@xlvane/compat` on the same input (Node.js 22.23). F6 describes a difference that xlvane keeps, and F8 values that xlvane refuses. F1, F2, F3, F4, F5, F7, F9, F10 and F12 of that review (merged-cell styles, row styles, the default font, six-digit colours, upper-case date formats, CSV formatter options, `latin1` CSV reading, `column.eachCell`) are fixed in 1.3.1 and described in the tables above, with the differences that remain.
193
+ Found by a review of 1.3.0 and checked by running exceljs 4.4.0 and `@xlvane/exceljs` on the same input (Node.js 22.23). F6 describes a difference that xlvane keeps, and F8 values that xlvane refuses. F1, F2, F3, F4, F5, F7, F9, F10 and F12 of that review (merged-cell styles, row styles, the default font, six-digit colours, upper-case date formats, CSV formatter options, `latin1` CSV reading, `column.eachCell`) are fixed in 1.3.1 and described in the tables above, with the differences that remain.
194
194
 
195
195
  - **F6** Dates from 1900-01-01 to 1900-02-28 differ by one day. xlvane writes and reads them with serial 1 = 1900-01-01 (ECMA-376 Part 4 §15.3.4, docs/facts/ecma-376.md E-15); exceljs writes 1900-01-15 as serial 16 and reads serial 15 as 1900-01-14 (`lib/utils/utils.js` L55-61), so here exceljs is the one that is off, and xlvane keeps its reading. From 1900-03-01 on both agree. Serial 60 (the 29 February 1900 that does not exist) and negative serials with a date format read as numbers (exceljs gives 1900-02-28 and dates before 1899-12-30). In a workbook with the 1904 date system a `Date` before 1904-01-01, such as a time-only value given as 1899-12-30 plus the time, throws `XLV_E_INVALID_VALUE` when written; exceljs writes a negative serial (-1461.44... for 1899-12-30T13:20). Time-only values in the 1900 date system and upper-case date formats such as `DD.MM.YYYY` (F6 and F7 of the 1.3.0 review) behave as in exceljs from 1.3.1.
196
196
  - **F8** Values exceljs writes without checks (`lib/xlsx/xform/sheet/cell-xform.js` L199-250, `render`) that xlvane refuses with `XLV_E_INVALID_VALUE` when the workbook is written: `NaN` and `Infinity` (exceljs writes `<v>NaN</v>`, `<v>Infinity</v>`), an invalid `Date` (exceljs writes `<v>NaN</v>`), dates before 1900-01-01 or after 9999-12-31 (exceljs writes the serial, for example -18260 for 1850-01-01), text of more than 32 767 characters, text with an unpaired UTF-16 surrogate, and formulas of more than 8 192 characters.
@@ -2,21 +2,21 @@
2
2
 
3
3
  xlvane is not affiliated with the ExcelJS project; its name is used only to identify the package.
4
4
 
5
- `@xlvane/compat` offers the commonly used part of the exceljs 4.4.0 API on top of xlvane. It is installed under the name `exceljs` with an npm alias, so code that imports `exceljs` keeps its imports:
5
+ `@xlvane/exceljs` offers the commonly used part of the exceljs 4.4.0 API on top of xlvane. It is installed under the name `exceljs` with an npm alias, so code that imports `exceljs` keeps its imports:
6
6
 
7
7
  ```json
8
8
  "dependencies": {
9
- "exceljs": "npm:@xlvane/compat@^1"
9
+ "exceljs": "npm:@xlvane/exceljs@^1"
10
10
  }
11
11
  ```
12
12
 
13
- npm installs an alias `<alias>@npm:<name>` under the alias name in `node_modules` (npm/cli `docs/lib/content/using-npm/package-spec.md`, "Aliases"; docs/exceljs-compat.md), so `import ExcelJS from 'exceljs'` and `require('exceljs')` load `@xlvane/compat`. What is supported, partly supported and not supported is listed method by method in [docs/exceljs-compat.md](https://github.com/DevXord/xlvane/blob/main/docs/exceljs-compat.md) (also in `node_modules/xlvane/docs/exceljs-compat.md` after installing xlvane).
13
+ npm installs an alias `<alias>@npm:<name>` under the alias name in `node_modules` (npm/cli `docs/lib/content/using-npm/package-spec.md`, "Aliases"; docs/exceljs-compat.md), so `import ExcelJS from 'exceljs'` and `require('exceljs')` load `@xlvane/exceljs`. What is supported, partly supported and not supported is listed method by method in [docs/exceljs-compat.md](https://github.com/DevXord/xlvane/blob/main/docs/exceljs-compat.md) (also in `node_modules/xlvane/docs/exceljs-compat.md` after installing xlvane).
14
14
 
15
15
  This guide uses the `xlvane migrate` command of the `xlvane` package. The `xlvane` commands, the report shown below and the TypeScript examples are checked by the tests in `tests/docs/`; the npm commands were run with npm 10.9.9 on 2026-11-03.
16
16
 
17
17
  ## Before you start
18
18
 
19
- - **Node.js.** `@xlvane/compat` is an ES module and declares `engines.node` `>=22.12`. `require('exceljs')` of an ES module works without a flag from Node.js 22.12 (docs/exceljs-compat.md); `import` works too, and so do named imports such as `import { Workbook } from 'exceljs'`.
19
+ - **Node.js.** `@xlvane/exceljs` is an ES module and declares `engines.node` `>=22.12`. `require('exceljs')` of an ES module works without a flag from Node.js 22.12 (docs/exceljs-compat.md); `import` works too, and so do named imports such as `import { Workbook } from 'exceljs'`.
20
20
  - **Version control.** Commit `package.json` and the lockfile first, so the change can be reviewed and undone.
21
21
 
22
22
  ## 1. See what would change
@@ -30,9 +30,9 @@ npx xlvane migrate
30
30
  `xlvane migrate` does the following, and nothing else:
31
31
 
32
32
  1. It reads `package.json` of the project directory (the current directory, or the directory given as the first argument). A `package.json` that is a symbolic link is refused.
33
- 2. It looks for an `"exceljs"` entry in `dependencies`, `devDependencies`, `optionalDependencies` and `peerDependencies`, and shows how each would change to `"npm:@xlvane/compat@^1"`. Other sections, such as `overrides`, are not changed.
33
+ 2. It looks for an `"exceljs"` entry in `dependencies`, `devDependencies`, `optionalDependencies` and `peerDependencies`, and shows how each would change to `"npm:@xlvane/exceljs@^1"`. Other sections, such as `overrides`, are not changed.
34
34
  3. It prints the Node.js requirement of `require('exceljs')` next to the project's own `engines.node`.
35
- 4. It scans the source files of the project (`.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, `.tsx`, up to 2 MiB each and 10 000 files) for exceljs API that `@xlvane/compat` does not support: `ModelContainer` and deep imports of `exceljs/lib/...`. Only files that contain the text `exceljs` are checked; `node_modules`, folders whose names start with a dot, and symbolic links are skipped. The matching is textual, so a finding is a place to look at, not proof.
35
+ 4. It scans the source files of the project (`.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, `.tsx`, up to 2 MiB each and 10 000 files) for exceljs API that `@xlvane/exceljs` does not support: `ModelContainer` and deep imports of `exceljs/lib/...`. Only files that contain the text `exceljs` are checked; `node_modules`, folders whose names start with a dot, and symbolic links are skipped. The matching is textual, so a finding is a place to look at, not proof.
36
36
  5. It writes nothing unless `--force` is given.
37
37
 
38
38
  For a project whose `package.json` has `"exceljs": "^4.4.0"` in `dependencies`, with a file `src/report.js` that imports `exceljs` and a file `src/legacy.cjs` that requires `exceljs/lib/xlsx/xform/base-xform`, the report is:
@@ -40,10 +40,10 @@ For a project whose `package.json` has `"exceljs": "^4.4.0"` in `dependencies`,
40
40
  ```text
41
41
  Change in package.json:
42
42
  dependencies: - "exceljs": "^4.4.0"
43
- + "exceljs": "npm:@xlvane/compat@^1"
44
- Node.js: require('exceljs') of @xlvane/compat needs Node.js 22.12 or later (package.json engines.node: not set).
43
+ + "exceljs": "npm:@xlvane/exceljs@^1"
44
+ Node.js: require('exceljs') of @xlvane/exceljs needs Node.js 22.12 or later (package.json engines.node: not set).
45
45
 
46
- Scanned 2 source files for exceljs API that @xlvane/compat does not fully support:
46
+ Scanned 2 source files for exceljs API that @xlvane/exceljs does not fully support:
47
47
  not supported src/legacy.cjs:1:27 deep import (exceljs/lib/...)
48
48
  Details: docs/exceljs-compat.md. Unsupported calls throw XLV_E_NOT_SUPPORTED at run time.
49
49
 
@@ -61,18 +61,18 @@ npx xlvane migrate --json
61
61
  ```sh
62
62
  npx xlvane migrate --force --dry-run # show the change without writing it
63
63
  npx xlvane migrate --force # change package.json
64
- npm install # install @xlvane/compat under the name exceljs
64
+ npm install # install @xlvane/exceljs under the name exceljs
65
65
  ```
66
66
 
67
67
  `--force` replaces only the value of each `"exceljs"` entry; the rest of `package.json` keeps its formatting and key order. Instead of `xlvane migrate`, the alias can also be installed directly:
68
68
 
69
69
  ```sh
70
- npm install exceljs@npm:@xlvane/compat@^1
70
+ npm install exceljs@npm:@xlvane/exceljs@^1
71
71
  ```
72
72
 
73
- npm then saves the version it installed as the range (with npm 10.9.9 and `@xlvane/compat` 1.2.2: `"exceljs": "npm:@xlvane/compat@^1.2.2"`).
73
+ npm then saves the version it installed as the range (with npm 10.9.9 and `@xlvane/exceljs` 1.2.2: `"exceljs": "npm:@xlvane/exceljs@^1.2.2"`).
74
74
 
75
- The code stays as it was. For example, this exceljs code runs unchanged on `@xlvane/compat`:
75
+ The code stays as it was. For example, this exceljs code runs unchanged on `@xlvane/exceljs`:
76
76
 
77
77
  ```ts
78
78
  import ExcelJS from 'exceljs';
@@ -97,7 +97,7 @@ In CommonJS, `const ExcelJS = require('exceljs');` gives the same object.
97
97
 
98
98
  - **Run the project's tests.** Unsupported API throws an `XlvError` whose `code` is `XLV_E_NOT_SUPPORTED` and whose message names the method; nothing is dropped silently.
99
99
  - **Look at each finding of `xlvane migrate`.** Deep imports of `exceljs/lib/...` do not resolve (`exceljs/dist/es5` and the `exceljs/dist/exceljs*.js` files do); `ModelContainer` throws `XLV_E_NOT_SUPPORTED` when it is constructed.
100
- - **Read the differences.** [docs/exceljs-compat.md](https://github.com/DevXord/xlvane/blob/main/docs/exceljs-compat.md) lists every method with its status and the exceljs source of each behaviour, and ends with the differences found in reviews and cross-checks. The ones most likely to matter are summarised in the [@xlvane/compat README](https://github.com/DevXord/xlvane/blob/main/packages/compat/README.md#differences-from-exceljs): CSV output escapes text that starts like a formula (`formulaInjection: "off"` writes it unchanged, as exceljs does), a sheet id outside 1 to 65534 is written as the lowest unused id, only the first view of a worksheet is written, the module object is frozen, the streaming writer compresses in JavaScript, and input files are checked against ZIP and XML limits.
100
+ - **Read the differences.** [docs/exceljs-compat.md](https://github.com/DevXord/xlvane/blob/main/docs/exceljs-compat.md) lists every method with its status and the exceljs source of each behaviour, and ends with the differences found in reviews and cross-checks. The ones most likely to matter are summarised in the [@xlvane/exceljs README](https://github.com/DevXord/xlvane/blob/main/packages/exceljs/README.md#differences-from-exceljs): CSV output escapes text that starts like a formula (`formulaInjection: "off"` writes it unchanged, as exceljs does), a sheet id outside 1 to 65534 is written as the lowest unused id, only the first view of a worksheet is written, the module object is frozen, the streaming writer compresses in JavaScript, and input files are checked against ZIP and XML limits.
101
101
  - **TypeScript.** The type names of exceljs's `index.d.ts` are exported and work with `moduleResolution` `bundler` and `nodenext` and with `module: commonjs`. Under `module: node16`, TypeScript refuses `import ExcelJS = require('exceljs')` of an ES module (TS1471); use `nodenext` or `commonjs`.
102
102
  - **Browsers and Workers.** The methods that read or write files (`xlsx.readFile`, `xlsx.writeFile`, `csv.readFile`, `csv.writeFile`, the `filename` forms of the streaming classes and of `addImage`) work in Node.js, Bun and Deno; in browsers and Workers they throw `XLV_E_NOT_SUPPORTED`.
103
103
 
@@ -111,7 +111,7 @@ try {
111
111
  await workbook.xlsx.readFile('report.xlsx');
112
112
  } catch (error) {
113
113
  const code = (error as { code?: unknown }).code;
114
- if (code === 'XLV_E_NOT_SUPPORTED') console.error('Not supported by @xlvane/compat:', (error as Error).message);
114
+ if (code === 'XLV_E_NOT_SUPPORTED') console.error('Not supported by @xlvane/exceljs:', (error as Error).message);
115
115
  else throw error;
116
116
  }
117
117
  ```
@@ -128,4 +128,4 @@ npm replaces the alias in `package.json` and `node_modules`. Restoring `package.
128
128
 
129
129
  ## Reporting a problem
130
130
 
131
- When exceljs code behaves differently on `@xlvane/compat` and the difference is not listed in docs/exceljs-compat.md, please open an issue at https://github.com/DevXord/xlvane/issues with a small script that shows it.
131
+ When exceljs code behaves differently on `@xlvane/exceljs` and the difference is not listed in docs/exceljs-compat.md, please open an issue at https://github.com/DevXord/xlvane/issues with a small script that shows it.
package/llms-full.txt CHANGED
@@ -1,4 +1,4 @@
1
- # xlvane 1.3.1: documentation in one file
1
+ # xlvane 1.3.3: documentation in one file
2
2
 
3
3
  This file joins the README of the xlvane package, the Agent Skill and the documentation in docs/. It is generated by scripts/package-docs.mjs; the separate files are in the same package.
4
4
 
@@ -37,11 +37,11 @@ From a shell: `npx xlvane inspect orders.xlsx`, then `npx xlvane read orders.xls
37
37
  - [Large files: streaming](#large-files-streaming)
38
38
  - [Inspecting a workbook](#inspecting-a-workbook) · [Errors and warnings](#errors-and-warnings) · [Untrusted input and limits](#untrusted-input-and-limits)
39
39
  - [Limitations](#limitations) · [Package size](#package-size) · [Links](#links)
40
- - exceljs users: [`@xlvane/compat`](https://www.npmjs.com/package/@xlvane/compat) and `xlvane migrate`
40
+ - exceljs users: [`@xlvane/exceljs`](https://www.npmjs.com/package/@xlvane/exceljs) and `xlvane migrate`
41
41
 
42
42
  ## Tested environments
43
43
 
44
- The core API (reading, writing, inspect, tables, CSV, editing, diff, streaming with Web Streams) and `@xlvane/compat` are tested in Node.js 22, 24 and 26, Bun, Deno, Chromium (Playwright) and the Cloudflare Workers runtime (workerd), with the same test bundle (`npm run test:runtimes`). In Deno, import from `npm:xlvane`; in browsers and Workers, through a bundler such as Vite, esbuild or webpack. `xlvane/node` and the command line need Node.js. Reading is tested on 340 files of the Apache POI test corpus (written by Excel for Windows, Mac and the web, LibreOffice, ONLYOFFICE and others, and damaged files) and on files saved by LibreOffice; see `tests/corpus/`.
44
+ The core API (reading, writing, inspect, tables, CSV, editing, diff, streaming with Web Streams) and `@xlvane/exceljs` are tested in Node.js 22, 24 and 26, Bun, Deno, Chromium (Playwright) and the Cloudflare Workers runtime (workerd), with the same test bundle (`npm run test:runtimes`). In Deno, import from `npm:xlvane`; in browsers and Workers, through a bundler such as Vite, esbuild or webpack. `xlvane/node` and the command line need Node.js. Reading is tested on 340 files of the Apache POI test corpus (written by Excel for Windows, Mac and the web, LibreOffice, ONLYOFFICE and others, and damaged files) and on files saved by LibreOffice; see `tests/corpus/`.
45
45
 
46
46
  ## Command line in 5 minutes
47
47
 
@@ -64,7 +64,7 @@ xlvane help edit # usage and examples of one command
64
64
  - `--json` prints one JSON document per command with a documented schema ([docs/cli-json.md](https://github.com/DevXord/xlvane/blob/main/docs/cli-json.md)). Exit codes: 0 success, 1 a check found something (`diff`, `validate`), 2 usage error, 3 input or file error.
65
65
  - Colour (red errors, yellow warnings, green results, bold headings) is used only on a terminal and never carries information alone; `NO_COLOR` or `TERM=dumb` turn it off, `FORCE_COLOR=1` turns it on. Control characters from files, such as an escape character in a cell, are shown as `\x1b` and never reach the terminal.
66
66
  - Tables and summaries go to separate streams: `xlvane read report.xlsx > out.txt` writes only the table; the row count and warnings notes go to stderr.
67
- - `xlvane migrate` prepares a project for `@xlvane/compat`, and `xlvane mcp` starts the MCP server from `@xlvane/mcp` (a separate package; [its README](https://github.com/DevXord/xlvane/blob/main/packages/mcp/README.md)).
67
+ - `xlvane migrate` prepares a project for `@xlvane/exceljs`, and `xlvane mcp` starts the MCP server from `@xlvane/mcp` (a separate package; [its README](https://github.com/DevXord/xlvane/blob/main/packages/mcp/README.md)).
68
68
 
69
69
  ## Reading a workbook
70
70
 
@@ -639,7 +639,7 @@ Formulas on every sheet, merged cells, links, notes, conditional formats (also e
639
639
 
640
640
  In Node.js, `xlvane/node` adds `readWorkbookFile`, `inspectFile` and `writeWorkbookFile` (which never replaces an existing file unless `{ overwrite: true }` is passed). `toCSV`, `fromCSV`, `toJSON` and `fromJSON` convert tables. For very large files use `openWorkbookStream` and `writeWorkbookStream`.
641
641
 
642
- Code written for the `exceljs` API can run on xlvane through `@xlvane/compat` (`"exceljs": "npm:@xlvane/compat@^1"` in package.json); unsupported exceljs features throw `XLV_E_NOT_SUPPORTED`.
642
+ Code written for the `exceljs` API can run on xlvane through `@xlvane/exceljs` (`"exceljs": "npm:@xlvane/exceljs@^1"` in package.json); unsupported exceljs features throw `XLV_E_NOT_SUPPORTED`.
643
643
 
644
644
  ## Command line
645
645
 
@@ -697,7 +697,7 @@ Each code links to its section, which says what to do. The CLI prints the code a
697
697
  | --- | --- |
698
698
  | [`XLV_E_INVALID_INPUT`](#xlv_e_invalid_input) | The input is not what the function expects: `readWorkbook` and `inspect` accept a `Uint8Array`, an `ArrayBuffer` (or another typed-array … |
699
699
  | [`XLV_E_INVALID_OPTION`](#xlv_e_invalid_option) | An option is unknown, has the wrong type or is out of range. |
700
- | [`XLV_E_INVALID_ARGUMENT`](#xlv_e_invalid_argument) | An argument would lose or move data: a method of `@xlvane/compat` where exceljs 4.4.0 accepts it silently, or `appendRows` with array rows when the starting column is ambiguous. |
700
+ | [`XLV_E_INVALID_ARGUMENT`](#xlv_e_invalid_argument) | An argument would lose or move data: a method of `@xlvane/exceljs` where exceljs 4.4.0 accepts it silently, or `appendRows` with array rows when the starting column is ambiguous. |
701
701
  | [`XLV_E_LIMIT_EXCEEDED`](#xlv_e_limit_exceeded) | The file exceeds one of the resource limits (`ReadLimits`): input size, number of ZIP entries, decompressed size of one entry or of all … |
702
702
  | [`XLV_E_NOT_ZIP`](#xlv_e_not_zip) | The input is not a ZIP archive, so it cannot be an XLSX file. |
703
703
  | [`XLV_E_UNSUPPORTED_CONTAINER`](#xlv_e_unsupported_container) | The input is a Compound File Binary container (signature `D0 CF 11 E0 A1 B1 1A E1`). |
@@ -731,7 +731,7 @@ Each code links to its section, which says what to do. The CLI prints the code a
731
731
  | [`XLV_E_INVALID_ROWS`](#xlv_e_invalid_rows) | Rows given to `writeTable`, `fromJSON` or `appendRows` have the wrong shape: not an array, rows mixing objects and arrays, a value that … |
732
732
  | [`XLV_E_JSON_INVALID`](#xlv_e_json_invalid) | The text given to `fromJSON` is not valid JSON. |
733
733
  | [`XLV_E_CSV_MALFORMED`](#xlv_e_csv_malformed) | The CSV text given to `fromCSV` has a quoted field that is never closed, text right after a closing quote, or bytes that are not valid … |
734
- | [`XLV_E_NOT_SUPPORTED`](#xlv_e_not_supported) | `@xlvane/compat` was asked for an exceljs feature it does not implement, for example a rich-text or hyperlink value, images, tables, … |
734
+ | [`XLV_E_NOT_SUPPORTED`](#xlv_e_not_supported) | `@xlvane/exceljs` was asked for an exceljs feature it does not implement, for example a rich-text or hyperlink value, images, tables, … |
735
735
  | [`XLV_E_USAGE`](#xlv_e_usage) | The `xlvane` command line was used incorrectly: an unknown command or option, a missing or extra argument, an option without its value, … |
736
736
  | [`XLV_E_INTERNAL`](#xlv_e_internal) | The `xlvane` command line caught an error that is not an `XlvError`. |
737
737
  | [`XLV_E_NOT_INSTALLED`](#xlv_e_not_installed) | `xlvane mcp` needs the separate package `@xlvane/mcp`, which could not be loaded. |
@@ -772,7 +772,7 @@ The settings of a note box (`box` of a note: `margins` in millimetres from 0 to
772
772
  **Fix:** correct the option name or value.
773
773
 
774
774
  ### XLV_E_INVALID_ARGUMENT
775
- An argument of a method of `@xlvane/compat` is not valid, in a case where exceljs 4.4.0 accepts it and loses or moves data without an error: for example `insertRow(0, …)`, a row position given as a string, a negative count in `spliceRows` or `spliceColumns`, an outline level outside 0–7 set on a row or column (exceljs writes it), `duplicateRow` of a row that does not exist, `insertRows` without an array of values, or rows or columns pushed beyond the sheet (row 1048576, column XFD). `details.method`, `details.argument` and `details.value` name the method, the argument and its value (docs/exceljs-compat.md).
775
+ An argument of a method of `@xlvane/exceljs` is not valid, in a case where exceljs 4.4.0 accepts it and loses or moves data without an error: for example `insertRow(0, …)`, a row position given as a string, a negative count in `spliceRows` or `spliceColumns`, an outline level outside 0–7 set on a row or column (exceljs writes it), `duplicateRow` of a row that does not exist, `insertRows` without an array of values, or rows or columns pushed beyond the sheet (row 1048576, column XFD). `details.method`, `details.argument` and `details.value` name the method, the argument and its value (docs/exceljs-compat.md).
776
776
  `appendRows` throws it for array rows when tables that start in different columns reach the sheet's last used row, so the column where the rows start is ambiguous (D-K04); `details.tables` names the tables and `details.row` the row. Pass object rows keyed by header text.
777
777
  **Fix:** pass a whole number in the range the hint gives (rows from 1, columns from 1), or remove rows at the end of the sheet before inserting.
778
778
 
@@ -781,21 +781,21 @@ The file exceeds one of the resource limits (`ReadLimits`): input size, number o
781
781
 
782
782
  Some limits also bound work derived from a small file (1.1.1, D-H01):
783
783
 
784
- - `maxCells` (`details.limit` `maxCells`, `details.value` the budget): `toCSV`, `readTable`, `toJSON`, `readTableStream`, `xlvane read` and `xlvane convert` write at most `max(maxCells, 16 × cells read)` positions (rows × columns of the output), so a few cells far apart cannot make them produce a value for every position between; `@xlvane/compat`'s `xlsx.load` creates at most as many cells for merged ranges, tables and column definitions, and looks up at most 64 Mi rows (or 16 per cell read) for row settings up to the sheets' dimensions. Pass a smaller `range`, or raise `maxCells` for a trusted file.
784
+ - `maxCells` (`details.limit` `maxCells`, `details.value` the budget): `toCSV`, `readTable`, `toJSON`, `readTableStream`, `xlvane read` and `xlvane convert` write at most `max(maxCells, 16 × cells read)` positions (rows × columns of the output), so a few cells far apart cannot make them produce a value for every position between; `@xlvane/exceljs`'s `xlsx.load` creates at most as many cells for merged ranges, tables and column definitions, and looks up at most 64 Mi rows (or 16 per cell read) for row settings up to the sheets' dimensions. Pass a smaller `range`, or raise `maxCells` for a trusted file.
785
785
  - `maxXmlTextLength`: also the length of an XML comment or processing instruction.
786
786
  - `maxSharedStringChars`: also the text of shared formulas, counted apart from shared strings: the length of each sharing cell's formula, as moved to that cell. From 1.2.3 (D-J01) also the header names that `readTable`, `toJSON` and `readTableStream` repeat in every row object: the sum of the key lengths times the number of rows (a long header over many rows would otherwise make JSON text far larger than the file); `readTableStream` counts one row at a time.
787
787
 
788
788
  From 1.2.3 (D-J01):
789
789
 
790
- - `maxCells`: `fromCSV`, `fromJSON` and `writeTable` write at most `max(maxCells, 16 × cells written)` positions (rows × columns), so one very wide row followed by many short ones cannot make them visit every position; each takes a `maxCells` option (default 5 000 000). While streaming, one `<row>` element may hold at most 16 384 cells (`details.value` 16384), the most a row can have, because its cells are held until the element ends. `@xlvane/compat` `xlsx.load` also counts the cells of defined names against its budget, and its `xlsx.read`, `csv.read` and `stream.xlsx.WorkbookReader` stop collecting a stream after `maxInputBytes` (256 MiB; `details.limit` `maxInputBytes`).
790
+ - `maxCells`: `fromCSV`, `fromJSON` and `writeTable` write at most `max(maxCells, 16 × cells written)` positions (rows × columns), so one very wide row followed by many short ones cannot make them visit every position; each takes a `maxCells` option (default 5 000 000). While streaming, one `<row>` element may hold at most 16 384 cells (`details.value` 16384), the most a row can have, because its cells are held until the element ends. `@xlvane/exceljs` `xlsx.load` also counts the cells of defined names against its budget, and its `xlsx.read`, `csv.read` and `stream.xlsx.WorkbookReader` stop collecting a stream after `maxInputBytes` (256 MiB; `details.limit` `maxInputBytes`).
791
791
 
792
792
  From 1.3.0 (D-K04):
793
793
 
794
794
  - `maxCells`: `editCells` and `appendRows` check, before building any cell, that the cells of the workbook (with a value or only a style) plus the new cells stay within `maxCells`, so the result can be read with the same limits, and they write at most 1 000 000 cells per call unless `limits.maxCells` is given, then at most `maxCells` (`details.limit` `maxCells`, `details.value` the limit). Each cell written takes about 0.5 KB of memory while the file is rebuilt; split the edits into several calls, or pass a larger `maxCells` if there is enough memory.
795
795
  - `maxCells`: `insertRows` with `style: 'above'` or `'below'` (and `xlvane edit --insert-rows` with a style) counts the formatted cells copied into the new rows (the formatted cells of the copied row times the number of rows) plus the cells of the workbook against `maxCells`, before the rows are built. Insert fewer rows, use `style: 'none'`, or raise `maxCells`.
796
- - `sharedFormulaText`: `@xlvane/compat` `cell.formula` of a `{ sharedFormula }` dependent moves the master's formula once and keeps the result; the text moved per workbook (master text read plus moved text built) is limited to 512 Mi characters, the default `maxSharedStringChars` with which `readWorkbook` expands shared formulas, and for masters longer than 8192 characters (the longest formula Office writes, [MS-OI29500] §2.1.1085 a) to 32 Mi characters; also in `stream.xlsx.WorkbookReader` (per read). `location` names the dependent cell; its cached `cell.result` stays readable.
796
+ - `sharedFormulaText`: `@xlvane/exceljs` `cell.formula` of a `{ sharedFormula }` dependent moves the master's formula once and keeps the result; the text moved per workbook (master text read plus moved text built) is limited to 512 Mi characters, the default `maxSharedStringChars` with which `readWorkbook` expands shared formulas, and for masters longer than 8192 characters (the longest formula Office writes, [MS-OI29500] §2.1.1085 a) to 32 Mi characters; also in `stream.xlsx.WorkbookReader` (per read). `location` names the dependent cell; its cached `cell.result` stays readable.
797
797
 
798
- From 1.3.0 (D-K03): `@xlvane/compat` `xlsx.load` limits merged cells to `max(1 048 576, cells in the file)` (`details.limit` `mergedCells`; each merged position becomes a cell, which a row or column style gives a style, so a few bytes of `mergeCell` could ask for millions of styled cells), and `csv.read` stops at more than 1 048 576 rows (`details.limit` `maxRows`) 16 384 fields in a row (`details.limit` `maxColumns`, with `location.line`) or 5 000 000 fields in all (`details.limit` `maxCells`) while it parses.
798
+ From 1.3.0 (D-K03): `@xlvane/exceljs` `xlsx.load` limits merged cells to `max(1 048 576, cells in the file)` (`details.limit` `mergedCells`; each merged position becomes a cell, which a row or column style gives a style, so a few bytes of `mergeCell` could ask for millions of styled cells), and `csv.read` stops at more than 1 048 576 rows (`details.limit` `maxRows`) 16 384 fields in a row (`details.limit` `maxColumns`, with `location.line`) or 5 000 000 fields in all (`details.limit` `maxCells`) while it parses.
799
799
 
800
800
  The MCP server (`@xlvane/mcp`) returns it as a tool error for a file larger than `--max-file-size` (`details.limit` `maxFileBytes`; `convert` to JSON stops building the text at that size), for a workbook with more cells than `--max-cells` (`details.limit` `maxCells`) and for a result longer than `--max-response-chars` (`details.limit` `maxResponseChars`; `read_table` instead returns the rows that fit). `xlvane convert` to JSON returns it when the text would be longer than a JavaScript string can be.
801
801
 
@@ -966,12 +966,12 @@ The CSV text given to `fromCSV` has a quoted field that is never closed, text ri
966
966
  **Fix:** close the quoted field or double the quotes inside it (`""`), or convert the file to UTF-8.
967
967
 
968
968
  ### XLV_E_NOT_SUPPORTED
969
- `@xlvane/compat` was asked for an exceljs feature it does not implement, for example a rich-text or hyperlink value, images, tables, conditional formatting, data validation, notes, CSV, protection or `insertRow`. `details.feature` names it. The error is thrown where the feature is used, so nothing is dropped silently.
969
+ `@xlvane/exceljs` was asked for an exceljs feature it does not implement, for example a rich-text or hyperlink value, images, tables, conditional formatting, data validation, notes, CSV, protection or `insertRow`. `details.feature` names it. The error is thrown where the feature is used, so nothing is dropped silently.
970
970
  `hashPassword` and `verifyPassword` throw it for a hash algorithm other than SHA-1, SHA-256, SHA-384 and SHA-512, and `hashPassword` without a `salt` throws it in a runtime that has no `crypto.getRandomValues` (pass your own random salt there; SR-50, D-C08).
971
971
  `editCells` throws it for an array or shared formula in an edit (it writes plain formulas only), and for a cell inside an array formula's range or the master of a shared formula with other cells in its range (D-E02); `details.cell` names it.
972
972
  `appendRows` throws it when a table ends with a totals row on the sheet's last used row (the new rows would fall below the totals row; the hint gives the `insertRows` call that grows the table instead), or when growing a table for the new rows would overlap another table (D-R03).
973
973
  `insertRows` and `deleteRows` (and `xlvane edit --insert-rows` / `--delete-rows`) also throw it when the sheet has content whose cell references xlvane cannot move yet: tables, charts, shapes and other drawing objects (pictures alone are moved, and deleting rows that would cut a picture is refused), pivot tables, form controls, embedded objects, custom sheet views, threaded comments, extended content such as sparklines or slicers (the conditional formats and data validations of the [MS-XLSX] extension are moved, D-F04), a chart or pivot cache elsewhere that names the sheet (also when the XML escapes the name, such as `R&amp;D`, or quotes it, such as `'O''Brien'!`; pivot cache definitions are found by part name, content type or workbook relationship, D-K04), a drawing, chart or pivot cache relationship whose target is not a part of the package (for example a chart stored under a percent-encoded name; `details.type` and `details.target`), a data table, an array formula the change would split, or a formula or defined name that cannot be adjusted safely (for example a 3-D reference such as `Jan:Mar!A1` that includes the sheet, D-B01). The message names the part or the cell, and `details` gives the element, relationship type or formula.
974
- **Fix:** for `@xlvane/compat`, see docs/exceljs-compat.md for the supported subset; remove the call, or keep using exceljs for files that need the feature.
974
+ **Fix:** for `@xlvane/exceljs`, see docs/exceljs-compat.md for the supported subset; remove the call, or keep using exceljs for files that need the feature.
975
975
  For `insertRows`/`deleteRows`, insert or delete the rows in a spreadsheet application, or remove the named content first.
976
976
 
977
977
  ### XLV_E_USAGE
@@ -1307,19 +1307,19 @@ The error envelope is defined in [cli-json/common.schema.json](cli-json/common.s
1307
1307
 
1308
1308
  <!-- file: docs/exceljs-compat.md -->
1309
1309
 
1310
- # exceljs compatibility (`@xlvane/compat`)
1310
+ # exceljs compatibility (`@xlvane/exceljs`)
1311
1311
 
1312
- `@xlvane/compat` offers the commonly used part of the exceljs 4.4.0 API on top of xlvane, so that code written for exceljs keeps working after one change in `package.json`:
1312
+ `@xlvane/exceljs` offers the commonly used part of the exceljs 4.4.0 API on top of xlvane, so that code written for exceljs keeps working after one change in `package.json`:
1313
1313
 
1314
1314
  ```json
1315
1315
  "dependencies": {
1316
- "exceljs": "npm:@xlvane/compat@^1"
1316
+ "exceljs": "npm:@xlvane/exceljs@^1"
1317
1317
  }
1318
1318
  ```
1319
1319
 
1320
- npm installs an alias `<alias>@npm:<name>` under the alias name in `node_modules` (npm/cli `docs/lib/content/using-npm/package-spec.md`, "Aliases"), so `require('exceljs')` and `import ExcelJS from 'exceljs'` load `@xlvane/compat`.
1320
+ npm installs an alias `<alias>@npm:<name>` under the alias name in `node_modules` (npm/cli `docs/lib/content/using-npm/package-spec.md`, "Aliases"), so `require('exceljs')` and `import ExcelJS from 'exceljs'` load `@xlvane/exceljs`.
1321
1321
 
1322
- - **ESM:** `import ExcelJS from 'exceljs'` works as with exceljs. `@xlvane/compat` is an ES module, so named imports (`import { Workbook } from 'exceljs'`) work too; exceljs 4.4.0 rejects them because it is a CommonJS package.
1322
+ - **ESM:** `import ExcelJS from 'exceljs'` works as with exceljs. `@xlvane/exceljs` is an ES module, so named imports (`import { Workbook } from 'exceljs'`) work too; exceljs 4.4.0 rejects them because it is a CommonJS package.
1323
1323
  - **CommonJS:** `const ExcelJS = require('exceljs')` needs **Node.js 22.12 or later**. The package is ESM-only and exports the `ExcelJS` object under the name `"module.exports"`, which `require()` of an ES module returns directly from Node.js 22.12 on (Node.js `doc/api/modules.md`, "Loading ECMAScript modules using `require()`"). `engines.node` is `>=22.12`.
1324
1324
  - **Unsupported API** throws an `XlvError` with code `XLV_E_NOT_SUPPORTED`, naming the method (docs/errors.md). Options and settings that are accepted but not handled as exceljs handles them are described with the API they belong to (for example `formatterOptions.objectMode` of `csv.write` has no effect); the [Known differences from the 1.3.0 review](#known-differences-from-the-130-review) lists further differences in values.
1325
1325
 
@@ -1462,7 +1462,7 @@ Status: **supported** means the same behaviour as exceljs for the cases covered
1462
1462
  | Other deep imports (`exceljs/lib/...`) | not supported | Internal files of exceljs; not offered. |
1463
1463
  | `ModelContainer` | not supported | exceljs exports it as a holder of a workbook model with an `xlsx` property (`lib/exceljs.nodejs.js` L3, `lib/doc/modelcontainer.js`). The class is on the module object so that code referring to it loads; constructing it throws `XLV_E_NOT_SUPPORTED`. `xlvane migrate` lists its uses. |
1464
1464
  | `RelationshipType`, `DocumentType`, `ReadingOrder` | supported | The enums of `lib/doc/enums.js`, on the module object and as named exports. |
1465
- | `PaperSize` | supported | exceljs declares it as a `const enum` in index.d.ts (inlined by TypeScript, absent at run time); @xlvane/compat exports it as an object and on the default export. |
1465
+ | `PaperSize` | supported | exceljs declares it as a `const enum` in index.d.ts (inlined by TypeScript, absent at run time); @xlvane/exceljs exports it as an object and on the default export. |
1466
1466
  | TypeScript types (`ExcelJS.Worksheet`, `ExcelJS.Fill`, `ExcelJS.stream.xlsx.WorkbookWriterOptions`, …) | supported | The type names of exceljs's index.d.ts are exported and usable through `import * as ExcelJS`, `import ExcelJS from`, and `import ExcelJS = require('exceljs')`, under `moduleResolution` bundler, nodenext (ESM and CommonJS) and `module: commonjs` (`tests/exceljs/types-compat.test.ts`, which type-checks code from the exceljs README). In a CommonJS project TypeScript refuses `import ExcelJS = require(...)` of an ES module under `module: node16` (TS1471, checked with TypeScript 5.9.3); `module: nodenext` and `module: commonjs` accept it. `Buffer` is `Uint8Array`. Enums (`ValueType`, `FormulaType`, `ErrorValue`, `PaperSize`) are also types. `WorkbookStreamReaderOptions` is an alias of `WorkbookReaderOptions`. As in exceljs's declarations, `getTable(name)` returns `Table`, `workbook.getImage(id)` returns `Image`, `getImages()[i].range` is required and `fillFormula`'s `results` is `(row, col) => value`, a flat or a 2-D array (index.d.ts L1327, L1342–1346, L1365, L1780); at run time an unknown table name or image id gives `undefined`, as in exceljs. The module object is frozen: adding or replacing its properties (monkey-patching) has no effect. |
1467
1467
  | Bundling for browsers and Cloudflare Workers | supported | The file helpers of `xlvane/node` are loaded only by `readFile`/`writeFile` and the `filename` forms of the streaming classes, through the package imports `#xlvane-node` and `#node-fs` (package.json `imports`), which resolve to `xlvane/node` and a re-export of `node:fs/promises` under the `node` condition (Node.js, Bun, Deno) and to a module that fails to load elsewhere, so bundlers such as esbuild, vite and wrangler leave out every `node:` import (D-R07); in browsers and Workers these methods throw `XLV_E_NOT_SUPPORTED`. `npm run test:runtimes` bundles the built packages for the browser and runs them in Chromium and workerd. |
1468
1468
 
@@ -1477,7 +1477,7 @@ A workbook loaded with `xlsx.load()` is written again by `xlsx.writeBuffer()` (`
1477
1477
  - Row heights above 409.5 points are read as 409.5; 409.5 itself, which Excel writes, is accepted.
1478
1478
  - A table whose style is a custom style of the file is written without a style name, because xlvane does not write the file's custom table styles; a style name set in code must still be one of the built-in names.
1479
1479
  - Totals-row formulas keep their cached results.
1480
- - Charts are not kept. exceljs 4.4.0 has no chart API (`lib/` mentions charts only in a comment of `lib/xlsx/xform/book/workbook-xform.js` L174–178; docs/facts/charts.md CH-30) and drops the charts of a file it reads and writes again; `@xlvane/compat` does the same and offers no chart API. xlvane itself writes charts with `NewSheet.addChart` and reads them as `Sheet.charts`.
1480
+ - Charts are not kept. exceljs 4.4.0 has no chart API (`lib/` mentions charts only in a comment of `lib/xlsx/xform/book/workbook-xform.js` L174–178; docs/facts/charts.md CH-30) and drops the charts of a file it reads and writes again; `@xlvane/exceljs` does the same and offers no chart API. xlvane itself writes charts with `NewSheet.addChart` and reads them as `Sheet.charts`.
1481
1481
  - `activeTab` and `firstSheet` count chart sheets in the file; chart sheets are not loaded, so the indexes are mapped to the worksheet they fall on, or the worksheet before a chart sheet.
1482
1482
  - Row height, visibility and outline level are also read for rows without cells, up to the sheet's `dimension` or its last cell; rows after both are not looked at.
1483
1483
 
@@ -1493,13 +1493,13 @@ A workbook loaded with `xlsx.load()` is written again by `xlsx.writeBuffer()` (`
1493
1493
 
1494
1494
  ## Known differences found by the cross-check
1495
1495
 
1496
- `tests/exceljs/cross-check.test.ts` runs `tests/exceljs/sample-project` against exceljs 4.4.0 and stores its output in `expected-exceljs-4.4.0.json`. `tests/exceljs/alias.test.ts` requires @xlvane/compat to produce the same output, except for the entries of `KNOWN_DIFFERENCES` in `tests/exceljs/project-helper.ts`, which are listed here:
1496
+ `tests/exceljs/cross-check.test.ts` runs `tests/exceljs/sample-project` against exceljs 4.4.0 and stores its output in `expected-exceljs-4.4.0.json`. `tests/exceljs/alias.test.ts` requires @xlvane/exceljs to produce the same output, except for the entries of `KNOWN_DIFFERENCES` in `tests/exceljs/project-helper.ts`, which are listed here:
1497
1497
 
1498
1498
  - None so far for what the sample reads back. The sample covers document properties (including `company` and `manager`), rich text, a column style, defined names (including `cell.name`), the built-in date format, a tab colour, a zoomed frozen view external, `mailto:` and `#` links (without tooltips, which exceljs does not read back), gradient fills, a diagonal border, alignment (`textRotation`, `shrinkToFit`, `readingOrder`) and protection, a shared formula from `fillFormula`, outline levels of rows and columns, workbook views, and `insertRow` with style `'i'`, `spliceRows`, `duplicateRow`, `spliceColumns`, `insertRows` and `row.splice` on plain values (no formulas, merges, notes or names, which exceljs does not move); CSV written with the default and with custom options and read back (no formula-like text, no formula result 0, no gap before the first row); `cross-check.test.ts` and `alias.test.ts` also run the documented deep imports (`deep-imports.cjs`); `alias.test.ts` also checks that LibreOffice shows the dates as exceljs's files do (`1/31/2024`).
1499
1499
 
1500
1500
  ## Known differences from the 1.3.0 review
1501
1501
 
1502
- Found by a review of 1.3.0 and checked by running exceljs 4.4.0 and `@xlvane/compat` on the same input (Node.js 22.23). F6 describes a difference that xlvane keeps, and F8 values that xlvane refuses. F1, F2, F3, F4, F5, F7, F9, F10 and F12 of that review (merged-cell styles, row styles, the default font, six-digit colours, upper-case date formats, CSV formatter options, `latin1` CSV reading, `column.eachCell`) are fixed in 1.3.1 and described in the tables above, with the differences that remain.
1502
+ Found by a review of 1.3.0 and checked by running exceljs 4.4.0 and `@xlvane/exceljs` on the same input (Node.js 22.23). F6 describes a difference that xlvane keeps, and F8 values that xlvane refuses. F1, F2, F3, F4, F5, F7, F9, F10 and F12 of that review (merged-cell styles, row styles, the default font, six-digit colours, upper-case date formats, CSV formatter options, `latin1` CSV reading, `column.eachCell`) are fixed in 1.3.1 and described in the tables above, with the differences that remain.
1503
1503
 
1504
1504
  - **F6** Dates from 1900-01-01 to 1900-02-28 differ by one day. xlvane writes and reads them with serial 1 = 1900-01-01 (ECMA-376 Part 4 §15.3.4, docs/facts/ecma-376.md E-15); exceljs writes 1900-01-15 as serial 16 and reads serial 15 as 1900-01-14 (`lib/utils/utils.js` L55-61), so here exceljs is the one that is off, and xlvane keeps its reading. From 1900-03-01 on both agree. Serial 60 (the 29 February 1900 that does not exist) and negative serials with a date format read as numbers (exceljs gives 1900-02-28 and dates before 1899-12-30). In a workbook with the 1904 date system a `Date` before 1904-01-01, such as a time-only value given as 1899-12-30 plus the time, throws `XLV_E_INVALID_VALUE` when written; exceljs writes a negative serial (-1461.44... for 1899-12-30T13:20). Time-only values in the 1900 date system and upper-case date formats such as `DD.MM.YYYY` (F6 and F7 of the 1.3.0 review) behave as in exceljs from 1.3.1.
1505
1505
  - **F8** Values exceljs writes without checks (`lib/xlsx/xform/sheet/cell-xform.js` L199-250, `render`) that xlvane refuses with `XLV_E_INVALID_VALUE` when the workbook is written: `NaN` and `Infinity` (exceljs writes `<v>NaN</v>`, `<v>Infinity</v>`), an invalid `Date` (exceljs writes `<v>NaN</v>`), dates before 1900-01-01 or after 9999-12-31 (exceljs writes the serial, for example -18260 for 1850-01-01), text of more than 32 767 characters, text with an unpaired UTF-16 surrogate, and formulas of more than 8 192 characters.
@@ -1510,21 +1510,21 @@ Found by a review of 1.3.0 and checked by running exceljs 4.4.0 and `@xlvane/com
1510
1510
 
1511
1511
  xlvane is not affiliated with the ExcelJS project; its name is used only to identify the package.
1512
1512
 
1513
- `@xlvane/compat` offers the commonly used part of the exceljs 4.4.0 API on top of xlvane. It is installed under the name `exceljs` with an npm alias, so code that imports `exceljs` keeps its imports:
1513
+ `@xlvane/exceljs` offers the commonly used part of the exceljs 4.4.0 API on top of xlvane. It is installed under the name `exceljs` with an npm alias, so code that imports `exceljs` keeps its imports:
1514
1514
 
1515
1515
  ```json
1516
1516
  "dependencies": {
1517
- "exceljs": "npm:@xlvane/compat@^1"
1517
+ "exceljs": "npm:@xlvane/exceljs@^1"
1518
1518
  }
1519
1519
  ```
1520
1520
 
1521
- npm installs an alias `<alias>@npm:<name>` under the alias name in `node_modules` (npm/cli `docs/lib/content/using-npm/package-spec.md`, "Aliases"; docs/exceljs-compat.md), so `import ExcelJS from 'exceljs'` and `require('exceljs')` load `@xlvane/compat`. What is supported, partly supported and not supported is listed method by method in [docs/exceljs-compat.md](https://github.com/DevXord/xlvane/blob/main/docs/exceljs-compat.md) (also in `node_modules/xlvane/docs/exceljs-compat.md` after installing xlvane).
1521
+ npm installs an alias `<alias>@npm:<name>` under the alias name in `node_modules` (npm/cli `docs/lib/content/using-npm/package-spec.md`, "Aliases"; docs/exceljs-compat.md), so `import ExcelJS from 'exceljs'` and `require('exceljs')` load `@xlvane/exceljs`. What is supported, partly supported and not supported is listed method by method in [docs/exceljs-compat.md](https://github.com/DevXord/xlvane/blob/main/docs/exceljs-compat.md) (also in `node_modules/xlvane/docs/exceljs-compat.md` after installing xlvane).
1522
1522
 
1523
1523
  This guide uses the `xlvane migrate` command of the `xlvane` package. The `xlvane` commands, the report shown below and the TypeScript examples are checked by the tests in `tests/docs/`; the npm commands were run with npm 10.9.9 on 2026-11-03.
1524
1524
 
1525
1525
  ## Before you start
1526
1526
 
1527
- - **Node.js.** `@xlvane/compat` is an ES module and declares `engines.node` `>=22.12`. `require('exceljs')` of an ES module works without a flag from Node.js 22.12 (docs/exceljs-compat.md); `import` works too, and so do named imports such as `import { Workbook } from 'exceljs'`.
1527
+ - **Node.js.** `@xlvane/exceljs` is an ES module and declares `engines.node` `>=22.12`. `require('exceljs')` of an ES module works without a flag from Node.js 22.12 (docs/exceljs-compat.md); `import` works too, and so do named imports such as `import { Workbook } from 'exceljs'`.
1528
1528
  - **Version control.** Commit `package.json` and the lockfile first, so the change can be reviewed and undone.
1529
1529
 
1530
1530
  ## 1. See what would change
@@ -1538,9 +1538,9 @@ npx xlvane migrate
1538
1538
  `xlvane migrate` does the following, and nothing else:
1539
1539
 
1540
1540
  1. It reads `package.json` of the project directory (the current directory, or the directory given as the first argument). A `package.json` that is a symbolic link is refused.
1541
- 2. It looks for an `"exceljs"` entry in `dependencies`, `devDependencies`, `optionalDependencies` and `peerDependencies`, and shows how each would change to `"npm:@xlvane/compat@^1"`. Other sections, such as `overrides`, are not changed.
1541
+ 2. It looks for an `"exceljs"` entry in `dependencies`, `devDependencies`, `optionalDependencies` and `peerDependencies`, and shows how each would change to `"npm:@xlvane/exceljs@^1"`. Other sections, such as `overrides`, are not changed.
1542
1542
  3. It prints the Node.js requirement of `require('exceljs')` next to the project's own `engines.node`.
1543
- 4. It scans the source files of the project (`.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, `.tsx`, up to 2 MiB each and 10 000 files) for exceljs API that `@xlvane/compat` does not support: `ModelContainer` and deep imports of `exceljs/lib/...`. Only files that contain the text `exceljs` are checked; `node_modules`, folders whose names start with a dot, and symbolic links are skipped. The matching is textual, so a finding is a place to look at, not proof.
1543
+ 4. It scans the source files of the project (`.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, `.tsx`, up to 2 MiB each and 10 000 files) for exceljs API that `@xlvane/exceljs` does not support: `ModelContainer` and deep imports of `exceljs/lib/...`. Only files that contain the text `exceljs` are checked; `node_modules`, folders whose names start with a dot, and symbolic links are skipped. The matching is textual, so a finding is a place to look at, not proof.
1544
1544
  5. It writes nothing unless `--force` is given.
1545
1545
 
1546
1546
  For a project whose `package.json` has `"exceljs": "^4.4.0"` in `dependencies`, with a file `src/report.js` that imports `exceljs` and a file `src/legacy.cjs` that requires `exceljs/lib/xlsx/xform/base-xform`, the report is:
@@ -1548,10 +1548,10 @@ For a project whose `package.json` has `"exceljs": "^4.4.0"` in `dependencies`,
1548
1548
  ```text
1549
1549
  Change in package.json:
1550
1550
  dependencies: - "exceljs": "^4.4.0"
1551
- + "exceljs": "npm:@xlvane/compat@^1"
1552
- Node.js: require('exceljs') of @xlvane/compat needs Node.js 22.12 or later (package.json engines.node: not set).
1551
+ + "exceljs": "npm:@xlvane/exceljs@^1"
1552
+ Node.js: require('exceljs') of @xlvane/exceljs needs Node.js 22.12 or later (package.json engines.node: not set).
1553
1553
 
1554
- Scanned 2 source files for exceljs API that @xlvane/compat does not fully support:
1554
+ Scanned 2 source files for exceljs API that @xlvane/exceljs does not fully support:
1555
1555
  not supported src/legacy.cjs:1:27 deep import (exceljs/lib/...)
1556
1556
  Details: docs/exceljs-compat.md. Unsupported calls throw XLV_E_NOT_SUPPORTED at run time.
1557
1557
 
@@ -1569,18 +1569,18 @@ npx xlvane migrate --json
1569
1569
  ```sh
1570
1570
  npx xlvane migrate --force --dry-run # show the change without writing it
1571
1571
  npx xlvane migrate --force # change package.json
1572
- npm install # install @xlvane/compat under the name exceljs
1572
+ npm install # install @xlvane/exceljs under the name exceljs
1573
1573
  ```
1574
1574
 
1575
1575
  `--force` replaces only the value of each `"exceljs"` entry; the rest of `package.json` keeps its formatting and key order. Instead of `xlvane migrate`, the alias can also be installed directly:
1576
1576
 
1577
1577
  ```sh
1578
- npm install exceljs@npm:@xlvane/compat@^1
1578
+ npm install exceljs@npm:@xlvane/exceljs@^1
1579
1579
  ```
1580
1580
 
1581
- npm then saves the version it installed as the range (with npm 10.9.9 and `@xlvane/compat` 1.2.2: `"exceljs": "npm:@xlvane/compat@^1.2.2"`).
1581
+ npm then saves the version it installed as the range (with npm 10.9.9 and `@xlvane/exceljs` 1.2.2: `"exceljs": "npm:@xlvane/exceljs@^1.2.2"`).
1582
1582
 
1583
- The code stays as it was. For example, this exceljs code runs unchanged on `@xlvane/compat`:
1583
+ The code stays as it was. For example, this exceljs code runs unchanged on `@xlvane/exceljs`:
1584
1584
 
1585
1585
  ```ts
1586
1586
  import ExcelJS from 'exceljs';
@@ -1605,7 +1605,7 @@ In CommonJS, `const ExcelJS = require('exceljs');` gives the same object.
1605
1605
 
1606
1606
  - **Run the project's tests.** Unsupported API throws an `XlvError` whose `code` is `XLV_E_NOT_SUPPORTED` and whose message names the method; nothing is dropped silently.
1607
1607
  - **Look at each finding of `xlvane migrate`.** Deep imports of `exceljs/lib/...` do not resolve (`exceljs/dist/es5` and the `exceljs/dist/exceljs*.js` files do); `ModelContainer` throws `XLV_E_NOT_SUPPORTED` when it is constructed.
1608
- - **Read the differences.** [docs/exceljs-compat.md](https://github.com/DevXord/xlvane/blob/main/docs/exceljs-compat.md) lists every method with its status and the exceljs source of each behaviour, and ends with the differences found in reviews and cross-checks. The ones most likely to matter are summarised in the [@xlvane/compat README](https://github.com/DevXord/xlvane/blob/main/packages/compat/README.md#differences-from-exceljs): CSV output escapes text that starts like a formula (`formulaInjection: "off"` writes it unchanged, as exceljs does), a sheet id outside 1 to 65534 is written as the lowest unused id, only the first view of a worksheet is written, the module object is frozen, the streaming writer compresses in JavaScript, and input files are checked against ZIP and XML limits.
1608
+ - **Read the differences.** [docs/exceljs-compat.md](https://github.com/DevXord/xlvane/blob/main/docs/exceljs-compat.md) lists every method with its status and the exceljs source of each behaviour, and ends with the differences found in reviews and cross-checks. The ones most likely to matter are summarised in the [@xlvane/exceljs README](https://github.com/DevXord/xlvane/blob/main/packages/exceljs/README.md#differences-from-exceljs): CSV output escapes text that starts like a formula (`formulaInjection: "off"` writes it unchanged, as exceljs does), a sheet id outside 1 to 65534 is written as the lowest unused id, only the first view of a worksheet is written, the module object is frozen, the streaming writer compresses in JavaScript, and input files are checked against ZIP and XML limits.
1609
1609
  - **TypeScript.** The type names of exceljs's `index.d.ts` are exported and work with `moduleResolution` `bundler` and `nodenext` and with `module: commonjs`. Under `module: node16`, TypeScript refuses `import ExcelJS = require('exceljs')` of an ES module (TS1471); use `nodenext` or `commonjs`.
1610
1610
  - **Browsers and Workers.** The methods that read or write files (`xlsx.readFile`, `xlsx.writeFile`, `csv.readFile`, `csv.writeFile`, the `filename` forms of the streaming classes and of `addImage`) work in Node.js, Bun and Deno; in browsers and Workers they throw `XLV_E_NOT_SUPPORTED`.
1611
1611
 
@@ -1619,7 +1619,7 @@ try {
1619
1619
  await workbook.xlsx.readFile('report.xlsx');
1620
1620
  } catch (error) {
1621
1621
  const code = (error as { code?: unknown }).code;
1622
- if (code === 'XLV_E_NOT_SUPPORTED') console.error('Not supported by @xlvane/compat:', (error as Error).message);
1622
+ if (code === 'XLV_E_NOT_SUPPORTED') console.error('Not supported by @xlvane/exceljs:', (error as Error).message);
1623
1623
  else throw error;
1624
1624
  }
1625
1625
  ```
@@ -1636,7 +1636,7 @@ npm replaces the alias in `package.json` and `node_modules`. Restoring `package.
1636
1636
 
1637
1637
  ## Reporting a problem
1638
1638
 
1639
- When exceljs code behaves differently on `@xlvane/compat` and the difference is not listed in docs/exceljs-compat.md, please open an issue at https://github.com/DevXord/xlvane/issues with a small script that shows it.
1639
+ When exceljs code behaves differently on `@xlvane/exceljs` and the difference is not listed in docs/exceljs-compat.md, please open an issue at https://github.com/DevXord/xlvane/issues with a small script that shows it.
1640
1640
 
1641
1641
  <!-- file: docs/xlsx-cves.md -->
1642
1642
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xlvane",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "Read, inspect and write XLSX files; input is treated as untrusted. ESM only, one runtime dependency (fflate).",
5
5
  "keywords": [
6
6
  "xlsx",
@@ -10,7 +10,7 @@
10
10
  "spreadsheetml"
11
11
  ],
12
12
  "license": "MIT",
13
- "homepage": "https://github.com/DevXord/xlvane#readme",
13
+ "homepage": "https://xlvane.github.io/",
14
14
  "bugs": {
15
15
  "url": "https://github.com/DevXord/xlvane/issues"
16
16
  },
@@ -187,7 +187,7 @@ Formulas on every sheet, merged cells, links, notes, conditional formats (also e
187
187
 
188
188
  In Node.js, `xlvane/node` adds `readWorkbookFile`, `inspectFile` and `writeWorkbookFile` (which never replaces an existing file unless `{ overwrite: true }` is passed). `toCSV`, `fromCSV`, `toJSON` and `fromJSON` convert tables. For very large files use `openWorkbookStream` and `writeWorkbookStream`.
189
189
 
190
- Code written for the `exceljs` API can run on xlvane through `@xlvane/compat` (`"exceljs": "npm:@xlvane/compat@^1"` in package.json); unsupported exceljs features throw `XLV_E_NOT_SUPPORTED`.
190
+ Code written for the `exceljs` API can run on xlvane through `@xlvane/exceljs` (`"exceljs": "npm:@xlvane/exceljs@^1"` in package.json); unsupported exceljs features throw `XLV_E_NOT_SUPPORTED`.
191
191
 
192
192
  ## Command line
193
193