token-goat 2.9.13 → 2.9.15

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.
Files changed (52) hide show
  1. package/README.md +28 -1
  2. package/dist/token-goat-chunk-2X2EBBC6.mjs +277 -0
  3. package/dist/token-goat-chunk-3BTK54F3.mjs +1733 -0
  4. package/dist/token-goat-chunk-3NSDDTGL.mjs +34 -0
  5. package/dist/token-goat-chunk-4EXFN2AW.mjs +29 -0
  6. package/dist/token-goat-chunk-5V7DAC7V.mjs +123 -0
  7. package/dist/token-goat-chunk-6DLVZDB6.mjs +34 -0
  8. package/dist/token-goat-chunk-7ZYK25AO.mjs +24 -0
  9. package/dist/token-goat-chunk-A4JYKD5H.mjs +144 -0
  10. package/dist/token-goat-chunk-AH6QILZM.mjs +26 -0
  11. package/dist/token-goat-chunk-ASYEPR3S.mjs +212 -0
  12. package/dist/{token-goat-chunk-RDITECDL.mjs → token-goat-chunk-ATIFTMRC.mjs} +31 -13
  13. package/dist/{token-goat-chunk-ZZI3IDQZ.mjs → token-goat-chunk-BL5LNGBG.mjs} +3935 -11949
  14. package/dist/{token-goat-chunk-4NXUKV7D.mjs → token-goat-chunk-C5JIO6HK.mjs} +8 -4
  15. package/dist/{token-goat-chunk-FZU7GMUS.mjs → token-goat-chunk-DQ4J5AFF.mjs} +50 -18
  16. package/dist/token-goat-chunk-ERTXEKB6.mjs +228 -0
  17. package/dist/{token-goat-chunk-6B44WLIF.mjs → token-goat-chunk-GIIHUSZX.mjs} +142 -21
  18. package/dist/token-goat-chunk-GMOUBOX4.mjs +386 -0
  19. package/dist/{token-goat-chunk-3ESRORNM.mjs → token-goat-chunk-GMQQA7E4.mjs} +12576 -12326
  20. package/dist/token-goat-chunk-IVUQLQWN.mjs +2046 -0
  21. package/dist/token-goat-chunk-K7F2BFIK.mjs +2430 -0
  22. package/dist/{token-goat-chunk-U7X6LQD2.mjs → token-goat-chunk-LCZBPOIN.mjs} +10197 -9717
  23. package/dist/token-goat-chunk-LMFO66YD.mjs +331 -0
  24. package/dist/token-goat-chunk-LT7JRU6K.mjs +22 -0
  25. package/dist/token-goat-chunk-MZDIJJ3R.mjs +420 -0
  26. package/dist/token-goat-chunk-NDPO7GAH.mjs +177 -0
  27. package/dist/token-goat-chunk-NDRP4KJQ.mjs +4371 -0
  28. package/dist/token-goat-chunk-NEI4NC54.mjs +424 -0
  29. package/dist/token-goat-chunk-NU7TLMQK.mjs +585 -0
  30. package/dist/token-goat-chunk-OSUFN2FV.mjs +326 -0
  31. package/dist/token-goat-chunk-OUGNPMDA.mjs +959 -0
  32. package/dist/token-goat-chunk-PM76YS22.mjs +1341 -0
  33. package/dist/token-goat-chunk-S4XRY446.mjs +2637 -0
  34. package/dist/{token-goat-chunk-YOA4N6WA.mjs → token-goat-chunk-SFAS46RE.mjs} +5 -3
  35. package/dist/{token-goat-chunk-QWSUZWFP.mjs → token-goat-chunk-SZWYESBS.mjs} +793 -650
  36. package/dist/{token-goat-chunk-B3CTCQTH.mjs → token-goat-chunk-XEPXYDPI.mjs} +3 -2
  37. package/dist/token-goat-chunk-XTQAOTSO.mjs +89 -0
  38. package/dist/token-goat-chunk-Y4AFKTHK.mjs +22 -0
  39. package/dist/token-goat-chunk-YKG35VHC.mjs +228 -0
  40. package/dist/{token-goat-chunk-JOXLE672.mjs → token-goat-chunk-YQ7WI2CO.mjs} +990 -106
  41. package/dist/{token-goat-chunk-2WC4ZUXN.mjs → token-goat-chunk-YZX7EFG4.mjs} +1 -1
  42. package/dist/token-goat-chunk-Z6UXPYJA.mjs +62 -0
  43. package/dist/token-goat-hook.mjs +16 -8
  44. package/dist/token-goat.core.mjs +27 -10
  45. package/docs/cli.md +9 -6
  46. package/package.json +4 -2
  47. package/dist/token-goat-chunk-FQCNJV4V.mjs +0 -693
  48. package/dist/token-goat-chunk-JVNPCQB7.mjs +0 -31
  49. package/dist/token-goat-chunk-P2PU4CR5.mjs +0 -26
  50. package/dist/token-goat-chunk-QKXBGBQR.mjs +0 -3653
  51. package/dist/token-goat-chunk-UM47DRD3.mjs +0 -242
  52. package/dist/token-goat-chunk-UMXJN7DI.mjs +0 -5521
