@bendyline/squisq-formats 2.5.0 → 2.6.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/NOTICE.md +10 -9
- package/dist/{chunk-2LT3JL7U.js → chunk-3ITGQRL5.js} +8 -8
- package/dist/{chunk-FMQWNPCV.js → chunk-AGGNLRHV.js} +6 -6
- package/dist/{chunk-AONELFLA.js → chunk-B7GEAZBI.js} +6 -1
- package/dist/chunk-CKSTGNVZ.js +724 -0
- package/dist/chunk-DXYWKZ52.js +57 -0
- package/dist/{chunk-T4PX33AG.js → chunk-EEDQRZ2M.js} +17 -1
- package/dist/chunk-FLR2ARKC.js +240 -0
- package/dist/{chunk-JTGWQK5V.js → chunk-GRKQTQOF.js} +64 -12
- package/dist/{chunk-A6LSCIO5.js → chunk-OBADJV7C.js} +286 -420
- package/dist/{chunk-AD2WT564.js → chunk-Q77KNJIN.js} +45 -0
- package/dist/{chunk-5PUIFU5I.js → chunk-VDTGQ4MW.js} +1 -1
- package/dist/{chunk-6RQOV3B3.js → chunk-VPWPEMZJ.js} +1 -1
- package/dist/{chunk-FIOSE4BO.js → chunk-XJNOZTAY.js} +6 -6
- package/dist/csv/index.d.ts +67 -1
- package/dist/csv/index.js +10 -3
- package/dist/data/index.d.ts +78 -0
- package/dist/data/index.js +30 -0
- package/dist/docx/index.js +3 -3
- package/dist/epub/index.js +4 -4
- package/dist/export-6iQXd-lQ.d.ts +366 -0
- package/dist/html/index.d.ts +2 -8
- package/dist/html/index.js +3 -3
- package/dist/{images-ESPQKVTW.js → images-JLBFCDD4.js} +1 -1
- package/dist/{import-B0gBYUmd.d.ts → import-C7c9tQHK.d.ts} +5 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +33 -26
- package/dist/infer/index.js +6 -6
- package/dist/materialize-A34OZGEU.js +11 -0
- package/dist/outside-in/index.d.ts +3 -3
- package/dist/outside-in/index.js +2 -2
- package/dist/pdf/index.js +2 -2
- package/dist/pptx/index.js +3 -3
- package/dist/registry/index.d.ts +4 -4
- package/dist/registry/index.js +1 -1
- package/dist/{types-DByrrXeB.d.ts → types-Dzd_5H2A.d.ts} +5 -5
- package/dist/xlsx/index.d.ts +85 -4
- package/dist/xlsx/index.js +25 -4
- package/package.json +18 -3
- package/dist/export-m0tr9r9d.d.ts +0 -130
- package/dist/{chunk-KMBBO5H7.js → chunk-7DQP2I57.js} +4 -4
- package/dist/{chunk-M7XPXGXW.js → chunk-ROF7SSQP.js} +3 -3
|
@@ -1,23 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from "./chunk-AVOZAKGP.js";
|
|
2
|
+
planDataSidecar
|
|
3
|
+
} from "./chunk-DXYWKZ52.js";
|
|
5
4
|
import {
|
|
6
|
-
createPackage
|
|
7
|
-
} from "./chunk-ILCJ3WFD.js";
|
|
8
|
-
import {
|
|
9
|
-
escapeXml,
|
|
10
|
-
xmlDeclaration
|
|
11
|
-
} from "./chunk-JU2RHXUB.js";
|
|
12
|
-
import {
|
|
13
|
-
CONTENT_TYPE_XLSX_STYLES,
|
|
14
|
-
CONTENT_TYPE_XLSX_WORKBOOK,
|
|
15
|
-
CONTENT_TYPE_XLSX_WORKSHEET,
|
|
16
5
|
NS_R,
|
|
17
6
|
NS_SML,
|
|
18
|
-
REL_OFFICE_DOCUMENT,
|
|
19
|
-
REL_STYLES,
|
|
20
|
-
REL_WORKSHEET,
|
|
21
7
|
baseDirOf,
|
|
22
8
|
getPartRelationships,
|
|
23
9
|
getPartXml,
|
|
@@ -25,9 +11,6 @@ import {
|
|
|
25
11
|
requireMainPartPath
|
|
26
12
|
} from "./chunk-S5PCVMKU.js";
|
|
27
13
|
|
|
28
|
-
// src/xlsx/index.ts
|
|
29
|
-
import { markdownToDoc } from "@bendyline/squisq/doc";
|
|
30
|
-
|
|
31
14
|
// src/xlsx/cells.ts
|
|
32
15
|
var MAX_COL_INDEX = 16383;
|
|
33
16
|
var MAX_ROW_INDEX = 1048575;
|
|
@@ -387,7 +370,116 @@ function peelCaptionRow(grid, rect) {
|
|
|
387
370
|
return { caption, rect: { ...rect, top: rect.top + 1 } };
|
|
388
371
|
}
|
|
389
372
|
|
|
373
|
+
// src/xlsx/tables.ts
|
|
374
|
+
function columnLetter2(index) {
|
|
375
|
+
let n = index;
|
|
376
|
+
let out = "";
|
|
377
|
+
do {
|
|
378
|
+
out = String.fromCharCode(65 + n % 26) + out;
|
|
379
|
+
n = Math.floor(n / 26) - 1;
|
|
380
|
+
} while (n >= 0);
|
|
381
|
+
return out;
|
|
382
|
+
}
|
|
383
|
+
function a1(row, col) {
|
|
384
|
+
return `${columnLetter2(col)}${row + 1}`;
|
|
385
|
+
}
|
|
386
|
+
function regionHasHeader(cells) {
|
|
387
|
+
if (cells.length < 2) return false;
|
|
388
|
+
const first = cells[0];
|
|
389
|
+
if (!first || first.length === 0) return false;
|
|
390
|
+
return first.every((cell) => cell.kind === "string");
|
|
391
|
+
}
|
|
392
|
+
function cellValue(cell) {
|
|
393
|
+
if (cell.kind === "empty" || cell.kind === "error") return null;
|
|
394
|
+
if (cell.value !== void 0) return cell.value;
|
|
395
|
+
return cell.text === "" ? null : cell.text;
|
|
396
|
+
}
|
|
397
|
+
function dominantKind(kinds) {
|
|
398
|
+
const counts = /* @__PURE__ */ new Map();
|
|
399
|
+
let total = 0;
|
|
400
|
+
for (const kind of kinds) {
|
|
401
|
+
if (kind === "empty") continue;
|
|
402
|
+
counts.set(kind, (counts.get(kind) ?? 0) + 1);
|
|
403
|
+
total += 1;
|
|
404
|
+
}
|
|
405
|
+
if (total === 0) return "empty";
|
|
406
|
+
let best = "string";
|
|
407
|
+
let bestCount = 0;
|
|
408
|
+
for (const [kind, count] of counts) {
|
|
409
|
+
if (count > bestCount) {
|
|
410
|
+
best = kind;
|
|
411
|
+
bestCount = count;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return bestCount * 2 > total ? best : "mixed";
|
|
415
|
+
}
|
|
416
|
+
function sliceRegion(grid, rect) {
|
|
417
|
+
const out = [];
|
|
418
|
+
for (let r = rect.top; r <= rect.bottom; r++) {
|
|
419
|
+
const row = [];
|
|
420
|
+
for (let c = rect.left; c <= rect.right; c++) {
|
|
421
|
+
row.push(grid[r]?.[c] ?? { text: "", kind: "empty" });
|
|
422
|
+
}
|
|
423
|
+
out.push(row);
|
|
424
|
+
}
|
|
425
|
+
return out;
|
|
426
|
+
}
|
|
427
|
+
function regionToTable(sheet, grid, rect, title, minRows) {
|
|
428
|
+
const cells = sliceRegion(grid, rect);
|
|
429
|
+
if (cells.length === 0) return null;
|
|
430
|
+
const hasHeader = regionHasHeader(cells);
|
|
431
|
+
const body = hasHeader ? cells.slice(1) : cells;
|
|
432
|
+
if (body.length < minRows) return null;
|
|
433
|
+
if (!body.some((row) => row.some(isOccupied))) return null;
|
|
434
|
+
const width = cells.reduce((max, row) => Math.max(max, row.length), 0);
|
|
435
|
+
const columns = [];
|
|
436
|
+
for (let c = 0; c < width; c++) {
|
|
437
|
+
const header = hasHeader ? cells[0]?.[c]?.text ?? "" : "";
|
|
438
|
+
columns.push({
|
|
439
|
+
name: header.trim() || columnLetter2(rect.left + c),
|
|
440
|
+
kind: dominantKind(body.map((row) => row[c]?.kind ?? "empty"))
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
return {
|
|
444
|
+
sheet,
|
|
445
|
+
anchor: a1(rect.top, rect.left),
|
|
446
|
+
...title ? { title } : {},
|
|
447
|
+
columns,
|
|
448
|
+
hasHeader,
|
|
449
|
+
rows: body.map(
|
|
450
|
+
(row) => Array.from({ length: width }, (_, c) => cellValue(row[c] ?? { text: "", kind: "empty" }))
|
|
451
|
+
)
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
function gridToTables(sheet, grid, merges = [], options = {}) {
|
|
455
|
+
if (grid.length === 0) return [];
|
|
456
|
+
const minRows = options.minRows ?? 1;
|
|
457
|
+
const plan = detectRegions(grid, merges, {
|
|
458
|
+
...options.maxRegionsPerSheet !== void 0 ? { maxRegionsPerSheet: options.maxRegionsPerSheet } : {},
|
|
459
|
+
...options.minRegionCells !== void 0 ? { minRegionCells: options.minRegionCells } : {},
|
|
460
|
+
...options.signal ? { signal: options.signal } : {}
|
|
461
|
+
});
|
|
462
|
+
if (plan.degraded || plan.regions.length === 0) {
|
|
463
|
+
const rect = {
|
|
464
|
+
top: 0,
|
|
465
|
+
left: 0,
|
|
466
|
+
bottom: grid.length - 1,
|
|
467
|
+
right: grid.reduce((max, row) => Math.max(max, row.length), 1) - 1
|
|
468
|
+
};
|
|
469
|
+
const whole = regionToTable(sheet, grid, rect, void 0, minRows);
|
|
470
|
+
return whole ? [whole] : [];
|
|
471
|
+
}
|
|
472
|
+
const out = [];
|
|
473
|
+
for (const region of plan.regions) {
|
|
474
|
+
const table = regionToTable(sheet, grid, region.rect, region.title, minRows);
|
|
475
|
+
if (table) out.push(table);
|
|
476
|
+
}
|
|
477
|
+
return out;
|
|
478
|
+
}
|
|
479
|
+
|
|
390
480
|
// src/xlsx/import.ts
|
|
481
|
+
import { stringifyMarkdown } from "@bendyline/squisq/markdown";
|
|
482
|
+
import { MemoryContentContainer } from "@bendyline/squisq/storage";
|
|
391
483
|
var XLSX_MAIN_PART = "xl/workbook.xml";
|
|
392
484
|
function attrNS(el, ns, local, fallback) {
|
|
393
485
|
return el.getAttributeNS(ns, local) ?? el.getAttribute(fallback);
|
|
@@ -401,7 +493,7 @@ function resolveTarget(baseDir, target) {
|
|
|
401
493
|
}
|
|
402
494
|
return stack.join("/");
|
|
403
495
|
}
|
|
404
|
-
async function
|
|
496
|
+
async function listSheetParts(pkg, mainPart) {
|
|
405
497
|
const wb = await getPartXml(pkg, mainPart);
|
|
406
498
|
if (!wb) {
|
|
407
499
|
throw new Error(`Invalid XLSX package: workbook part "${mainPart}" could not be parsed.`);
|
|
@@ -417,11 +509,22 @@ async function readWorkbook(pkg, mainPart) {
|
|
|
417
509
|
const target = rid ? relById.get(rid) : void 0;
|
|
418
510
|
if (target) out.push({ name, path: resolveTarget(baseDirOf(mainPart), target) });
|
|
419
511
|
}
|
|
512
|
+
return out;
|
|
513
|
+
}
|
|
514
|
+
async function readWorkbook(pkg, mainPart) {
|
|
515
|
+
const wb = await getPartXml(pkg, mainPart);
|
|
516
|
+
if (!wb) {
|
|
517
|
+
throw new Error(`Invalid XLSX package: workbook part "${mainPart}" could not be parsed.`);
|
|
518
|
+
}
|
|
519
|
+
const sheets = await listSheetParts(pkg, mainPart);
|
|
420
520
|
const workbookPr = wb.getElementsByTagNameNS(NS_SML, "workbookPr")[0];
|
|
421
521
|
const date1904Value = workbookPr?.getAttribute("date1904");
|
|
522
|
+
const calcPr = wb.getElementsByTagNameNS(NS_SML, "calcPr")[0];
|
|
523
|
+
const fullCalcValue = calcPr?.getAttribute("fullCalcOnLoad");
|
|
422
524
|
return {
|
|
423
|
-
sheets
|
|
424
|
-
date1904: date1904Value === "1" || date1904Value === "true"
|
|
525
|
+
sheets,
|
|
526
|
+
date1904: date1904Value === "1" || date1904Value === "true",
|
|
527
|
+
fullCalcOnLoad: fullCalcValue === "1" || fullCalcValue === "true"
|
|
425
528
|
};
|
|
426
529
|
}
|
|
427
530
|
function isPhonetic(el, root) {
|
|
@@ -553,6 +656,16 @@ function excelTimeText(serial, includeSeconds, elapsedHours) {
|
|
|
553
656
|
const seconds = totalSeconds % 60;
|
|
554
657
|
return `${twoDigits(hours)}:${twoDigits(minutes)}${includeSeconds ? `:${twoDigits(seconds)}` : ""}`;
|
|
555
658
|
}
|
|
659
|
+
function dateValueText(serial, kind, style, date1904) {
|
|
660
|
+
if (!Number.isFinite(serial)) return null;
|
|
661
|
+
const normalized = style ? normalizeFormatCode(style.formatCode) : "";
|
|
662
|
+
if (kind === "time")
|
|
663
|
+
return excelTimeText(serial, /s/.test(normalized), /\[[h]+\]/.test(normalized));
|
|
664
|
+
const date = excelDateText(serial, date1904);
|
|
665
|
+
if (!date) return null;
|
|
666
|
+
if (kind === "datetime") return `${date} ${excelTimeText(serial, /s/.test(normalized), false)}`;
|
|
667
|
+
return date;
|
|
668
|
+
}
|
|
556
669
|
function formattedNumberText(raw, style, date1904) {
|
|
557
670
|
if (!style) return raw;
|
|
558
671
|
const value = Number(raw);
|
|
@@ -581,32 +694,37 @@ function formattedNumberText(raw, style, date1904) {
|
|
|
581
694
|
function readFormula(cell, row, col, ctx) {
|
|
582
695
|
const fEls = cell.getElementsByTagNameNS(NS_SML, "f");
|
|
583
696
|
const f = fEls.length ? fEls[0] : null;
|
|
584
|
-
if (!f) return "";
|
|
697
|
+
if (!f) return { text: "" };
|
|
585
698
|
const text = (f.textContent ?? "").trim();
|
|
586
|
-
if (f.getAttribute("t") !== "shared") return text;
|
|
699
|
+
if (f.getAttribute("t") !== "shared") return { text };
|
|
587
700
|
const si = f.getAttribute("si");
|
|
588
|
-
if (si === null) return text;
|
|
701
|
+
if (si === null) return { text };
|
|
589
702
|
if (text !== "") {
|
|
590
703
|
ctx.sharedFormulas.set(si, { text, row, col });
|
|
591
|
-
return text;
|
|
704
|
+
return { text, sharedRole: "master" };
|
|
592
705
|
}
|
|
593
706
|
const master = ctx.sharedFormulas.get(si);
|
|
594
|
-
if (!master) return "";
|
|
707
|
+
if (!master) return { text: "", sharedRole: "follower" };
|
|
595
708
|
try {
|
|
596
|
-
return
|
|
709
|
+
return {
|
|
710
|
+
text: translateFormula(master.text, row - master.row, col - master.col),
|
|
711
|
+
sharedRole: "follower"
|
|
712
|
+
};
|
|
597
713
|
} catch {
|
|
598
|
-
return "";
|
|
714
|
+
return { text: "", sharedRole: "follower" };
|
|
599
715
|
}
|
|
600
716
|
}
|
|
601
717
|
function readCell(cell, row, col, ctx) {
|
|
602
|
-
const formula = readFormula(cell, row, col, ctx);
|
|
603
|
-
const withFormula = (text2, kind2) => {
|
|
718
|
+
const { text: formula, sharedRole } = readFormula(cell, row, col, ctx);
|
|
719
|
+
const withFormula = (text2, kind2, value) => {
|
|
604
720
|
const out = { text: text2, kind: text2 === "" ? "empty" : kind2 };
|
|
605
721
|
if (formula !== "") out.formula = formula;
|
|
722
|
+
if (sharedRole !== void 0) out.sharedFormulaRole = sharedRole;
|
|
723
|
+
if (value !== void 0 && out.kind !== "empty") out.value = value;
|
|
606
724
|
return out;
|
|
607
725
|
};
|
|
608
726
|
const stringCell = (item) => {
|
|
609
|
-
const out = withFormula(item.text, "string");
|
|
727
|
+
const out = withFormula(item.text, "string", item.text);
|
|
610
728
|
if (item.rich && out.kind !== "empty") out.richText = item.rich;
|
|
611
729
|
return out;
|
|
612
730
|
};
|
|
@@ -619,14 +737,19 @@ function readCell(cell, row, col, ctx) {
|
|
|
619
737
|
const v = vEls.length ? vEls[0].textContent ?? "" : "";
|
|
620
738
|
if (v === "") return withFormula("", "empty");
|
|
621
739
|
if (t === "s") return stringCell(ctx.shared[Number.parseInt(v, 10)] ?? { text: "" });
|
|
622
|
-
if (t === "b") return withFormula(v === "1" ? "TRUE" : "FALSE", "bool");
|
|
740
|
+
if (t === "b") return withFormula(v === "1" ? "TRUE" : "FALSE", "bool", v === "1");
|
|
623
741
|
if (t === "e") return withFormula(v, "error");
|
|
624
|
-
if (t === "str") return withFormula(v, "string");
|
|
742
|
+
if (t === "str") return withFormula(v, "string", v);
|
|
625
743
|
const style = ctx.styles[Number.parseInt(cell.getAttribute("s") ?? "0", 10)];
|
|
626
744
|
const text = formattedNumberText(v, style, ctx.date1904);
|
|
627
745
|
const dateLike = style ? numberFormatKind(style.formatCode) : "general";
|
|
628
746
|
const kind = dateLike === "date" || dateLike === "time" || dateLike === "datetime" ? "date" : "number";
|
|
629
|
-
|
|
747
|
+
const numeric = Number(v);
|
|
748
|
+
if (kind === "date") {
|
|
749
|
+
const iso = dateValueText(numeric, dateLike, style, ctx.date1904);
|
|
750
|
+
return withFormula(text, kind, iso ?? text);
|
|
751
|
+
}
|
|
752
|
+
return withFormula(text, kind, Number.isFinite(numeric) ? numeric : v);
|
|
630
753
|
}
|
|
631
754
|
async function sheetToCells(pkg, path, shared, styles, date1904) {
|
|
632
755
|
const doc = await getPartXml(pkg, path);
|
|
@@ -723,7 +846,70 @@ function annotatedHeading(depth, text, params) {
|
|
|
723
846
|
templateAnnotation: { template: "dataTable", params }
|
|
724
847
|
};
|
|
725
848
|
}
|
|
849
|
+
async function xlsxToTables(data, options = {}) {
|
|
850
|
+
const pkg = await openPackage(data, options);
|
|
851
|
+
const mainPart = requireMainPartPath(pkg, XLSX_MAIN_PART, "XLSX");
|
|
852
|
+
const [{ sheets, date1904 }, shared, styles] = await Promise.all([
|
|
853
|
+
readWorkbook(pkg, mainPart),
|
|
854
|
+
readSharedStrings(pkg),
|
|
855
|
+
readCellStyles(pkg)
|
|
856
|
+
]);
|
|
857
|
+
let selected = sheets;
|
|
858
|
+
if (options.sheet !== void 0) {
|
|
859
|
+
const picked = typeof options.sheet === "number" ? sheets[options.sheet] : sheets.find((s) => s.name === options.sheet);
|
|
860
|
+
selected = picked ? [picked] : [];
|
|
861
|
+
}
|
|
862
|
+
const out = [];
|
|
863
|
+
for (const sheet of selected) {
|
|
864
|
+
const { cells, merges } = await sheetToCells(pkg, sheet.path, shared, styles, date1904);
|
|
865
|
+
out.push(...gridToTables(sheet.name, cells, merges, options));
|
|
866
|
+
}
|
|
867
|
+
return out;
|
|
868
|
+
}
|
|
869
|
+
async function xlsxToCellGrids(data, options = {}) {
|
|
870
|
+
const pkg = await openPackage(data, options);
|
|
871
|
+
const mainPart = requireMainPartPath(pkg, XLSX_MAIN_PART, "XLSX");
|
|
872
|
+
const [{ sheets, date1904, fullCalcOnLoad }, shared, styles] = await Promise.all([
|
|
873
|
+
readWorkbook(pkg, mainPart),
|
|
874
|
+
readSharedStrings(pkg),
|
|
875
|
+
readCellStyles(pkg)
|
|
876
|
+
]);
|
|
877
|
+
let selected = sheets;
|
|
878
|
+
if (options.sheet !== void 0) {
|
|
879
|
+
const picked = typeof options.sheet === "number" ? sheets[options.sheet] : sheets.find((s) => s.name === options.sheet);
|
|
880
|
+
selected = picked ? [picked] : [];
|
|
881
|
+
}
|
|
882
|
+
const out = [];
|
|
883
|
+
for (const sheet of selected) {
|
|
884
|
+
const { cells, merges } = await sheetToCells(pkg, sheet.path, shared, styles, date1904);
|
|
885
|
+
out.push({ name: sheet.name, cells, merges });
|
|
886
|
+
}
|
|
887
|
+
return { sheets: out, date1904, fullCalcOnLoad };
|
|
888
|
+
}
|
|
726
889
|
async function xlsxToMarkdownDoc(data, options = {}) {
|
|
890
|
+
return workbookToMarkdown(data, options, void 0);
|
|
891
|
+
}
|
|
892
|
+
function shouldSpillRegion(spill, rect, hasHeader) {
|
|
893
|
+
if (spill.mode === "always") return true;
|
|
894
|
+
const height = rect.bottom - rect.top + 1;
|
|
895
|
+
const width = rect.right - rect.left + 1;
|
|
896
|
+
const dataRows = height - (hasHeader ? 1 : 0);
|
|
897
|
+
return dataRows > spill.maxInlineRows || height * width > spill.maxInlineCells;
|
|
898
|
+
}
|
|
899
|
+
function shouldSpillGrid(spill, cells) {
|
|
900
|
+
if (spill.mode === "always") return true;
|
|
901
|
+
const width = cells.reduce((max, row) => Math.max(max, row.length), 0);
|
|
902
|
+
return cells.length - 1 > spill.maxInlineRows || cells.length * width > spill.maxInlineCells;
|
|
903
|
+
}
|
|
904
|
+
function sidecarLinkParagraph(spill) {
|
|
905
|
+
return {
|
|
906
|
+
type: "paragraph",
|
|
907
|
+
children: [
|
|
908
|
+
{ type: "link", url: spill.src, children: [{ type: "text", value: spill.fileName }] }
|
|
909
|
+
]
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
async function workbookToMarkdown(data, options, spill) {
|
|
727
913
|
const pkg = await openPackage(data, options);
|
|
728
914
|
const mainPart = requireMainPartPath(pkg, XLSX_MAIN_PART, "XLSX");
|
|
729
915
|
const [{ sheets, date1904 }, shared, styles] = await Promise.all([
|
|
@@ -747,6 +933,14 @@ async function xlsxToMarkdownDoc(data, options = {}) {
|
|
|
747
933
|
}
|
|
748
934
|
if (cells.length === 0) continue;
|
|
749
935
|
if (!useRegions) {
|
|
936
|
+
if (spill && shouldSpillGrid(spill, cells)) {
|
|
937
|
+
children.push(
|
|
938
|
+
annotatedHeading(single ? 1 : 2, sheet.name, { src: spill.src, sheet: sheet.name }),
|
|
939
|
+
sidecarLinkParagraph(spill)
|
|
940
|
+
);
|
|
941
|
+
spill.used = true;
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
750
944
|
children.push(cellsToTable(cells));
|
|
751
945
|
continue;
|
|
752
946
|
}
|
|
@@ -757,6 +951,14 @@ async function xlsxToMarkdownDoc(data, options = {}) {
|
|
|
757
951
|
});
|
|
758
952
|
for (const warning of plan.warnings) console.warn(`XLSX import: ${sheet.name}: ${warning}`);
|
|
759
953
|
if (plan.degraded || plan.regions.length === 0 && plan.strays.length === 0) {
|
|
954
|
+
if (spill && shouldSpillGrid(spill, cells)) {
|
|
955
|
+
children.push(
|
|
956
|
+
annotatedHeading(single ? 1 : 2, sheet.name, { src: spill.src, sheet: sheet.name }),
|
|
957
|
+
sidecarLinkParagraph(spill)
|
|
958
|
+
);
|
|
959
|
+
spill.used = true;
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
760
962
|
children.push(cellsToTable(cells));
|
|
761
963
|
continue;
|
|
762
964
|
}
|
|
@@ -765,6 +967,21 @@ async function xlsxToMarkdownDoc(data, options = {}) {
|
|
|
765
967
|
const slice = sliceRect(cells, region.rect, EMPTY_CELL);
|
|
766
968
|
const anchor = formatCellRef(region.rect.top, region.rect.left);
|
|
767
969
|
const title = region.title ?? `${sheet.name} \u2014 ${anchor}`;
|
|
970
|
+
const hasHeaderRow = inferHeader(slice);
|
|
971
|
+
if (spill && shouldSpillRegion(spill, region.rect, hasHeaderRow)) {
|
|
972
|
+
children.push(
|
|
973
|
+
annotatedHeading(depth, title, {
|
|
974
|
+
src: spill.src,
|
|
975
|
+
sheet: sheet.name,
|
|
976
|
+
anchor,
|
|
977
|
+
...hasHeaderRow ? {} : { headerRow: "false" },
|
|
978
|
+
...region.titleCell ? { titleAnchor: formatCellRef(region.titleCell.row, region.titleCell.col) } : {}
|
|
979
|
+
}),
|
|
980
|
+
sidecarLinkParagraph(spill)
|
|
981
|
+
);
|
|
982
|
+
spill.used = true;
|
|
983
|
+
continue;
|
|
984
|
+
}
|
|
768
985
|
children.push(
|
|
769
986
|
annotatedHeading(depth, title, {
|
|
770
987
|
sheet: sheet.name,
|
|
@@ -773,7 +990,7 @@ async function xlsxToMarkdownDoc(data, options = {}) {
|
|
|
773
990
|
// says. (`headerRow`, not `header` — `dataTable` already declares a
|
|
774
991
|
// `headers` input, and two params one letter apart in the same
|
|
775
992
|
// annotation is a trap for anyone reading or editing the markdown.)
|
|
776
|
-
...
|
|
993
|
+
...hasHeaderRow ? {} : { headerRow: "false" },
|
|
777
994
|
// A caption promoted into the heading has left its cell behind;
|
|
778
995
|
// record where, so the reverse path can put the text back.
|
|
779
996
|
...region.titleCell ? { titleAnchor: formatCellRef(region.titleCell.row, region.titleCell.col) } : {}
|
|
@@ -804,394 +1021,43 @@ async function xlsxToMarkdownDoc(data, options = {}) {
|
|
|
804
1021
|
}
|
|
805
1022
|
return { type: "document", children };
|
|
806
1023
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
function cellKey(row, col) {
|
|
819
|
-
return row * KEY_STRIDE + col;
|
|
820
|
-
}
|
|
821
|
-
function keyRow(key) {
|
|
822
|
-
return Math.floor(key / KEY_STRIDE);
|
|
823
|
-
}
|
|
824
|
-
function keyCol(key) {
|
|
825
|
-
return key - keyRow(key) * KEY_STRIDE;
|
|
826
|
-
}
|
|
827
|
-
function tableToGrid(table) {
|
|
828
|
-
return table.children.map(
|
|
829
|
-
(row) => row.children.map((cell) => extractPlainText(cell.children))
|
|
830
|
-
);
|
|
831
|
-
}
|
|
832
|
-
function tableToRichGrid(table) {
|
|
833
|
-
return table.children.map(
|
|
834
|
-
(row) => row.children.map((cell) => hasRichCellContent(cell.children) ? cell.children : void 0)
|
|
835
|
-
);
|
|
836
|
-
}
|
|
837
|
-
function readRole(raw) {
|
|
838
|
-
return raw === "formulas" || raw === "loose" ? raw : "values";
|
|
839
|
-
}
|
|
840
|
-
function collectEntries(nodes) {
|
|
841
|
-
const entries = [];
|
|
842
|
-
let pending = null;
|
|
843
|
-
for (const node of nodes) {
|
|
844
|
-
if (node.type === "heading") {
|
|
845
|
-
pending = node;
|
|
846
|
-
continue;
|
|
847
|
-
}
|
|
848
|
-
if (node.type !== "table") continue;
|
|
849
|
-
const params = pending?.templateAnnotation?.params ?? {};
|
|
850
|
-
const sheetKey = typeof params.sheet === "string" && params.sheet !== "" ? params.sheet : null;
|
|
851
|
-
entries.push({
|
|
852
|
-
table: node,
|
|
853
|
-
headingText: pending ? extractPlainText(pending.children) : "",
|
|
854
|
-
params,
|
|
855
|
-
sheetKey,
|
|
856
|
-
role: readRole(params.role)
|
|
857
|
-
});
|
|
858
|
-
pending = null;
|
|
859
|
-
}
|
|
860
|
-
return entries;
|
|
861
|
-
}
|
|
862
|
-
function groupEntries(entries) {
|
|
863
|
-
const groups = [];
|
|
864
|
-
const bySheet = /* @__PURE__ */ new Map();
|
|
865
|
-
for (const entry of entries) {
|
|
866
|
-
if (entry.sheetKey !== null) {
|
|
867
|
-
let group = bySheet.get(entry.sheetKey);
|
|
868
|
-
if (!group) {
|
|
869
|
-
group = { candidate: entry.sheetKey, entries: [], anchored: true };
|
|
870
|
-
bySheet.set(entry.sheetKey, group);
|
|
871
|
-
groups.push(group);
|
|
872
|
-
}
|
|
873
|
-
group.entries.push(entry);
|
|
874
|
-
continue;
|
|
875
|
-
}
|
|
876
|
-
groups.push({ candidate: entry.headingText || null, entries: [entry], anchored: false });
|
|
877
|
-
}
|
|
878
|
-
return groups;
|
|
879
|
-
}
|
|
880
|
-
function place(cells, row, col, cell, clashes) {
|
|
881
|
-
const key = cellKey(row, col);
|
|
882
|
-
if (cells.has(key)) clashes.push(formatCellRef(row, col));
|
|
883
|
-
cells.set(key, cell);
|
|
884
|
-
}
|
|
885
|
-
function overlayFormula(cells, row, col, formula) {
|
|
886
|
-
const key = cellKey(row, col);
|
|
887
|
-
const existing = cells.get(key);
|
|
888
|
-
cells.set(key, { text: existing?.text ?? "", formula });
|
|
889
|
-
}
|
|
890
|
-
function formulaSource(raw) {
|
|
891
|
-
const trimmed = raw.trim();
|
|
892
|
-
return trimmed.startsWith("=") ? trimmed.slice(1) : trimmed;
|
|
893
|
-
}
|
|
894
|
-
function placeValues(entry, cells, warnings, sheetName, clashes) {
|
|
895
|
-
const grid = tableToGrid(entry.table);
|
|
896
|
-
const richGrid = tableToRichGrid(entry.table);
|
|
897
|
-
const anchorRaw = entry.params.anchor ?? "A1";
|
|
898
|
-
let anchor = parseCellRef(anchorRaw);
|
|
899
|
-
if (!anchor) {
|
|
900
|
-
warnings.push(
|
|
901
|
-
`Sheet "${sheetName}": anchor "${anchorRaw}" is not a valid cell reference; placed at A1 instead.`
|
|
902
|
-
);
|
|
903
|
-
anchor = { row: 0, col: 0 };
|
|
904
|
-
}
|
|
905
|
-
const height = grid.length;
|
|
906
|
-
const width = grid.reduce((m, r) => Math.max(m, r.length), 0);
|
|
907
|
-
if (anchor.row + height - 1 > MAX_ROW_INDEX || anchor.col + width - 1 > MAX_COL_INDEX) {
|
|
908
|
-
warnings.push(
|
|
909
|
-
`Sheet "${sheetName}": a table anchored at ${anchorRaw} runs past the end of the sheet; placed at A1 instead.`
|
|
910
|
-
);
|
|
911
|
-
anchor = { row: 0, col: 0 };
|
|
912
|
-
}
|
|
913
|
-
const titleRef = entry.params.titleAnchor;
|
|
914
|
-
if (titleRef !== void 0 && entry.headingText !== "") {
|
|
915
|
-
const at = parseCellRef(titleRef);
|
|
916
|
-
if (at) place(cells, at.row, at.col, { text: entry.headingText }, clashes);
|
|
917
|
-
}
|
|
918
|
-
for (let r = 0; r < grid.length; r++) {
|
|
919
|
-
const row = grid[r];
|
|
920
|
-
for (let c = 0; c < row.length; c++) {
|
|
921
|
-
const text = row[c];
|
|
922
|
-
if (text === "") continue;
|
|
923
|
-
const rich = richGrid[r]?.[c];
|
|
924
|
-
place(cells, anchor.row + r, anchor.col + c, rich ? { text, rich } : { text }, clashes);
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
function placeFormulas(entry, cells, warnings, sheetName) {
|
|
929
|
-
const grid = tableToGrid(entry.table);
|
|
930
|
-
if (grid.length < 2) return;
|
|
931
|
-
const anchorRaw = entry.params.anchor ?? "A1";
|
|
932
|
-
const anchor = parseCellRef(anchorRaw);
|
|
933
|
-
if (!anchor) {
|
|
934
|
-
warnings.push(
|
|
935
|
-
`Sheet "${sheetName}": formulas block anchor "${anchorRaw}" is not a valid cell reference; skipped.`
|
|
936
|
-
);
|
|
937
|
-
return;
|
|
938
|
-
}
|
|
939
|
-
const columns = grid[0].map((letters) => {
|
|
940
|
-
const trimmed = letters.trim();
|
|
941
|
-
if (!/^[A-Za-z]{1,3}$/.test(trimmed)) return -1;
|
|
942
|
-
const col = columnIndexFromLetters(trimmed);
|
|
943
|
-
return col >= 0 && col <= MAX_COL_INDEX ? col : -1;
|
|
944
|
-
});
|
|
945
|
-
for (let r = 1; r < grid.length; r++) {
|
|
946
|
-
const row = grid[r];
|
|
947
|
-
for (let c = 0; c < row.length; c++) {
|
|
948
|
-
const raw = row[c];
|
|
949
|
-
if (raw.trim() === "") continue;
|
|
950
|
-
const mapped = columns[c];
|
|
951
|
-
const col = mapped !== void 0 && mapped >= 0 ? mapped : anchor.col + c;
|
|
952
|
-
const targetRow = anchor.row + r - 1;
|
|
953
|
-
if (targetRow > MAX_ROW_INDEX) continue;
|
|
954
|
-
overlayFormula(cells, targetRow, col, formulaSource(raw));
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
function placeLoose(entry, cells, warnings, sheetName, clashes) {
|
|
959
|
-
const grid = tableToGrid(entry.table);
|
|
960
|
-
const richGrid = tableToRichGrid(entry.table);
|
|
961
|
-
let skipped = 0;
|
|
962
|
-
for (let r = 1; r < grid.length; r++) {
|
|
963
|
-
const row = grid[r];
|
|
964
|
-
const ref = (row[0] ?? "").trim();
|
|
965
|
-
if (ref === "") continue;
|
|
966
|
-
const at = parseCellRef(ref);
|
|
967
|
-
if (!at) {
|
|
968
|
-
skipped++;
|
|
969
|
-
continue;
|
|
970
|
-
}
|
|
971
|
-
const text = row[1] ?? "";
|
|
972
|
-
const formula = formulaSource(row[2] ?? "");
|
|
973
|
-
const rich = richGrid[r]?.[1];
|
|
974
|
-
const planned = { text };
|
|
975
|
-
if (formula !== "") planned.formula = formula;
|
|
976
|
-
if (rich) planned.rich = rich;
|
|
977
|
-
place(cells, at.row, at.col, planned, clashes);
|
|
978
|
-
}
|
|
979
|
-
if (skipped > 0) {
|
|
980
|
-
warnings.push(
|
|
981
|
-
`Sheet "${sheetName}": ${skipped} loose-cell row(s) had an invalid cell reference and were skipped.`
|
|
982
|
-
);
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
function planWorkbook(doc, options) {
|
|
986
|
-
const warnings = [];
|
|
987
|
-
const groups = groupEntries(collectEntries(doc.children));
|
|
988
|
-
const used = /* @__PURE__ */ new Set();
|
|
989
|
-
const sheets = [];
|
|
990
|
-
groups.forEach((group, index) => {
|
|
991
|
-
const fallback = `${options.sheetNamePrefix}${index + 1}`;
|
|
992
|
-
const name = options.sanitize(group.candidate ?? fallback, used, fallback);
|
|
993
|
-
const cells = /* @__PURE__ */ new Map();
|
|
994
|
-
const clashes = [];
|
|
995
|
-
for (const entry of group.entries) {
|
|
996
|
-
if (entry.role === "values") placeValues(entry, cells, warnings, name, clashes);
|
|
997
|
-
}
|
|
998
|
-
for (const entry of group.entries) {
|
|
999
|
-
if (entry.role === "formulas") placeFormulas(entry, cells, warnings, name);
|
|
1000
|
-
}
|
|
1001
|
-
for (const entry of group.entries) {
|
|
1002
|
-
if (entry.role === "loose") placeLoose(entry, cells, warnings, name, clashes);
|
|
1003
|
-
}
|
|
1004
|
-
if (clashes.length > 0) {
|
|
1005
|
-
const shown = clashes.slice(0, 5).join(", ");
|
|
1006
|
-
const rest = clashes.length > 5 ? ", and more" : "";
|
|
1007
|
-
warnings.push(
|
|
1008
|
-
`Sheet "${name}": ${clashes.length} overlapping cell(s) (${shown}${rest}); the later block won.`
|
|
1009
|
-
);
|
|
1010
|
-
}
|
|
1011
|
-
sheets.push({ name, cells, anchored: group.anchored });
|
|
1012
|
-
});
|
|
1013
|
-
let cellCount = 0;
|
|
1014
|
-
for (const sheet of sheets) cellCount += sheet.cells.size;
|
|
1015
|
-
return { sheets, warnings, cellCount };
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
// src/xlsx/export.ts
|
|
1019
|
-
var NUMERIC_RE = /^-?\d+(\.\d+)?$/;
|
|
1020
|
-
function isSafeNumericCell(value) {
|
|
1021
|
-
if (!NUMERIC_RE.test(value)) return false;
|
|
1022
|
-
const unsigned = value.startsWith("-") ? value.slice(1) : value;
|
|
1023
|
-
const [integer] = unsigned.split(".");
|
|
1024
|
-
if (integer.length > 1 && integer.startsWith("0")) return false;
|
|
1025
|
-
const significantDigits = unsigned.replace(".", "").replace(/^0+/, "");
|
|
1026
|
-
if (significantDigits.length > 15) return false;
|
|
1027
|
-
return Number.isFinite(Number(value));
|
|
1028
|
-
}
|
|
1029
|
-
function cleanSheetName(raw) {
|
|
1030
|
-
return raw.replace(/[[\]:*?/\\]/g, "").trim().slice(0, 31).trim().replace(/^'+|'+$/g, "");
|
|
1031
|
-
}
|
|
1032
|
-
function sanitizeSheetName(candidate, used, fallback) {
|
|
1033
|
-
let base = cleanSheetName(candidate) || cleanSheetName(fallback) || "Sheet";
|
|
1034
|
-
let name = base;
|
|
1035
|
-
let n = 2;
|
|
1036
|
-
while (used.has(name.toLocaleLowerCase("en-US"))) {
|
|
1037
|
-
const suffix = String(n++);
|
|
1038
|
-
base = base.slice(0, 31 - suffix.length);
|
|
1039
|
-
name = `${base}${suffix}`;
|
|
1040
|
-
}
|
|
1041
|
-
used.add(name.toLocaleLowerCase("en-US"));
|
|
1042
|
-
return name;
|
|
1043
|
-
}
|
|
1044
|
-
var ERROR_VALUE_RE = /^#[A-Z0-9_/]+[!?]?$/;
|
|
1045
|
-
function cellXml(cell, ref, inferNumericCells) {
|
|
1046
|
-
const { text, formula } = cell;
|
|
1047
|
-
if (formula !== void 0 && formula !== "") {
|
|
1048
|
-
const f = `<f>${escapeXml(formula)}</f>`;
|
|
1049
|
-
if (text === "") return `<c r="${ref}">${f}</c>`;
|
|
1050
|
-
if (isSafeNumericCell(text)) return `<c r="${ref}">${f}<v>${escapeXml(text)}</v></c>`;
|
|
1051
|
-
if (ERROR_VALUE_RE.test(text)) return `<c r="${ref}" t="e">${f}<v>${escapeXml(text)}</v></c>`;
|
|
1052
|
-
return `<c r="${ref}" t="str">${f}<v>${escapeXml(text)}</v></c>`;
|
|
1053
|
-
}
|
|
1054
|
-
if (inferNumericCells && isSafeNumericCell(text)) {
|
|
1055
|
-
return `<c r="${ref}"><v>${escapeXml(text)}</v></c>`;
|
|
1056
|
-
}
|
|
1057
|
-
if (cell.rich) {
|
|
1058
|
-
return `<c r="${ref}" t="inlineStr"><is>${richRunsXml(cell.rich)}</is></c>`;
|
|
1059
|
-
}
|
|
1060
|
-
return `<c r="${ref}" t="inlineStr"><is><t xml:space="preserve">${escapeXml(text)}</t></is></c>`;
|
|
1061
|
-
}
|
|
1062
|
-
function richRunsXml(nodes) {
|
|
1063
|
-
const runs = [];
|
|
1064
|
-
const emit = (text, vertAlign) => {
|
|
1065
|
-
if (text === "") return;
|
|
1066
|
-
const rPr = vertAlign ? `<rPr><vertAlign val="${vertAlign}"/></rPr>` : "";
|
|
1067
|
-
runs.push(`<r>${rPr}<t xml:space="preserve">${escapeXml(text)}</t></r>`);
|
|
1024
|
+
var XLSX_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
1025
|
+
async function xlsxToContainer(data, options = {}) {
|
|
1026
|
+
const plan = planDataSidecar(options.sourceName, "workbook.xlsx");
|
|
1027
|
+
const mode = options.sidecar ?? "auto";
|
|
1028
|
+
const spill = mode === "never" ? void 0 : {
|
|
1029
|
+
src: plan.sidecarPath,
|
|
1030
|
+
fileName: plan.fileName,
|
|
1031
|
+
mode,
|
|
1032
|
+
maxInlineRows: options.maxInlineRows ?? 100,
|
|
1033
|
+
maxInlineCells: options.maxInlineCells ?? 2e3,
|
|
1034
|
+
used: false
|
|
1068
1035
|
};
|
|
1069
|
-
const
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
} else {
|
|
1076
|
-
emit(inlineToPlainText(node), vertAlign);
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
};
|
|
1080
|
-
walk(nodes, null);
|
|
1081
|
-
return runs.join("");
|
|
1082
|
-
}
|
|
1083
|
-
function worksheetXml(sheet, inferNumericCells) {
|
|
1084
|
-
const keys = [...sheet.cells.keys()].sort((a, b) => a - b);
|
|
1085
|
-
const rows = [];
|
|
1086
|
-
let maxRow = 0;
|
|
1087
|
-
let maxCol = 0;
|
|
1088
|
-
let i = 0;
|
|
1089
|
-
while (i < keys.length) {
|
|
1090
|
-
const rowIdx = keyRow(keys[i]);
|
|
1091
|
-
let cellsXml = "";
|
|
1092
|
-
while (i < keys.length && keyRow(keys[i]) === rowIdx) {
|
|
1093
|
-
const key = keys[i];
|
|
1094
|
-
const col = keyCol(key);
|
|
1095
|
-
if (col > maxCol) maxCol = col;
|
|
1096
|
-
cellsXml += cellXml(
|
|
1097
|
-
sheet.cells.get(key),
|
|
1098
|
-
`${columnLetter(col)}${rowIdx + 1}`,
|
|
1099
|
-
inferNumericCells
|
|
1100
|
-
);
|
|
1101
|
-
i++;
|
|
1102
|
-
}
|
|
1103
|
-
if (rowIdx > maxRow) maxRow = rowIdx;
|
|
1104
|
-
rows.push(`<row r="${rowIdx + 1}">${cellsXml}</row>`);
|
|
1036
|
+
const markdownDoc = await workbookToMarkdown(data, options, spill);
|
|
1037
|
+
const container = new MemoryContentContainer();
|
|
1038
|
+
await container.writeDocument(stringifyMarkdown(markdownDoc), plan.markdownFilename);
|
|
1039
|
+
if (spill?.used) {
|
|
1040
|
+
const bytes = data instanceof Blob ? await data.arrayBuffer() : data;
|
|
1041
|
+
await container.writeFile(plan.sidecarPath, bytes, XLSX_MIME);
|
|
1105
1042
|
}
|
|
1106
|
-
|
|
1107
|
-
return `${xmlDeclaration()}
|
|
1108
|
-
<worksheet xmlns="${NS_SML}" xmlns:r="${NS_R}"><dimension ref="${dimension}"/><sheetData>${rows.join("")}</sheetData></worksheet>`;
|
|
1109
|
-
}
|
|
1110
|
-
function workbookXml(sheets, hasFormulas) {
|
|
1111
|
-
const sheetEls = sheets.map(
|
|
1112
|
-
(sheet, i) => `<sheet name="${escapeXml(sheet.name)}" sheetId="${i + 1}" r:id="rId${i + 1}"/>`
|
|
1113
|
-
).join("");
|
|
1114
|
-
const calcPr = hasFormulas ? `<calcPr calcId="0" fullCalcOnLoad="1"/>` : "";
|
|
1115
|
-
return `${xmlDeclaration()}
|
|
1116
|
-
<workbook xmlns="${NS_SML}" xmlns:r="${NS_R}"><sheets>${sheetEls}</sheets>${calcPr}</workbook>`;
|
|
1117
|
-
}
|
|
1118
|
-
function stylesXml() {
|
|
1119
|
-
return `${xmlDeclaration()}
|
|
1120
|
-
<styleSheet xmlns="${NS_SML}"><fonts count="1"><font><sz val="11"/><name val="Calibri"/></font></fonts><fills count="1"><fill><patternFill patternType="none"/></fill></fills><borders count="1"><border/></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/></cellXfs></styleSheet>`;
|
|
1121
|
-
}
|
|
1122
|
-
async function markdownDocToXlsx(doc, options = {}) {
|
|
1123
|
-
options.signal?.throwIfAborted();
|
|
1124
|
-
const prefix = cleanSheetName(options.sheetNamePrefix ?? "Sheet") || "Sheet";
|
|
1125
|
-
const maxCells = options.maxCells ?? 1e5;
|
|
1126
|
-
if (!Number.isSafeInteger(maxCells) || maxCells < 0) {
|
|
1127
|
-
throw new RangeError("maxCells must be a non-negative safe integer");
|
|
1128
|
-
}
|
|
1129
|
-
const plan = planWorkbook(doc, { sheetNamePrefix: prefix, sanitize: sanitizeSheetName });
|
|
1130
|
-
for (const warning of plan.warnings) options.onWarning?.(warning);
|
|
1131
|
-
if (plan.cellCount > maxCells) {
|
|
1132
|
-
throw new RangeError(`XLSX export exceeds the ${maxCells}-cell safety limit`);
|
|
1133
|
-
}
|
|
1134
|
-
let sheets = plan.sheets;
|
|
1135
|
-
if (sheets.length === 0) {
|
|
1136
|
-
sheets = [
|
|
1137
|
-
{
|
|
1138
|
-
name: sanitizeSheetName(`${prefix}1`, /* @__PURE__ */ new Set(), "Sheet1"),
|
|
1139
|
-
cells: /* @__PURE__ */ new Map(),
|
|
1140
|
-
anchored: false
|
|
1141
|
-
}
|
|
1142
|
-
];
|
|
1143
|
-
}
|
|
1144
|
-
const anchored = sheets.some((sheet) => sheet.anchored);
|
|
1145
|
-
const inferNumericCells = options.inferNumericCells ?? anchored;
|
|
1146
|
-
const hasFormulas = sheets.some((sheet) => {
|
|
1147
|
-
for (const cell of sheet.cells.values()) if (cell.formula) return true;
|
|
1148
|
-
return false;
|
|
1149
|
-
});
|
|
1150
|
-
const pkg = createPackage();
|
|
1151
|
-
sheets.forEach((sheet, i) => {
|
|
1152
|
-
if ((i & 31) === 0) options.signal?.throwIfAborted();
|
|
1153
|
-
const sheetPath = `xl/worksheets/sheet${i + 1}.xml`;
|
|
1154
|
-
pkg.addPart(sheetPath, worksheetXml(sheet, inferNumericCells), CONTENT_TYPE_XLSX_WORKSHEET);
|
|
1155
|
-
pkg.addRelationship("xl/workbook.xml", {
|
|
1156
|
-
id: `rId${i + 1}`,
|
|
1157
|
-
type: REL_WORKSHEET,
|
|
1158
|
-
target: `worksheets/sheet${i + 1}.xml`
|
|
1159
|
-
});
|
|
1160
|
-
});
|
|
1161
|
-
pkg.addPart("xl/styles.xml", stylesXml(), CONTENT_TYPE_XLSX_STYLES);
|
|
1162
|
-
pkg.addRelationship("xl/workbook.xml", {
|
|
1163
|
-
id: `rId${sheets.length + 1}`,
|
|
1164
|
-
type: REL_STYLES,
|
|
1165
|
-
target: "styles.xml"
|
|
1166
|
-
});
|
|
1167
|
-
pkg.addPart("xl/workbook.xml", workbookXml(sheets, hasFormulas), CONTENT_TYPE_XLSX_WORKBOOK);
|
|
1168
|
-
pkg.addRelationship("", {
|
|
1169
|
-
id: "rId1",
|
|
1170
|
-
type: REL_OFFICE_DOCUMENT,
|
|
1171
|
-
target: "xl/workbook.xml"
|
|
1172
|
-
});
|
|
1173
|
-
if (options.title || options.author) {
|
|
1174
|
-
pkg.setCoreProperties({
|
|
1175
|
-
title: options.title,
|
|
1176
|
-
creator: options.author,
|
|
1177
|
-
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1178
|
-
modified: (/* @__PURE__ */ new Date()).toISOString()
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
return pkg.toArrayBuffer();
|
|
1182
|
-
}
|
|
1183
|
-
async function docToXlsx(doc, options) {
|
|
1184
|
-
return markdownDocToXlsx(docToMarkdown(doc), options);
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
// src/xlsx/index.ts
|
|
1188
|
-
async function xlsxToDoc(data, options) {
|
|
1189
|
-
return markdownToDoc(await xlsxToMarkdownDoc(data, options));
|
|
1043
|
+
return container;
|
|
1190
1044
|
}
|
|
1191
1045
|
|
|
1192
1046
|
export {
|
|
1047
|
+
MAX_COL_INDEX,
|
|
1048
|
+
MAX_ROW_INDEX,
|
|
1049
|
+
columnLetter,
|
|
1050
|
+
columnIndexFromLetters,
|
|
1051
|
+
colIndex,
|
|
1052
|
+
parseCellRef,
|
|
1053
|
+
formatCellRef,
|
|
1054
|
+
columnLetter2,
|
|
1055
|
+
gridToTables,
|
|
1056
|
+
listSheetParts,
|
|
1057
|
+
readCellStyles,
|
|
1058
|
+
numberFormatKind,
|
|
1059
|
+
xlsxToTables,
|
|
1060
|
+
xlsxToCellGrids,
|
|
1193
1061
|
xlsxToMarkdownDoc,
|
|
1194
|
-
|
|
1195
|
-
docToXlsx,
|
|
1196
|
-
xlsxToDoc
|
|
1062
|
+
xlsxToContainer
|
|
1197
1063
|
};
|