@particle-academy/holy-sheet 2.10.0 → 2.10.2
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/CHANGELOG.md +34 -0
- package/README.md +7 -0
- package/dist/index.cjs +306 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -4
- package/dist/index.d.ts +18 -4
- package/dist/index.js +306 -102
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -242,12 +242,12 @@ function parseRows(csv, delimiter, quote2) {
|
|
|
242
242
|
// src/workbook/cell-address.ts
|
|
243
243
|
var CellAddress = {
|
|
244
244
|
/** 0-based column index → Excel-style letters. */
|
|
245
|
-
letter(
|
|
246
|
-
if (
|
|
247
|
-
throw new Error(`[holy-sheet] column index must be \u2265 0, got ${
|
|
245
|
+
letter(index2) {
|
|
246
|
+
if (index2 < 0) {
|
|
247
|
+
throw new Error(`[holy-sheet] column index must be \u2265 0, got ${index2}`);
|
|
248
248
|
}
|
|
249
249
|
let letters = "";
|
|
250
|
-
let n =
|
|
250
|
+
let n = index2;
|
|
251
251
|
do {
|
|
252
252
|
letters = String.fromCharCode(65 + n % 26) + letters;
|
|
253
253
|
n = Math.floor(n / 26) - 1;
|
|
@@ -300,8 +300,8 @@ var ColumnWidths = {
|
|
|
300
300
|
return Number.isInteger(key) && key >= 0 && key <= ColumnWidths.MAX_INDEX ? key : null;
|
|
301
301
|
}
|
|
302
302
|
if (typeof key === "string" && /^[0-9]{1,5}$/.test(key)) {
|
|
303
|
-
const
|
|
304
|
-
return
|
|
303
|
+
const index2 = parseInt(key, 10);
|
|
304
|
+
return index2 <= ColumnWidths.MAX_INDEX ? index2 : null;
|
|
305
305
|
}
|
|
306
306
|
return null;
|
|
307
307
|
},
|
|
@@ -560,6 +560,14 @@ var DateConverter = {
|
|
|
560
560
|
};
|
|
561
561
|
|
|
562
562
|
// src/exceptions.ts
|
|
563
|
+
var ArchiveRefused = class _ArchiveRefused extends Error {
|
|
564
|
+
constructor(reason) {
|
|
565
|
+
super(`Source archive refused: ${reason}`);
|
|
566
|
+
this.reason = reason;
|
|
567
|
+
this.name = "ArchiveRefused";
|
|
568
|
+
Object.setPrototypeOf(this, _ArchiveRefused.prototype);
|
|
569
|
+
}
|
|
570
|
+
};
|
|
563
571
|
var SchemaException = class _SchemaException extends Error {
|
|
564
572
|
constructor(errors, message) {
|
|
565
573
|
super(message ?? summarize(errors));
|
|
@@ -800,23 +808,23 @@ var Normalizer = class {
|
|
|
800
808
|
for (const [colIdx, columnDef] of (sheet.columns ?? []).entries()) {
|
|
801
809
|
if (columnDef === null || typeof columnDef !== "object") continue;
|
|
802
810
|
if (columnDef.width === void 0) continue;
|
|
803
|
-
const
|
|
811
|
+
const index2 = ColumnWidths.index(colIdx);
|
|
804
812
|
const width = ColumnWidths.width(columnDef.width);
|
|
805
|
-
if (
|
|
806
|
-
out.set(
|
|
813
|
+
if (index2 === null || width === null) continue;
|
|
814
|
+
out.set(index2, width);
|
|
807
815
|
}
|
|
808
|
-
for (const [
|
|
809
|
-
out.set(
|
|
816
|
+
for (const [index2, width] of this.normalizeColumnWidths(sheet.columnWidths ?? {})) {
|
|
817
|
+
out.set(index2, width);
|
|
810
818
|
}
|
|
811
819
|
return new Map([...out.entries()].sort((a, b) => a[0] - b[0]));
|
|
812
820
|
}
|
|
813
821
|
normalizeColumnWidths(widths) {
|
|
814
822
|
const out = /* @__PURE__ */ new Map();
|
|
815
823
|
for (const [key, px] of Object.entries(widths)) {
|
|
816
|
-
const
|
|
824
|
+
const index2 = ColumnWidths.index(key);
|
|
817
825
|
const width = ColumnWidths.width(px);
|
|
818
|
-
if (
|
|
819
|
-
out.set(
|
|
826
|
+
if (index2 === null || width === null) continue;
|
|
827
|
+
out.set(index2, width);
|
|
820
828
|
}
|
|
821
829
|
return out;
|
|
822
830
|
}
|
|
@@ -928,14 +936,14 @@ function normalizePoints(points2, count) {
|
|
|
928
936
|
const byIndex = /* @__PURE__ */ new Map();
|
|
929
937
|
for (const p of Object.values(points2)) {
|
|
930
938
|
const rec = isPlainObject(p) || Array.isArray(p) ? p : null;
|
|
931
|
-
const
|
|
939
|
+
const index2 = rec ? rec.index : void 0;
|
|
932
940
|
const color2 = rec ? rec.color : void 0;
|
|
933
941
|
const m = typeof color2 === "string" ? /^#([0-9A-Fa-f]{6})$/.exec(color2) : null;
|
|
934
|
-
if (typeof
|
|
935
|
-
byIndex.set(
|
|
942
|
+
if (typeof index2 === "number" && Number.isInteger(index2) && index2 >= 0 && index2 < count && m) {
|
|
943
|
+
byIndex.set(index2, m[1].toUpperCase());
|
|
936
944
|
}
|
|
937
945
|
}
|
|
938
|
-
return [...byIndex.entries()].sort((a, b) => a[0] - b[0]).map(([
|
|
946
|
+
return [...byIndex.entries()].sort((a, b) => a[0] - b[0]).map(([index2, color2]) => ({ index: index2, color: color2 }));
|
|
939
947
|
}
|
|
940
948
|
var CHART_TYPES = ["column", "bar", "line", "pie"];
|
|
941
949
|
function normalizeCharts(charts, sheetName2, cells) {
|
|
@@ -1069,13 +1077,13 @@ var FormulaLinter = class {
|
|
|
1069
1077
|
return issues;
|
|
1070
1078
|
}
|
|
1071
1079
|
buildIndex(wb) {
|
|
1072
|
-
const
|
|
1080
|
+
const index2 = /* @__PURE__ */ new Map();
|
|
1073
1081
|
for (const sheet of wb.sheets) {
|
|
1074
1082
|
for (const [address, cell] of sheet.cells) {
|
|
1075
|
-
|
|
1083
|
+
index2.set(sheet.name + "!" + address, cell);
|
|
1076
1084
|
}
|
|
1077
1085
|
}
|
|
1078
|
-
return
|
|
1086
|
+
return index2;
|
|
1079
1087
|
}
|
|
1080
1088
|
isError(v) {
|
|
1081
1089
|
return typeof v === "string" && v.length > 0 && v[0] === "#";
|
|
@@ -1589,21 +1597,21 @@ var Repairer = class {
|
|
|
1589
1597
|
const widths = {};
|
|
1590
1598
|
let changed = false;
|
|
1591
1599
|
for (const [key, px] of Object.entries(sheet.columnWidths)) {
|
|
1592
|
-
let
|
|
1593
|
-
if (
|
|
1600
|
+
let index2 = ColumnWidths.index(key);
|
|
1601
|
+
if (index2 === null) {
|
|
1594
1602
|
const letters = ColumnWidths.fromLetters(key);
|
|
1595
1603
|
if (letters !== null) {
|
|
1596
|
-
|
|
1597
|
-
this.repairs.push(`converted '${path}.columnWidths.${key}' to column index ${
|
|
1604
|
+
index2 = letters;
|
|
1605
|
+
this.repairs.push(`converted '${path}.columnWidths.${key}' to column index ${index2}`);
|
|
1598
1606
|
changed = true;
|
|
1599
1607
|
}
|
|
1600
1608
|
}
|
|
1601
|
-
if (
|
|
1609
|
+
if (index2 === null || ColumnWidths.width(px) === null) {
|
|
1602
1610
|
this.repairs.push(`dropped '${path}.columnWidths.${key}' (not a column index and a width)`);
|
|
1603
1611
|
changed = true;
|
|
1604
1612
|
continue;
|
|
1605
1613
|
}
|
|
1606
|
-
widths[String(
|
|
1614
|
+
widths[String(index2)] = px;
|
|
1607
1615
|
}
|
|
1608
1616
|
if (changed) {
|
|
1609
1617
|
sheet.columnWidths = widths;
|
|
@@ -2027,14 +2035,14 @@ function validatePoints(points2, at2, values2) {
|
|
|
2027
2035
|
const errors = [];
|
|
2028
2036
|
points2.forEach((p, k) => {
|
|
2029
2037
|
const rec = isPlainObject(p) || Array.isArray(p) ? p : null;
|
|
2030
|
-
const
|
|
2038
|
+
const index2 = rec ? rec.index ?? null : null;
|
|
2031
2039
|
const color2 = rec ? rec.color ?? null : null;
|
|
2032
|
-
if (typeof
|
|
2040
|
+
if (typeof index2 !== "number" || !Number.isInteger(index2) || index2 < 0 || index2 >= count) {
|
|
2033
2041
|
errors.push(error(
|
|
2034
2042
|
`${at2}[${k}].index`,
|
|
2035
2043
|
"an index within values (0 to " + Math.max(0, count - 1) + ")",
|
|
2036
|
-
typeOf(
|
|
2037
|
-
|
|
2044
|
+
typeOf(index2),
|
|
2045
|
+
index2,
|
|
2038
2046
|
'The 0-based position of the point in its values range: "B5:B7" has points 0, 1 and 2.'
|
|
2039
2047
|
));
|
|
2040
2048
|
}
|
|
@@ -2429,8 +2437,17 @@ function buildTree(t, lengths, off, num) {
|
|
|
2429
2437
|
let i;
|
|
2430
2438
|
let sum = 0;
|
|
2431
2439
|
for (i = 0; i < 16; i++) t.table[i] = 0;
|
|
2432
|
-
for (i = 0; i < num; i++)
|
|
2440
|
+
for (i = 0; i < num; i++) {
|
|
2441
|
+
const length = lengths[off + i];
|
|
2442
|
+
if (length === void 0 || length > 15) throw new Error("holy-sheet: invalid DEFLATE tree");
|
|
2443
|
+
t.table[length]++;
|
|
2444
|
+
}
|
|
2433
2445
|
t.table[0] = 0;
|
|
2446
|
+
let slots = 1;
|
|
2447
|
+
for (i = 1; i <= 15; i++) {
|
|
2448
|
+
slots = slots * 2 - t.table[i];
|
|
2449
|
+
if (slots < 0) throw new Error("holy-sheet: oversubscribed DEFLATE tree");
|
|
2450
|
+
}
|
|
2434
2451
|
for (i = 0; i < 16; i++) {
|
|
2435
2452
|
OFFS[i] = sum;
|
|
2436
2453
|
sum += t.table[i];
|
|
@@ -2450,6 +2467,7 @@ var Reader = class {
|
|
|
2450
2467
|
};
|
|
2451
2468
|
function getBit(d) {
|
|
2452
2469
|
if (d.bitcount-- === 0) {
|
|
2470
|
+
if (d.index >= d.source.length) throw new Error("holy-sheet: truncated DEFLATE input");
|
|
2453
2471
|
d.tag = d.source[d.index++];
|
|
2454
2472
|
d.bitcount = 7;
|
|
2455
2473
|
}
|
|
@@ -2470,6 +2488,7 @@ function decodeSymbol(d, t) {
|
|
|
2470
2488
|
do {
|
|
2471
2489
|
cur = 2 * cur + getBit(d);
|
|
2472
2490
|
len++;
|
|
2491
|
+
if (len > 15) throw new Error("holy-sheet: invalid DEFLATE code");
|
|
2473
2492
|
sum += t.table[len];
|
|
2474
2493
|
cur -= t.table[len];
|
|
2475
2494
|
} while (cur >= 0);
|
|
@@ -2480,6 +2499,7 @@ function decodeTrees(d, lt, dt) {
|
|
|
2480
2499
|
const hlit = readBits(d, 5, 257);
|
|
2481
2500
|
const hdist = readBits(d, 5, 1);
|
|
2482
2501
|
const hclen = readBits(d, 4, 4);
|
|
2502
|
+
if (hlit > 286) throw new Error("holy-sheet: invalid DEFLATE literal count");
|
|
2483
2503
|
let i;
|
|
2484
2504
|
for (i = 0; i < 19; i++) lengths[i] = 0;
|
|
2485
2505
|
for (i = 0; i < hclen; i++) {
|
|
@@ -2492,32 +2512,44 @@ function decodeTrees(d, lt, dt) {
|
|
|
2492
2512
|
const sym = decodeSymbol(d, codeTree);
|
|
2493
2513
|
switch (sym) {
|
|
2494
2514
|
case 16: {
|
|
2515
|
+
if (num === 0) throw new Error("holy-sheet: invalid DEFLATE repeat");
|
|
2495
2516
|
const prev = lengths[num - 1];
|
|
2496
|
-
|
|
2517
|
+
const repeat = readBits(d, 2, 3);
|
|
2518
|
+
if (num + repeat > hlit + hdist) throw new Error("holy-sheet: invalid DEFLATE repeat");
|
|
2519
|
+
for (let length = repeat; length; length--) lengths[num++] = prev;
|
|
2497
2520
|
break;
|
|
2498
2521
|
}
|
|
2499
|
-
case 17:
|
|
2500
|
-
|
|
2522
|
+
case 17: {
|
|
2523
|
+
const repeat = readBits(d, 3, 3);
|
|
2524
|
+
if (num + repeat > hlit + hdist) throw new Error("holy-sheet: invalid DEFLATE repeat");
|
|
2525
|
+
for (let length = repeat; length; length--) lengths[num++] = 0;
|
|
2501
2526
|
break;
|
|
2502
|
-
|
|
2503
|
-
|
|
2527
|
+
}
|
|
2528
|
+
case 18: {
|
|
2529
|
+
const repeat = readBits(d, 7, 11);
|
|
2530
|
+
if (num + repeat > hlit + hdist) throw new Error("holy-sheet: invalid DEFLATE repeat");
|
|
2531
|
+
for (let length = repeat; length; length--) lengths[num++] = 0;
|
|
2504
2532
|
break;
|
|
2533
|
+
}
|
|
2505
2534
|
default:
|
|
2506
2535
|
lengths[num++] = sym;
|
|
2507
2536
|
break;
|
|
2508
2537
|
}
|
|
2509
2538
|
}
|
|
2539
|
+
if (lengths[256] === 0) throw new Error("holy-sheet: missing DEFLATE end code");
|
|
2510
2540
|
buildTree(lt, lengths, 0, hlit);
|
|
2511
2541
|
buildTree(dt, lengths, hlit, hdist);
|
|
2512
2542
|
}
|
|
2513
2543
|
var Out = class {
|
|
2514
|
-
constructor() {
|
|
2515
|
-
this.
|
|
2544
|
+
constructor(limit) {
|
|
2545
|
+
this.limit = limit;
|
|
2516
2546
|
this.len = 0;
|
|
2547
|
+
this.buf = new Uint8Array(Math.min(1024, limit));
|
|
2517
2548
|
}
|
|
2518
2549
|
push(b) {
|
|
2550
|
+
if (this.len >= this.limit) throw new Error("holy-sheet: DEFLATE output limit exceeded");
|
|
2519
2551
|
if (this.len >= this.buf.length) {
|
|
2520
|
-
const next = new Uint8Array(this.buf.length * 2);
|
|
2552
|
+
const next = new Uint8Array(Math.min(this.limit, Math.max(1, this.buf.length * 2)));
|
|
2521
2553
|
next.set(this.buf);
|
|
2522
2554
|
this.buf = next;
|
|
2523
2555
|
}
|
|
@@ -2532,9 +2564,12 @@ function inflateBlockData(d, out, lt, dt) {
|
|
|
2532
2564
|
out.push(sym);
|
|
2533
2565
|
} else {
|
|
2534
2566
|
const lengthSym = sym - 257;
|
|
2567
|
+
if (lengthSym < 0 || lengthSym >= LENGTH_BITS.length) throw new Error("holy-sheet: invalid DEFLATE length");
|
|
2535
2568
|
const length = readBits(d, LENGTH_BITS[lengthSym], LENGTH_BASE[lengthSym]);
|
|
2536
2569
|
const distSym = decodeSymbol(d, dt);
|
|
2570
|
+
if (distSym < 0 || distSym >= DIST_BITS.length) throw new Error("holy-sheet: invalid DEFLATE distance");
|
|
2537
2571
|
const dist = readBits(d, DIST_BITS[distSym], DIST_BASE[distSym]);
|
|
2572
|
+
if (dist > out.len) throw new Error("holy-sheet: DEFLATE distance before output");
|
|
2538
2573
|
const offs = out.len - dist;
|
|
2539
2574
|
for (let i = 0; i < length; i++) out.push(out.buf[offs + i]);
|
|
2540
2575
|
}
|
|
@@ -2542,13 +2577,20 @@ function inflateBlockData(d, out, lt, dt) {
|
|
|
2542
2577
|
}
|
|
2543
2578
|
function inflateUncompressedBlock(d, out) {
|
|
2544
2579
|
d.bitcount = 0;
|
|
2580
|
+
if (d.index + 4 > d.source.length) throw new Error("holy-sheet: truncated DEFLATE input");
|
|
2545
2581
|
let length = d.source[d.index + 1] * 256 + d.source[d.index];
|
|
2582
|
+
const complement = d.source[d.index + 3] * 256 + d.source[d.index + 2];
|
|
2583
|
+
if ((length ^ complement) !== 65535) throw new Error("holy-sheet: invalid DEFLATE stored length");
|
|
2546
2584
|
d.index += 4;
|
|
2585
|
+
if (d.index + length > d.source.length) throw new Error("holy-sheet: truncated DEFLATE input");
|
|
2547
2586
|
for (; length; length--) out.push(d.source[d.index++]);
|
|
2548
2587
|
}
|
|
2549
|
-
function inflateRaw(source) {
|
|
2588
|
+
function inflateRaw(source, maxOutputBytes = Number.POSITIVE_INFINITY) {
|
|
2589
|
+
if (maxOutputBytes !== Number.POSITIVE_INFINITY && (!Number.isSafeInteger(maxOutputBytes) || maxOutputBytes < 0)) {
|
|
2590
|
+
throw new Error("holy-sheet: invalid DEFLATE output limit");
|
|
2591
|
+
}
|
|
2550
2592
|
const d = new Reader(source);
|
|
2551
|
-
const out = new Out();
|
|
2593
|
+
const out = new Out(maxOutputBytes);
|
|
2552
2594
|
const lt = new Tree();
|
|
2553
2595
|
const dt = new Tree();
|
|
2554
2596
|
let bfinal;
|
|
@@ -2570,41 +2612,166 @@ function inflateRaw(source) {
|
|
|
2570
2612
|
return out.buf.subarray(0, out.len);
|
|
2571
2613
|
}
|
|
2572
2614
|
|
|
2573
|
-
// src/zip/
|
|
2574
|
-
var
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2615
|
+
// src/zip/source-archive.ts
|
|
2616
|
+
var DEFAULT_ARCHIVE_LIMITS = Object.freeze({
|
|
2617
|
+
maxArchiveBytes: 67108864,
|
|
2618
|
+
maxEntries: 16384,
|
|
2619
|
+
maxPartBytes: 67108864,
|
|
2620
|
+
maxExpandedBytes: 268435456,
|
|
2621
|
+
maxCompressionRatio: 1e3
|
|
2622
|
+
});
|
|
2623
|
+
var corrupt = () => {
|
|
2624
|
+
throw new ArchiveRefused("archive_corrupt");
|
|
2625
|
+
};
|
|
2626
|
+
var SourceArchive = class _SourceArchive {
|
|
2627
|
+
constructor(original, parts) {
|
|
2628
|
+
this.original = original;
|
|
2629
|
+
this.parts = parts;
|
|
2630
|
+
}
|
|
2631
|
+
static open(input, options = {}) {
|
|
2632
|
+
for (const [key, value] of Object.entries(options)) {
|
|
2633
|
+
if (!Object.prototype.hasOwnProperty.call(DEFAULT_ARCHIVE_LIMITS, key) || !Number.isSafeInteger(value) || value < 1) throw new ArchiveRefused("archive_limits");
|
|
2634
|
+
}
|
|
2635
|
+
const limits = { ...DEFAULT_ARCHIVE_LIMITS, ...options };
|
|
2636
|
+
if (input.length > limits.maxArchiveBytes) throw new ArchiveRefused("archive_limit");
|
|
2637
|
+
const bytes = input.slice();
|
|
2638
|
+
const records = index(bytes, limits);
|
|
2639
|
+
const parts = /* @__PURE__ */ new Map();
|
|
2640
|
+
for (const record of records) {
|
|
2641
|
+
const compressed = bytes.subarray(record.start, record.start + record.compressed);
|
|
2642
|
+
let payload;
|
|
2643
|
+
try {
|
|
2644
|
+
payload = record.method === 0 ? compressed.slice() : inflateRaw(compressed, record.size + 1);
|
|
2645
|
+
} catch {
|
|
2646
|
+
throw new ArchiveRefused("archive_corrupt");
|
|
2647
|
+
}
|
|
2648
|
+
if (payload.length !== record.size || crc32(payload) !== record.crc) corrupt();
|
|
2649
|
+
parts.set(record.name, payload);
|
|
2650
|
+
}
|
|
2651
|
+
return new _SourceArchive(bytes, parts);
|
|
2652
|
+
}
|
|
2653
|
+
names() {
|
|
2654
|
+
return [...this.parts.keys()];
|
|
2655
|
+
}
|
|
2656
|
+
read(name) {
|
|
2657
|
+
return this.parts.get(name)?.slice() ?? null;
|
|
2658
|
+
}
|
|
2659
|
+
toBytes() {
|
|
2660
|
+
return this.original.slice();
|
|
2661
|
+
}
|
|
2662
|
+
};
|
|
2663
|
+
function index(bytes, limits) {
|
|
2664
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2665
|
+
const bounds = (at3, size, end2 = bytes.length) => {
|
|
2666
|
+
if (at3 < 0 || size < 0 || at3 + size > end2 || at3 + size > bytes.length) corrupt();
|
|
2667
|
+
};
|
|
2668
|
+
const u16 = (at3) => {
|
|
2669
|
+
bounds(at3, 2);
|
|
2670
|
+
return view.getUint16(at3, true);
|
|
2671
|
+
};
|
|
2672
|
+
const u32 = (at3) => {
|
|
2673
|
+
bounds(at3, 4);
|
|
2674
|
+
return view.getUint32(at3, true);
|
|
2675
|
+
};
|
|
2676
|
+
let end = -1;
|
|
2677
|
+
for (let at3 = bytes.length - 22; at3 >= Math.max(0, bytes.length - 65557); at3--) {
|
|
2678
|
+
if (u32(at3) === 101010256 && at3 + 22 + u16(at3 + 20) === bytes.length && u32(at3 + 16) + u32(at3 + 12) === at3) {
|
|
2679
|
+
end = at3;
|
|
2581
2680
|
break;
|
|
2582
2681
|
}
|
|
2583
2682
|
}
|
|
2584
|
-
if (
|
|
2585
|
-
const count =
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
const
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2683
|
+
if (end === -1) corrupt();
|
|
2684
|
+
const count = u16(end + 10), directory = u32(end + 16);
|
|
2685
|
+
if (u16(end + 4) !== 0 || u16(end + 6) !== 0 || u16(end + 8) !== count || count === 65535) throw new ArchiveRefused("archive_unsupported");
|
|
2686
|
+
if (count > limits.maxEntries) throw new ArchiveRefused("archive_limit");
|
|
2687
|
+
if (end - directory < count * 46) corrupt();
|
|
2688
|
+
const records = [], seen = /* @__PURE__ */ new Set(), regions = [];
|
|
2689
|
+
let at2 = directory, expanded = 0;
|
|
2690
|
+
const extra = (start, length) => {
|
|
2691
|
+
const finish = start + length;
|
|
2692
|
+
while (start < finish) {
|
|
2693
|
+
bounds(start, 4, finish);
|
|
2694
|
+
const id = u16(start), size = u16(start + 2);
|
|
2695
|
+
bounds(start + 4, size, finish);
|
|
2696
|
+
if (id === 1 || id === 39169) throw new ArchiveRefused("archive_unsupported");
|
|
2697
|
+
start += 4 + size;
|
|
2698
|
+
}
|
|
2699
|
+
};
|
|
2700
|
+
for (let i = 0; i < count; i++) {
|
|
2701
|
+
bounds(at2, 46, end);
|
|
2702
|
+
if (u32(at2) !== 33639248) corrupt();
|
|
2703
|
+
const flags = u16(at2 + 8), method = u16(at2 + 10), crc = u32(at2 + 16);
|
|
2704
|
+
const compressed = u32(at2 + 20), size = u32(at2 + 24), local = u32(at2 + 42);
|
|
2705
|
+
const nameLength = u16(at2 + 28), extraLength = u16(at2 + 30), commentLength = u16(at2 + 32);
|
|
2706
|
+
if ((flags & -2063) !== 0 || ![0, 8].includes(method) || method === 0 && (flags & 6) !== 0 || u16(at2 + 34) !== 0 || [compressed, size, local].includes(4294967295) || u16(at2 + 6) > 20) throw new ArchiveRefused("archive_unsupported");
|
|
2707
|
+
bounds(at2 + 46, nameLength + extraLength + commentLength, end);
|
|
2708
|
+
const name = partName(bytes.subarray(at2 + 46, at2 + 46 + nameLength), flags);
|
|
2709
|
+
if (seen.has(name)) throw new ArchiveRefused("archive_duplicate");
|
|
2710
|
+
seen.add(name);
|
|
2711
|
+
expanded += size;
|
|
2712
|
+
if (size > limits.maxPartBytes || expanded > limits.maxExpandedBytes || size > Math.max(1, compressed) * limits.maxCompressionRatio) throw new ArchiveRefused("archive_limit");
|
|
2713
|
+
if (method === 0 && compressed !== size) corrupt();
|
|
2714
|
+
extra(at2 + 46 + nameLength, extraLength);
|
|
2715
|
+
bounds(local, 30, directory);
|
|
2716
|
+
if (u32(local) !== 67324752 || u16(local + 4) !== u16(at2 + 6) || u16(local + 6) !== flags || u16(local + 8) !== method) corrupt();
|
|
2717
|
+
const localName2 = u16(local + 26), localExtra = u16(local + 28);
|
|
2718
|
+
const start = local + 30 + localName2 + localExtra;
|
|
2719
|
+
bounds(local + 30, localName2 + localExtra + compressed, directory);
|
|
2720
|
+
const rawName = bytes.subarray(local + 30, local + 30 + localName2);
|
|
2721
|
+
const centralName = bytes.subarray(at2 + 46, at2 + 46 + nameLength);
|
|
2722
|
+
if (rawName.length !== centralName.length || !rawName.every((byte, pos) => byte === centralName[pos])) corrupt();
|
|
2723
|
+
extra(local + 30 + localName2, localExtra);
|
|
2724
|
+
for (const [offset, expected] of [[14, crc], [18, compressed], [22, size]]) {
|
|
2725
|
+
const value = u32(local + offset);
|
|
2726
|
+
if (value !== expected && !((flags & 8) !== 0 && value === 0)) corrupt();
|
|
2727
|
+
}
|
|
2728
|
+
let finish = start + compressed;
|
|
2729
|
+
if ((flags & 8) !== 0) {
|
|
2730
|
+
let found = false;
|
|
2731
|
+
for (const prefix of [0, 4]) {
|
|
2732
|
+
if (finish + prefix + 12 <= directory && (prefix === 0 || u32(finish) === 134695760) && u32(finish + prefix) === crc && u32(finish + prefix + 4) === compressed && u32(finish + prefix + 8) === size) {
|
|
2733
|
+
finish += prefix + 12;
|
|
2734
|
+
found = true;
|
|
2735
|
+
break;
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
if (!found) corrupt();
|
|
2739
|
+
}
|
|
2740
|
+
records.push({ name, method, crc, size, compressed, start });
|
|
2741
|
+
regions.push([local, finish]);
|
|
2742
|
+
at2 += 46 + nameLength + extraLength + commentLength;
|
|
2743
|
+
}
|
|
2744
|
+
if (at2 !== end) corrupt();
|
|
2745
|
+
regions.sort((a, b) => a[0] - b[0]);
|
|
2746
|
+
let previous = 0;
|
|
2747
|
+
for (const [start, finish] of regions) {
|
|
2748
|
+
if (start < previous) corrupt();
|
|
2749
|
+
previous = finish;
|
|
2750
|
+
}
|
|
2751
|
+
return records;
|
|
2752
|
+
}
|
|
2753
|
+
function partName(bytes, flags) {
|
|
2754
|
+
let name;
|
|
2755
|
+
try {
|
|
2756
|
+
name = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
2757
|
+
} catch {
|
|
2758
|
+
throw new ArchiveRefused("archive_path");
|
|
2607
2759
|
}
|
|
2760
|
+
if (name === "" || name.startsWith("/") || name.includes(String.fromCharCode(92)) || name.includes(":")) throw new ArchiveRefused("archive_path");
|
|
2761
|
+
for (const byte of bytes) {
|
|
2762
|
+
if (byte < 32 || byte === 127) throw new ArchiveRefused("archive_path");
|
|
2763
|
+
if (byte > 127 && (flags & 2048) === 0) throw new ArchiveRefused("archive_unsupported");
|
|
2764
|
+
}
|
|
2765
|
+
const parts = (name.endsWith("/") ? name.slice(0, -1) : name).split("/");
|
|
2766
|
+
if (parts.some((part2) => part2 === "" || part2 === "." || part2 === "..")) throw new ArchiveRefused("archive_path");
|
|
2767
|
+
return name;
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
// src/zip/zip-reader.ts
|
|
2771
|
+
function unzipSync(data, limits = {}) {
|
|
2772
|
+
const source = SourceArchive.open(data, limits);
|
|
2773
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
2774
|
+
for (const name of source.names()) result[name] = source.read(name);
|
|
2608
2775
|
return result;
|
|
2609
2776
|
}
|
|
2610
2777
|
|
|
@@ -2652,23 +2819,56 @@ var ODS_MIMETYPES = /* @__PURE__ */ new Set([
|
|
|
2652
2819
|
"application/vnd.oasis.opendocument.spreadsheet",
|
|
2653
2820
|
"application/vnd.oasis.opendocument.spreadsheet-template"
|
|
2654
2821
|
]);
|
|
2655
|
-
var
|
|
2822
|
+
var decoder = new TextDecoder();
|
|
2656
2823
|
var FormatSniffer = {
|
|
2657
2824
|
sniff(bytes, path = null) {
|
|
2658
2825
|
let files;
|
|
2659
2826
|
try {
|
|
2660
2827
|
files = unzipSync(bytes);
|
|
2661
2828
|
} catch (e) {
|
|
2829
|
+
if (e instanceof ArchiveRefused && (e.reason !== "archive_corrupt" || bytes[0] === 80 && bytes[1] === 75)) throw e;
|
|
2662
2830
|
if (e instanceof Error && e.message.includes("unsupported zip method")) throw e;
|
|
2663
2831
|
throw UnsupportedFormatException.notAZip(path);
|
|
2664
2832
|
}
|
|
2665
|
-
const mimetype = files["mimetype"] ? phpTrim(
|
|
2833
|
+
const mimetype = files["mimetype"] ? phpTrim(decoder.decode(files["mimetype"])) : null;
|
|
2666
2834
|
if (mimetype !== null && ODS_MIMETYPES.has(mimetype)) return { format: "ods", files };
|
|
2667
2835
|
if (files["xl/workbook.xml"]) return { format: "xlsx", files };
|
|
2668
2836
|
throw UnsupportedFormatException.unknownPackage(path, mimetype);
|
|
2669
2837
|
}
|
|
2670
2838
|
};
|
|
2671
2839
|
|
|
2840
|
+
// src/reader/file-input.ts
|
|
2841
|
+
async function readFileBounded(path) {
|
|
2842
|
+
const fs = await import('fs');
|
|
2843
|
+
if (!fs.statSync(path).isFile()) throw new ArchiveRefused("archive_path");
|
|
2844
|
+
const fd = fs.openSync(path, "r");
|
|
2845
|
+
const limit = DEFAULT_ARCHIVE_LIMITS.maxArchiveBytes;
|
|
2846
|
+
try {
|
|
2847
|
+
const stat = fs.fstatSync(fd);
|
|
2848
|
+
if (!stat.isFile()) throw new ArchiveRefused("archive_path");
|
|
2849
|
+
if (stat.size > limit) throw new ArchiveRefused("archive_limit");
|
|
2850
|
+
const chunks = [];
|
|
2851
|
+
let total = 0;
|
|
2852
|
+
for (; ; ) {
|
|
2853
|
+
const chunk = new Uint8Array(Math.min(65536, limit + 1 - total));
|
|
2854
|
+
const count = fs.readSync(fd, chunk, 0, chunk.length, null);
|
|
2855
|
+
if (count === 0) break;
|
|
2856
|
+
if (total + count > limit) throw new ArchiveRefused("archive_limit");
|
|
2857
|
+
chunks.push(chunk.subarray(0, count));
|
|
2858
|
+
total += count;
|
|
2859
|
+
}
|
|
2860
|
+
const bytes = new Uint8Array(total);
|
|
2861
|
+
let at2 = 0;
|
|
2862
|
+
for (const chunk of chunks) {
|
|
2863
|
+
bytes.set(chunk, at2);
|
|
2864
|
+
at2 += chunk.length;
|
|
2865
|
+
}
|
|
2866
|
+
return bytes;
|
|
2867
|
+
} finally {
|
|
2868
|
+
fs.closeSync(fd);
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
|
|
2672
2872
|
// src/reader/ods/ods-formula.ts
|
|
2673
2873
|
function odsFormulaToA1(formula2) {
|
|
2674
2874
|
let grammar = "of";
|
|
@@ -3448,7 +3648,7 @@ function at(node, name) {
|
|
|
3448
3648
|
var MAX_ROWS = 1048576;
|
|
3449
3649
|
var MAX_COLUMNS = 16384;
|
|
3450
3650
|
var UNIX_EPOCH_SERIAL = 25569;
|
|
3451
|
-
var
|
|
3651
|
+
var decoder2 = new TextDecoder();
|
|
3452
3652
|
var OdsReader = class {
|
|
3453
3653
|
describe(bytes) {
|
|
3454
3654
|
return WorkbookSchema.fromWorkbook(this.readWorkbook(bytes));
|
|
@@ -3458,7 +3658,7 @@ var OdsReader = class {
|
|
|
3458
3658
|
}
|
|
3459
3659
|
/** Read an already-unzipped package (name -> bytes). */
|
|
3460
3660
|
readFiles(files) {
|
|
3461
|
-
const getText = (name) => files[name] ?
|
|
3661
|
+
const getText = (name) => files[name] ? decoder2.decode(files[name]) : null;
|
|
3462
3662
|
const content = getText("content.xml");
|
|
3463
3663
|
if (content === null) throw new Error("[holy-sheet] missing content.xml");
|
|
3464
3664
|
const contentDoc = parseXml(content, { namespaces: true });
|
|
@@ -3820,7 +4020,7 @@ function points(ser) {
|
|
|
3820
4020
|
byIndex.set(parseInt(idx, 10), color2);
|
|
3821
4021
|
}
|
|
3822
4022
|
}
|
|
3823
|
-
return [...byIndex.entries()].sort((a, b) => a[0] - b[0]).map(([
|
|
4023
|
+
return [...byIndex.entries()].sort((a, b) => a[0] - b[0]).map(([index2, color2]) => ({ index: index2, color: color2 }));
|
|
3824
4024
|
}
|
|
3825
4025
|
function seriesColor(ser) {
|
|
3826
4026
|
const spPr = el(ser, "spPr");
|
|
@@ -4128,7 +4328,7 @@ function parseFrozen(xml) {
|
|
|
4128
4328
|
}
|
|
4129
4329
|
|
|
4130
4330
|
// src/reader/xlsx-reader.ts
|
|
4131
|
-
var
|
|
4331
|
+
var decoder3 = new TextDecoder();
|
|
4132
4332
|
var XlsxReader = class {
|
|
4133
4333
|
describe(bytes) {
|
|
4134
4334
|
return WorkbookSchema.fromWorkbook(this.readWorkbook(bytes));
|
|
@@ -4138,7 +4338,7 @@ var XlsxReader = class {
|
|
|
4138
4338
|
}
|
|
4139
4339
|
/** Read an already-unzipped package (name -> bytes), so a caller that sniffed it does not unzip twice. */
|
|
4140
4340
|
readFiles(files) {
|
|
4141
|
-
const getText = (name) => files[name] ?
|
|
4341
|
+
const getText = (name) => files[name] ? decoder3.decode(files[name]) : null;
|
|
4142
4342
|
const stylesXml = getText("xl/styles.xml");
|
|
4143
4343
|
const stylesIndex = stylesXml ? StylesParser.parse(stylesXml) : [];
|
|
4144
4344
|
const sharedStringsXml = getText("xl/sharedStrings.xml");
|
|
@@ -4479,7 +4679,8 @@ var ChartXml = {
|
|
|
4479
4679
|
} else {
|
|
4480
4680
|
plot = `<c:barChart><c:barDir val="${type === "bar" ? "bar" : "col"}"/><c:grouping val="clustered"/><c:varyColors val="0"/>` + series + labels + '<c:gapWidth val="80"/><c:axId val="10"/><c:axId val="20"/></c:barChart>';
|
|
4481
4681
|
}
|
|
4482
|
-
const
|
|
4682
|
+
const zeroBase = type !== "line" && nonNegative(chart, workbook);
|
|
4683
|
+
const axesXml = type === "pie" ? "" : axes(type === "bar", chart.format, zeroBase);
|
|
4483
4684
|
const legend = chart.legend ?? (chart.series.length > 1 || type === "pie");
|
|
4484
4685
|
const title = chart.title !== null ? `<c:title><c:tx><c:rich><a:bodyPr/><a:lstStyle/><a:p><a:pPr><a:defRPr sz="1200" b="1"/></a:pPr><a:r><a:rPr lang="en-US" sz="1200" b="1"/><a:t>${text(chart.title)}</a:t></a:r></a:p></c:rich></c:tx><c:overlay val="0"/></c:title><c:autoTitleDeleted val="0"/>` : '<c:autoTitleDeleted val="1"/>';
|
|
4485
4686
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><c:chartSpace xmlns:c="${NS_C}" xmlns:a="${NS_A}" xmlns:r="${NS_R}"><c:roundedCorners val="0"/><c:chart>` + title + "<c:plotArea><c:layout/>" + plot + axesXml + "</c:plotArea>" + (legend ? '<c:legend><c:legendPos val="b"/><c:overlay val="0"/></c:legend>' : "") + '<c:plotVisOnly val="1"/><c:dispBlanksAs val="gap"/></c:chart><c:spPr><a:noFill/><a:ln><a:noFill/></a:ln></c:spPr>' + textProps("595959", 900) + "</c:chartSpace>";
|
|
@@ -4540,11 +4741,14 @@ function dataLabels(type, format) {
|
|
|
4540
4741
|
const pos = type === "line" ? "t" : type === "pie" ? "bestFit" : "outEnd";
|
|
4541
4742
|
return "<c:dLbls>" + (format !== null ? `<c:numFmt formatCode="${attr2(format)}" sourceLinked="0"/>` : "") + "<c:spPr><a:noFill/><a:ln><a:noFill/></a:ln></c:spPr>" + textProps("404040", 900) + `<c:dLblPos val="${pos}"/><c:showLegendKey val="0"/><c:showVal val="1"/><c:showCatName val="0"/><c:showSerName val="0"/><c:showPercent val="0"/><c:showBubbleSize val="0"/></c:dLbls>`;
|
|
4542
4743
|
}
|
|
4543
|
-
function
|
|
4744
|
+
function nonNegative(chart, workbook) {
|
|
4745
|
+
return chart.series.every((s) => values(s.values, workbook).every((v) => typeof v !== "number" || !(v < 0)));
|
|
4746
|
+
}
|
|
4747
|
+
function axes(horizontal, format, zeroBase = false) {
|
|
4544
4748
|
const catPos = horizontal ? "l" : "b";
|
|
4545
4749
|
const valPos = horizontal ? "b" : "l";
|
|
4546
4750
|
const numFmt = format !== null ? `<c:numFmt formatCode="${attr2(format)}" sourceLinked="0"/>` : '<c:numFmt formatCode="General" sourceLinked="1"/>';
|
|
4547
|
-
return `<c:catAx><c:axId val="10"/><c:scaling><c:orientation val="${horizontal ? "maxMin" : "minMax"}"/></c:scaling><c:delete val="0"/><c:axPos val="${catPos}"/><c:numFmt formatCode="General" sourceLinked="1"/><c:majorTickMark val="none"/><c:minorTickMark val="none"/><c:tickLblPos val="low"/><c:spPr><a:ln w="9525"><a:solidFill><a:srgbClr val="BFBFBF"/></a:solidFill></a:ln></c:spPr><c:crossAx val="20"/><c:crosses val="autoZero"/><c:auto val="1"/><c:lblAlgn val="ctr"/><c:lblOffset val="100"/><c:noMultiLvlLbl val="0"/></c:catAx><c:valAx><c:axId val="20"/><c:scaling><c:orientation val="minMax"
|
|
4751
|
+
return `<c:catAx><c:axId val="10"/><c:scaling><c:orientation val="${horizontal ? "maxMin" : "minMax"}"/></c:scaling><c:delete val="0"/><c:axPos val="${catPos}"/><c:numFmt formatCode="General" sourceLinked="1"/><c:majorTickMark val="none"/><c:minorTickMark val="none"/><c:tickLblPos val="low"/><c:spPr><a:ln w="9525"><a:solidFill><a:srgbClr val="BFBFBF"/></a:solidFill></a:ln></c:spPr><c:crossAx val="20"/><c:crosses val="autoZero"/><c:auto val="1"/><c:lblAlgn val="ctr"/><c:lblOffset val="100"/><c:noMultiLvlLbl val="0"/></c:catAx><c:valAx><c:axId val="20"/><c:scaling><c:orientation val="minMax"/>` + (zeroBase ? '<c:min val="0"/>' : "") + `</c:scaling><c:delete val="0"/><c:axPos val="${valPos}"/><c:majorGridlines><c:spPr><a:ln w="9525"><a:solidFill><a:srgbClr val="E5E7EB"/></a:solidFill></a:ln></c:spPr></c:majorGridlines>` + numFmt + `<c:majorTickMark val="none"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:spPr><a:ln><a:noFill/></a:ln></c:spPr><c:crossAx val="10"/><c:crosses val="${horizontal ? "max" : "autoZero"}"/><c:crossBetween val="between"/></c:valAx>`;
|
|
4548
4752
|
}
|
|
4549
4753
|
function textProps(color2, size) {
|
|
4550
4754
|
return `<c:txPr><a:bodyPr/><a:lstStyle/><a:p><a:pPr><a:defRPr sz="${size}"><a:solidFill><a:srgbClr val="${color2}"/></a:solidFill></a:defRPr></a:pPr><a:endParaRPr lang="en-US"/></a:p></c:txPr>`;
|
|
@@ -5004,11 +5208,11 @@ var SheetReducer = {
|
|
|
5004
5208
|
if (!isArr(get(op, "sheet"))) {
|
|
5005
5209
|
return schema;
|
|
5006
5210
|
}
|
|
5007
|
-
const
|
|
5008
|
-
if (
|
|
5211
|
+
const index2 = has(op, "index") ? phpInteger(op.index) : sheets.length;
|
|
5212
|
+
if (index2 === null) {
|
|
5009
5213
|
return schema;
|
|
5010
5214
|
}
|
|
5011
|
-
sheets.splice(Math.max(0, Math.min(sheets.length,
|
|
5215
|
+
sheets.splice(Math.max(0, Math.min(sheets.length, index2)), 0, op.sheet);
|
|
5012
5216
|
return { ...schema, sheets };
|
|
5013
5217
|
}
|
|
5014
5218
|
const at2 = find(sheets, phpString(get(op, "sheet") ?? ""));
|
|
@@ -5184,11 +5388,11 @@ function shiftColumns(sheet, at2, delta) {
|
|
|
5184
5388
|
});
|
|
5185
5389
|
if (isArr(get(sheet, "columnWidths"))) {
|
|
5186
5390
|
const widths = /* @__PURE__ */ new Map();
|
|
5187
|
-
for (const [
|
|
5188
|
-
if (!isIndexKey(
|
|
5391
|
+
for (const [index2, width] of entriesOf(sheet.columnWidths)) {
|
|
5392
|
+
if (!isIndexKey(index2)) {
|
|
5189
5393
|
continue;
|
|
5190
5394
|
}
|
|
5191
|
-
const i = phpInt2(
|
|
5395
|
+
const i = phpInt2(index2);
|
|
5192
5396
|
const number = i + 1;
|
|
5193
5397
|
if (number < at2) {
|
|
5194
5398
|
widths.set(i, width);
|
|
@@ -5197,8 +5401,8 @@ function shiftColumns(sheet, at2, delta) {
|
|
|
5197
5401
|
}
|
|
5198
5402
|
}
|
|
5199
5403
|
const sorted = {};
|
|
5200
|
-
for (const [
|
|
5201
|
-
sorted[
|
|
5404
|
+
for (const [index2, width] of [...widths.entries()].sort((x, y) => x[0] - y[0])) {
|
|
5405
|
+
sorted[index2] = width;
|
|
5202
5406
|
}
|
|
5203
5407
|
sheet = setOrUnset(sheet, "columnWidths", sorted, EMPTY);
|
|
5204
5408
|
}
|
|
@@ -5461,22 +5665,22 @@ function granular(a, b) {
|
|
|
5461
5665
|
ops.push({ type: "rename_sheet", sheet: name, name: renames.get(name) });
|
|
5462
5666
|
}
|
|
5463
5667
|
}
|
|
5464
|
-
namesB.forEach((name,
|
|
5668
|
+
namesB.forEach((name, index2) => {
|
|
5465
5669
|
if (unmatchedAdded.includes(name)) {
|
|
5466
|
-
ops.push({ type: "add_sheet", index, sheet: sheetsB[
|
|
5670
|
+
ops.push({ type: "add_sheet", index: index2, sheet: sheetsB[index2] });
|
|
5467
5671
|
}
|
|
5468
5672
|
});
|
|
5469
5673
|
let state = SheetReducer.applyAll(a, ops);
|
|
5470
|
-
namesB.forEach((name,
|
|
5674
|
+
namesB.forEach((name, index2) => {
|
|
5471
5675
|
const current = new Map(entriesOf(get(state, "sheets") ?? []).map(([key, sheet]) => [key, sheetName(sheet)]));
|
|
5472
|
-
if ((current.get(String(
|
|
5473
|
-
const op = { type: "move_sheet", sheet: name, toIndex:
|
|
5676
|
+
if ((current.get(String(index2)) ?? null) !== name) {
|
|
5677
|
+
const op = { type: "move_sheet", sheet: name, toIndex: index2 };
|
|
5474
5678
|
ops.push(op);
|
|
5475
5679
|
state = SheetReducer.apply(state, op);
|
|
5476
5680
|
}
|
|
5477
5681
|
});
|
|
5478
|
-
sheetsB.forEach((target,
|
|
5479
|
-
const current = state.sheets[
|
|
5682
|
+
sheetsB.forEach((target, index2) => {
|
|
5683
|
+
const current = state.sheets[index2];
|
|
5480
5684
|
if (SheetDiff.same(current, target)) {
|
|
5481
5685
|
return;
|
|
5482
5686
|
}
|
|
@@ -6127,7 +6331,7 @@ var holy_sheet_schema_default = {
|
|
|
6127
6331
|
};
|
|
6128
6332
|
|
|
6129
6333
|
// src/agent.ts
|
|
6130
|
-
var VERSION = "2.10.
|
|
6334
|
+
var VERSION = "2.10.2";
|
|
6131
6335
|
function toU8(input) {
|
|
6132
6336
|
return input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
6133
6337
|
}
|
|
@@ -6172,8 +6376,8 @@ var Agent = {
|
|
|
6172
6376
|
async describe(path) {
|
|
6173
6377
|
const fs = await import('fs');
|
|
6174
6378
|
if (!fs.existsSync(path)) return { error: "not_found", path };
|
|
6175
|
-
const bytes =
|
|
6176
|
-
return readSpreadsheet(
|
|
6379
|
+
const bytes = await readFileBounded(path);
|
|
6380
|
+
return readSpreadsheet(bytes, path);
|
|
6177
6381
|
},
|
|
6178
6382
|
/** Validate + conservative repairs in one call. */
|
|
6179
6383
|
validateAndRepair(schema) {
|
|
@@ -6291,6 +6495,7 @@ var HolySheet = class {
|
|
|
6291
6495
|
HolySheet.VERSION = VERSION;
|
|
6292
6496
|
|
|
6293
6497
|
exports.Agent = Agent;
|
|
6498
|
+
exports.ArchiveRefused = ArchiveRefused;
|
|
6294
6499
|
exports.ArrayBuilder = ArrayBuilder;
|
|
6295
6500
|
exports.CellAddress = CellAddress;
|
|
6296
6501
|
exports.CsvBuilder = CsvBuilder;
|