@@ -0,0 +1,585 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ queryCsv,
5
+ quoteCsvCell
6
+ } from "./token-goat-chunk-YKG35VHC.mjs";
7
+ import {
8
+ NotAnOfficeDocumentError,
9
+ assertOoxmlWithinDeadline,
10
+ decodeZipEntry,
11
+ ooxmlPartBudget,
12
+ ooxmlWorkDeadline,
13
+ parseOoxmlPart,
14
+ readOoxmlZip
15
+ } from "./token-goat-chunk-MZDIJJ3R.mjs";
16
+ import {
17
+ DocumentRefusedError
18
+ } from "./token-goat-chunk-Y4AFKTHK.mjs";
19
+ import {
20
+ displaySafeText
21
+ } from "./token-goat-chunk-ERTXEKB6.mjs";
22
+ import {
23
+ init_define_import_meta_env
24
+ } from "./token-goat-chunk-A37V4PBF.mjs";
25
+
26
+ // src/xlsx_extract.ts
27
+ init_define_import_meta_env();
28
+
29
+ // src/xlsx_reader.ts
30
+ init_define_import_meta_env();
31
+ var EMPTY_CELL = Object.freeze({ value: null, text: "" });
32
+ function asArray(val) {
33
+ if (val === void 0 || val === null) return [];
34
+ if (Array.isArray(val)) return val.filter((v) => v !== null && typeof v === "object");
35
+ if (typeof val === "object") return [val];
36
+ return [];
37
+ }
38
+ function textOf(node) {
39
+ if (node === void 0 || node === null) return "";
40
+ if (typeof node === "string") return node;
41
+ if (typeof node === "number" || typeof node === "boolean") return String(node);
42
+ if (Array.isArray(node)) return node.map(textOf).join("");
43
+ const t = node["#text"];
44
+ return t === void 0 ? "" : String(t);
45
+ }
46
+ function attr(node, name) {
47
+ if (node === void 0) return void 0;
48
+ const v = node[`@_${name}`];
49
+ return v === void 0 || v === null ? void 0 : String(v);
50
+ }
51
+ function isTruthyAttr(v) {
52
+ return v === "1" || v === "true";
53
+ }
54
+ function refToColumn(ref) {
55
+ let n = 0;
56
+ for (const ch of ref) {
57
+ const code = ch.toUpperCase().charCodeAt(0);
58
+ if (code < 65 || code > 90) break;
59
+ n = n * 26 + (code - 64);
60
+ }
61
+ return n;
62
+ }
63
+ function refToRow(ref) {
64
+ const m = /(\d+)\s*$/.exec(ref);
65
+ return m ? parseInt(m[1], 10) : 0;
66
+ }
67
+ var BUILTIN_DATE_FORMAT_IDS = /* @__PURE__ */ new Set([14, 15, 16, 17, 18, 19, 20, 21, 22, 45, 46, 47]);
68
+ function formatCodeIsDate(formatCode) {
69
+ const stripped = formatCode.replace(/"[^"]*"/g, "").replace(/\[[^\]]*\]/g, "").replace(/\\./g, "");
70
+ return /[ymdhs]/i.test(stripped);
71
+ }
72
+ function serialToDate(serial, date1904) {
73
+ if (date1904) return new Date(Date.UTC(1904, 0, 1) + Math.round(serial * 864e5));
74
+ const adjusted = serial >= 61 ? serial - 1 : serial;
75
+ return new Date(Date.UTC(1899, 11, 31) + Math.round(adjusted * 864e5));
76
+ }
77
+ function numberToText(n) {
78
+ return String(n);
79
+ }
80
+ function parseStyles(xml, parsed) {
81
+ if (xml === null || parsed === null || typeof parsed !== "object") return { dateStyles: [] };
82
+ const sheet = parsed["styleSheet"];
83
+ if (sheet === void 0 || sheet === null || typeof sheet !== "object") return { dateStyles: [] };
84
+ const root = sheet;
85
+ const customDateFormats = /* @__PURE__ */ new Set();
86
+ for (const fmt of asArray(root["numFmts"]?.["numFmt"])) {
87
+ const id = Number(attr(fmt, "numFmtId"));
88
+ const code = attr(fmt, "formatCode");
89
+ if (Number.isFinite(id) && code !== void 0 && formatCodeIsDate(code)) customDateFormats.add(id);
90
+ }
91
+ const dateStyles = [];
92
+ for (const xf of asArray(root["cellXfs"]?.["xf"])) {
93
+ const id = Number(attr(xf, "numFmtId") ?? "0");
94
+ dateStyles.push(Number.isFinite(id) && (BUILTIN_DATE_FORMAT_IDS.has(id) || customDateFormats.has(id)));
95
+ }
96
+ return { dateStyles };
97
+ }
98
+ function parseSharedStrings(parsed) {
99
+ if (parsed === null || typeof parsed !== "object") return [];
100
+ const sst = parsed["sst"];
101
+ if (sst === void 0 || sst === null || typeof sst !== "object") return [];
102
+ return asArray(sst["si"]).map((si) => {
103
+ if (si["t"] !== void 0) return textOf(si["t"]);
104
+ const runs = asArray(si["r"]);
105
+ if (runs.length > 0) return runs.map((r) => textOf(r["t"])).join("");
106
+ return "";
107
+ });
108
+ }
109
+ function parseWorkbookRels(parsed) {
110
+ const out = /* @__PURE__ */ new Map();
111
+ if (parsed === null || typeof parsed !== "object") return out;
112
+ const rels = parsed["Relationships"];
113
+ if (rels === void 0 || rels === null || typeof rels !== "object") return out;
114
+ for (const rel of asArray(rels["Relationship"])) {
115
+ const id = attr(rel, "Id");
116
+ const target = attr(rel, "Target");
117
+ if (id === void 0 || target === void 0) continue;
118
+ const normalized = target.startsWith("/") ? target.slice(1) : `xl/${target.replace(/^\.\//, "")}`;
119
+ out.set(id, normalized);
120
+ }
121
+ return out;
122
+ }
123
+ function buildCell(c, shared, styles, date1904) {
124
+ const type = attr(c, "t") ?? "n";
125
+ const styleIdx = Number(attr(c, "s") ?? "-1");
126
+ const isDateStyle = Number.isInteger(styleIdx) && styleIdx >= 0 && styles.dateStyles[styleIdx] === true;
127
+ const hasV = c["v"] !== void 0;
128
+ const hasIs = c["is"] !== void 0;
129
+ const fNode = c["f"];
130
+ const formula = fNode === void 0 ? "" : textOf(fNode);
131
+ if (!hasV && !hasIs && formula === "") return null;
132
+ let raw;
133
+ let text;
134
+ if (type === "s") {
135
+ const idx = Number(textOf(c["v"]));
136
+ const s = Number.isInteger(idx) ? shared[idx] ?? "" : "";
137
+ raw = s;
138
+ text = s;
139
+ } else if (type === "inlineStr") {
140
+ const isNode = c["is"];
141
+ const s = isNode !== void 0 && isNode !== null && typeof isNode === "object" ? (() => {
142
+ const node = isNode;
143
+ if (node["t"] !== void 0) return textOf(node["t"]);
144
+ return asArray(node["r"]).map((r) => textOf(r["t"])).join("");
145
+ })() : textOf(isNode);
146
+ raw = s;
147
+ text = s;
148
+ } else if (type === "str") {
149
+ const s = textOf(c["v"]);
150
+ raw = s;
151
+ text = s;
152
+ } else if (type === "b") {
153
+ const b = textOf(c["v"]).trim() === "1";
154
+ raw = b;
155
+ text = b ? "TRUE" : "FALSE";
156
+ } else if (type === "e") {
157
+ const e = textOf(c["v"]);
158
+ raw = { error: e };
159
+ text = e;
160
+ } else {
161
+ const n = Number(textOf(c["v"]));
162
+ if (!Number.isFinite(n)) {
163
+ raw = null;
164
+ text = "";
165
+ } else if (isDateStyle) {
166
+ const d = serialToDate(n, date1904);
167
+ raw = d;
168
+ text = d.toISOString();
169
+ } else {
170
+ raw = n;
171
+ text = numberToText(n);
172
+ }
173
+ }
174
+ if (formula !== "") return { value: { formula, result: raw }, text, formula };
175
+ return { value: raw, text };
176
+ }
177
+ function parseSheet(parsed, shared, styles, date1904) {
178
+ const cells = /* @__PURE__ */ new Map();
179
+ let rowCount = 0;
180
+ let columnCount = 0;
181
+ let populatedRows = 0;
182
+ if (parsed === null || typeof parsed !== "object") return { cells, rowCount, columnCount, populatedRows };
183
+ const ws = parsed["worksheet"];
184
+ if (ws === void 0 || ws === null || typeof ws !== "object") return { cells, rowCount, columnCount, populatedRows };
185
+ const sheetData = ws["sheetData"];
186
+ if (sheetData === void 0 || sheetData === null || typeof sheetData !== "object") {
187
+ return { cells, rowCount, columnCount, populatedRows };
188
+ }
189
+ let fallbackRow = 0;
190
+ for (const row of asArray(sheetData["row"])) {
191
+ const declaredRow = Number(attr(row, "r"));
192
+ const rowIdx = Number.isInteger(declaredRow) && declaredRow > 0 ? declaredRow : fallbackRow + 1;
193
+ fallbackRow = rowIdx;
194
+ let fallbackCol = 0;
195
+ const rowCells = /* @__PURE__ */ new Map();
196
+ for (const c of asArray(row["c"])) {
197
+ const ref = attr(c, "r");
198
+ const declaredCol = ref === void 0 ? 0 : refToColumn(ref);
199
+ const colIdx = declaredCol > 0 ? declaredCol : fallbackCol + 1;
200
+ fallbackCol = colIdx;
201
+ const cell = buildCell(c, shared, styles, date1904);
202
+ if (cell === null) continue;
203
+ rowCells.set(colIdx, cell);
204
+ if (colIdx > columnCount) columnCount = colIdx;
205
+ }
206
+ if (rowCells.size === 0) continue;
207
+ cells.set(rowIdx, rowCells);
208
+ populatedRows++;
209
+ if (rowIdx > rowCount) rowCount = rowIdx;
210
+ }
211
+ return { cells, rowCount, columnCount, populatedRows };
212
+ }
213
+ function makeWorksheet(name, data) {
214
+ function getRow(r) {
215
+ const rowCells = data.cells.get(r);
216
+ return {
217
+ get values() {
218
+ const out = [];
219
+ if (rowCells !== void 0) for (const [col, cell] of rowCells) out[col] = cell.value;
220
+ return out;
221
+ },
222
+ eachCell(opts, cb) {
223
+ if (opts.includeEmpty) {
224
+ let maxCol = 0;
225
+ if (rowCells !== void 0) {
226
+ for (const c of rowCells.keys()) if (c > maxCol) maxCol = c;
227
+ }
228
+ for (let c = 1; c <= maxCol; c++) cb(rowCells?.get(c) ?? EMPTY_CELL, c);
229
+ return;
230
+ }
231
+ if (rowCells === void 0) return;
232
+ for (const col of [...rowCells.keys()].sort((a, b) => a - b)) cb(rowCells.get(col), col);
233
+ }
234
+ };
235
+ }
236
+ return {
237
+ name,
238
+ rowCount: data.rowCount,
239
+ columnCount: data.columnCount,
240
+ actualRowCount: data.populatedRows,
241
+ getRow,
242
+ getCell(addr) {
243
+ return data.cells.get(refToRow(addr))?.get(refToColumn(addr)) ?? EMPTY_CELL;
244
+ }
245
+ };
246
+ }
247
+ async function readXlsxWorkbook(filePath, deadline = ooxmlWorkDeadline()) {
248
+ const entries = await readOoxmlZip(filePath, ".xlsx");
249
+ const budget = ooxmlPartBudget();
250
+ const workbookXml = decodeZipEntry(entries, "xl/workbook.xml", budget);
251
+ if (workbookXml === null) throw new NotAnOfficeDocumentError(`not a valid .xlsx file: ${filePath}`);
252
+ const workbookRoot = await parseOoxmlPart(workbookXml);
253
+ const wbNode = workbookRoot?.["workbook"];
254
+ if (wbNode === void 0 || wbNode === null || typeof wbNode !== "object") {
255
+ throw new NotAnOfficeDocumentError(`not a valid .xlsx file: ${filePath}`);
256
+ }
257
+ const wb = wbNode;
258
+ const date1904 = isTruthyAttr(attr(wb["workbookPr"], "date1904"));
259
+ const relsXml = decodeZipEntry(entries, "xl/_rels/workbook.xml.rels", budget);
260
+ const rels = parseWorkbookRels(relsXml === null ? null : await parseOoxmlPart(relsXml));
261
+ const sharedXml = decodeZipEntry(entries, "xl/sharedStrings.xml", budget);
262
+ const shared = sharedXml === null ? [] : parseSharedStrings(await parseOoxmlPart(sharedXml));
263
+ const stylesXml = decodeZipEntry(entries, "xl/styles.xml", budget);
264
+ const styles = parseStyles(stylesXml, stylesXml === null ? null : await parseOoxmlPart(stylesXml));
265
+ const worksheets = [];
266
+ const parsedByPart = /* @__PURE__ */ new Map();
267
+ for (const sheet of asArray(wb["sheets"]?.["sheet"])) {
268
+ const name = attr(sheet, "name") ?? "";
269
+ const rid = attr(sheet, "r:id") ?? attr(sheet, "relationshipId");
270
+ const partPath = rid === void 0 ? void 0 : rels.get(rid);
271
+ const cached = partPath === void 0 ? void 0 : parsedByPart.get(partPath);
272
+ if (cached !== void 0) {
273
+ worksheets.push(makeWorksheet(name, cached));
274
+ continue;
275
+ }
276
+ assertOoxmlWithinDeadline(deadline, "Narrow the read to specific sheets with xlsx-head, or use a smaller workbook.");
277
+ const sheetXml = partPath === void 0 ? null : decodeZipEntry(entries, partPath, budget);
278
+ const data = sheetXml === null ? { cells: /* @__PURE__ */ new Map(), rowCount: 0, columnCount: 0, populatedRows: 0 } : parseSheet(await parseOoxmlPart(sheetXml), shared, styles, date1904);
279
+ if (partPath !== void 0) parsedByPart.set(partPath, data);
280
+ worksheets.push(makeWorksheet(name, data));
281
+ }
282
+ return {
283
+ worksheets,
284
+ getWorksheet: (name) => worksheets.find((ws) => ws.name === name)
285
+ };
286
+ }
287
+
288
+ // src/xlsx_extract.ts
289
+ var loadWorkbook = readXlsxWorkbook;
290
+ function requireSheet(wb, sheetName) {
291
+ if (sheetName !== void 0 && sheetName.trim() !== "") {
292
+ const ws = wb.getWorksheet(sheetName);
293
+ if (ws === void 0) {
294
+ throw new Error(`unknown sheet: ${sheetName} (available: ${wb.worksheets.map((s) => s.name).join(", ")})`);
295
+ }
296
+ return ws;
297
+ }
298
+ const first = wb.worksheets[0];
299
+ if (first === void 0) {
300
+ throw new Error("workbook contains no worksheets");
301
+ }
302
+ return first;
303
+ }
304
+ var MAX_XLSX_SCAN_CELLS = 2e7;
305
+ var XlsxScanTooLargeError = class extends DocumentRefusedError {
306
+ constructor(extent, cells, hint) {
307
+ super(`${extent} (${cells.toLocaleString()} cells), over the ${MAX_XLSX_SCAN_CELLS.toLocaleString()}-cell scan limit; ${hint}`, "XlsxScanTooLargeError");
308
+ }
309
+ };
310
+ function assertCellCount(cells, extent, hint) {
311
+ if (cells > MAX_XLSX_SCAN_CELLS) throw new XlsxScanTooLargeError(extent, cells, hint);
312
+ }
313
+ function assertScannableExtent(ws) {
314
+ assertCellCount(
315
+ (ws.rowCount || 0) * (ws.columnCount || 0),
316
+ `sheet "${ws.name}" declares a used range of ${ws.rowCount} rows x ${ws.columnCount} cols`,
317
+ "read a bounded range with xlsx-range --range"
318
+ );
319
+ }
320
+ function colLettersToIndex(letters) {
321
+ let n = 0;
322
+ for (const ch of letters.toUpperCase()) n = n * 26 + (ch.charCodeAt(0) - 64);
323
+ return n;
324
+ }
325
+ function indexToColLetters(idx) {
326
+ let n = idx;
327
+ let s = "";
328
+ while (n > 0) {
329
+ const rem = (n - 1) % 26;
330
+ s = String.fromCharCode(65 + rem) + s;
331
+ n = Math.floor((n - 1) / 26);
332
+ }
333
+ return s;
334
+ }
335
+ function decodeCellRef(ref) {
336
+ const m = /^([A-Za-z]+)(\d+)$/.exec(ref.trim());
337
+ if (!m) throw new Error(`invalid cell reference: ${ref}`);
338
+ return { c: colLettersToIndex(m[1]), r: parseInt(m[2], 10) };
339
+ }
340
+ function decodeRange(ref) {
341
+ const parts = ref.split(":");
342
+ const startRef = parts[0] !== void 0 && parts[0] !== "" ? parts[0] : ref;
343
+ const endRef = parts[1] !== void 0 && parts[1] !== "" ? parts[1] : startRef;
344
+ const start = decodeCellRef(startRef);
345
+ const end = decodeCellRef(endRef);
346
+ return {
347
+ s: { r: Math.min(start.r, end.r), c: Math.min(start.c, end.c) },
348
+ e: { r: Math.max(start.r, end.r), c: Math.max(start.c, end.c) }
349
+ };
350
+ }
351
+ function encodeCell(cell) {
352
+ return `${indexToColLetters(cell.c)}${cell.r}`;
353
+ }
354
+ function formatDateCell(d) {
355
+ const isDateOnly = d.getUTCHours() === 0 && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0 && d.getUTCMilliseconds() === 0;
356
+ return isDateOnly ? d.toISOString().slice(0, 10) : d.toISOString();
357
+ }
358
+ function cellText(cell) {
359
+ if (cell.value === null || cell.value === void 0) return "";
360
+ if (cell.value instanceof Date) return formatDateCell(cell.value);
361
+ const v = cell.value;
362
+ if (typeof v === "object" && v !== null) {
363
+ const obj = v;
364
+ if (Array.isArray(obj.richText)) return obj.richText.map((t) => t.text).join("");
365
+ if (typeof obj.error === "string") return obj.error;
366
+ if (obj.result !== void 0) {
367
+ if (obj.result instanceof Date) return formatDateCell(obj.result);
368
+ if (typeof obj.result === "object" && obj.result !== null && typeof obj.result.error === "string") {
369
+ return obj.result.error;
370
+ }
371
+ return String(obj.result);
372
+ }
373
+ if (obj.text !== void 0) return String(obj.text);
374
+ }
375
+ return cell.text !== "" ? cell.text : String(cell.value);
376
+ }
377
+ function cellFormula(cell) {
378
+ const v = cell.value;
379
+ if (typeof v === "object" && v !== null) {
380
+ const obj = v;
381
+ if (typeof obj.formula === "string") return obj.formula;
382
+ }
383
+ return void 0;
384
+ }
385
+ function usedRange(ws) {
386
+ assertScannableExtent(ws);
387
+ let maxCol = 0;
388
+ const rowCount = ws.rowCount || 0;
389
+ for (let r = 1; r <= rowCount; r++) {
390
+ const row = ws.getRow(r);
391
+ row.eachCell({ includeEmpty: false }, (_cell, colNumber) => {
392
+ if (colNumber > maxCol) maxCol = colNumber;
393
+ });
394
+ }
395
+ const rows = rowCount;
396
+ const cols = maxCol;
397
+ if (rows === 0 || cols === 0) {
398
+ return { ref: "(empty)", rows: 0, cols: 0 };
399
+ }
400
+ return { ref: `A1:${indexToColLetters(cols)}${rows}`, rows, cols };
401
+ }
402
+ async function listSheets(filePath, deadline = ooxmlWorkDeadline()) {
403
+ const wb = await loadWorkbook(filePath, deadline);
404
+ return wb.worksheets.map((ws) => {
405
+ assertOoxmlWithinDeadline(deadline, "Narrow the read to specific sheets with xlsx-head, or use a smaller workbook.");
406
+ const { ref, rows, cols } = usedRange(ws);
407
+ return { name: ws.name, ref, rows, cols };
408
+ });
409
+ }
410
+ function headSheetFromWorksheet(ws, rows, columns) {
411
+ assertScannableExtent(ws);
412
+ const rowCount = ws.rowCount || 0;
413
+ const sheetCols = ws.columnCount || 0;
414
+ const scanRows = Math.min(rowCount, rows + 1);
415
+ const aoa = [];
416
+ for (let r = 1; r <= scanRows; r++) {
417
+ const rowVals = [];
418
+ for (let c = 1; c <= sheetCols; c++) {
419
+ rowVals.push(cellText(ws.getCell(encodeCell({ r, c }))));
420
+ }
421
+ aoa.push(rowVals);
422
+ }
423
+ let header = Array.from({ length: sheetCols }, (_, i) => String(aoa[0]?.[i] ?? ""));
424
+ let dataRows = aoa.slice(1, 1 + rows).map(
425
+ (r) => Array.from({ length: sheetCols }, (_, i) => String(r[i] ?? ""))
426
+ );
427
+ if (columns !== void 0 && columns.length > 0) {
428
+ const normCols = columns.map((c) => c.trim()).filter(Boolean);
429
+ const selectedIndices = [];
430
+ for (const req of normCols) {
431
+ let idx = header.findIndex((h) => h === req);
432
+ if (idx === -1) {
433
+ idx = header.findIndex((h) => h.toLowerCase() === req.toLowerCase());
434
+ }
435
+ if (idx === -1 && /^[A-Za-z]+$/.test(req)) {
436
+ const colNum = colLettersToIndex(req);
437
+ if (colNum >= 1 && colNum <= sheetCols) {
438
+ idx = colNum - 1;
439
+ }
440
+ }
441
+ if (idx !== -1 && !selectedIndices.includes(idx)) {
442
+ selectedIndices.push(idx);
443
+ } else if (idx === -1) {
444
+ throw new Error(`unknown column: ${req} (available: ${header.filter(Boolean).join(", ")})`);
445
+ }
446
+ }
447
+ header = selectedIndices.map((i) => header[i] ?? "");
448
+ dataRows = dataRows.map((r) => selectedIndices.map((i) => r[i] ?? ""));
449
+ }
450
+ const lines = [header.map(quoteCsvCell).join(",")];
451
+ for (const r of dataRows) lines.push(r.map(quoteCsvCell).join(","));
452
+ if (rowCount - 1 > dataRows.length) {
453
+ lines.push(`...(${rowCount - 1 - dataRows.length} more rows elided; use --rows to see more, or xlsx-query for filtering)`);
454
+ }
455
+ return lines.join("\n");
456
+ }
457
+ async function headSheet(filePath, sheetName, rows = 20, columns) {
458
+ const wb = await loadWorkbook(filePath);
459
+ const ws = requireSheet(wb, sheetName);
460
+ return headSheetFromWorksheet(ws, rows, columns);
461
+ }
462
+ async function allSheetsHeadText(filePath, rows, deadline = ooxmlWorkDeadline()) {
463
+ const wb = await loadWorkbook(filePath, deadline);
464
+ const sheetTexts = [];
465
+ for (const ws of wb.worksheets) {
466
+ assertOoxmlWithinDeadline(deadline, "Narrow the read to specific sheets with xlsx-head, or use a smaller workbook.");
467
+ sheetTexts.push(`# Sheet: ${ws.name}
468
+ ${headSheetFromWorksheet(ws, rows)}`);
469
+ }
470
+ return sheetTexts.join("\n\n");
471
+ }
472
+ async function rangeSheet(filePath, sheetName, rangeSpec, showFormulas) {
473
+ const wb = await loadWorkbook(filePath);
474
+ const ws = requireSheet(wb, sheetName);
475
+ const range = decodeRange(rangeSpec);
476
+ const rangeRows = range.e.r - range.s.r + 1;
477
+ const rangeCols = range.e.c - range.s.c + 1;
478
+ assertCellCount(rangeRows * rangeCols, `range ${rangeSpec} covers ${rangeRows} rows x ${rangeCols} cols`, "ask for a smaller --range");
479
+ const rowsOut = [];
480
+ for (let r = range.s.r; r <= range.e.r; r++) {
481
+ const rowOut = [];
482
+ for (let c = range.s.c; c <= range.e.c; c++) {
483
+ const addr = encodeCell({ r, c });
484
+ const cell = ws.getCell(addr);
485
+ if (showFormulas && cellFormula(cell) !== void 0) {
486
+ rowOut.push(`=${cellFormula(cell)}`);
487
+ } else {
488
+ rowOut.push(cellText(cell));
489
+ }
490
+ }
491
+ rowsOut.push(rowOut);
492
+ }
493
+ const colLabels = rowsOut[0]?.map((_, i) => indexToColLetters(range.s.c + i)) ?? [];
494
+ return { header: colLabels, rows: rowsOut };
495
+ }
496
+ function formatXlsxRange(result) {
497
+ const lines = [result.header.map(quoteCsvCell).join(",")];
498
+ for (const r of result.rows) lines.push(r.map(quoteCsvCell).join(","));
499
+ return lines.join("\n");
500
+ }
501
+ async function sheetToCsv(ws) {
502
+ const rowCount = ws.rowCount || 0;
503
+ const { cols: sheetCols } = usedRange(ws);
504
+ const lines = [];
505
+ for (let r = 1; r <= rowCount; r++) {
506
+ const vals = [];
507
+ for (let c = 1; c <= sheetCols; c++) {
508
+ vals.push(cellText(ws.getCell(encodeCell({ r, c }))));
509
+ }
510
+ lines.push(vals.map(quoteCsvCell).join(","));
511
+ }
512
+ return lines.join("\n");
513
+ }
514
+ async function querySheet(filePath, sheetName, opts) {
515
+ const wb = await loadWorkbook(filePath);
516
+ const ws = requireSheet(wb, sheetName);
517
+ const csvText = await sheetToCsv(ws);
518
+ return queryCsv(csvText, opts);
519
+ }
520
+ async function xlsxColumns(filePath, sheetName, sampleLimit = 100) {
521
+ const wb = await loadWorkbook(filePath);
522
+ const ws = requireSheet(wb, sheetName);
523
+ assertScannableExtent(ws);
524
+ const rowCount = ws.rowCount || 0;
525
+ const { cols: sheetCols } = usedRange(ws);
526
+ if (rowCount === 0 || sheetCols === 0) {
527
+ return { sheetName: ws.name, totalSheetRows: 0, sampleRows: 0, columns: [] };
528
+ }
529
+ const sampleRows = Math.min(Math.max(1, sampleLimit), Math.max(1, rowCount - 1));
530
+ const headers = [];
531
+ for (let c = 1; c <= sheetCols; c++) {
532
+ const val = cellText(ws.getCell(encodeCell({ r: 1, c })));
533
+ headers.push(val || `(col ${indexToColLetters(c)})`);
534
+ }
535
+ const colSummaries = headers.map((name, i) => ({
536
+ letter: indexToColLetters(i + 1),
537
+ name,
538
+ index: i + 1,
539
+ nonEmptyRows: 0,
540
+ sampleRows,
541
+ sampleValues: []
542
+ }));
543
+ for (let r = 2; r <= 1 + sampleRows; r++) {
544
+ for (let c = 1; c <= sheetCols; c++) {
545
+ const txt = cellText(ws.getCell(encodeCell({ r, c })));
546
+ if (txt !== "") {
547
+ const summary = colSummaries[c - 1];
548
+ summary.nonEmptyRows++;
549
+ if (summary.sampleValues.length < 3 && !summary.sampleValues.includes(txt)) {
550
+ summary.sampleValues.push(txt);
551
+ }
552
+ }
553
+ }
554
+ }
555
+ return {
556
+ sheetName: ws.name,
557
+ totalSheetRows: Math.max(0, rowCount - 1),
558
+ sampleRows,
559
+ columns: colSummaries
560
+ };
561
+ }
562
+ function formatXlsxColumns(result) {
563
+ if (result.columns.length === 0) return `Sheet "${displaySafeText(result.sheetName)}" is empty`;
564
+ const lines = [
565
+ `Sheet: ${displaySafeText(result.sheetName)} (${result.totalSheetRows} data rows, ${result.columns.length} columns; sampled first ${result.sampleRows} rows)`
566
+ ];
567
+ for (const c of result.columns) {
568
+ const pct = result.sampleRows > 0 ? Math.round(c.nonEmptyRows / c.sampleRows * 100) : 0;
569
+ const samples = c.sampleValues.length > 0 ? ` (e.g. ${c.sampleValues.map((v) => JSON.stringify(v.length > 30 ? v.slice(0, 27) + "..." : v)).join(", ")})` : " (all empty)";
570
+ lines.push(` ${c.letter.padEnd(4)} ${displaySafeText(c.name).padEnd(25)} ${c.nonEmptyRows}/${c.sampleRows} (${pct}%)${samples}`);
571
+ }
572
+ return lines.join("\n");
573
+ }
574
+
575
+ export {
576
+ XlsxScanTooLargeError,
577
+ listSheets,
578
+ headSheet,
579
+ allSheetsHeadText,
580
+ rangeSheet,
581
+ formatXlsxRange,
582
+ querySheet,
583
+ xlsxColumns,
584
+ formatXlsxColumns
585
+ };