xlsx-for-ai 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/index.js +55 -5
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// Self-respawn with a larger V8 heap before loading anything else.
|
|
4
|
+
// Some real-world .xlsx files (sub-1MB on disk but with huge calc chains or
|
|
5
|
+
// shared-string tables) blow Node's default ~4GB heap during parse. Re-execing
|
|
6
|
+
// with --max-old-space-size=8192 fixes this transparently. The sentinel env
|
|
7
|
+
// var prevents an infinite respawn loop.
|
|
8
|
+
if (!process.env.XLSX_FOR_AI_RESPAWNED) {
|
|
9
|
+
const v8 = require('v8');
|
|
10
|
+
const heapLimitMB = v8.getHeapStatistics().heap_size_limit / 1024 / 1024;
|
|
11
|
+
if (heapLimitMB < 8000) {
|
|
12
|
+
const { spawnSync } = require('child_process');
|
|
13
|
+
const r = spawnSync(
|
|
14
|
+
process.execPath,
|
|
15
|
+
['--max-old-space-size=8192', __filename, ...process.argv.slice(2)],
|
|
16
|
+
{ stdio: 'inherit', env: { ...process.env, XLSX_FOR_AI_RESPAWNED: '1' } }
|
|
17
|
+
);
|
|
18
|
+
process.exit(r.status ?? 1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
3
22
|
const path = require('path');
|
|
4
23
|
const fs = require('fs');
|
|
5
24
|
const ExcelJS = require('exceljs');
|
|
@@ -537,8 +556,32 @@ async function main() {
|
|
|
537
556
|
process.exit(1);
|
|
538
557
|
}
|
|
539
558
|
|
|
559
|
+
const stat = fs.statSync(xlsxPath);
|
|
560
|
+
if (stat.size === 0) {
|
|
561
|
+
console.error(`File is empty (0 bytes), not a valid xlsx: ${xlsxPath}`);
|
|
562
|
+
process.exit(1);
|
|
563
|
+
}
|
|
564
|
+
// Minimum valid zip is a 22-byte end-of-central-directory record. Anything
|
|
565
|
+
// smaller cannot be an xlsx; ExcelJS would crash with a misleading
|
|
566
|
+
// "Corrupted zip" error from deep in its parser.
|
|
567
|
+
if (stat.size < 22) {
|
|
568
|
+
console.error(`File is too small (${stat.size} bytes) to be a valid xlsx: ${xlsxPath}`);
|
|
569
|
+
process.exit(1);
|
|
570
|
+
}
|
|
571
|
+
|
|
540
572
|
const wb = new ExcelJS.Workbook();
|
|
541
|
-
|
|
573
|
+
try {
|
|
574
|
+
await wb.xlsx.readFile(xlsxPath);
|
|
575
|
+
} catch (err) {
|
|
576
|
+
const msg = err && err.message ? err.message : String(err);
|
|
577
|
+
console.error(`Failed to read ${xlsxPath}: ${msg}`);
|
|
578
|
+
if (/End of data reached|Corrupted zip|invalid signature/i.test(msg)) {
|
|
579
|
+
console.error('Hint: file may be truncated or not a real xlsx. Try opening it in Excel to confirm.');
|
|
580
|
+
} else if (/Cannot read propert/i.test(msg)) {
|
|
581
|
+
console.error('Hint: file parsed as a zip but a workbook part is malformed. Try --list-sheets for a lighter probe.');
|
|
582
|
+
}
|
|
583
|
+
process.exit(1);
|
|
584
|
+
}
|
|
542
585
|
|
|
543
586
|
// --list-sheets: print summary and exit
|
|
544
587
|
if (opts.listSheets) {
|
|
@@ -551,9 +594,12 @@ async function main() {
|
|
|
551
594
|
: wb.worksheets;
|
|
552
595
|
|
|
553
596
|
if (sheets.length === 0) {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
597
|
+
if (sheetFilter) {
|
|
598
|
+
console.error(`Sheet "${sheetFilter}" not found. Available: ${wb.worksheets.map(s => s.name).join(', ')}`);
|
|
599
|
+
} else {
|
|
600
|
+
console.error('No sheets in workbook.');
|
|
601
|
+
console.error('Hint: this can happen when a non-Excel tool wrote the file with backslashes in zip entry paths (e.g. xl\\worksheets\\sheet1.xml). ExcelJS only recognizes forward-slash entries.');
|
|
602
|
+
}
|
|
557
603
|
process.exit(1);
|
|
558
604
|
}
|
|
559
605
|
|
|
@@ -601,6 +647,10 @@ async function main() {
|
|
|
601
647
|
}
|
|
602
648
|
|
|
603
649
|
main().catch((err) => {
|
|
604
|
-
|
|
650
|
+
const msg = err && err.message ? err.message : String(err);
|
|
651
|
+
console.error(msg);
|
|
652
|
+
if (/Invalid string length/i.test(msg)) {
|
|
653
|
+
console.error('Hint: this sheet renders to a text dump larger than V8\'s 512MB string limit. Try --max-rows N or --max-cols N to bound the output, or --json which streams per cell.');
|
|
654
|
+
}
|
|
605
655
|
process.exit(1);
|
|
606
656
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xlsx-for-ai",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "CLI that converts .xlsx files into rich text or JSON dumps that AI coding agents (Claude, Cursor, Copilot, ChatGPT, etc.) can read — preserving values, formulas, formatting, colors, column widths, frozen panes, named ranges, tables, and more.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|