@bendyline/squisq-formats 2.4.6 → 2.5.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.
@@ -10,8 +10,8 @@ import {
10
10
  resolveOutsideInLayout,
11
11
  withOutsideInMarkdownEditing,
12
12
  withOutsideInMetadata
13
- } from "../chunk-BVGJ54NV.js";
14
- import "../chunk-DNGNODJP.js";
13
+ } from "../chunk-5PUIFU5I.js";
14
+ import "../chunk-JTGWQK5V.js";
15
15
  import "../chunk-KXOZMWBS.js";
16
16
  import "../chunk-7AWFHP5U.js";
17
17
  export {
package/dist/pdf/index.js CHANGED
@@ -5,9 +5,10 @@ import {
5
5
  pdfToContainer,
6
6
  pdfToDoc,
7
7
  pdfToMarkdownDoc
8
- } from "../chunk-KT5DX2QP.js";
8
+ } from "../chunk-M7XPXGXW.js";
9
9
  import "../chunk-IIQYS2YH.js";
10
10
  import "../chunk-USU6HTKB.js";
11
+ import "../chunk-BXWNU4T5.js";
11
12
  export {
12
13
  configurePdfWorker,
13
14
  docToPdf,
@@ -4,13 +4,13 @@ import {
4
4
  pptxToContainer,
5
5
  pptxToDoc,
6
6
  pptxToMarkdownDoc
7
- } from "../chunk-XCV242AO.js";
7
+ } from "../chunk-FMQWNPCV.js";
8
8
  import {
9
9
  analyzePptxLayouts,
10
10
  inspectPptxLayouts
11
11
  } from "../chunk-6N2J7C2B.js";
12
- import "../chunk-DWNNYO5H.js";
13
- import "../chunk-6X5XN3CZ.js";
12
+ import "../chunk-A6N6IN3I.js";
13
+ import "../chunk-AVOZAKGP.js";
14
14
  import "../chunk-ILCJ3WFD.js";
15
15
  import "../chunk-JU2RHXUB.js";
16
16
  import "../chunk-S5PCVMKU.js";
@@ -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-HDLauUoa.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-HDLauUoa.js';
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-DByrrXeB.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-DByrrXeB.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-D9msROJS.js';
11
+ import '../export-m0tr9r9d.js';
12
12
  import '../csv/index.js';
13
13
  import '../pdf/index.js';
14
14
  import '../import-B0gBYUmd.js';
@@ -9,7 +9,7 @@ import {
9
9
  defaultRegistry,
10
10
  prepareConversion,
11
11
  resolveConversionLimits
12
- } from "../chunk-DNGNODJP.js";
12
+ } from "../chunk-JTGWQK5V.js";
13
13
  import {
14
14
  ConversionError
15
15
  } from "../chunk-KXOZMWBS.js";
@@ -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-D9msROJS.js';
7
+ import { a as XlsxImportOptions, X as XlsxExportOptions } from './export-m0tr9r9d.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';
@@ -1,6 +1,6 @@
1
1
  import { Doc } from '@bendyline/squisq/schemas';
2
- import { a as XlsxImportOptions } from '../export-D9msROJS.js';
3
- export { X as XlsxExportOptions, d as docToXlsx, m as markdownDocToXlsx, x as xlsxToMarkdownDoc } from '../export-D9msROJS.js';
2
+ import { a as XlsxImportOptions } from '../export-m0tr9r9d.js';
3
+ export { X as XlsxExportOptions, d as docToXlsx, m as markdownDocToXlsx, x as xlsxToMarkdownDoc } from '../export-m0tr9r9d.js';
4
4
  import '@bendyline/squisq/markdown';
5
5
  import '../reader-B_m1aKZC.js';
6
6
  import '../zipLimits-BOKCB7qk.js';
@@ -3,8 +3,8 @@ import {
3
3
  markdownDocToXlsx,
4
4
  xlsxToDoc,
5
5
  xlsxToMarkdownDoc
6
- } from "../chunk-UIBTXX4L.js";
7
- import "../chunk-6X5XN3CZ.js";
6
+ } from "../chunk-A6LSCIO5.js";
7
+ import "../chunk-AVOZAKGP.js";
8
8
  import "../chunk-ILCJ3WFD.js";
9
9
  import "../chunk-JU2RHXUB.js";
10
10
  import "../chunk-S5PCVMKU.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq-formats",
