xlvane 1.1.0 → 1.1.1
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 +4 -3
- package/dist/cli.js +147 -43
- package/dist/index.d.ts +5 -4
- package/dist/index.js +3 -3
- package/dist/{node-files-B0iqSJIJ.js → node-files-CsQVpKgP.js} +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +3 -3
- package/dist/{options-CwSp2pA4.js → options-Ba6r4zP1.js} +313 -74
- package/dist/{rows-DKwlr0rg.js → rows-Biu_ddwz.js} +59 -15
- package/dist/{stream-write-GJXORYQ2.d.ts → stream-write-CaGFWPhB.d.ts} +8 -5
- package/dist/{stream-write-BKppyMz0.js → stream-write-CtWyTd44.js} +24 -9
- package/docs/errors.md +17 -0
- package/docs/exceljs-compat.md +1 -1
- package/llms-full.txt +23 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -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
|
|
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 {
|
|
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-
|
|
4
|
-
import { i as readInput } from "./node-files-
|
|
2
|
+
import { On as XlvError, Vt as suggest, _ as isoDate, b as readWorkbook, dn as parseRange, g as inspect } from "./options-Ba6r4zP1.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-Biu_ddwz.js";
|
|
4
|
+
import { i as readInput } from "./node-files-CsQVpKgP.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
|
-
|
|
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`
|
|
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
|
-
/**
|
|
535
|
-
|
|
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
|
|
539
|
-
*
|
|
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);
|
|
@@ -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,23 +1821,23 @@ 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((
|
|
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
|
}
|
|
@@ -1866,10 +1888,11 @@ async function sourceFiles(root) {
|
|
|
1866
1888
|
const path = join(dir, name);
|
|
1867
1889
|
let info;
|
|
1868
1890
|
try {
|
|
1869
|
-
info = await
|
|
1891
|
+
info = await lstat(path);
|
|
1870
1892
|
} catch {
|
|
1871
1893
|
continue;
|
|
1872
1894
|
}
|
|
1895
|
+
if (info.isSymbolicLink()) continue;
|
|
1873
1896
|
if (info.isDirectory()) await walk(path);
|
|
1874
1897
|
else if (info.isFile() && SOURCE.test(name) && info.size <= MAX_FILE_BYTES) files.push(path);
|
|
1875
1898
|
}
|
|
@@ -1898,6 +1921,75 @@ function scanSource(file, text) {
|
|
|
1898
1921
|
});
|
|
1899
1922
|
return findings;
|
|
1900
1923
|
}
|
|
1924
|
+
/**
|
|
1925
|
+
* Offsets `[start, end)` of the string value (with its quotes) at `path` in valid JSON text, the
|
|
1926
|
+
* one JSON.parse reads when keys repeat, or `null`. Keys are compared after decoding their
|
|
1927
|
+
* escapes. Values off the path are skipped without recursion.
|
|
1928
|
+
*/
|
|
1929
|
+
function stringValueSpan(text, path) {
|
|
1930
|
+
let i = 0;
|
|
1931
|
+
const space = () => {
|
|
1932
|
+
while (i < text.length && " \r\n".includes(text[i])) i++;
|
|
1933
|
+
};
|
|
1934
|
+
/** Skips a string starting at i (on its opening quote); returns its raw text. */
|
|
1935
|
+
const string = () => {
|
|
1936
|
+
const start = i++;
|
|
1937
|
+
while (text[i] !== "\"") i += text[i] === "\\" ? 2 : 1;
|
|
1938
|
+
i++;
|
|
1939
|
+
return text.slice(start, i);
|
|
1940
|
+
};
|
|
1941
|
+
/** Skips any value starting at i, iteratively. */
|
|
1942
|
+
const skip = () => {
|
|
1943
|
+
let depth = 0;
|
|
1944
|
+
do {
|
|
1945
|
+
const c = text[i];
|
|
1946
|
+
if (c === "\"") string();
|
|
1947
|
+
else {
|
|
1948
|
+
if (c === "{" || c === "[") depth++;
|
|
1949
|
+
else if (c === "}" || c === "]") depth--;
|
|
1950
|
+
i++;
|
|
1951
|
+
if (depth === 0 && c !== "{" && c !== "[") while (i < text.length && !",]} \r\n".includes(text[i])) i++;
|
|
1952
|
+
}
|
|
1953
|
+
} while (depth > 0 && i < text.length);
|
|
1954
|
+
};
|
|
1955
|
+
const value = (level) => {
|
|
1956
|
+
space();
|
|
1957
|
+
if (level === path.length) {
|
|
1958
|
+
if (text[i] !== "\"") {
|
|
1959
|
+
skip();
|
|
1960
|
+
return null;
|
|
1961
|
+
}
|
|
1962
|
+
const start = i;
|
|
1963
|
+
string();
|
|
1964
|
+
return [start, i];
|
|
1965
|
+
}
|
|
1966
|
+
if (text[i] !== "{") {
|
|
1967
|
+
skip();
|
|
1968
|
+
return null;
|
|
1969
|
+
}
|
|
1970
|
+
i++;
|
|
1971
|
+
let found = null;
|
|
1972
|
+
space();
|
|
1973
|
+
if (text[i] === "}") {
|
|
1974
|
+
i++;
|
|
1975
|
+
return null;
|
|
1976
|
+
}
|
|
1977
|
+
for (;;) {
|
|
1978
|
+
space();
|
|
1979
|
+
const key = JSON.parse(string());
|
|
1980
|
+
space();
|
|
1981
|
+
i++;
|
|
1982
|
+
if (key === path[level]) found = value(level + 1);
|
|
1983
|
+
else {
|
|
1984
|
+
space();
|
|
1985
|
+
skip();
|
|
1986
|
+
}
|
|
1987
|
+
space();
|
|
1988
|
+
if (text[i++] === "}") return found;
|
|
1989
|
+
}
|
|
1990
|
+
};
|
|
1991
|
+
return value(0);
|
|
1992
|
+
}
|
|
1901
1993
|
function jsonError(path, cause) {
|
|
1902
1994
|
return new XlvError("XLV_E_JSON_INVALID", `"${path}" is not a valid package.json.`, {
|
|
1903
1995
|
hint: "Fix the JSON syntax of package.json and run the command again.",
|
|
@@ -1945,11 +2037,14 @@ async function run$1(ctx) {
|
|
|
1945
2037
|
}
|
|
1946
2038
|
let write = null;
|
|
1947
2039
|
if (changes.length > 0 && flag(ctx.args, "force")) {
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
2040
|
+
const spans = changes.map((c) => stringValueSpan(text, [c.section, "exceljs"])).filter((s) => s !== null);
|
|
2041
|
+
let updated = "";
|
|
2042
|
+
let at = 0;
|
|
2043
|
+
for (const [start, end] of spans.sort((a, b) => a[0] - b[0])) {
|
|
2044
|
+
updated += `${text.slice(at, start)}"${ALIAS}"`;
|
|
2045
|
+
at = end;
|
|
1952
2046
|
}
|
|
2047
|
+
updated += text.slice(at);
|
|
1953
2048
|
write = await writeOutput(ctx, pkgPath, updated, {
|
|
1954
2049
|
force: true,
|
|
1955
2050
|
dryRun: flag(ctx.args, "dry-run")
|
|
@@ -2350,14 +2445,14 @@ async function run(argv, io) {
|
|
|
2350
2445
|
const err = new Output(useColor(io.env, io.stderrIsTTY), io.stderrIsTTY ? width : 100);
|
|
2351
2446
|
const stdout = (text) => io.stdout(terminalSafe(text, out.color));
|
|
2352
2447
|
const stderr = (text) => io.stderr(terminalSafe(text, err.color));
|
|
2353
|
-
const toJson = (value) => `${io.stdoutIsTTY ? JSON.stringify(value, null, 2) : JSON.stringify(value)}\n`;
|
|
2448
|
+
const toJson = (value) => `${jsonSafe(io.stdoutIsTTY ? JSON.stringify(value, null, 2) : JSON.stringify(value))}\n`;
|
|
2354
2449
|
const json = optionArgs(argv).includes("--json");
|
|
2355
2450
|
const [first, ...rest] = argv;
|
|
2356
2451
|
let spec;
|
|
2357
2452
|
const state = { lastFile: null };
|
|
2358
2453
|
try {
|
|
2359
2454
|
if (first === void 0 || first === "--json" && rest.length === 0) {
|
|
2360
|
-
|
|
2455
|
+
stdout(welcome(out, io.version, COMMANDS));
|
|
2361
2456
|
return EXIT.ok;
|
|
2362
2457
|
}
|
|
2363
2458
|
if (first === "--version" || first === "-v") {
|
|
@@ -2367,7 +2462,7 @@ async function run(argv, io) {
|
|
|
2367
2462
|
if (first === "help" || first === "--help" || first === "-h") {
|
|
2368
2463
|
const topic = rest.find((a) => !a.startsWith("-"));
|
|
2369
2464
|
if (topic === void 0) {
|
|
2370
|
-
|
|
2465
|
+
stdout(welcome(out, io.version, COMMANDS));
|
|
2371
2466
|
return EXIT.ok;
|
|
2372
2467
|
}
|
|
2373
2468
|
stdout(commandHelp(out, findCommand(topic)));
|
|
@@ -2542,6 +2637,15 @@ function formatError(err, error, tryCommand, verbose = false) {
|
|
|
2542
2637
|
""
|
|
2543
2638
|
].join("\n");
|
|
2544
2639
|
}
|
|
2640
|
+
/**
|
|
2641
|
+
* JSON text with DEL, the C1 controls (which include the 8-bit CSI U+009B), the bidirectional
|
|
2642
|
+
* formatting characters and U+2028/U+2029 written as `\uXXXX` escapes. JSON.stringify already
|
|
2643
|
+
* escapes C0 controls; these characters can occur only inside strings, so the escaped text is
|
|
2644
|
+
* valid JSON with the same value, and a terminal showing it does not act on them (D-H01).
|
|
2645
|
+
*/
|
|
2646
|
+
function jsonSafe(json) {
|
|
2647
|
+
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")}`);
|
|
2648
|
+
}
|
|
2545
2649
|
// src/cli/bin.ts
|
|
2546
2650
|
function version() {
|
|
2547
2651
|
try {
|
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-
|
|
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-CaGFWPhB.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 `=`, `+`, `-`, `@`,
|
|
25
|
-
*
|
|
26
|
-
* text instead of running them as formulas (OWASP CSV
|
|
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
|
|
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-
|
|
3
|
-
import { a as readTableStream, i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS, t as writeTableStream } from "./stream-write-
|
|
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-Ba6r4zP1.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-Biu_ddwz.js";
|
|
3
|
+
import { a as readTableStream, i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS, t as writeTableStream } from "./stream-write-CtWyTd44.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 {
|
|
1
|
+
import { Bt as resolveLimits, On as XlvError } from "./options-Ba6r4zP1.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-
|
|
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-CaGFWPhB.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 {
|
|
2
|
-
import { i as readInput, n as describePath, r as fileError, t as checkFile } from "./node-files-
|
|
3
|
-
import { i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS } from "./stream-write-
|
|
1
|
+
import { Bt as resolveLimits, On as XlvError, b as readWorkbook, g as inspect, m as writeWorkbook } from "./options-Ba6r4zP1.js";
|
|
2
|
+
import { i as readInput, n as describePath, r as fileError, t as checkFile } from "./node-files-CsQVpKgP.js";
|
|
3
|
+
import { i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS } from "./stream-write-CtWyTd44.js";
|
|
4
4
|
import { openAsBlob } from "node:fs";
|
|
5
5
|
import { open, unlink, writeFile } from "node:fs/promises";
|
|
6
6
|
// src/node.ts
|