@bendyline/squisq-formats 2.5.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +1 -1
- package/dist/{chunk-A6LSCIO5.js → chunk-RX55T5HO.js} +150 -5
- package/dist/{chunk-5PUIFU5I.js → chunk-TVUX3RUC.js} +1 -1
- package/dist/export-Boq78GMq.d.ts +270 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +9 -5
- package/dist/outside-in/index.d.ts +2 -2
- package/dist/outside-in/index.js +2 -2
- package/dist/registry/index.d.ts +3 -3
- package/dist/registry/index.js +1 -1
- package/dist/{types-DByrrXeB.d.ts → types-bwP9PBSk.d.ts} +1 -1
- package/dist/xlsx/index.d.ts +2 -2
- package/dist/xlsx/index.js +7 -3
- package/package.json +2 -2
- package/dist/export-m0tr9r9d.d.ts +0 -130
- /package/dist/{chunk-JTGWQK5V.js → chunk-5JQ5NDRC.js} +0 -0
package/NOTICE.md
CHANGED
|
@@ -10,7 +10,7 @@ Third-party components remain under their respective license terms.
|
|
|
10
10
|
| ---------------- | ------- | ----------------------- | ---------------------------------- |
|
|
11
11
|
| @pdf-lib/fontkit | 1.1.1 | MIT | https://github.com/Hopding/fontkit |
|
|
12
12
|
| @pdf-lib/upng | 1.0.1 | MIT | https://github.com/Hopding/upng |
|
|
13
|
-
| @xmldom/xmldom | 0.9.
|
|
13
|
+
| @xmldom/xmldom | 0.9.12 | MIT | https://github.com/xmldom/xmldom |
|
|
14
14
|
| jszip | 3.10.1 | MIT OR GPL-3.0-or-later | https://github.com/Stuk/jszip |
|
|
15
15
|
| pdf-lib | 1.17.1 | MIT | https://pdf-lib.js.org |
|
|
16
16
|
| pdfjs-dist | 4.10.38 | Apache-2.0 | https://mozilla.github.io/pdf.js |
|
|
@@ -387,6 +387,113 @@ function peelCaptionRow(grid, rect) {
|
|
|
387
387
|
return { caption, rect: { ...rect, top: rect.top + 1 } };
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
+
// src/xlsx/tables.ts
|
|
391
|
+
function columnLetter2(index) {
|
|
392
|
+
let n = index;
|
|
393
|
+
let out = "";
|
|
394
|
+
do {
|
|
395
|
+
out = String.fromCharCode(65 + n % 26) + out;
|
|
396
|
+
n = Math.floor(n / 26) - 1;
|
|
397
|
+
} while (n >= 0);
|
|
398
|
+
return out;
|
|
399
|
+
}
|
|
400
|
+
function a1(row, col) {
|
|
401
|
+
return `${columnLetter2(col)}${row + 1}`;
|
|
402
|
+
}
|
|
403
|
+
function regionHasHeader(cells) {
|
|
404
|
+
if (cells.length < 2) return false;
|
|
405
|
+
const first = cells[0];
|
|
406
|
+
if (!first || first.length === 0) return false;
|
|
407
|
+
return first.every((cell) => cell.kind === "string");
|
|
408
|
+
}
|
|
409
|
+
function cellValue(cell) {
|
|
410
|
+
if (cell.kind === "empty" || cell.kind === "error") return null;
|
|
411
|
+
if (cell.value !== void 0) return cell.value;
|
|
412
|
+
return cell.text === "" ? null : cell.text;
|
|
413
|
+
}
|
|
414
|
+
function dominantKind(kinds) {
|
|
415
|
+
const counts = /* @__PURE__ */ new Map();
|
|
416
|
+
let total = 0;
|
|
417
|
+
for (const kind of kinds) {
|
|
418
|
+
if (kind === "empty") continue;
|
|
419
|
+
counts.set(kind, (counts.get(kind) ?? 0) + 1);
|
|
420
|
+
total += 1;
|
|
421
|
+
}
|
|
422
|
+
if (total === 0) return "empty";
|
|
423
|
+
let best = "string";
|
|
424
|
+
let bestCount = 0;
|
|
425
|
+
for (const [kind, count] of counts) {
|
|
426
|
+
if (count > bestCount) {
|
|
427
|
+
best = kind;
|
|
428
|
+
bestCount = count;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return bestCount * 2 > total ? best : "mixed";
|
|
432
|
+
}
|
|
433
|
+
function sliceRegion(grid, rect) {
|
|
434
|
+
const out = [];
|
|
435
|
+
for (let r = rect.top; r <= rect.bottom; r++) {
|
|
436
|
+
const row = [];
|
|
437
|
+
for (let c = rect.left; c <= rect.right; c++) {
|
|
438
|
+
row.push(grid[r]?.[c] ?? { text: "", kind: "empty" });
|
|
439
|
+
}
|
|
440
|
+
out.push(row);
|
|
441
|
+
}
|
|
442
|
+
return out;
|
|
443
|
+
}
|
|
444
|
+
function regionToTable(sheet, grid, rect, title, minRows) {
|
|
445
|
+
const cells = sliceRegion(grid, rect);
|
|
446
|
+
if (cells.length === 0) return null;
|
|
447
|
+
const hasHeader = regionHasHeader(cells);
|
|
448
|
+
const body = hasHeader ? cells.slice(1) : cells;
|
|
449
|
+
if (body.length < minRows) return null;
|
|
450
|
+
if (!body.some((row) => row.some(isOccupied))) return null;
|
|
451
|
+
const width = cells.reduce((max, row) => Math.max(max, row.length), 0);
|
|
452
|
+
const columns = [];
|
|
453
|
+
for (let c = 0; c < width; c++) {
|
|
454
|
+
const header = hasHeader ? cells[0]?.[c]?.text ?? "" : "";
|
|
455
|
+
columns.push({
|
|
456
|
+
name: header.trim() || columnLetter2(rect.left + c),
|
|
457
|
+
kind: dominantKind(body.map((row) => row[c]?.kind ?? "empty"))
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
sheet,
|
|
462
|
+
anchor: a1(rect.top, rect.left),
|
|
463
|
+
...title ? { title } : {},
|
|
464
|
+
columns,
|
|
465
|
+
hasHeader,
|
|
466
|
+
rows: body.map(
|
|
467
|
+
(row) => Array.from({ length: width }, (_, c) => cellValue(row[c] ?? { text: "", kind: "empty" }))
|
|
468
|
+
)
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
function gridToTables(sheet, grid, merges = [], options = {}) {
|
|
472
|
+
if (grid.length === 0) return [];
|
|
473
|
+
const minRows = options.minRows ?? 1;
|
|
474
|
+
const plan = detectRegions(grid, merges, {
|
|
475
|
+
...options.maxRegionsPerSheet !== void 0 ? { maxRegionsPerSheet: options.maxRegionsPerSheet } : {},
|
|
476
|
+
...options.minRegionCells !== void 0 ? { minRegionCells: options.minRegionCells } : {},
|
|
477
|
+
...options.signal ? { signal: options.signal } : {}
|
|
478
|
+
});
|
|
479
|
+
if (plan.degraded || plan.regions.length === 0) {
|
|
480
|
+
const rect = {
|
|
481
|
+
top: 0,
|
|
482
|
+
left: 0,
|
|
483
|
+
bottom: grid.length - 1,
|
|
484
|
+
right: grid.reduce((max, row) => Math.max(max, row.length), 1) - 1
|
|
485
|
+
};
|
|
486
|
+
const whole = regionToTable(sheet, grid, rect, void 0, minRows);
|
|
487
|
+
return whole ? [whole] : [];
|
|
488
|
+
}
|
|
489
|
+
const out = [];
|
|
490
|
+
for (const region of plan.regions) {
|
|
491
|
+
const table = regionToTable(sheet, grid, region.rect, region.title, minRows);
|
|
492
|
+
if (table) out.push(table);
|
|
493
|
+
}
|
|
494
|
+
return out;
|
|
495
|
+
}
|
|
496
|
+
|
|
390
497
|
// src/xlsx/import.ts
|
|
391
498
|
var XLSX_MAIN_PART = "xl/workbook.xml";
|
|
392
499
|
function attrNS(el, ns, local, fallback) {
|
|
@@ -553,6 +660,16 @@ function excelTimeText(serial, includeSeconds, elapsedHours) {
|
|
|
553
660
|
const seconds = totalSeconds % 60;
|
|
554
661
|
return `${twoDigits(hours)}:${twoDigits(minutes)}${includeSeconds ? `:${twoDigits(seconds)}` : ""}`;
|
|
555
662
|
}
|
|
663
|
+
function dateValueText(serial, kind, style, date1904) {
|
|
664
|
+
if (!Number.isFinite(serial)) return null;
|
|
665
|
+
const normalized = style ? normalizeFormatCode(style.formatCode) : "";
|
|
666
|
+
if (kind === "time")
|
|
667
|
+
return excelTimeText(serial, /s/.test(normalized), /\[[h]+\]/.test(normalized));
|
|
668
|
+
const date = excelDateText(serial, date1904);
|
|
669
|
+
if (!date) return null;
|
|
670
|
+
if (kind === "datetime") return `${date} ${excelTimeText(serial, /s/.test(normalized), false)}`;
|
|
671
|
+
return date;
|
|
672
|
+
}
|
|
556
673
|
function formattedNumberText(raw, style, date1904) {
|
|
557
674
|
if (!style) return raw;
|
|
558
675
|
const value = Number(raw);
|
|
@@ -600,13 +717,14 @@ function readFormula(cell, row, col, ctx) {
|
|
|
600
717
|
}
|
|
601
718
|
function readCell(cell, row, col, ctx) {
|
|
602
719
|
const formula = readFormula(cell, row, col, ctx);
|
|
603
|
-
const withFormula = (text2, kind2) => {
|
|
720
|
+
const withFormula = (text2, kind2, value) => {
|
|
604
721
|
const out = { text: text2, kind: text2 === "" ? "empty" : kind2 };
|
|
605
722
|
if (formula !== "") out.formula = formula;
|
|
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,6 +846,26 @@ 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
|
+
}
|
|
726
869
|
async function xlsxToMarkdownDoc(data, options = {}) {
|
|
727
870
|
const pkg = await openPackage(data, options);
|
|
728
871
|
const mainPart = requireMainPartPath(pkg, XLSX_MAIN_PART, "XLSX");
|
|
@@ -1190,6 +1333,8 @@ async function xlsxToDoc(data, options) {
|
|
|
1190
1333
|
}
|
|
1191
1334
|
|
|
1192
1335
|
export {
|
|
1336
|
+
gridToTables,
|
|
1337
|
+
xlsxToTables,
|
|
1193
1338
|
xlsxToMarkdownDoc,
|
|
1194
1339
|
markdownDocToXlsx,
|
|
1195
1340
|
docToXlsx,
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { MarkdownInlineNode, MarkdownDocument } from '@bendyline/squisq/markdown';
|
|
2
|
+
import { O as OoxmlOpenOptions } from './reader-B_m1aKZC.js';
|
|
3
|
+
import { Doc } from '@bendyline/squisq/schemas';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Shared SpreadsheetML cell model and A1-reference arithmetic.
|
|
7
|
+
*
|
|
8
|
+
* Import and export both need to move between a zero-based `(row, col)` grid
|
|
9
|
+
* and Excel's `"B7"` addressing. That logic used to exist twice — `colIndex`
|
|
10
|
+
* in `import.ts` and `columnLetter` in `export.ts` — as two halves of the same
|
|
11
|
+
* bijection that never met. It lives here now, together with the richer cell
|
|
12
|
+
* record the region splitter needs.
|
|
13
|
+
*
|
|
14
|
+
* {@link XlsxCell} carries three things the old plain-string grid could not:
|
|
15
|
+
* the cell's *kind* (so a header row can be told apart from a data row, and so
|
|
16
|
+
* export can safely re-emit a number as a number), and its *formula* (so a
|
|
17
|
+
* round trip through markdown keeps `=B2*C2` rather than freezing the cached
|
|
18
|
+
* result).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** What a cell holds, beyond its display text. */
|
|
22
|
+
type XlsxCellKind = 'empty' | 'string' | 'number' | 'bool' | 'date' | 'error';
|
|
23
|
+
/** A single worksheet cell. */
|
|
24
|
+
interface XlsxCell {
|
|
25
|
+
/** Display text — the plain string, with all run formatting flattened out. */
|
|
26
|
+
text: string;
|
|
27
|
+
/** What the cell holds. `empty` iff `text` is `''`. */
|
|
28
|
+
kind: XlsxCellKind;
|
|
29
|
+
/** Formula source WITHOUT the leading `=`, when the cell carries one. */
|
|
30
|
+
formula?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Inline markdown for a cell whose rich text carries formatting worth
|
|
33
|
+
* keeping — today, superscript/subscript runs (`Fresh<sup>1</sup>`).
|
|
34
|
+
*
|
|
35
|
+
* Deliberately additive: `text` remains the flattened string, so region
|
|
36
|
+
* detection, header sniffing, numeric inference and export placement all
|
|
37
|
+
* keep working on exactly the value they saw before. Only the markdown table
|
|
38
|
+
* cell reads this, and only when it is present.
|
|
39
|
+
*/
|
|
40
|
+
richText?: MarkdownInlineNode[];
|
|
41
|
+
/**
|
|
42
|
+
* The cell's value as the sheet stores it, before number formatting.
|
|
43
|
+
*
|
|
44
|
+
* `text` is a rendering for people, and rendering destroys information a
|
|
45
|
+
* consumer doing arithmetic needs: a percent-formatted `0.15` renders as
|
|
46
|
+
* `"15.0%"`, a date is a serial rendered as text, and a zero-padded `7`
|
|
47
|
+
* renders as `"007"`. Anything reading a sheet as *data* — rather than as a
|
|
48
|
+
* document — must read this instead.
|
|
49
|
+
*
|
|
50
|
+
* Normalized rather than literally raw, where a literal value would be
|
|
51
|
+
* useless: a date arrives as an ISO `YYYY-MM-DD` (or `YYYY-MM-DD HH:MM`)
|
|
52
|
+
* string rather than an Excel serial, because the serial's meaning depends
|
|
53
|
+
* on a workbook-level 1900/1904 epoch flag that no downstream consumer
|
|
54
|
+
* should have to carry. Numbers, booleans and strings are exact.
|
|
55
|
+
*
|
|
56
|
+
* Absent for `empty` and `error` cells, which have no value to speak of.
|
|
57
|
+
*/
|
|
58
|
+
value?: number | boolean | string;
|
|
59
|
+
}
|
|
60
|
+
/** A zero-based, inclusive rectangle of cells. */
|
|
61
|
+
interface CellRect {
|
|
62
|
+
top: number;
|
|
63
|
+
left: number;
|
|
64
|
+
bottom: number;
|
|
65
|
+
right: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* XLSX → typed tables, for consumers reading a workbook as **data**.
|
|
70
|
+
*
|
|
71
|
+
* `xlsxToMarkdownDoc` renders a workbook for people: it flattens each cell to
|
|
72
|
+
* the string the sheet displays. That rendering is lossy in exactly the ways
|
|
73
|
+
* arithmetic cares about — a percent-formatted `0.15` becomes `"15.0%"`, a
|
|
74
|
+
* date becomes text, a zero-padded `7` becomes `"007"` — so anything that
|
|
75
|
+
* needs to sum, average or compare must not go through it.
|
|
76
|
+
*
|
|
77
|
+
* This module is the other path. It reuses the same region detection (a sheet
|
|
78
|
+
* is not one table; it is several islands with labels and totals in the gaps)
|
|
79
|
+
* and emits each island's cells as their underlying values, with the type the
|
|
80
|
+
* sheet gave them.
|
|
81
|
+
*
|
|
82
|
+
* Two kinds of region are deliberately excluded from the result. A
|
|
83
|
+
* `formulas` companion is presentation — the same cells again, showing their
|
|
84
|
+
* expressions rather than their results — and a `loose` bucket is stray labels
|
|
85
|
+
* and notes, which have no columns to speak of. Both are useful to a reader
|
|
86
|
+
* and meaningless to a query, so a consumer asking for tables gets neither.
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
/** One column of a detected table. */
|
|
90
|
+
interface XlsxTableColumn {
|
|
91
|
+
/** Header text when the region has a header row; otherwise a column letter. */
|
|
92
|
+
name: string;
|
|
93
|
+
/**
|
|
94
|
+
* The dominant cell kind in the column's body, so a consumer can pick a
|
|
95
|
+
* storage type without re-sniffing. `mixed` when no single kind holds a
|
|
96
|
+
* majority — the honest answer for a column that really is heterogeneous.
|
|
97
|
+
*/
|
|
98
|
+
kind: XlsxCellKind | 'mixed';
|
|
99
|
+
}
|
|
100
|
+
/** One data island, as values rather than as display text. */
|
|
101
|
+
interface XlsxTable {
|
|
102
|
+
/** Worksheet name. */
|
|
103
|
+
sheet: string;
|
|
104
|
+
/** A1 address of the region's top-left cell, e.g. `B4`. */
|
|
105
|
+
anchor: string;
|
|
106
|
+
/** Caption absorbed from directly above the region, when there was one. */
|
|
107
|
+
title?: string;
|
|
108
|
+
columns: XlsxTableColumn[];
|
|
109
|
+
/** True when row 0 was read as a header and is therefore not a data row. */
|
|
110
|
+
hasHeader: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Body rows, header excluded. A cell with no value — blank, or an error —
|
|
113
|
+
* is `null` rather than absent, so every row has the same arity as
|
|
114
|
+
* `columns`.
|
|
115
|
+
*/
|
|
116
|
+
rows: (string | number | boolean | null)[][];
|
|
117
|
+
}
|
|
118
|
+
interface XlsxTablesOptions {
|
|
119
|
+
/** Restrict to one sheet, by zero-based index or by name. */
|
|
120
|
+
sheet?: number | string;
|
|
121
|
+
maxRegionsPerSheet?: number;
|
|
122
|
+
minRegionCells?: number;
|
|
123
|
+
/** Skip regions with fewer than this many body rows. Default 1. */
|
|
124
|
+
minRows?: number;
|
|
125
|
+
signal?: AbortSignal;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Split one sheet's grid into typed tables.
|
|
129
|
+
*
|
|
130
|
+
* Exported separately from the workbook entry point so a caller that already
|
|
131
|
+
* has a grid — a test, or a consumer streaming sheets itself — does not have
|
|
132
|
+
* to re-open the package.
|
|
133
|
+
*/
|
|
134
|
+
declare function gridToTables(sheet: string, grid: readonly (readonly XlsxCell[])[], merges?: readonly CellRect[], options?: XlsxTablesOptions): XlsxTable[];
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* XLSX import — SpreadsheetML (.xlsx) → MarkdownDocument.
|
|
138
|
+
*
|
|
139
|
+
* Reuses the shared ooxml/ reader (zip + DOMParser). Reads the workbook's sheet
|
|
140
|
+
* list, resolves each sheet part via relationships, pulls shared strings, and
|
|
141
|
+
* turns each worksheet into markdown. By default every sheet is imported, each
|
|
142
|
+
* preceded by an H1 of the sheet name; pass `options.sheet` (index or name) to
|
|
143
|
+
* import just one.
|
|
144
|
+
*
|
|
145
|
+
* A sheet is NOT one table. It is usually several tables scattered across the
|
|
146
|
+
* grid with stray labels and notes in the gaps, so by default each worksheet is
|
|
147
|
+
* split into its contiguous data islands (see `regions.ts`) and every island
|
|
148
|
+
* becomes its own block:
|
|
149
|
+
*
|
|
150
|
+
* ```markdown
|
|
151
|
+
* ## Q3 Revenue {[dataTable sheet=Sales anchor=B7]}
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* The `sheet`/`anchor` params on the heading annotation are what let
|
|
155
|
+
* `markdownDocToXlsx` put each table back where it came from, so the round trip
|
|
156
|
+
* reproduces addresses rather than piling everything at A1. A region holding
|
|
157
|
+
* formulas additionally emits a `role=formulas` companion table, and every
|
|
158
|
+
* left-over single cell on a sheet collects into one `role=loose` table.
|
|
159
|
+
*
|
|
160
|
+
* Pass `{ regions: false }` for the historical behavior: one table per sheet,
|
|
161
|
+
* spanning the whole used range.
|
|
162
|
+
*/
|
|
163
|
+
|
|
164
|
+
interface XlsxImportOptions extends OoxmlOpenOptions {
|
|
165
|
+
/** Which sheet to import (0-based index or sheet name). Default: all sheets. */
|
|
166
|
+
sheet?: number | string;
|
|
167
|
+
/**
|
|
168
|
+
* Split each sheet into its contiguous data islands, one block each, anchored
|
|
169
|
+
* with `{[dataTable sheet=… anchor=…]}`. Default true. Set false for the
|
|
170
|
+
* historical one-table-per-sheet output.
|
|
171
|
+
*/
|
|
172
|
+
regions?: boolean;
|
|
173
|
+
/**
|
|
174
|
+
* Emit a `role=formulas` companion table for regions that contain formulas.
|
|
175
|
+
* Default true. Ignored when `regions` is false.
|
|
176
|
+
*/
|
|
177
|
+
formulas?: boolean;
|
|
178
|
+
/** Cap on region tables per sheet before the rest fold into loose cells. Default 64. */
|
|
179
|
+
maxRegionsPerSheet?: number;
|
|
180
|
+
/** Smallest island that stays a table of its own. Default 2 — single cells coalesce. */
|
|
181
|
+
minRegionCells?: number;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Read a workbook as typed tables rather than as a document.
|
|
185
|
+
*
|
|
186
|
+
* The data counterpart to {@link xlsxToMarkdownDoc}: same package, same sheet
|
|
187
|
+
* selection, same region detection — but each island's cells arrive as their
|
|
188
|
+
* underlying values, so a consumer can sum a column without first undoing a
|
|
189
|
+
* number format.
|
|
190
|
+
*/
|
|
191
|
+
declare function xlsxToTables(data: ArrayBuffer | Blob, options?: XlsxImportOptions & XlsxTablesOptions): Promise<XlsxTable[]>;
|
|
192
|
+
declare function xlsxToMarkdownDoc(data: ArrayBuffer | Blob, options?: XlsxImportOptions): Promise<MarkdownDocument>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* XLSX export — MarkdownDocument → SpreadsheetML (.xlsx).
|
|
196
|
+
*
|
|
197
|
+
* Tables-only fidelity (honestly documented): every `table` node in the
|
|
198
|
+
* markdown AST becomes worksheet cells; all other content (prose, lists,
|
|
199
|
+
* images, …) is dropped, and headings survive only as sheet names and as the
|
|
200
|
+
* carrier of placement metadata.
|
|
201
|
+
*
|
|
202
|
+
* Placement has two modes, decided per table by `workbookPlan.ts`. A table
|
|
203
|
+
* whose heading carries `{[dataTable sheet=… anchor=…]}` — what
|
|
204
|
+
* `xlsxToMarkdownDoc` emits for every data island it finds — is placed on the
|
|
205
|
+
* named sheet at the named cell, so several mini tables share one worksheet at
|
|
206
|
+
* their original addresses and formulas ride along. A table with no such
|
|
207
|
+
* annotation keeps the historical behavior exactly: its own worksheet, named
|
|
208
|
+
* from the nearest preceding heading, starting at A1.
|
|
209
|
+
*
|
|
210
|
+
* Cells are emitted as inline strings (`t="inlineStr"`) by default so no
|
|
211
|
+
* sharedStrings part is needed and identifier-like numbers remain lossless.
|
|
212
|
+
* Callers can explicitly opt into conservative numeric inference. The package
|
|
213
|
+
* is assembled with the shared ooxml/ writer (auto-generates
|
|
214
|
+
* `[Content_Types].xml` + `_rels`), so only the SpreadsheetML-specific parts
|
|
215
|
+
* (workbook, worksheets, styles) are written here.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* import { parseMarkdown } from '@bendyline/squisq/markdown';
|
|
220
|
+
* import { markdownDocToXlsx } from '@bendyline/squisq-formats/xlsx';
|
|
221
|
+
*
|
|
222
|
+
* const md = parseMarkdown('# Metrics\n\n| A | B |\n| - | - |\n| 1 | 2 |');
|
|
223
|
+
* const buffer = await markdownDocToXlsx(md);
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Options for XLSX export.
|
|
229
|
+
*/
|
|
230
|
+
interface XlsxExportOptions {
|
|
231
|
+
/** Cancel at bounded export checkpoints. */
|
|
232
|
+
signal?: AbortSignal;
|
|
233
|
+
/** Maximum cells emitted. Default: 100,000. */
|
|
234
|
+
maxCells?: number;
|
|
235
|
+
/** Workbook title (written to core properties). */
|
|
236
|
+
title?: string;
|
|
237
|
+
/** Workbook author (written to core properties). */
|
|
238
|
+
author?: string;
|
|
239
|
+
/** Prefix used for auto-named sheets when no heading precedes a table. Default: "Sheet". */
|
|
240
|
+
sheetNamePrefix?: string;
|
|
241
|
+
/**
|
|
242
|
+
* Emit canonical, Excel-safe number strings as numeric cells.
|
|
243
|
+
*
|
|
244
|
+
* Defaults to false for hand-authored documents — markdown tables have no
|
|
245
|
+
* column schema, so preserving authored text is the only lossless choice —
|
|
246
|
+
* and to true when the document carries `sheet=` anchors, which only an XLSX
|
|
247
|
+
* import produces. Leading-zero and >15-significant-digit values remain
|
|
248
|
+
* strings either way. Set explicitly to override both defaults.
|
|
249
|
+
*/
|
|
250
|
+
inferNumericCells?: boolean;
|
|
251
|
+
/**
|
|
252
|
+
* Called for each non-fatal placement problem (a malformed anchor, an
|
|
253
|
+
* overlapping region, an unusable loose-cell reference). Export never throws
|
|
254
|
+
* for these — a hand-edited markdown file must still convert.
|
|
255
|
+
*/
|
|
256
|
+
onWarning?: (message: string) => void;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Convert a MarkdownDocument to a .xlsx file (tables-only fidelity).
|
|
260
|
+
*
|
|
261
|
+
* Each markdown `table` becomes one worksheet; a document with no tables
|
|
262
|
+
* yields a single empty sheet (a valid, openable file — never throws).
|
|
263
|
+
*/
|
|
264
|
+
declare function markdownDocToXlsx(doc: MarkdownDocument, options?: XlsxExportOptions): Promise<ArrayBuffer>;
|
|
265
|
+
/**
|
|
266
|
+
* Convert a squisq Doc to a .xlsx file (via the markdown table model).
|
|
267
|
+
*/
|
|
268
|
+
declare function docToXlsx(doc: Doc, options?: XlsxExportOptions): Promise<ArrayBuffer>;
|
|
269
|
+
|
|
270
|
+
export { type XlsxExportOptions as X, type XlsxImportOptions as a, type XlsxTable as b, type XlsxTableColumn as c, type XlsxTablesOptions as d, docToXlsx as e, xlsxToTables as f, gridToTables as g, markdownDocToXlsx as m, xlsxToMarkdownDoc as x };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,13 +6,13 @@ export { PdfExportOptions, PdfImportOptions, configurePdfWorker, docToPdf, markd
|
|
|
6
6
|
export { HtmlZipExportOptions, docToHtml, docToHtmlZip } from './html/index.js';
|
|
7
7
|
export { EpubExportOptions, docToEpub, markdownDocToEpub } from './epub/index.js';
|
|
8
8
|
export { ExtractedFileTheme, InferSourceFormat, InferThemeOptions, InferredFileTheme, compileExtractedTheme, inferThemeFromFile } from './infer/index.js';
|
|
9
|
-
export { B as BUILTIN_FORMAT_IDS, a as BuiltinFormatOptions, C as ConversionLimits, b as ConversionResult, c as ConvertOptions, d as ConvertSource, D as DEFAULT_CONVERSION_LIMITS, e as DbkFormatOptions, F as FormatDefinition, f as FormatId, g as FormatRegistry, M as MarkdownFormatOptions, N as NormalizedInput, P as PreparedConversion, h as PreparedExportOptions, r as resolveConversionLimits } from './types-
|
|
9
|
+
export { B as BUILTIN_FORMAT_IDS, a as BuiltinFormatOptions, C as ConversionLimits, b as ConversionResult, c as ConvertOptions, d as ConvertSource, D as DEFAULT_CONVERSION_LIMITS, e as DbkFormatOptions, F as FormatDefinition, f as FormatId, g as FormatRegistry, M as MarkdownFormatOptions, N as NormalizedInput, P as PreparedConversion, h as PreparedExportOptions, r as resolveConversionLimits } from './types-bwP9PBSk.js';
|
|
10
10
|
export { ConversionError, ConversionErrorCode, ConversionErrorOptions, convert, createRegistry, defaultFormats, defaultRegistry, prepareConversion } from './registry/index.js';
|
|
11
11
|
export { ImportedOutsideInDocument, OUTSIDE_IN_FORMAT_IDS, OUTSIDE_IN_UPDATE_FROM_MARKDOWN_KEY, OutsideInFormatId, OutsideInLayout, OutsideInMetadata, RenderOutsideInOptions, chooseOutsideInMarkdownPath, importOutsideInDocument, isOutsideInMarkdownEditingEnabled, isOutsideInTargetPath, readOutsideInMetadata, renderOutsideInDocument, resolveOutsideInLayout, withOutsideInMarkdownEditing, withOutsideInMetadata } from './outside-in/index.js';
|
|
12
12
|
export { Z as ZipSafetyError, a as ZipSafetyErrorCode, b as ZipSafetyErrorOptions, c as ZipSafetyLimits } from './zipLimits-BOKCB7qk.js';
|
|
13
13
|
export { H as HtmlExportOptions, a as HtmlImportOptions, c as collectImagePaths, h as htmlToMarkdown, b as htmlToMarkdownDoc, d as htmlToMarkdownDocSync } from './import-B0gBYUmd.js';
|
|
14
14
|
export { P as PptxExportOptions, a as PptxImportOptions, d as docToPptx, m as markdownDocToPptx, p as pptxToMarkdownDoc } from './import-C16E8Y4X.js';
|
|
15
|
-
export { X as XlsxExportOptions, a as XlsxImportOptions, d as docToXlsx, m as markdownDocToXlsx, x as xlsxToMarkdownDoc } from './export-
|
|
15
|
+
export { X as XlsxExportOptions, a as XlsxImportOptions, b as XlsxTable, c as XlsxTableColumn, d as XlsxTablesOptions, e as docToXlsx, g as gridToTables, m as markdownDocToXlsx, x as xlsxToMarkdownDoc, f as xlsxToTables } from './export-Boq78GMq.js';
|
|
16
16
|
import '@bendyline/squisq/schemas';
|
|
17
17
|
import '@bendyline/squisq/markdown';
|
|
18
18
|
import './reader-B_m1aKZC.js';
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
resolveOutsideInLayout,
|
|
21
21
|
withOutsideInMarkdownEditing,
|
|
22
22
|
withOutsideInMetadata
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-TVUX3RUC.js";
|
|
24
24
|
import {
|
|
25
25
|
DEFAULT_CONVERSION_LIMITS,
|
|
26
26
|
convert,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
defaultRegistry,
|
|
30
30
|
prepareConversion,
|
|
31
31
|
resolveConversionLimits
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-5JQ5NDRC.js";
|
|
33
33
|
import {
|
|
34
34
|
ConversionError
|
|
35
35
|
} from "./chunk-KXOZMWBS.js";
|
|
@@ -53,10 +53,12 @@ import "./chunk-6N2J7C2B.js";
|
|
|
53
53
|
import "./chunk-A6N6IN3I.js";
|
|
54
54
|
import {
|
|
55
55
|
docToXlsx,
|
|
56
|
+
gridToTables,
|
|
56
57
|
markdownDocToXlsx,
|
|
57
58
|
xlsxToDoc,
|
|
58
|
-
xlsxToMarkdownDoc
|
|
59
|
-
|
|
59
|
+
xlsxToMarkdownDoc,
|
|
60
|
+
xlsxToTables
|
|
61
|
+
} from "./chunk-RX55T5HO.js";
|
|
60
62
|
import "./chunk-AVOZAKGP.js";
|
|
61
63
|
import {
|
|
62
64
|
csvToDoc,
|
|
@@ -117,6 +119,7 @@ export {
|
|
|
117
119
|
docToXlsx,
|
|
118
120
|
docxToDoc,
|
|
119
121
|
docxToMarkdownDoc,
|
|
122
|
+
gridToTables,
|
|
120
123
|
htmlToMarkdown,
|
|
121
124
|
htmlToMarkdownDoc,
|
|
122
125
|
htmlToMarkdownDocSync,
|
|
@@ -143,5 +146,6 @@ export {
|
|
|
143
146
|
withOutsideInMarkdownEditing,
|
|
144
147
|
withOutsideInMetadata,
|
|
145
148
|
xlsxToDoc,
|
|
146
|
-
xlsxToMarkdownDoc
|
|
149
|
+
xlsxToMarkdownDoc,
|
|
150
|
+
xlsxToTables
|
|
147
151
|
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { MarkdownDocument } from '@bendyline/squisq/markdown';
|
|
2
2
|
import { ContentContainer } from '@bendyline/squisq/storage';
|
|
3
|
-
import { c as ConvertOptions, b as ConversionResult } from '../types-
|
|
3
|
+
import { c as ConvertOptions, b as ConversionResult } from '../types-bwP9PBSk.js';
|
|
4
4
|
import '@bendyline/squisq/schemas';
|
|
5
5
|
import '@bendyline/squisq/transform';
|
|
6
6
|
import '../docx/index.js';
|
|
7
7
|
import '../reader-B_m1aKZC.js';
|
|
8
8
|
import '../zipLimits-BOKCB7qk.js';
|
|
9
9
|
import '../import-C16E8Y4X.js';
|
|
10
|
-
import '../export-
|
|
10
|
+
import '../export-Boq78GMq.js';
|
|
11
11
|
import '../csv/index.js';
|
|
12
12
|
import '../pdf/index.js';
|
|
13
13
|
import '../import-B0gBYUmd.js';
|
package/dist/outside-in/index.js
CHANGED
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
resolveOutsideInLayout,
|
|
11
11
|
withOutsideInMarkdownEditing,
|
|
12
12
|
withOutsideInMetadata
|
|
13
|
-
} from "../chunk-
|
|
14
|
-
import "../chunk-
|
|
13
|
+
} from "../chunk-TVUX3RUC.js";
|
|
14
|
+
import "../chunk-5JQ5NDRC.js";
|
|
15
15
|
import "../chunk-KXOZMWBS.js";
|
|
16
16
|
import "../chunk-7AWFHP5U.js";
|
|
17
17
|
export {
|
package/dist/registry/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as FormatId, g as FormatRegistry, F as FormatDefinition, d as ConvertSource, c as ConvertOptions, b as ConversionResult, P as PreparedConversion } from '../types-
|
|
2
|
-
export { B as BUILTIN_FORMAT_IDS, a as BuiltinFormatOptions, C as ConversionLimits, D as DEFAULT_CONVERSION_LIMITS, e as DbkFormatOptions, M as MarkdownFormatOptions, N as NormalizedInput, h as PreparedExportOptions, r as resolveConversionLimits } from '../types-
|
|
1
|
+
import { f as FormatId, g as FormatRegistry, F as FormatDefinition, d as ConvertSource, c as ConvertOptions, b as ConversionResult, P as PreparedConversion } from '../types-bwP9PBSk.js';
|
|
2
|
+
export { B as BUILTIN_FORMAT_IDS, a as BuiltinFormatOptions, C as ConversionLimits, D as DEFAULT_CONVERSION_LIMITS, e as DbkFormatOptions, M as MarkdownFormatOptions, N as NormalizedInput, h as PreparedExportOptions, r as resolveConversionLimits } from '../types-bwP9PBSk.js';
|
|
3
3
|
import '@bendyline/squisq/schemas';
|
|
4
4
|
import '@bendyline/squisq/transform';
|
|
5
5
|
import '@bendyline/squisq/markdown';
|
|
@@ -8,7 +8,7 @@ import '../docx/index.js';
|
|
|
8
8
|
import '../reader-B_m1aKZC.js';
|
|
9
9
|
import '../zipLimits-BOKCB7qk.js';
|
|
10
10
|
import '../import-C16E8Y4X.js';
|
|
11
|
-
import '../export-
|
|
11
|
+
import '../export-Boq78GMq.js';
|
|
12
12
|
import '../csv/index.js';
|
|
13
13
|
import '../pdf/index.js';
|
|
14
14
|
import '../import-B0gBYUmd.js';
|
package/dist/registry/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { ParseOptions, StringifyOptions, MarkdownDocument } from '@bendyline/squ
|
|
|
4
4
|
import { ContentContainer } from '@bendyline/squisq/storage';
|
|
5
5
|
import { DocxImportOptions, DocxExportOptions } from './docx/index.js';
|
|
6
6
|
import { a as PptxImportOptions, P as PptxExportOptions } from './import-C16E8Y4X.js';
|
|
7
|
-
import { a as XlsxImportOptions, X as XlsxExportOptions } from './export-
|
|
7
|
+
import { a as XlsxImportOptions, X as XlsxExportOptions } from './export-Boq78GMq.js';
|
|
8
8
|
import { CsvImportOptions, CsvExportOptions } from './csv/index.js';
|
|
9
9
|
import { PdfImportOptions, PdfExportOptions } from './pdf/index.js';
|
|
10
10
|
import { a as HtmlImportOptions, H as HtmlExportOptions } from './import-B0gBYUmd.js';
|
package/dist/xlsx/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Doc } from '@bendyline/squisq/schemas';
|
|
2
|
-
import { a as XlsxImportOptions } from '../export-
|
|
3
|
-
export { X as XlsxExportOptions, d as docToXlsx, m as markdownDocToXlsx, x as xlsxToMarkdownDoc } from '../export-
|
|
2
|
+
import { a as XlsxImportOptions } from '../export-Boq78GMq.js';
|
|
3
|
+
export { X as XlsxExportOptions, b as XlsxTable, c as XlsxTableColumn, d as XlsxTablesOptions, e as docToXlsx, g as gridToTables, m as markdownDocToXlsx, x as xlsxToMarkdownDoc, f as xlsxToTables } from '../export-Boq78GMq.js';
|
|
4
4
|
import '@bendyline/squisq/markdown';
|
|
5
5
|
import '../reader-B_m1aKZC.js';
|
|
6
6
|
import '../zipLimits-BOKCB7qk.js';
|
package/dist/xlsx/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
docToXlsx,
|
|
3
|
+
gridToTables,
|
|
3
4
|
markdownDocToXlsx,
|
|
4
5
|
xlsxToDoc,
|
|
5
|
-
xlsxToMarkdownDoc
|
|
6
|
-
|
|
6
|
+
xlsxToMarkdownDoc,
|
|
7
|
+
xlsxToTables
|
|
8
|
+
} from "../chunk-RX55T5HO.js";
|
|
7
9
|
import "../chunk-AVOZAKGP.js";
|
|
8
10
|
import "../chunk-ILCJ3WFD.js";
|
|
9
11
|
import "../chunk-JU2RHXUB.js";
|
|
@@ -11,7 +13,9 @@ import "../chunk-S5PCVMKU.js";
|
|
|
11
13
|
import "../chunk-7AWFHP5U.js";
|
|
12
14
|
export {
|
|
13
15
|
docToXlsx,
|
|
16
|
+
gridToTables,
|
|
14
17
|
markdownDocToXlsx,
|
|
15
18
|
xlsxToDoc,
|
|
16
|
-
xlsxToMarkdownDoc
|
|
19
|
+
xlsxToMarkdownDoc,
|
|
20
|
+
xlsxToTables
|
|
17
21
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bendyline/squisq-formats",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"description": "Document format converters — DOCX, PDF, OOXML import/export",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bendyline",
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"dependencies": {
|
|
113
113
|
"@pdf-lib/fontkit": "1.1.1",
|
|
114
114
|
"@pdf-lib/upng": "1.0.1",
|
|
115
|
-
"@xmldom/xmldom": "0.9.
|
|
115
|
+
"@xmldom/xmldom": "0.9.12",
|
|
116
116
|
"@bendyline/squisq": "2.10.0",
|
|
117
117
|
"jszip": "3.10.1",
|
|
118
118
|
"pdf-lib": "1.17.1",
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import { MarkdownDocument } from '@bendyline/squisq/markdown';
|
|
2
|
-
import { O as OoxmlOpenOptions } from './reader-B_m1aKZC.js';
|
|
3
|
-
import { Doc } from '@bendyline/squisq/schemas';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* XLSX import — SpreadsheetML (.xlsx) → MarkdownDocument.
|
|
7
|
-
*
|
|
8
|
-
* Reuses the shared ooxml/ reader (zip + DOMParser). Reads the workbook's sheet
|
|
9
|
-
* list, resolves each sheet part via relationships, pulls shared strings, and
|
|
10
|
-
* turns each worksheet into markdown. By default every sheet is imported, each
|
|
11
|
-
* preceded by an H1 of the sheet name; pass `options.sheet` (index or name) to
|
|
12
|
-
* import just one.
|
|
13
|
-
*
|
|
14
|
-
* A sheet is NOT one table. It is usually several tables scattered across the
|
|
15
|
-
* grid with stray labels and notes in the gaps, so by default each worksheet is
|
|
16
|
-
* split into its contiguous data islands (see `regions.ts`) and every island
|
|
17
|
-
* becomes its own block:
|
|
18
|
-
*
|
|
19
|
-
* ```markdown
|
|
20
|
-
* ## Q3 Revenue {[dataTable sheet=Sales anchor=B7]}
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* The `sheet`/`anchor` params on the heading annotation are what let
|
|
24
|
-
* `markdownDocToXlsx` put each table back where it came from, so the round trip
|
|
25
|
-
* reproduces addresses rather than piling everything at A1. A region holding
|
|
26
|
-
* formulas additionally emits a `role=formulas` companion table, and every
|
|
27
|
-
* left-over single cell on a sheet collects into one `role=loose` table.
|
|
28
|
-
*
|
|
29
|
-
* Pass `{ regions: false }` for the historical behavior: one table per sheet,
|
|
30
|
-
* spanning the whole used range.
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
interface XlsxImportOptions extends OoxmlOpenOptions {
|
|
34
|
-
/** Which sheet to import (0-based index or sheet name). Default: all sheets. */
|
|
35
|
-
sheet?: number | string;
|
|
36
|
-
/**
|
|
37
|
-
* Split each sheet into its contiguous data islands, one block each, anchored
|
|
38
|
-
* with `{[dataTable sheet=… anchor=…]}`. Default true. Set false for the
|
|
39
|
-
* historical one-table-per-sheet output.
|
|
40
|
-
*/
|
|
41
|
-
regions?: boolean;
|
|
42
|
-
/**
|
|
43
|
-
* Emit a `role=formulas` companion table for regions that contain formulas.
|
|
44
|
-
* Default true. Ignored when `regions` is false.
|
|
45
|
-
*/
|
|
46
|
-
formulas?: boolean;
|
|
47
|
-
/** Cap on region tables per sheet before the rest fold into loose cells. Default 64. */
|
|
48
|
-
maxRegionsPerSheet?: number;
|
|
49
|
-
/** Smallest island that stays a table of its own. Default 2 — single cells coalesce. */
|
|
50
|
-
minRegionCells?: number;
|
|
51
|
-
}
|
|
52
|
-
declare function xlsxToMarkdownDoc(data: ArrayBuffer | Blob, options?: XlsxImportOptions): Promise<MarkdownDocument>;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* XLSX export — MarkdownDocument → SpreadsheetML (.xlsx).
|
|
56
|
-
*
|
|
57
|
-
* Tables-only fidelity (honestly documented): every `table` node in the
|
|
58
|
-
* markdown AST becomes worksheet cells; all other content (prose, lists,
|
|
59
|
-
* images, …) is dropped, and headings survive only as sheet names and as the
|
|
60
|
-
* carrier of placement metadata.
|
|
61
|
-
*
|
|
62
|
-
* Placement has two modes, decided per table by `workbookPlan.ts`. A table
|
|
63
|
-
* whose heading carries `{[dataTable sheet=… anchor=…]}` — what
|
|
64
|
-
* `xlsxToMarkdownDoc` emits for every data island it finds — is placed on the
|
|
65
|
-
* named sheet at the named cell, so several mini tables share one worksheet at
|
|
66
|
-
* their original addresses and formulas ride along. A table with no such
|
|
67
|
-
* annotation keeps the historical behavior exactly: its own worksheet, named
|
|
68
|
-
* from the nearest preceding heading, starting at A1.
|
|
69
|
-
*
|
|
70
|
-
* Cells are emitted as inline strings (`t="inlineStr"`) by default so no
|
|
71
|
-
* sharedStrings part is needed and identifier-like numbers remain lossless.
|
|
72
|
-
* Callers can explicitly opt into conservative numeric inference. The package
|
|
73
|
-
* is assembled with the shared ooxml/ writer (auto-generates
|
|
74
|
-
* `[Content_Types].xml` + `_rels`), so only the SpreadsheetML-specific parts
|
|
75
|
-
* (workbook, worksheets, styles) are written here.
|
|
76
|
-
*
|
|
77
|
-
* @example
|
|
78
|
-
* ```ts
|
|
79
|
-
* import { parseMarkdown } from '@bendyline/squisq/markdown';
|
|
80
|
-
* import { markdownDocToXlsx } from '@bendyline/squisq-formats/xlsx';
|
|
81
|
-
*
|
|
82
|
-
* const md = parseMarkdown('# Metrics\n\n| A | B |\n| - | - |\n| 1 | 2 |');
|
|
83
|
-
* const buffer = await markdownDocToXlsx(md);
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Options for XLSX export.
|
|
89
|
-
*/
|
|
90
|
-
interface XlsxExportOptions {
|
|
91
|
-
/** Cancel at bounded export checkpoints. */
|
|
92
|
-
signal?: AbortSignal;
|
|
93
|
-
/** Maximum cells emitted. Default: 100,000. */
|
|
94
|
-
maxCells?: number;
|
|
95
|
-
/** Workbook title (written to core properties). */
|
|
96
|
-
title?: string;
|
|
97
|
-
/** Workbook author (written to core properties). */
|
|
98
|
-
author?: string;
|
|
99
|
-
/** Prefix used for auto-named sheets when no heading precedes a table. Default: "Sheet". */
|
|
100
|
-
sheetNamePrefix?: string;
|
|
101
|
-
/**
|
|
102
|
-
* Emit canonical, Excel-safe number strings as numeric cells.
|
|
103
|
-
*
|
|
104
|
-
* Defaults to false for hand-authored documents — markdown tables have no
|
|
105
|
-
* column schema, so preserving authored text is the only lossless choice —
|
|
106
|
-
* and to true when the document carries `sheet=` anchors, which only an XLSX
|
|
107
|
-
* import produces. Leading-zero and >15-significant-digit values remain
|
|
108
|
-
* strings either way. Set explicitly to override both defaults.
|
|
109
|
-
*/
|
|
110
|
-
inferNumericCells?: boolean;
|
|
111
|
-
/**
|
|
112
|
-
* Called for each non-fatal placement problem (a malformed anchor, an
|
|
113
|
-
* overlapping region, an unusable loose-cell reference). Export never throws
|
|
114
|
-
* for these — a hand-edited markdown file must still convert.
|
|
115
|
-
*/
|
|
116
|
-
onWarning?: (message: string) => void;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Convert a MarkdownDocument to a .xlsx file (tables-only fidelity).
|
|
120
|
-
*
|
|
121
|
-
* Each markdown `table` becomes one worksheet; a document with no tables
|
|
122
|
-
* yields a single empty sheet (a valid, openable file — never throws).
|
|
123
|
-
*/
|
|
124
|
-
declare function markdownDocToXlsx(doc: MarkdownDocument, options?: XlsxExportOptions): Promise<ArrayBuffer>;
|
|
125
|
-
/**
|
|
126
|
-
* Convert a squisq Doc to a .xlsx file (via the markdown table model).
|
|
127
|
-
*/
|
|
128
|
-
declare function docToXlsx(doc: Doc, options?: XlsxExportOptions): Promise<ArrayBuffer>;
|
|
129
|
-
|
|
130
|
-
export { type XlsxExportOptions as X, type XlsxImportOptions as a, docToXlsx as d, markdownDocToXlsx as m, xlsxToMarkdownDoc as x };
|
|
File without changes
|