3
- "version": "2.4.6",
3
+ "version": "2.5.0",
4
4
  "description": "Document format converters — DOCX, PDF, OOXML import/export",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",
@@ -113,7 +113,7 @@
113
113
  "@pdf-lib/fontkit": "1.1.1",
114
114
  "@pdf-lib/upng": "1.0.1",
115
115
  "@xmldom/xmldom": "0.9.11",
116
- "@bendyline/squisq": "2.9.0",
116
+ "@bendyline/squisq": "2.10.0",
117
117
  "jszip": "3.10.1",
118
118
  "pdf-lib": "1.17.1",
119
119
  "pdfjs-dist": "4.10.38"
@@ -1,446 +0,0 @@
1
- import {
2
- extractPlainText
3
- } from "./chunk-6X5XN3CZ.js";
4
- import {
5
- createPackage
6
- } from "./chunk-ILCJ3WFD.js";
7
- import {
8
- escapeXml,
9
- xmlDeclaration
10
- } from "./chunk-JU2RHXUB.js";
11
- import {
12
- CONTENT_TYPE_XLSX_STYLES,
13
- CONTENT_TYPE_XLSX_WORKBOOK,
14
- CONTENT_TYPE_XLSX_WORKSHEET,
15
- NS_R,
16
- NS_SML,
17
- REL_OFFICE_DOCUMENT,
18
- REL_STYLES,
19
- REL_WORKSHEET,
20
- baseDirOf,
21
- getPartRelationships,
22
- getPartXml,
23
- openPackage,
24
- requireMainPartPath
25
- } from "./chunk-S5PCVMKU.js";
26
-
27
- // src/xlsx/index.ts
28
- import { markdownToDoc } from "@bendyline/squisq/doc";
29
-
30
- // src/xlsx/import.ts
31
- var XLSX_MAIN_PART = "xl/workbook.xml";
32
- function attrNS(el, ns, local, fallback) {
33
- return el.getAttributeNS(ns, local) ?? el.getAttribute(fallback);
34
- }
35
- function resolveTarget(baseDir, target) {
36
- if (target.startsWith("/")) return target.replace(/^\//, "");
37
- const stack = baseDir ? baseDir.split("/") : [];
38
- for (const seg of target.split("/")) {
39
- if (seg === "..") stack.pop();
40
- else if (seg !== ".") stack.push(seg);
41
- }
42
- return stack.join("/");
43
- }
44
- async function readWorkbook(pkg, mainPart) {
45
- const wb = await getPartXml(pkg, mainPart);
46
- if (!wb) {
47
- throw new Error(`Invalid XLSX package: workbook part "${mainPart}" could not be parsed.`);
48
- }
49
- const rels = await getPartRelationships(pkg, mainPart);
50
- const relById = new Map(rels.map((r) => [r.id, r.target]));
51
- const out = [];
52
- const sheetEls = wb.getElementsByTagNameNS(NS_SML, "sheet");
53
- for (let i = 0; i < sheetEls.length; i++) {
54
- const el = sheetEls[i];
55
- const name = el.getAttribute("name") ?? `Sheet${i + 1}`;
56
- const rid = attrNS(el, NS_R, "id", "r:id");
57
- const target = rid ? relById.get(rid) : void 0;
58
- if (target) out.push({ name, path: resolveTarget(baseDirOf(mainPart), target) });
59
- }
60
- const workbookPr = wb.getElementsByTagNameNS(NS_SML, "workbookPr")[0];
61
- const date1904Value = workbookPr?.getAttribute("date1904");
62
- return {
63
- sheets: out,
64
- date1904: date1904Value === "1" || date1904Value === "true"
65
- };
66
- }
67
- function isPhonetic(el, root) {
68
- for (let node = el.parentNode; node && node !== root; node = node.parentNode) {
69
- if (node.nodeType !== 1) continue;
70
- const parent = node;
71
- if (parent.localName === "rPh" && parent.namespaceURI === NS_SML) return true;
72
- }
73
- return false;
74
- }
75
- function stringItemText(root) {
76
- const tEls = root.getElementsByTagNameNS(NS_SML, "t");
77
- let out = "";
78
- for (let i = 0; i < tEls.length; i++) {
79
- const t = tEls[i];
80
- if (isPhonetic(t, root)) continue;
81
- out += t.textContent ?? "";
82
- }
83
- return out;
84
- }
85
- async function readSharedStrings(pkg) {
86
- const doc = await getPartXml(pkg, "xl/sharedStrings.xml");
87
- if (!doc) return [];
88
- const siEls = doc.getElementsByTagNameNS(NS_SML, "si");
89
- const out = [];
90
- for (let i = 0; i < siEls.length; i++) out.push(stringItemText(siEls[i]));
91
- return out;
92
- }
93
- var BUILTIN_NUMBER_FORMATS = Object.freeze({
94
- 9: "0%",
95
- 10: "0.00%",
96
- 14: "mm-dd-yy",
97
- 15: "d-mmm-yy",
98
- 16: "d-mmm",
99
- 17: "mmm-yy",
100
- 18: "h:mm AM/PM",
101
- 19: "h:mm:ss AM/PM",
102
- 20: "h:mm",
103
- 21: "h:mm:ss",
104
- 22: "m/d/yy h:mm",
105
- 45: "mm:ss",
106
- 46: "[h]:mm:ss",
107
- 47: "mmss.0"
108
- });
109
- async function readCellStyles(pkg) {
110
- const doc = await getPartXml(pkg, "xl/styles.xml");
111
- if (!doc) return [];
112
- const custom = /* @__PURE__ */ new Map();
113
- const numFmtEls = doc.getElementsByTagNameNS(NS_SML, "numFmt");
114
- for (let i = 0; i < numFmtEls.length; i++) {
115
- const el = numFmtEls[i];
116
- const id = Number.parseInt(el.getAttribute("numFmtId") ?? "", 10);
117
- const code = el.getAttribute("formatCode");
118
- if (Number.isFinite(id) && code) custom.set(id, code);
119
- }
120
- const cellXfs = doc.getElementsByTagNameNS(NS_SML, "cellXfs")[0];
121
- if (!cellXfs) return [];
122
- const xfEls = cellXfs.getElementsByTagNameNS(NS_SML, "xf");
123
- const out = [];
124
- for (let i = 0; i < xfEls.length; i++) {
125
- const numFmtId = Number.parseInt(xfEls[i].getAttribute("numFmtId") ?? "0", 10);
126
- out.push({
127
- numFmtId,
128
- formatCode: custom.get(numFmtId) ?? BUILTIN_NUMBER_FORMATS[numFmtId] ?? "General"
129
- });
130
- }
131
- return out;
132
- }
133
- function colIndex(ref) {
134
- const m = /^([A-Za-z]+)/.exec(ref);
135
- if (!m) return 0;
136
- let n = 0;
137
- for (const ch of m[1].toUpperCase()) n = n * 26 + (ch.charCodeAt(0) - 64);
138
- return n - 1;
139
- }
140
- function normalizeFormatCode(formatCode) {
141
- return formatCode.split(";", 1)[0].replace(/"(?:[^"]|"")*"/g, "").replace(/\\./g, "").replace(/[_*]./g, "").replace(/\[(?!h+\]|m+\]|s+\])[^\]]*\]/gi, "").toLowerCase();
142
- }
143
- function numberFormatKind(formatCode) {
144
- const normalized = normalizeFormatCode(formatCode);
145
- if (normalized === "general") return "general";
146
- if (normalized.includes("%")) return "percent";
147
- if (/^0+$/.test(normalized)) return "zero-pad";
148
- const hasDate = /[yd]/.test(normalized);
149
- const hasTime = /[hs]|\[[hms]+\]/.test(normalized);
150
- if (hasDate && hasTime) return "datetime";
151
- if (hasDate) return "date";
152
- if (hasTime) return "time";
153
- return "general";
154
- }
155
- function twoDigits(value) {
156
- return String(value).padStart(2, "0");
157
- }
158
- function excelDateText(serial, date1904) {
159
- const wholeDays = Math.floor(serial);
160
- if (!date1904 && wholeDays === 60) return "1900-02-29";
161
- const epoch = date1904 ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, 31);
162
- const adjustedDays = !date1904 && wholeDays > 60 ? wholeDays - 1 : wholeDays;
163
- const date = new Date(epoch + adjustedDays * 864e5);
164
- if (!Number.isFinite(date.getTime())) return null;
165
- return `${date.getUTCFullYear()}-${twoDigits(date.getUTCMonth() + 1)}-${twoDigits(date.getUTCDate())}`;
166
- }
167
- function excelTimeText(serial, includeSeconds, elapsedHours) {
168
- const totalSeconds = Math.round((serial - Math.floor(serial)) * 86400);
169
- const hours = elapsedHours ? Math.floor(serial * 24) : Math.floor(totalSeconds / 3600) % 24;
170
- const minutes = Math.floor(totalSeconds / 60) % 60;
171
- const seconds = totalSeconds % 60;
172
- return `${twoDigits(hours)}:${twoDigits(minutes)}${includeSeconds ? `:${twoDigits(seconds)}` : ""}`;
173
- }
174
- function formattedNumberText(raw, style, date1904) {
175
- if (!style) return raw;
176
- const value = Number(raw);
177
- if (!Number.isFinite(value)) return raw;
178
- const normalized = normalizeFormatCode(style.formatCode);
179
- const kind = numberFormatKind(style.formatCode);
180
- if (kind === "date") return excelDateText(value, date1904) ?? raw;
181
- if (kind === "time") {
182
- return excelTimeText(value, /s/.test(normalized), /\[[h]+\]/.test(normalized));
183
- }
184
- if (kind === "datetime") {
185
- const date = excelDateText(value, date1904);
186
- return date ? `${date} ${excelTimeText(value, /s/.test(normalized), false)}` : raw;
187
- }
188
- if (kind === "percent") {
189
- const decimals = /0\.(0+)%/.exec(normalized)?.[1]?.length ?? 0;
190
- return `${(value * 100).toFixed(decimals)}%`;
191
- }
192
- if (kind === "zero-pad" && Number.isInteger(value)) {
193
- const width = normalized.length;
194
- const sign = value < 0 ? "-" : "";
195
- return `${sign}${String(Math.abs(value)).padStart(width, "0")}`;
196
- }
197
- return raw;
198
- }
199
- function cellText(cell, shared, styles, date1904) {
200
- const t = cell.getAttribute("t");
201
- if (t === "inlineStr") {
202
- const is = cell.getElementsByTagNameNS(NS_SML, "is")[0];
203
- return is ? stringItemText(is) : "";
204
- }
205
- const vEls = cell.getElementsByTagNameNS(NS_SML, "v");
206
- const v = vEls.length ? vEls[0].textContent ?? "" : "";
207
- if (t === "s") return shared[Number.parseInt(v, 10)] ?? "";
208
- if (t === "b") return v === "1" ? "TRUE" : "FALSE";
209
- const styleIndex = Number.parseInt(cell.getAttribute("s") ?? "0", 10);
210
- return formattedNumberText(v, styles[styleIndex], date1904);
211
- }
212
- async function sheetToGrid(pkg, path, shared, styles, date1904) {
213
- const doc = await getPartXml(pkg, path);
214
- if (!doc) return [];
215
- const rowEls = doc.getElementsByTagNameNS(NS_SML, "row");
216
- const byIndex = /* @__PURE__ */ new Map();
217
- let maxContentIdx = -1;
218
- let fallbackIdx = 0;
219
- for (let r = 0; r < rowEls.length; r++) {
220
- const rowEl = rowEls[r];
221
- const cells = rowEl.getElementsByTagNameNS(NS_SML, "c");
222
- const rowArr = [];
223
- for (let c = 0; c < cells.length; c++) {
224
- const cell = cells[c];
225
- const ref = cell.getAttribute("r");
226
- const idx = ref ? colIndex(ref) : rowArr.length;
227
- while (rowArr.length < idx) rowArr.push("");
228
- rowArr[idx] = cellText(cell, shared, styles, date1904);
229
- }
230
- const rowRef = Number.parseInt(rowEl.getAttribute("r") ?? "", 10);
231
- const rowIdx = Number.isFinite(rowRef) && rowRef > 0 ? rowRef - 1 : fallbackIdx;
232
- fallbackIdx = rowIdx + 1;
233
- byIndex.set(rowIdx, rowArr);
234
- if (rowArr.some((v) => v !== "")) maxContentIdx = Math.max(maxContentIdx, rowIdx);
235
- }
236
- const grid = [];
237
- for (let i = 0; i <= maxContentIdx; i++) grid.push(byIndex.get(i) ?? []);
238
- return grid;
239
- }
240
- function gridToTable(grid) {
241
- const maxCols = grid.reduce((m, r) => Math.max(m, r.length), 1);
242
- const rows = grid.map((cells, rowIdx) => {
243
- const children = [];
244
- for (let c = 0; c < maxCols; c++) {
245
- const value = cells[c] ?? "";
246
- children.push({
247
- type: "tableCell",
248
- ...rowIdx === 0 ? { isHeader: true } : {},
249
- children: value ? [{ type: "text", value }] : []
250
- });
251
- }
252
- return { type: "tableRow", children };
253
- });
254
- return { type: "table", children: rows };
255
- }
256
- async function xlsxToMarkdownDoc(data, options = {}) {
257
- const pkg = await openPackage(data, options);
258
- const mainPart = requireMainPartPath(pkg, XLSX_MAIN_PART, "XLSX");
259
- const [{ sheets, date1904 }, shared, styles] = await Promise.all([
260
- readWorkbook(pkg, mainPart),
261
- readSharedStrings(pkg),
262
- readCellStyles(pkg)
263
- ]);
264
- let selected = sheets;
265
- if (options.sheet !== void 0) {
266
- const picked = typeof options.sheet === "number" ? sheets[options.sheet] : sheets.find((s) => s.name === options.sheet);
267
- selected = picked ? [picked] : [];
268
- }
269
- const children = [];
270
- const single = selected.length === 1 && options.sheet !== void 0;
271
- for (const sheet of selected) {
272
- const grid = await sheetToGrid(pkg, sheet.path, shared, styles, date1904);
273
- if (!single) {
274
- children.push({ type: "heading", depth: 1, children: [{ type: "text", value: sheet.name }] });
275
- }
276
- if (grid.length > 0) children.push(gridToTable(grid));
277
- }
278
- return { type: "document", children };
279
- }
280
-
281
- // src/xlsx/export.ts
282
- import { docToMarkdown } from "@bendyline/squisq/doc";
283
- var NUMERIC_RE = /^-?\d+(\.\d+)?$/;
284
- function isSafeNumericCell(value) {
285
- if (!NUMERIC_RE.test(value)) return false;
286
- const unsigned = value.startsWith("-") ? value.slice(1) : value;
287
- const [integer] = unsigned.split(".");
288
- if (integer.length > 1 && integer.startsWith("0")) return false;
289
- const significantDigits = unsigned.replace(".", "").replace(/^0+/, "");
290
- if (significantDigits.length > 15) return false;
291
- return Number.isFinite(Number(value));
292
- }
293
- function cleanSheetName(value) {
294
- return value.replace(/[[\]:*?/\\]/g, "").trim().slice(0, 31).trim().replace(/^'+|'+$/g, "");
295
- }
296
- function sanitizeSheetName(raw, used, fallback) {
297
- const safeFallback = cleanSheetName(fallback) || "Sheet";
298
- const name = cleanSheetName(raw) || safeFallback;
299
- const key = name.toLocaleLowerCase("en-US");
300
- if (!used.has(key)) {
301
- used.add(key);
302
- return name;
303
- }
304
- for (let n = 2; ; n++) {
305
- const suffix = String(n);
306
- const base = name.slice(0, 31 - suffix.length);
307
- const candidate = `${base}${suffix}`;
308
- const candidateKey = candidate.toLocaleLowerCase("en-US");
309
- if (!used.has(candidateKey)) {
310
- used.add(candidateKey);
311
- return candidate;
312
- }
313
- }
314
- }
315
- function tableToGrid(table) {
316
- return table.children.map(
317
- (row) => row.children.map((cell) => extractPlainText(cell.children))
318
- );
319
- }
320
- function collectSheets(doc, prefix) {
321
- const used = /* @__PURE__ */ new Set();
322
- const sheets = [];
323
- let pendingHeading = null;
324
- const visit = (nodes) => {
325
- for (const node of nodes) {
326
- if (node.type === "heading") {
327
- pendingHeading = extractPlainText(node.children);
328
- } else if (node.type === "table") {
329
- const fallback = `${prefix}${sheets.length + 1}`;
330
- const name = sanitizeSheetName(pendingHeading ?? fallback, used, fallback);
331
- sheets.push({ name, grid: tableToGrid(node) });
332
- pendingHeading = null;
333
- }
334
- }
335
- };
336
- visit(doc.children);
337
- return sheets;
338
- }
339
- function columnLetter(index) {
340
- let n = index + 1;
341
- let letters = "";
342
- while (n > 0) {
343
- const rem = (n - 1) % 26;
344
- letters = String.fromCharCode(65 + rem) + letters;
345
- n = Math.floor((n - 1) / 26);
346
- }
347
- return letters;
348
- }
349
- function cellXml(value, ref, inferNumericCells) {
350
- if (inferNumericCells && isSafeNumericCell(value)) {
351
- return `<c r="${ref}"><v>${escapeXml(value)}</v></c>`;
352
- }
353
- return `<c r="${ref}" t="inlineStr"><is><t xml:space="preserve">${escapeXml(value)}</t></is></c>`;
354
- }
355
- function worksheetXml(grid, inferNumericCells) {
356
- const rows = [];
357
- for (let r = 0; r < grid.length; r++) {
358
- const cells = grid[r];
359
- const cellsXml = cells.map((value, c) => cellXml(value, `${columnLetter(c)}${r + 1}`, inferNumericCells)).join("");
360
- rows.push(`<row r="${r + 1}">${cellsXml}</row>`);
361
- }
362
- return `${xmlDeclaration()}
363
- <worksheet xmlns="${NS_SML}" xmlns:r="${NS_R}"><sheetData>${rows.join("")}</sheetData></worksheet>`;
364
- }
365
- function workbookXml(sheets) {
366
- const sheetEls = sheets.map(
367
- (sheet, i) => `<sheet name="${escapeXml(sheet.name)}" sheetId="${i + 1}" r:id="rId${i + 1}"/>`
368
- ).join("");
369
- return `${xmlDeclaration()}
370
- <workbook xmlns="${NS_SML}" xmlns:r="${NS_R}"><sheets>${sheetEls}</sheets></workbook>`;
371
- }
372
- function stylesXml() {
373
- return `${xmlDeclaration()}
374
- <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>`;
375
- }
376
- async function markdownDocToXlsx(doc, options = {}) {
377
- options.signal?.throwIfAborted();
378
- const prefix = cleanSheetName(options.sheetNamePrefix ?? "Sheet") || "Sheet";
379
- const inferNumericCells = options.inferNumericCells ?? false;
380
- let sheets = collectSheets(doc, prefix);
381
- const maxCells = options.maxCells ?? 1e5;
382
- if (!Number.isSafeInteger(maxCells) || maxCells < 0) {
383
- throw new RangeError("maxCells must be a non-negative safe integer");
384
- }
385
- const cellCount = sheets.reduce(
386
- (total, sheet) => total + sheet.grid.reduce((sum, row) => sum + row.length, 0),
387
- 0
388
- );
389
- if (cellCount > maxCells) {
390
- throw new RangeError(`XLSX export exceeds the ${maxCells}-cell safety limit`);
391
- }
392
- if (sheets.length === 0) {
393
- sheets = [{ name: sanitizeSheetName(`${prefix}1`, /* @__PURE__ */ new Set(), "Sheet1"), grid: [] }];
394
- }
395
- const pkg = createPackage();
396
- sheets.forEach((sheet, i) => {
397
- if ((i & 31) === 0) options.signal?.throwIfAborted();
398
- const sheetPath = `xl/worksheets/sheet${i + 1}.xml`;
399
- pkg.addPart(
400
- sheetPath,
401
- worksheetXml(sheet.grid, inferNumericCells),
402
- CONTENT_TYPE_XLSX_WORKSHEET
403
- );
404
- pkg.addRelationship("xl/workbook.xml", {
405
- id: `rId${i + 1}`,
406
- type: REL_WORKSHEET,
407
- target: `worksheets/sheet${i + 1}.xml`
408
- });
409
- });
410
- pkg.addPart("xl/styles.xml", stylesXml(), CONTENT_TYPE_XLSX_STYLES);
411
- pkg.addRelationship("xl/workbook.xml", {
412
- id: `rId${sheets.length + 1}`,
413
- type: REL_STYLES,
414
- target: "styles.xml"
415
- });
416
- pkg.addPart("xl/workbook.xml", workbookXml(sheets), CONTENT_TYPE_XLSX_WORKBOOK);
417
- pkg.addRelationship("", {
418
- id: "rId1",
419
- type: REL_OFFICE_DOCUMENT,
420
- target: "xl/workbook.xml"
421
- });
422
- if (options.title || options.author) {
423
- pkg.setCoreProperties({
424
- title: options.title,
425
- creator: options.author,
426
- created: (/* @__PURE__ */ new Date()).toISOString(),
427
- modified: (/* @__PURE__ */ new Date()).toISOString()
428
- });
429
- }
430
- return pkg.toArrayBuffer();
431
- }
432
- async function docToXlsx(doc, options) {
433
- return markdownDocToXlsx(docToMarkdown(doc), options);
434
- }
435
-
436
- // src/xlsx/index.ts
437
- async function xlsxToDoc(data, options) {
438
- return markdownToDoc(await xlsxToMarkdownDoc(data, options));
439
- }
440
-
441
- export {
442
- xlsxToMarkdownDoc,
443
- markdownDocToXlsx,
444
- docToXlsx,
445
- xlsxToDoc
446
- };
@@ -1,81 +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
9
- * sheet list, resolves each sheet part via relationships, pulls shared strings,
10
- * and turns each worksheet's cell grid into a markdown table (first row treated
11
- * as the header). By default every sheet is imported, each preceded by an H1 of
12
- * the sheet name; pass `options.sheet` (index or name) to import just one.
13
- */
14
-
15
- interface XlsxImportOptions extends OoxmlOpenOptions {
16
- /** Which sheet to import (0-based index or sheet name). Default: all sheets. */
17
- sheet?: number | string;
18
- }
19
- declare function xlsxToMarkdownDoc(data: ArrayBuffer | Blob, options?: XlsxImportOptions): Promise<MarkdownDocument>;
20
-
21
- /**
22
- * XLSX export — MarkdownDocument → SpreadsheetML (.xlsx).
23
- *
24
- * Tables-only fidelity (honestly documented): every `table` node in the
25
- * markdown AST becomes one worksheet; all other content (headings, prose,
26
- * lists, images, …) is dropped except that the nearest preceding heading is
27
- * used to name the sheet. This mirrors the import side (`xlsxToMarkdownDoc`),
28
- * which turns each worksheet grid back into a markdown table.
29
- *
30
- * Cells are emitted as inline strings (`t="inlineStr"`) by default so no
31
- * sharedStrings part is needed and identifier-like numbers remain lossless.
32
- * Callers can explicitly opt into conservative numeric inference. The package
33
- * is assembled with the shared ooxml/ writer (auto-generates
34
- * `[Content_Types].xml` + `_rels`), so only the SpreadsheetML-specific parts
35
- * (workbook, worksheets, styles) are written here.
36
- *
37
- * @example
38
- * ```ts
39
- * import { parseMarkdown } from '@bendyline/squisq/markdown';
40
- * import { markdownDocToXlsx } from '@bendyline/squisq-formats/xlsx';
41
- *
42
- * const md = parseMarkdown('# Metrics\n\n| A | B |\n| - | - |\n| 1 | 2 |');
43
- * const buffer = await markdownDocToXlsx(md);
44
- * ```
45
- */
46
-
47
- /**
48
- * Options for XLSX export.
49
- */
50
- interface XlsxExportOptions {
51
- /** Cancel at bounded export checkpoints. */
52
- signal?: AbortSignal;
53
- /** Maximum cells emitted. Default: 100,000. */
54
- maxCells?: number;
55
- /** Workbook title (written to core properties). */
56
- title?: string;
57
- /** Workbook author (written to core properties). */
58
- author?: string;
59
- /** Prefix used for auto-named sheets when no heading precedes a table. Default: "Sheet". */
60
- sheetNamePrefix?: string;
61
- /**
62
- * Emit canonical, Excel-safe number strings as numeric cells. Default false:
63
- * Markdown tables have no column schema, so preserving authored text is the
64
- * only lossless default. Leading-zero and >15-significant-digit values remain
65
- * strings even when this option is enabled.
66
- */
67
- inferNumericCells?: boolean;
68
- }
69
- /**
70
- * Convert a MarkdownDocument to a .xlsx file (tables-only fidelity).
71
- *
72
- * Each markdown `table` becomes one worksheet; a document with no tables
73
- * yields a single empty sheet (a valid, openable file — never throws).
74
- */
75
- declare function markdownDocToXlsx(doc: MarkdownDocument, options?: XlsxExportOptions): Promise<ArrayBuffer>;
76
- /**
77
- * Convert a squisq Doc to a .xlsx file (via the markdown table model).
78
- */
79
- declare function docToXlsx(doc: Doc, options?: XlsxExportOptions): Promise<ArrayBuffer>;
80
-
81
- export { type XlsxExportOptions as X, type XlsxImportOptions as a, docToXlsx as d, markdownDocToXlsx as m, xlsxToMarkdownDoc as x };