xlvane 1.1.0 → 1.2.0

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
@@ -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`.
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)).
62
62
 
63
63
  ## Reading a workbook
64
64
 
@@ -385,10 +385,10 @@ Limits can be changed per call, for example `readWorkbook(bytes, { limits: { max
385
385
  | `maxXmlDepth` | 128 | deeply nested XML |
386
386
  | `maxXmlAttributes` | 256 | elements with huge numbers of attributes |
387
387
  | `maxXmlNameLength` | 1 024 | huge element or attribute names |
388
- | `maxXmlTextLength` | 8 Mi characters | huge text nodes or attribute values |
388
+ | `maxXmlTextLength` | 8 Mi characters | huge text nodes, attribute values, comments or processing instructions |
389
389
  | `maxXmlTreeElements` | 1 000 000 | huge workbook, styles or relationship parts (elements plus attributes) |
390
- | `maxCells` | 5 000 000 | workbooks too large to hold in memory (measured: about 180 bytes per numeric cell, Node.js 26) |
391
- | `maxSharedStringChars` | 512 Mi characters | many cells pointing at one huge shared string (a few MB that become many GB when values are copied) |
390
+ | `maxCells` | 5 000 000 | workbooks too large to hold in memory (measured: about 180 bytes per numeric cell, Node.js 26); also bounds the output of `toCSV`, `readTable`, `toJSON` and `readTableStream` to `max(maxCells, 16 × cells read)` positions |
391
+ | `maxSharedStringChars` | 512 Mi characters | many cells pointing at one huge shared string (a few MB that become many GB when values are copied); counted separately, the same for cells sharing one huge formula |
392
392
 
393
393
  ## Package size
394
394
 
@@ -403,6 +403,7 @@ Limits can be changed per call, for example `readWorkbook(bytes, { limits: { max
403
403
 
404
404
  ## Links
405
405
 
406
+ - Website with the guide and an in-browser demo: [xlvane.github.io](https://xlvane.github.io)
406
407
  - Changes in each version: [CHANGELOG.md](https://github.com/DevXord/xlvane/blob/main/CHANGELOG.md)
407
408
  - Bugs and questions: [GitHub issues](https://github.com/DevXord/xlvane/issues)
408
409
  - Reporting a vulnerability: [SECURITY.md](https://github.com/DevXord/xlvane/blob/main/SECURITY.md)
package/dist/cli.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { Bt as suggest, En as XlvError, _ as isoDate, b as readWorkbook, g as inspect, ln as parseRange } from "./options-CwSp2pA4.js";
3
- import { a as appendRows, c as fromCSV, d as fromJSON, f as pickSheet, h as toJSON, l as inferValue, n as insertRows, o as editCells, p as readTable, s as diff, t as deleteRows, u as toCSV } from "./rows-DKwlr0rg.js";
4
- import { i as readInput } from "./node-files-B0iqSJIJ.js";
2
+ import { On as XlvError, Vt as suggest, _ as isoDate, b as readWorkbook, dn as parseRange, g as inspect } from "./options-Ba1iWD-Z.js";
3
+ import { a as appendRows, c as fromCSV, d as fromJSON, f as pickSheet, h as toJSON, l as inferValue, n as insertRows, o as editCells, p as readTable, s as diff, t as deleteRows, u as toCSV } from "./rows-IWKIxHt9.js";
4
+ import { i as readInput } from "./node-files-CDb6TyZb.js";
5
5
  import { existsSync, readFileSync } from "node:fs";
6
- import { chmod, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
6
+ import { chmod, lstat, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
7
7
  import process from "node:process";
8
8
  import { createRequire } from "node:module";
9
9
  import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
@@ -463,8 +463,15 @@ var Output = class {
463
463
  this.color = color;
464
464
  this.width = width;
465
465
  }
466
+ /**
467
+ * Colour codes are written with {@link STYLE_MARK} in place of ESC, and an ESC already in the
468
+ * text (from a file) is escaped, so that the final filter ({@link terminalSafe}) can tell the
469
+ * CLI's own colour codes from the same bytes in a sheet name or cell (D-H01).
470
+ */
466
471
  style(format, text) {
467
- return this.color && text !== "" ? nodeUtil.styleText(format, text, { validateStream: false }) : text;
472
+ if (!this.color || text === "") return text;
473
+ const safe = text.includes("\x1B") ? text.split("\x1B").join("\\x1b") : text;
474
+ return nodeUtil.styleText(format, safe, { validateStream: false }).split("\x1B").join(STYLE_MARK);
468
475
  }
469
476
  bold(text) {
470
477
  return this.style("bold", text);
@@ -519,7 +526,8 @@ function oneLine(text) {
519
526
  * which includes the 8-bit CSI U+009B) written as `\x1b`, and bidirectional formatting characters
520
527
  * written as `\u202e`, so text from a file, such as a cell
521
528
  * holding `_x001B_]0;title_x0007_`, cannot move the cursor, change the window title or hide
522
- * output (docs/decisions.md D-R02). Used for all human-readable output; `--json` is unchanged.
529
+ * output (docs/decisions.md D-R02). Used for all human-readable output; `--json` writes the same
530
+ * characters as `\uXXXX` escapes instead (D-H01).
523
531
  */
524
532
  function escapeControls(text) {
525
533
  return text.replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g, (c) => `\\x${c.charCodeAt(0).toString(16).padStart(2, "0")}`).replace(BIDI, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
@@ -531,27 +539,40 @@ function escapeControls(text) {
531
539
  * `\u202e` in human-readable output, like other control characters (D-R08).
532
540
  */
533
541
  const BIDI = /[\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/g;
534
- /** The colour sequences `Output` writes (styleText: bold, dim, red, green, yellow, cyan and their resets). */
535
- const OWN_STYLES = /\u001b\[(?:1|2|22|31|32|33|36|39)m/y;
542
+ /**
543
+ * Stands for ESC in the colour codes `Output` writes until {@link terminalSafe} turns it back:
544
+ * NUL and 16 random hexadecimal digits, new for each process, so text from a file cannot contain
545
+ * it by chance or design. Before 1.1.1 the filter kept every ESC sequence that looked like one of
546
+ * the CLI's colours, including ones from a sheet name (D-H01).
547
+ */
548
+ const STYLE_MARK = `\u0000${Array.from(globalThis.crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(8)), (b) => b.toString(16).padStart(2, "0")).join("")}`;
549
+ /** The colour sequences `Output` writes (styleText: bold, dim, red, green, yellow, cyan and their resets), after the mark. */
550
+ const OWN_STYLE = /^\[(?:1|2|22|31|32|33|36|39)m/;
551
+ const MARKED_STYLE = new RegExp(`${STYLE_MARK}\\[[0-9;]*m`, "g");
536
552
  /**
537
553
  * Final filter for human-readable output: escapes every control character (see
538
- * {@link escapeControls}) except line feeds, tabs and, when `keepStyles` is true, the exact
539
- * colour sequences that `Output` itself writes. Applied to everything the CLI prints for people.
554
+ * {@link escapeControls}) except line feeds and tabs. When `keepStyles` is true, the colour codes
555
+ * that `Output` wrote (marked with {@link STYLE_MARK}) are turned into ESC sequences; any ESC in
556
+ * the text itself is escaped. Applied to everything the CLI prints for people.
540
557
  */
541
558
  function terminalSafe(text, keepStyles) {
559
+ if (!text.includes(STYLE_MARK)) return controlsSafe(text);
560
+ const parts = text.split(STYLE_MARK);
561
+ let result = controlsSafe(parts[0] ?? "");
562
+ for (const part of parts.slice(1)) {
563
+ const own = OWN_STYLE.exec(part)?.[0];
564
+ if (own === void 0) result += controlsSafe(part);
565
+ else result += (keepStyles ? `\u001b${own}` : "") + controlsSafe(part.slice(own.length));
566
+ }
567
+ return result;
568
+ }
569
+ /** Escapes the control characters of text (see {@link escapeControls}) except line feeds and tabs. */
570
+ function controlsSafe(text) {
542
571
  let result = "";
543
572
  let start = 0;
544
573
  for (let i = 0; i < text.length; i++) {
545
574
  const code = text.charCodeAt(i);
546
575
  if (!(code < 32 && code !== 10 && code !== 9 || code >= 127 && code <= 159 || code === 1564 || code === 8206 || code === 8207 || code >= 8234 && code <= 8238 || code >= 8294 && code <= 8297)) continue;
547
- if (keepStyles && code === 27) {
548
- OWN_STYLES.lastIndex = i;
549
- const m = OWN_STYLES.exec(text);
550
- if (m !== null) {
551
- i += m[0].length - 1;
552
- continue;
553
- }
554
- }
555
576
  result += text.slice(start, i) + escapeControls(text[i]);
556
577
  start = i + 1;
557
578
  }
@@ -591,6 +612,7 @@ const segmenter = typeof Intl === "object" && typeof Intl.Segmenter === "functio
591
612
  */
592
613
  function displayWidth(text) {
593
614
  if (text.includes("\x1B")) text = text.replace(/\u001b\[[0-9;]*m/g, "");
615
+ if (text.includes(STYLE_MARK)) text = text.replace(MARKED_STYLE, "");
594
616
  let width = 0;
595
617
  for (let i = 0; i < text.length; i++) {
596
618
  const code = text.charCodeAt(i);
@@ -913,7 +935,7 @@ function welcome(out, version, commands) {
913
935
  "",
914
936
  `${out.bold("Commands:")} ${commands.map((c) => c.name).join(", ")}`,
915
937
  `${out.bold("More:")} xlvane help <command> · Docs: ${DOCS_URL}`,
916
- `For AI agents and scripts: add --json to any command (${DOCS_IN_PACKAGE}/cli-json.md)`,
938
+ `For AI agents and scripts: add --json to any command (${DOCS_IN_PACKAGE}/cli-json.md), or run "xlvane mcp"`,
917
939
  ""
918
940
  ].join("\n");
919
941
  }
@@ -1334,7 +1356,7 @@ const DEFAULT_LIMIT$1 = 50;
1334
1356
  function showCell(c) {
1335
1357
  if (c === null) return "(empty)";
1336
1358
  const value = c.value === null ? "" : typeof c.value === "string" ? JSON.stringify(c.value) : String(c.value);
1337
- return c.formula !== null ? `=${c.formula}${value !== "" ? ` (${value})` : ""}` : value === "" ? "(no value)" : value;
1359
+ return c.formula !== null ? `=${escapeControls(c.formula)}${value !== "" ? ` (${value})` : ""}` : value === "" ? "(no value)" : value;
1338
1360
  }
1339
1361
  function kindLabel(out, kind) {
1340
1362
  const text = kind.padEnd(7);
@@ -1393,14 +1415,14 @@ const diffCommand = {
1393
1415
  result: r,
1394
1416
  exitCode: r.equal ? 0 : 1,
1395
1417
  render: (out) => {
1396
- if (r.equal) return `${out.green("No differences")} between ${a} and ${b}.`;
1418
+ if (r.equal) return `${out.green("No differences")} between ${escapeControls(a)} and ${escapeControls(b)}.`;
1397
1419
  const s = r.summary;
1398
- const lines = [`${out.bold(`${a} → ${b}`)}: ${plural(s.cellsChanged, "cell")} changed, ${String(s.cellsAdded)} added, ${String(s.cellsRemoved)} removed` + (s.sheetsAdded + s.sheetsRemoved > 0 ? `; sheets added: ${String(s.sheetsAdded)}, removed: ${String(s.sheetsRemoved)}` : "")];
1399
- for (const name of r.sheetsAdded) lines.push(`${out.green("added sheet")} "${name}"`);
1400
- for (const name of r.sheetsRemoved) lines.push(`${out.red("removed sheet")} "${name}"`);
1420
+ const lines = [`${out.bold(`${escapeControls(a)} → ${escapeControls(b)}`)}: ${plural(s.cellsChanged, "cell")} changed, ${String(s.cellsAdded)} added, ${String(s.cellsRemoved)} removed` + (s.sheetsAdded + s.sheetsRemoved > 0 ? `; sheets added: ${String(s.sheetsAdded)}, removed: ${String(s.sheetsRemoved)}` : "")];
1421
+ for (const name of r.sheetsAdded) lines.push(`${out.green("added sheet")} "${escapeControls(name)}"`);
1422
+ for (const name of r.sheetsRemoved) lines.push(`${out.red("removed sheet")} "${escapeControls(name)}"`);
1401
1423
  for (const sheet of r.sheets) {
1402
1424
  if (sheet.cells.length === 0 && !sheet.state) continue;
1403
- lines.push("", out.bold(`Sheet "${sheet.name}"`));
1425
+ lines.push("", out.bold(`Sheet "${escapeControls(sheet.name)}"`));
1404
1426
  if (sheet.state) lines.push(` ${out.yellow("changed")} visibility: ${sheet.state.before} → ${sheet.state.after}`);
1405
1427
  for (const c of sheet.cells.slice(0, limit)) {
1406
1428
  const style = c.kind === "changed" && showCell(c.before) === showCell(c.after) ? " (formatting)" : "";
@@ -1757,17 +1779,17 @@ const inspectCommand = {
1757
1779
  }
1758
1780
  };
1759
1781
  function renderReport(out, file, r, verbose) {
1760
- const lines = [`${out.bold(file)}: ${r.format}, ${plural(r.sheetCount, "sheet")}, date system ${r.dateSystem}${r.conformance === "strict" ? ", Strict conformance" : ""}`];
1782
+ const lines = [`${out.bold(escapeControls(file))}: ${r.format}, ${plural(r.sheetCount, "sheet")}, date system ${r.dateSystem}${r.conformance === "strict" ? ", Strict conformance" : ""}`];
1761
1783
  if (r.hasMacros) lines.push("Contains macros (not run).");
1762
1784
  if (r.externalLinkCount > 0) lines.push(`Links to ${plural(r.externalLinkCount, "other workbook")} (not followed).`);
1763
1785
  const props = Object.entries(r.properties);
1764
1786
  if (props.length > 0) {
1765
1787
  const keyWidth = Math.max(...props.map(([k]) => k.length));
1766
- lines.push(out.bold("Properties:"), ...props.map(([k, v]) => ` ${k.padEnd(keyWidth)} ${v}`));
1788
+ lines.push(out.bold("Properties:"), ...props.map(([k, v]) => ` ${k.padEnd(keyWidth)} ${escapeControls(String(v))}`));
1767
1789
  }
1768
1790
  const names = verbose ? r.definedNames : r.definedNames.filter((n) => !(n.hidden && n.name.startsWith("_xlnm.")));
1769
1791
  if (names.length > 0) {
1770
- const shown = names.slice(0, 5).map((n) => `${n.name}${n.sheet === null ? "" : ` (sheet "${n.sheet}")`}${n.hidden ? " (hidden)" : ""} =${n.refersTo}`);
1792
+ const shown = names.slice(0, 5).map((n) => `${escapeControls(n.name)}${n.sheet === null ? "" : ` (sheet "${escapeControls(n.sheet)}")`}${n.hidden ? " (hidden)" : ""} =${escapeControls(n.refersTo)}`);
1771
1793
  const more = names.length > 5 || r.definedNamesTruncated ? `, … (${r.definedNamesTruncated ? "more than " : ""}${String(names.length)} in total; see --json)` : "";
1772
1794
  lines.push(`${out.bold("Defined names:")} ${shown.join(", ")}${more}`);
1773
1795
  }
@@ -1775,16 +1797,16 @@ function renderReport(out, file, r, verbose) {
1775
1797
  lines.push("");
1776
1798
  const state = s.state === "visible" ? "" : ` (${s.state})`;
1777
1799
  if (s.kind !== "worksheet") {
1778
- lines.push(`${out.bold(`Sheet "${s.name}"`)}${state}: ${s.kind}, no cells`);
1800
+ lines.push(`${out.bold(`Sheet "${escapeControls(s.name)}"`)}${state}: ${s.kind}, no cells`);
1779
1801
  continue;
1780
1802
  }
1781
1803
  if (s.usedRange === null) {
1782
- lines.push(`${out.bold(`Sheet "${s.name}"`)}${state}: empty`);
1804
+ lines.push(`${out.bold(`Sheet "${escapeControls(s.name)}"`)}${state}: empty`);
1783
1805
  continue;
1784
1806
  }
1785
- lines.push(`${out.bold(`Sheet "${s.name}"`)}${state}: ${s.usedRange}, ${plural(s.rowCount, "row")} × ${plural(s.columnCount, "column")}, ${plural(s.cellCount, "cell")}, ${plural(s.formulaCount, "formula")}`);
1807
+ lines.push(`${out.bold(`Sheet "${escapeControls(s.name)}"`)}${state}: ${s.usedRange}, ${plural(s.rowCount, "row")} × ${plural(s.columnCount, "column")}, ${plural(s.cellCount, "cell")}, ${plural(s.formulaCount, "formula")}`);
1786
1808
  lines.push(s.headerRow ? ` Header row: ${String(s.headerRow.row)} (${s.headerRow.confidence} confidence)` : " Header row: none detected");
1787
- if (s.mergedRangeCount > 0) lines.push(` Merged: ${s.mergedRanges.slice(0, 10).join(", ")}${s.mergedRangeCount > 10 ? `, … (${String(s.mergedRangeCount)} in total)` : ""}`);
1809
+ if (s.mergedRangeCount > 0) lines.push(` Merged: ${escapeControls(s.mergedRanges.slice(0, 10).join(", "))}${s.mergedRangeCount > 10 ? `, … (${String(s.mergedRangeCount)} in total)` : ""}`);
1788
1810
  if (s.columns.length > 0) {
1789
1811
  lines.push(out.table([
1790
1812
  "Column",
@@ -1799,29 +1821,98 @@ function renderReport(out, file, r, verbose) {
1799
1821
  ]), " "));
1800
1822
  if (s.columnsTruncated) lines.push(` … ${plural(s.columnCount - s.columns.length, "more column")}; use --max-columns ${String(s.columnCount)} to see them`);
1801
1823
  }
1802
- if (s.formulas.length > 0) lines.push(` Formulas: ${s.formulas.slice(0, 3).map((f) => `${f.cell} =${f.formula ?? "(shared)"}`).join(", ")}`);
1824
+ if (s.formulas.length > 0) lines.push(` Formulas: ${s.formulas.slice(0, 3).map((f) => `${f.cell} =${escapeControls(f.formula ?? "(shared)")}`).join(", ")}`);
1803
1825
  if (s.richTextCellCount > 0) lines.push(` Rich text: ${plural(s.richTextCellCount, "cell")} (${s.richTextCells.slice(0, 5).join(", ")}${s.richTextCellCount > 5 ? ", …" : ""})`);
1804
1826
  if (s.styledColumns.length > 0) lines.push(` Column styles: ${s.styledColumns.slice(0, 10).join(", ")}${s.styledColumns.length > 10 ? ", …" : ""}`);
1805
1827
  if (s.hyperlinkCount > 0) {
1806
- const shown = s.hyperlinks.slice(0, 3).map((l) => `${l.ref} → ${l.target ?? ""}${l.location === null ? "" : `${l.target === null ? "" : "#"}${l.location}`}`);
1828
+ const shown = s.hyperlinks.slice(0, 3).map((l) => `${l.ref} → ${escapeControls(l.target ?? "")}${l.location === null ? "" : `${l.target === null ? "" : "#"}${escapeControls(l.location)}`}`);
1807
1829
  lines.push(` Hyperlinks: ${plural(s.hyperlinkCount, "link")} (${shown.join(", ")}${s.hyperlinkCount > 3 ? ", …" : ""})`);
1808
1830
  }
1809
1831
  if (s.imageCount > 0) lines.push(` Images: ${plural(s.imageCount, "picture")} (${s.images.slice(0, 5).map((i) => `${i.cell ?? "absolute"} ${i.format ?? "other"}`).join(", ")}${s.imageCount > 5 ? ", …" : ""})`);
1810
1832
  if (s.noteCount > 0) lines.push(` Notes: ${plural(s.noteCount, "note")} (${s.notes.slice(0, 5).join(", ")}${s.noteCount > 5 ? ", …" : ""})`);
1811
- if (s.tables.length > 0) lines.push(` Tables: ${s.tables.slice(0, 5).map((t) => `${t.name} ${t.ref}`).join(", ")}${s.tables.length > 5 ? ", …" : ""}`);
1833
+ if (s.tables.length > 0) lines.push(` Tables: ${s.tables.slice(0, 5).map((table) => `${escapeControls(table.name)} ${escapeControls(table.ref)}`).join(", ")}${s.tables.length > 5 ? ", …" : ""}`);
1812
1834
  if (s.dataValidationCount > 0 || s.conditionalFormatCount > 0) {
1813
1835
  const parts = [s.dataValidationCount > 0 ? plural(s.dataValidationCount, "data validation") : null, s.conditionalFormatCount > 0 ? plural(s.conditionalFormatCount, "conditional format rule") : null];
1814
1836
  lines.push(` Rules: ${parts.filter((p) => p !== null).join(", ")}`);
1815
1837
  }
1816
1838
  if (s.protected) lines.push(" Protected: yes");
1817
1839
  if (s.printArea !== null || s.pageBreakCount > 0) {
1818
- const parts = [s.printArea === null ? null : `print area ${s.printArea.join(", ")}`, s.pageBreakCount > 0 ? plural(s.pageBreakCount, "page break") : null];
1840
+ const parts = [s.printArea === null ? null : `print area ${escapeControls(s.printArea.join(", "))}`, s.pageBreakCount > 0 ? plural(s.pageBreakCount, "page break") : null];
1819
1841
  lines.push(` Printing: ${parts.filter((p) => p !== null).join(", ")}`);
1820
1842
  }
1821
1843
  }
1822
1844
  if (r.warnings.length > 0) lines.push("", ...warningsBlock(out, r.warnings));
1823
1845
  return lines.join("\n");
1824
1846
  }
1847
+ // src/cli/commands/mcp.ts
1848
+ /** The package that holds the MCP server; xlvane does not depend on it (docs/PLAN.md section 3). */
1849
+ const MCP_PACKAGE = "@xlvane/mcp";
1850
+ /**
1851
+ * Whether loading failed because @xlvane/mcp itself is missing. A missing dependency of an
1852
+ * installed @xlvane/mcp has the same error code but names that dependency (D-I04).
1853
+ */
1854
+ function isModuleNotFound(error) {
1855
+ const code = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
1856
+ const message = error instanceof Error ? error.message : "";
1857
+ return (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") && (message.includes(`'@xlvane/mcp'`) || message.includes(`"@xlvane/mcp"`));
1858
+ }
1859
+ /** Options of the xlvane command line itself, which the server does not take. */
1860
+ const OWN_OPTIONS = /* @__PURE__ */ new Set([
1861
+ "--quiet",
1862
+ "-q",
1863
+ "--verbose"
1864
+ ]);
1865
+ const mcpCommand = {
1866
+ name: "mcp",
1867
+ summary: "Start the MCP server for AI agents",
1868
+ description: "Starts the Model Context Protocol server from the separate package @xlvane/mcp over stdin and stdout, so that an AI agent can inspect, read, convert and compare spreadsheets through tools instead of code. The arguments after \"mcp\" are passed to the server: --root <dir> (required, repeatable) names a directory the tools may use, --allow-write adds the tools that write files, and --max-file-size <bytes>, --max-rows <n> and --max-response-chars <n> set its limits. --json is not available, because stdout carries the protocol. If @xlvane/mcp is not installed, the command prints how to install it. The exit code is the server's: 0 when the client closed the connection, 2 for wrong arguments, 3 for a directory that cannot be used.",
1869
+ usage: "[server options]",
1870
+ positionals: {
1871
+ min: 0,
1872
+ max: Number.POSITIVE_INFINITY,
1873
+ names: []
1874
+ },
1875
+ passThrough: true,
1876
+ options: {},
1877
+ examples: [{
1878
+ command: "xlvane mcp --root ./data",
1879
+ description: "Serve the files in ./data, read-only"
1880
+ }, {
1881
+ command: "xlvane mcp --root ./data --allow-write",
1882
+ description: "Also allow writing files there"
1883
+ }],
1884
+ related: ["inspect", "read"],
1885
+ async run(ctx) {
1886
+ if (ctx.json) throw usageError("\"xlvane mcp\" does not take --json: the server uses stdout for the protocol.", "Run \"xlvane mcp --root <dir>\" without --json; the server reports its own errors as MCP results.", {
1887
+ command: "mcp",
1888
+ option: "--json"
1889
+ });
1890
+ let mod;
1891
+ try {
1892
+ mod = await ctx.io.importModule(MCP_PACKAGE);
1893
+ } catch (error) {
1894
+ if (!isModuleNotFound(error)) throw error;
1895
+ throw new XlvError("XLV_E_NOT_INSTALLED", `The MCP server is in the separate package ${MCP_PACKAGE}, which is not installed.`, {
1896
+ hint: `Install it next to xlvane with "npm install ${MCP_PACKAGE}", then run "xlvane mcp" again.`,
1897
+ details: { package: MCP_PACKAGE },
1898
+ cause: error
1899
+ });
1900
+ }
1901
+ if (typeof mod.runCli !== "function") throw new XlvError("XLV_E_NOT_SUPPORTED", `The installed ${MCP_PACKAGE} does not contain the MCP server yet.`, {
1902
+ hint: `Update ${MCP_PACKAGE} to a version that provides the server.`,
1903
+ details: {
1904
+ package: MCP_PACKAGE,
1905
+ feature: "runCli"
1906
+ }
1907
+ });
1908
+ const code = await mod.runCli(ctx.argv.filter((a) => !OWN_OPTIONS.has(a)));
1909
+ return {
1910
+ result: { exitCode: code },
1911
+ exitCode: code === 0 || code === 1 || code === 2 ? code : 3,
1912
+ render: () => ""
1913
+ };
1914
+ }
1915
+ };
1825
1916
  // src/cli/commands/migrate.ts
1826
1917
  /** The dependency value that installs @xlvane/compat under the name exceljs (npm alias). */
1827
1918
  const ALIAS = "npm:@xlvane/compat@^1";
@@ -1866,10 +1957,11 @@ async function sourceFiles(root) {
1866
1957
  const path = join(dir, name);
1867
1958
  let info;
1868
1959
  try {
1869
- info = await stat(path);
1960
+ info = await lstat(path);
1870
1961
  } catch {
1871
1962
  continue;
1872
1963
  }
1964
+ if (info.isSymbolicLink()) continue;
1873
1965
  if (info.isDirectory()) await walk(path);
1874
1966
  else if (info.isFile() && SOURCE.test(name) && info.size <= MAX_FILE_BYTES) files.push(path);
1875
1967
  }
@@ -1898,6 +1990,75 @@ function scanSource(file, text) {
1898
1990
  });
1899
1991
  return findings;
1900
1992
  }
1993
+ /**
1994
+ * Offsets `[start, end)` of the string value (with its quotes) at `path` in valid JSON text, the
1995
+ * one JSON.parse reads when keys repeat, or `null`. Keys are compared after decoding their
1996
+ * escapes. Values off the path are skipped without recursion.
1997
+ */
1998
+ function stringValueSpan(text, path) {
1999
+ let i = 0;
2000
+ const space = () => {
2001
+ while (i < text.length && " \r\n".includes(text[i])) i++;
2002
+ };
2003
+ /** Skips a string starting at i (on its opening quote); returns its raw text. */
2004
+ const string = () => {
2005
+ const start = i++;
2006
+ while (text[i] !== "\"") i += text[i] === "\\" ? 2 : 1;
2007
+ i++;
2008
+ return text.slice(start, i);
2009
+ };
2010
+ /** Skips any value starting at i, iteratively. */
2011
+ const skip = () => {
2012
+ let depth = 0;
2013
+ do {
2014
+ const c = text[i];
2015
+ if (c === "\"") string();
2016
+ else {
2017
+ if (c === "{" || c === "[") depth++;
2018
+ else if (c === "}" || c === "]") depth--;
2019
+ i++;
2020
+ if (depth === 0 && c !== "{" && c !== "[") while (i < text.length && !",]} \r\n".includes(text[i])) i++;
2021
+ }
2022
+ } while (depth > 0 && i < text.length);
2023
+ };
2024
+ const value = (level) => {
2025
+ space();
2026
+ if (level === path.length) {
2027
+ if (text[i] !== "\"") {
2028
+ skip();
2029
+ return null;
2030
+ }
2031
+ const start = i;
2032
+ string();
2033
+ return [start, i];
2034
+ }
2035
+ if (text[i] !== "{") {
2036
+ skip();
2037
+ return null;
2038
+ }
2039
+ i++;
2040
+ let found = null;
2041
+ space();
2042
+ if (text[i] === "}") {
2043
+ i++;
2044
+ return null;
2045
+ }
2046
+ for (;;) {
2047
+ space();
2048
+ const key = JSON.parse(string());
2049
+ space();
2050
+ i++;
2051
+ if (key === path[level]) found = value(level + 1);
2052
+ else {
2053
+ space();
2054
+ skip();
2055
+ }
2056
+ space();
2057
+ if (text[i++] === "}") return found;
2058
+ }
2059
+ };
2060
+ return value(0);
2061
+ }
1901
2062
  function jsonError(path, cause) {
1902
2063
  return new XlvError("XLV_E_JSON_INVALID", `"${path}" is not a valid package.json.`, {
1903
2064
  hint: "Fix the JSON syntax of package.json and run the command again.",
@@ -1945,11 +2106,14 @@ async function run$1(ctx) {
1945
2106
  }
1946
2107
  let write = null;
1947
2108
  if (changes.length > 0 && flag(ctx.args, "force")) {
1948
- let updated = text;
1949
- for (const c of changes) {
1950
- const escaped = c.from.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1951
- updated = updated.replace(new RegExp(`("exceljs"\\s*:\\s*)"${escaped}"`), `$1"${ALIAS}"`);
2109
+ const spans = changes.map((c) => stringValueSpan(text, [c.section, "exceljs"])).filter((s) => s !== null);
2110
+ let updated = "";
2111
+ let at = 0;
2112
+ for (const [start, end] of spans.sort((a, b) => a[0] - b[0])) {
2113
+ updated += `${text.slice(at, start)}"${ALIAS}"`;
2114
+ at = end;
1952
2115
  }
2116
+ updated += text.slice(at);
1953
2117
  write = await writeOutput(ctx, pkgPath, updated, {
1954
2118
  force: true,
1955
2119
  dryRun: flag(ctx.args, "dry-run")
@@ -2326,7 +2490,8 @@ const COMMANDS = [
2326
2490
  };
2327
2491
  }
2328
2492
  },
2329
- migrateCommand
2493
+ migrateCommand,
2494
+ mcpCommand
2330
2495
  ];
2331
2496
  /** Exit codes (docs/cli-json.md). */
2332
2497
  const EXIT = {
@@ -2350,14 +2515,14 @@ async function run(argv, io) {
2350
2515
  const err = new Output(useColor(io.env, io.stderrIsTTY), io.stderrIsTTY ? width : 100);
2351
2516
  const stdout = (text) => io.stdout(terminalSafe(text, out.color));
2352
2517
  const stderr = (text) => io.stderr(terminalSafe(text, err.color));
2353
- const toJson = (value) => `${io.stdoutIsTTY ? JSON.stringify(value, null, 2) : JSON.stringify(value)}\n`;
2518
+ const toJson = (value) => `${jsonSafe(io.stdoutIsTTY ? JSON.stringify(value, null, 2) : JSON.stringify(value))}\n`;
2354
2519
  const json = optionArgs(argv).includes("--json");
2355
2520
  const [first, ...rest] = argv;
2356
2521
  let spec;
2357
2522
  const state = { lastFile: null };
2358
2523
  try {
2359
2524
  if (first === void 0 || first === "--json" && rest.length === 0) {
2360
- io.stdout(welcome(out, io.version, COMMANDS));
2525
+ stdout(welcome(out, io.version, COMMANDS));
2361
2526
  return EXIT.ok;
2362
2527
  }
2363
2528
  if (first === "--version" || first === "-v") {
@@ -2367,7 +2532,7 @@ async function run(argv, io) {
2367
2532
  if (first === "help" || first === "--help" || first === "-h") {
2368
2533
  const topic = rest.find((a) => !a.startsWith("-"));
2369
2534
  if (topic === void 0) {
2370
- io.stdout(welcome(out, io.version, COMMANDS));
2535
+ stdout(welcome(out, io.version, COMMANDS));
2371
2536
  return EXIT.ok;
2372
2537
  }
2373
2538
  stdout(commandHelp(out, findCommand(topic)));
@@ -2379,8 +2544,11 @@ async function run(argv, io) {
2379
2544
  stdout(commandHelp(out, spec));
2380
2545
  return EXIT.ok;
2381
2546
  }
2382
- const args = parseCommandArgs(spec, rest);
2383
- checkPositionals(spec, args);
2547
+ const args = spec.passThrough ? {
2548
+ positionals: rest,
2549
+ values: {}
2550
+ } : parseCommandArgs(spec, rest);
2551
+ if (!spec.passThrough) checkPositionals(spec, args);
2384
2552
  const quiet = args.values["quiet"] === true;
2385
2553
  const ctx = {
2386
2554
  io,
@@ -2510,6 +2678,7 @@ function suggestCommand(error, first, rest, spec) {
2510
2678
  const at = rest.findIndex((a, i) => a === path && rest[i - 1] !== "-o" && rest[i - 1] !== "--output");
2511
2679
  if (at >= 0) return commandLine([spec.name, ...rest.map((a, i) => i === at ? suggestions[0] : a)]);
2512
2680
  }
2681
+ if (error.code === "XLV_E_NOT_INSTALLED" && typeof d["package"] === "string") return `npm install ${d["package"]}`;
2513
2682
  return null;
2514
2683
  }
2515
2684
  /** Where the problem is, as one line; `null` when the message already says it all. */
@@ -2542,6 +2711,15 @@ function formatError(err, error, tryCommand, verbose = false) {
2542
2711
  ""
2543
2712
  ].join("\n");
2544
2713
  }
2714
+ /**
2715
+ * JSON text with DEL, the C1 controls (which include the 8-bit CSI U+009B), the bidirectional
2716
+ * formatting characters and U+2028/U+2029 written as `\uXXXX` escapes. JSON.stringify already
2717
+ * escapes C0 controls; these characters can occur only inside strings, so the escaped text is
2718
+ * valid JSON with the same value, and a terminal showing it does not act on them (D-H01).
2719
+ */
2720
+ function jsonSafe(json) {
2721
+ return json.replace(/[\u007f-\u009f\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069\u2028\u2029]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
2722
+ }
2545
2723
  // src/cli/bin.ts
2546
2724
  function version() {
2547
2725
  try {
@@ -2563,6 +2741,7 @@ run(process.argv.slice(2), {
2563
2741
  stdoutIsTTY: process.stdout.isTTY === true,
2564
2742
  stderrIsTTY: process.stderr.isTTY === true,
2565
2743
  columns: process.stdout.columns,
2744
+ importModule: (specifier) => import(specifier),
2566
2745
  version: version()
2567
2746
  }).then((code) => {
2568
2747
  process.exitCode = code;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as InspectOptions, $n as verifyPassword, $t as DataValidationOperator, A as toJSON, An as Hyperlink, At as Workbook, B as FormulaResult, Bn as PrintErrors, Bt as CfValue, C as TableRow, Cn as ImageAnchorInput, Ct as Sheet, D as fromJSON, Dn as SheetImage, Dt as SheetState, E as WriteTableOptions, En as ImagePositionInput, Et as SheetProperties, F as CellInput, Fn as PageOrder, Ft as TableDefinitionColumn, G as SheetPropertiesOptions, Gn as SheetProtectionOptions, Gt as ConditionalFormatRule, H as NewSheet, Hn as PrintTitles, Ht as CfValueType, I as ColumnOptions, In as PageOrientation, It as TableInput, J as WriteWorkbookOptions, Jn as HashPasswordOptions, Jt as DataBarAxisPosition, K as SheetViewOptions, Kn as WorkbookProtection, Kt as ConditionalFormatRuleInput, L as CreateWorkbookOptions, Ln as PageSetup, Lt as TableStyleOptions, M as StandardSchemaV1, Mn as HeaderFooter, Mt as WorkbookView, N as AddSheetOptions, Nn as PageBreaks, Nt as TableColumnInput, O as readTable, On as WorkbookImage, Ot as SheetView, P as CalculationOptions, Pn as PageMargins, Pt as TableDefinition, Q as InspectDefinedName, Qn as legacyPasswordHash, Qt as DataValidationImeMode, R as ERROR_VALUES, Rn as PageSetupOptions, Rt as TotalsRowFunction, S as TableResult, Sn as ImageAnchor, St as RowInfo, T as ToJSONOptions, Tn as ImageOptions, Tt as SheetLayout, U as NewWorkbook, Un as SheetProtection, Ut as ConditionalFormat, V as FreezeOptions, Vn as PrintOptions, Vt as CfValueInput, W as RowOptions, Wn as SheetProtectionFlags, Wt as ConditionalFormatOperator, X as writeWorkbook, Xn as PasswordVerifier, Xt as DataValidation, Y as createWorkbook, Yn as PasswordHash, Yt as DataBarDirection, Z as InspectColumn, Zn as hashPassword, Zt as DataValidationErrorStyle, _ as JsonTable, _n as ReadingOrder, _r as DefinedNameOptions, _t as DateSystem, a as WriteWorkbookStreamOptions, an as BorderEdge, ar as XlvDetails, at as ReadOptions, b as TableColumnSpec, bn as VerticalAlignment, bt as FrozenPanes, c as OpenWorkbookStreamOptions, cn as CellStyle, cr as XlvErrorInit, ct as NoteBox, d as StreamRow, dn as FontScheme, dr as XlvWarning, dt as NoteMargins, en as DataValidationRule, er as ShaAlgorithm, et as InspectReport, f as StreamSheetInfo, fn as FontStyle, fr as XlvWarningCode, ft as Cell, g as readTableStream, gn as ProtectionStyle, gr as DefinedName, gt as Conformance, h as openWorkbookStream, hn as PatternType, hr as ReadLimits, ht as ColumnInfo, i as WriteTableStreamOptions, in as AlignmentStyle, ir as XlvDetailValue, it as inspect, j as writeTable, jn as HyperlinkTarget, jt as WorkbookFormat, k as readTableAsync, kn as imageFormat, kt as SplitPanes, l as ReadTableStreamOptions, ln as Color, lr as XlvErrorJSON, lt as NoteBoxInput, m as WorkbookStream, mn as HorizontalAlignment, mr as DEFAULT_READ_LIMITS, mt as CellValue, n as StreamRowInput, nn as IconSetType, nr as ERROR_CODES, nt as InspectTypeCounts, o as writeTableStream, on as BorderLineStyle, or as XlvError, ot as readWorkbook, p as TableStreamItem, pn as GradientFill, pr as isXlvError, pt as CellType, q as WorkbookViewOptions, qn as WorkbookProtectionOptions, qt as ConditionalFormatType, r as StreamSheetSpec, rn as TimePeriod, rr as WARNING_CODES, rt as InspectValue, s as writeWorkbookStream, sn as BorderStyle, sr as XlvErrorCode, st as Note, t as StreamDefinedName, tn as DataValidationType, tr as WorkbookProperties, tt as InspectSheet, u as STREAM_LIMIT_DEFAULTS, un as FillStyle, ur as XlvLocation, ut as NoteInput, v as ReadTableOptions, vn as UnderlineStyle, vt as Formula, w as TableValue, wn as ImageFormat, wt as SheetKind, x as TableIssue, xn as AnchorMarker, xt as RichTextRun, y as TableColumn, yn as VerticalAlignRun, yt as FormulaKind, z as ErrorValue, zn as PrintCellComments, zt as CfIcon } from "./stream-write-GJXORYQ2.js";
1
+ import { $ as InspectOptions, $n as verifyPassword, $t as DataValidationOperator, A as toJSON, An as Hyperlink, At as Workbook, B as FormulaResult, Bn as PrintErrors, Bt as CfValue, C as TableRow, Cn as ImageAnchorInput, Ct as Sheet, D as fromJSON, Dn as SheetImage, Dt as SheetState, E as WriteTableOptions, En as ImagePositionInput, Et as SheetProperties, F as CellInput, Fn as PageOrder, Ft as TableDefinitionColumn, G as SheetPropertiesOptions, Gn as SheetProtectionOptions, Gt as ConditionalFormatRule, H as NewSheet, Hn as PrintTitles, Ht as CfValueType, I as ColumnOptions, In as PageOrientation, It as TableInput, J as WriteWorkbookOptions, Jn as HashPasswordOptions, Jt as DataBarAxisPosition, K as SheetViewOptions, Kn as WorkbookProtection, Kt as ConditionalFormatRuleInput, L as CreateWorkbookOptions, Ln as PageSetup, Lt as TableStyleOptions, M as StandardSchemaV1, Mn as HeaderFooter, Mt as WorkbookView, N as AddSheetOptions, Nn as PageBreaks, Nt as TableColumnInput, O as readTable, On as WorkbookImage, Ot as SheetView, P as CalculationOptions, Pn as PageMargins, Pt as TableDefinition, Q as InspectDefinedName, Qn as legacyPasswordHash, Qt as DataValidationImeMode, R as ERROR_VALUES, Rn as PageSetupOptions, Rt as TotalsRowFunction, S as TableResult, Sn as ImageAnchor, St as RowInfo, T as ToJSONOptions, Tn as ImageOptions, Tt as SheetLayout, U as NewWorkbook, Un as SheetProtection, Ut as ConditionalFormat, V as FreezeOptions, Vn as PrintOptions, Vt as CfValueInput, W as RowOptions, Wn as SheetProtectionFlags, Wt as ConditionalFormatOperator, X as writeWorkbook, Xn as PasswordVerifier, Xt as DataValidation, Y as createWorkbook, Yn as PasswordHash, Yt as DataBarDirection, Z as InspectColumn, Zn as hashPassword, Zt as DataValidationErrorStyle, _ as JsonTable, _n as ReadingOrder, _r as DefinedNameOptions, _t as DateSystem, a as WriteWorkbookStreamOptions, an as BorderEdge, ar as XlvDetails, at as ReadOptions, b as TableColumnSpec, bn as VerticalAlignment, bt as FrozenPanes, c as OpenWorkbookStreamOptions, cn as CellStyle, cr as XlvErrorInit, ct as NoteBox, d as StreamRow, dn as FontScheme, dr as XlvWarning, dt as NoteMargins, en as DataValidationRule, er as ShaAlgorithm, et as InspectReport, f as StreamSheetInfo, fn as FontStyle, fr as XlvWarningCode, ft as Cell, g as readTableStream, gn as ProtectionStyle, gr as DefinedName, gt as Conformance, h as openWorkbookStream, hn as PatternType, hr as ReadLimits, ht as ColumnInfo, i as WriteTableStreamOptions, in as AlignmentStyle, ir as XlvDetailValue, it as inspect, j as writeTable, jn as HyperlinkTarget, jt as WorkbookFormat, k as readTableAsync, kn as imageFormat, kt as SplitPanes, l as ReadTableStreamOptions, ln as Color, lr as XlvErrorJSON, lt as NoteBoxInput, m as WorkbookStream, mn as HorizontalAlignment, mr as DEFAULT_READ_LIMITS, mt as CellValue, n as StreamRowInput, nn as IconSetType, nr as ERROR_CODES, nt as InspectTypeCounts, o as writeTableStream, on as BorderLineStyle, or as XlvError, ot as readWorkbook, p as TableStreamItem, pn as GradientFill, pr as isXlvError, pt as CellType, q as WorkbookViewOptions, qn as WorkbookProtectionOptions, qt as ConditionalFormatType, r as StreamSheetSpec, rn as TimePeriod, rr as WARNING_CODES, rt as InspectValue, s as writeWorkbookStream, sn as BorderStyle, sr as XlvErrorCode, st as Note, t as StreamDefinedName, tn as DataValidationType, tr as WorkbookProperties, tt as InspectSheet, u as STREAM_LIMIT_DEFAULTS, un as FillStyle, ur as XlvLocation, ut as NoteInput, v as ReadTableOptions, vn as UnderlineStyle, vt as Formula, w as TableValue, wn as ImageFormat, wt as SheetKind, x as TableIssue, xn as AnchorMarker, xt as RichTextRun, y as TableColumn, yn as VerticalAlignRun, yt as FormulaKind, z as ErrorValue, zn as PrintCellComments, zt as CfIcon } from "./stream-write-BVaFkgwO.js";
2
2
  /**
3
3
  * Options for {@link toCSV}.
4
4
  *
@@ -21,9 +21,10 @@ interface ToCSVOptions {
21
21
  /** Start with a UTF-8 byte order mark, which helps Excel detect UTF-8. Default `false`. */
22
22
  readonly bom?: boolean;
23
23
  /**
24
- * `"escape"` (default): text cells that start with `=`, `+`, `-`, `@`, tab, CR, LF or their
25
- * full-width forms get a leading `'` and quotes, so spreadsheet applications show them as
26
- * text instead of running them as formulas (OWASP CSV Injection). `"off"`: write them as is.
24
+ * `"escape"` (default): text cells that start with `=`, `+`, `-`, `@`, their full-width or small
25
+ * forms, or a control character (tab, CR, LF, NUL, …) get a leading `'` and quotes, so
26
+ * spreadsheet applications show them as text instead of running them as formulas (OWASP CSV
27
+ * Injection). `"off"`: write them as is.
27
28
  */
28
29
  readonly formulaInjection?: "escape" | "off";
29
30
  /** Read limits for byte input; see `ReadLimits`. */
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Dn as isXlvError, En as XlvError, Gt as legacyPasswordHash, Kt as verifyPassword, Rt as DEFAULT_READ_LIMITS, Tn as WARNING_CODES, Wt as hashPassword, Zt as imageFormat, b as readWorkbook, c as NewSheet, f as createWorkbook, g as inspect, l as NewWorkbook, m as writeWorkbook, s as ERROR_VALUES, wn as ERROR_CODES, z as shiftFormula } from "./options-CwSp2pA4.js";
2
- import { a as appendRows, c as fromCSV, d as fromJSON, g as writeTable, h as toJSON, i as adjustRange, m as readTableAsync, n as insertRows, o as editCells, p as readTable, r as adjustFormula, s as diff, t as deleteRows, u as toCSV } from "./rows-DKwlr0rg.js";
3
- import { a as readTableStream, i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS, t as writeTableStream } from "./stream-write-BKppyMz0.js";
1
+ import { Dn as WARNING_CODES, En as ERROR_CODES, Gt as hashPassword, Kt as legacyPasswordHash, On as XlvError, Qt as imageFormat, Rt as DEFAULT_READ_LIMITS, b as readWorkbook, c as NewSheet, f as createWorkbook, g as inspect, kn as isXlvError, l as NewWorkbook, m as writeWorkbook, qt as verifyPassword, s as ERROR_VALUES, z as shiftFormula } from "./options-Ba1iWD-Z.js";
2
+ import { a as appendRows, c as fromCSV, d as fromJSON, g as writeTable, h as toJSON, i as adjustRange, m as readTableAsync, n as insertRows, o as editCells, p as readTable, r as adjustFormula, s as diff, t as deleteRows, u as toCSV } from "./rows-IWKIxHt9.js";
3
+ import { a as readTableStream, i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS, t as writeTableStream } from "./stream-write-BGuUjlXo.js";
4
4
  export { DEFAULT_READ_LIMITS, ERROR_CODES, ERROR_VALUES, NewSheet, NewWorkbook, STREAM_LIMIT_DEFAULTS, WARNING_CODES, XlvError, adjustFormula, adjustRange, appendRows, createWorkbook, deleteRows, diff, editCells, fromCSV, fromJSON, hashPassword, imageFormat, insertRows, inspect, isXlvError, legacyPasswordHash, openWorkbookStream, readTable, readTableAsync, readTableStream, readWorkbook, shiftFormula, toCSV, toJSON, verifyPassword, writeTable, writeTableStream, writeWorkbook, writeWorkbookStream };
@@ -1,4 +1,4 @@
1
- import { En as XlvError, zt as resolveLimits } from "./options-CwSp2pA4.js";
1
+ import { Bt as resolveLimits, On as XlvError } from "./options-Ba1iWD-Z.js";
2
2
  import { readFile, stat } from "node:fs/promises";
3
3
  // src/util/node-files.ts
4
4
  /** The path as shown in messages. */
package/dist/node.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as InspectOptions, At as Workbook, J as WriteWorkbookOptions, U as NewWorkbook, a as WriteWorkbookStreamOptions, at as ReadOptions, c as OpenWorkbookStreamOptions, et as InspectReport, m as WorkbookStream } from "./stream-write-GJXORYQ2.js";
1
+ import { $ as InspectOptions, At as Workbook, J as WriteWorkbookOptions, U as NewWorkbook, a as WriteWorkbookStreamOptions, at as ReadOptions, c as OpenWorkbookStreamOptions, et as InspectReport, m as WorkbookStream } from "./stream-write-BVaFkgwO.js";
2
2
  /**
3
3
  * Reads an XLSX file from disk. Node.js only; in other runtimes pass the bytes to
4
4
  * `readWorkbook` from `xlvane`. The file size is checked against `limits.maxInputBytes`
package/dist/node.js CHANGED
@@ -1,6 +1,6 @@
1
- import { En as XlvError, b as readWorkbook, g as inspect, m as writeWorkbook, zt as resolveLimits } from "./options-CwSp2pA4.js";
2
- import { i as readInput, n as describePath, r as fileError, t as checkFile } from "./node-files-B0iqSJIJ.js";
3
- import { i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS } from "./stream-write-BKppyMz0.js";
1
+ import { Bt as resolveLimits, On as XlvError, b as readWorkbook, g as inspect, m as writeWorkbook } from "./options-Ba1iWD-Z.js";
2
+ import { i as readInput, n as describePath, r as fileError, t as checkFile } from "./node-files-CDb6TyZb.js";
3
+ import { i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS } from "./stream-write-BGuUjlXo.js";
4
4
  import { openAsBlob } from "node:fs";
5
5
  import { open, unlink, writeFile } from "node:fs/promises";
6
6
  // src/node.ts