@bendyline/squisq-formats 2.5.1 → 2.6.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.
Files changed (41) hide show
  1. package/NOTICE.md +10 -9
  2. package/dist/{chunk-TVUX3RUC.js → chunk-2OCP46K5.js} +10 -3
  3. package/dist/{chunk-2LT3JL7U.js → chunk-3ITGQRL5.js} +8 -8
  4. package/dist/{chunk-FMQWNPCV.js → chunk-AGGNLRHV.js} +6 -6
  5. package/dist/{chunk-AONELFLA.js → chunk-B7GEAZBI.js} +6 -1
  6. package/dist/chunk-CKSTGNVZ.js +724 -0
  7. package/dist/chunk-DXYWKZ52.js +57 -0
  8. package/dist/chunk-FLR2ARKC.js +240 -0
  9. package/dist/{chunk-5JQ5NDRC.js → chunk-JPU5GPGG.js} +64 -12
  10. package/dist/{chunk-RX55T5HO.js → chunk-OBADJV7C.js} +136 -415
  11. package/dist/{chunk-T4PX33AG.js → chunk-POO3PJFH.js} +23 -3
  12. package/dist/{chunk-AD2WT564.js → chunk-Q77KNJIN.js} +45 -0
  13. package/dist/{chunk-6RQOV3B3.js → chunk-VPWPEMZJ.js} +1 -1
  14. package/dist/{chunk-FIOSE4BO.js → chunk-XJNOZTAY.js} +6 -6
  15. package/dist/csv/index.d.ts +67 -1
  16. package/dist/csv/index.js +10 -3
  17. package/dist/data/index.d.ts +78 -0
  18. package/dist/data/index.js +30 -0
  19. package/dist/docx/index.js +3 -3
  20. package/dist/epub/index.js +4 -4
  21. package/dist/{export-Boq78GMq.d.ts → export-6iQXd-lQ.d.ts} +98 -2
  22. package/dist/html/index.d.ts +2 -8
  23. package/dist/html/index.js +3 -3
  24. package/dist/{images-ESPQKVTW.js → images-JLBFCDD4.js} +1 -1
  25. package/dist/{import-B0gBYUmd.d.ts → import-D59rxNTj.d.ts} +11 -3
  26. package/dist/index.d.ts +3 -3
  27. package/dist/index.js +29 -26
  28. package/dist/infer/index.js +6 -6
  29. package/dist/materialize-A34OZGEU.js +11 -0
  30. package/dist/outside-in/index.d.ts +4 -4
  31. package/dist/outside-in/index.js +2 -2
  32. package/dist/pdf/index.js +2 -2
  33. package/dist/pptx/index.js +3 -3
  34. package/dist/registry/index.d.ts +4 -4
  35. package/dist/registry/index.js +1 -1
  36. package/dist/{types-bwP9PBSk.d.ts → types-BD23kHNG.d.ts} +5 -5
  37. package/dist/xlsx/index.d.ts +85 -4
  38. package/dist/xlsx/index.js +21 -4
  39. package/package.json +17 -2
  40. package/dist/{chunk-KMBBO5H7.js → chunk-7DQP2I57.js} +4 -4
  41. package/dist/{chunk-M7XPXGXW.js → chunk-ROF7SSQP.js} +3 -3
@@ -0,0 +1,724 @@
1
+ import {
2
+ extractPlainText,
3
+ inlineToPlainText
4
+ } from "./chunk-AVOZAKGP.js";
5
+ import {
6
+ MAX_COL_INDEX,
7
+ MAX_ROW_INDEX,
8
+ colIndex,
9
+ columnIndexFromLetters,
10
+ columnLetter,
11
+ formatCellRef,
12
+ listSheetParts,
13
+ numberFormatKind,
14
+ parseCellRef,
15
+ readCellStyles,
16
+ xlsxToMarkdownDoc
17
+ } from "./chunk-OBADJV7C.js";
18
+ import {
19
+ createPackage
20
+ } from "./chunk-ILCJ3WFD.js";
21
+ import {
22
+ escapeXml,
23
+ xmlDeclaration
24
+ } from "./chunk-JU2RHXUB.js";
25
+ import {
26
+ CONTENT_TYPE_XLSX_STYLES,
27
+ CONTENT_TYPE_XLSX_WORKBOOK,
28
+ CONTENT_TYPE_XLSX_WORKSHEET,
29
+ NS_R,
30
+ NS_SML,
31
+ REL_OFFICE_DOCUMENT,
32
+ REL_STYLES,
33
+ REL_WORKSHEET,
34
+ getPartBinary,
35
+ openPackage,
36
+ requireMainPartPath
37
+ } from "./chunk-S5PCVMKU.js";
38
+
39
+ // src/xlsx/index.ts
40
+ import { markdownToDoc } from "@bendyline/squisq/doc";
41
+
42
+ // src/xlsx/export.ts
43
+ import { docToMarkdown } from "@bendyline/squisq/doc";
44
+
45
+ // src/xlsx/workbookPlan.ts
46
+ function hasRichCellContent(nodes) {
47
+ return nodes.some(
48
+ (n) => n.type === "superscript" || n.type === "subscript" || "children" in n && Array.isArray(n.children) && hasRichCellContent(n.children)
49
+ );
50
+ }
51
+ var KEY_STRIDE = MAX_COL_INDEX + 1;
52
+ function cellKey(row, col) {
53
+ return row * KEY_STRIDE + col;
54
+ }
55
+ function keyRow(key) {
56
+ return Math.floor(key / KEY_STRIDE);
57
+ }
58
+ function keyCol(key) {
59
+ return key - keyRow(key) * KEY_STRIDE;
60
+ }
61
+ function tableToGrid(table) {
62
+ return table.children.map(
63
+ (row) => row.children.map((cell) => extractPlainText(cell.children))
64
+ );
65
+ }
66
+ function tableToRichGrid(table) {
67
+ return table.children.map(
68
+ (row) => row.children.map((cell) => hasRichCellContent(cell.children) ? cell.children : void 0)
69
+ );
70
+ }
71
+ function readRole(raw) {
72
+ return raw === "formulas" || raw === "loose" ? raw : "values";
73
+ }
74
+ function collectEntries(nodes) {
75
+ const entries = [];
76
+ let pending = null;
77
+ for (const node of nodes) {
78
+ if (node.type === "heading") {
79
+ pending = node;
80
+ continue;
81
+ }
82
+ if (node.type !== "table") continue;
83
+ const params = pending?.templateAnnotation?.params ?? {};
84
+ const sheetKey = typeof params.sheet === "string" && params.sheet !== "" ? params.sheet : null;
85
+ entries.push({
86
+ table: node,
87
+ headingText: pending ? extractPlainText(pending.children) : "",
88
+ params,
89
+ sheetKey,
90
+ role: readRole(params.role)
91
+ });
92
+ pending = null;
93
+ }
94
+ return entries;
95
+ }
96
+ function groupEntries(entries) {
97
+ const groups = [];
98
+ const bySheet = /* @__PURE__ */ new Map();
99
+ for (const entry of entries) {
100
+ if (entry.sheetKey !== null) {
101
+ let group = bySheet.get(entry.sheetKey);
102
+ if (!group) {
103
+ group = { candidate: entry.sheetKey, entries: [], anchored: true };
104
+ bySheet.set(entry.sheetKey, group);
105
+ groups.push(group);
106
+ }
107
+ group.entries.push(entry);
108
+ continue;
109
+ }
110
+ groups.push({ candidate: entry.headingText || null, entries: [entry], anchored: false });
111
+ }
112
+ return groups;
113
+ }
114
+ function place(cells, row, col, cell, clashes) {
115
+ const key = cellKey(row, col);
116
+ if (cells.has(key)) clashes.push(formatCellRef(row, col));
117
+ cells.set(key, cell);
118
+ }
119
+ function overlayFormula(cells, row, col, formula) {
120
+ const key = cellKey(row, col);
121
+ const existing = cells.get(key);
122
+ cells.set(key, { text: existing?.text ?? "", formula });
123
+ }
124
+ function formulaSource(raw) {
125
+ const trimmed = raw.trim();
126
+ return trimmed.startsWith("=") ? trimmed.slice(1) : trimmed;
127
+ }
128
+ function placeValues(entry, cells, warnings, sheetName, clashes) {
129
+ const grid = tableToGrid(entry.table);
130
+ const richGrid = tableToRichGrid(entry.table);
131
+ const anchorRaw = entry.params.anchor ?? "A1";
132
+ let anchor = parseCellRef(anchorRaw);
133
+ if (!anchor) {
134
+ warnings.push(
135
+ `Sheet "${sheetName}": anchor "${anchorRaw}" is not a valid cell reference; placed at A1 instead.`
136
+ );
137
+ anchor = { row: 0, col: 0 };
138
+ }
139
+ const height = grid.length;
140
+ const width = grid.reduce((m, r) => Math.max(m, r.length), 0);
141
+ if (anchor.row + height - 1 > MAX_ROW_INDEX || anchor.col + width - 1 > MAX_COL_INDEX) {
142
+ warnings.push(
143
+ `Sheet "${sheetName}": a table anchored at ${anchorRaw} runs past the end of the sheet; placed at A1 instead.`
144
+ );
145
+ anchor = { row: 0, col: 0 };
146
+ }
147
+ const titleRef = entry.params.titleAnchor;
148
+ if (titleRef !== void 0 && entry.headingText !== "") {
149
+ const at = parseCellRef(titleRef);
150
+ if (at) place(cells, at.row, at.col, { text: entry.headingText }, clashes);
151
+ }
152
+ for (let r = 0; r < grid.length; r++) {
153
+ const row = grid[r];
154
+ for (let c = 0; c < row.length; c++) {
155
+ const text = row[c];
156
+ if (text === "") continue;
157
+ const rich = richGrid[r]?.[c];
158
+ place(cells, anchor.row + r, anchor.col + c, rich ? { text, rich } : { text }, clashes);
159
+ }
160
+ }
161
+ }
162
+ function placeFormulas(entry, cells, warnings, sheetName) {
163
+ const grid = tableToGrid(entry.table);
164
+ if (grid.length < 2) return;
165
+ const anchorRaw = entry.params.anchor ?? "A1";
166
+ const anchor = parseCellRef(anchorRaw);
167
+ if (!anchor) {
168
+ warnings.push(
169
+ `Sheet "${sheetName}": formulas block anchor "${anchorRaw}" is not a valid cell reference; skipped.`
170
+ );
171
+ return;
172
+ }
173
+ const columns = grid[0].map((letters) => {
174
+ const trimmed = letters.trim();
175
+ if (!/^[A-Za-z]{1,3}$/.test(trimmed)) return -1;
176
+ const col = columnIndexFromLetters(trimmed);
177
+ return col >= 0 && col <= MAX_COL_INDEX ? col : -1;
178
+ });
179
+ for (let r = 1; r < grid.length; r++) {
180
+ const row = grid[r];
181
+ for (let c = 0; c < row.length; c++) {
182
+ const raw = row[c];
183
+ if (raw.trim() === "") continue;
184
+ const mapped = columns[c];
185
+ const col = mapped !== void 0 && mapped >= 0 ? mapped : anchor.col + c;
186
+ const targetRow = anchor.row + r - 1;
187
+ if (targetRow > MAX_ROW_INDEX) continue;
188
+ overlayFormula(cells, targetRow, col, formulaSource(raw));
189
+ }
190
+ }
191
+ }
192
+ function placeLoose(entry, cells, warnings, sheetName, clashes) {
193
+ const grid = tableToGrid(entry.table);
194
+ const richGrid = tableToRichGrid(entry.table);
195
+ let skipped = 0;
196
+ for (let r = 1; r < grid.length; r++) {
197
+ const row = grid[r];
198
+ const ref = (row[0] ?? "").trim();
199
+ if (ref === "") continue;
200
+ const at = parseCellRef(ref);
201
+ if (!at) {
202
+ skipped++;
203
+ continue;
204
+ }
205
+ const text = row[1] ?? "";
206
+ const formula = formulaSource(row[2] ?? "");
207
+ const rich = richGrid[r]?.[1];
208
+ const planned = { text };
209
+ if (formula !== "") planned.formula = formula;
210
+ if (rich) planned.rich = rich;
211
+ place(cells, at.row, at.col, planned, clashes);
212
+ }
213
+ if (skipped > 0) {
214
+ warnings.push(
215
+ `Sheet "${sheetName}": ${skipped} loose-cell row(s) had an invalid cell reference and were skipped.`
216
+ );
217
+ }
218
+ }
219
+ function planWorkbook(doc, options) {
220
+ const warnings = [];
221
+ const groups = groupEntries(collectEntries(doc.children));
222
+ const used = /* @__PURE__ */ new Set();
223
+ const sheets = [];
224
+ groups.forEach((group, index) => {
225
+ const fallback = `${options.sheetNamePrefix}${index + 1}`;
226
+ const name = options.sanitize(group.candidate ?? fallback, used, fallback);
227
+ const cells = /* @__PURE__ */ new Map();
228
+ const clashes = [];
229
+ for (const entry of group.entries) {
230
+ if (entry.role === "values") placeValues(entry, cells, warnings, name, clashes);
231
+ }
232
+ for (const entry of group.entries) {
233
+ if (entry.role === "formulas") placeFormulas(entry, cells, warnings, name);
234
+ }
235
+ for (const entry of group.entries) {
236
+ if (entry.role === "loose") placeLoose(entry, cells, warnings, name, clashes);
237
+ }
238
+ if (clashes.length > 0) {
239
+ const shown = clashes.slice(0, 5).join(", ");
240
+ const rest = clashes.length > 5 ? ", and more" : "";
241
+ warnings.push(
242
+ `Sheet "${name}": ${clashes.length} overlapping cell(s) (${shown}${rest}); the later block won.`
243
+ );
244
+ }
245
+ sheets.push({ name, cells, anchored: group.anchored });
246
+ });
247
+ let cellCount = 0;
248
+ for (const sheet of sheets) cellCount += sheet.cells.size;
249
+ return { sheets, warnings, cellCount };
250
+ }
251
+
252
+ // src/xlsx/export.ts
253
+ var NUMERIC_RE = /^-?\d+(\.\d+)?$/;
254
+ function isSafeNumericCell(value) {
255
+ if (!NUMERIC_RE.test(value)) return false;
256
+ const unsigned = value.startsWith("-") ? value.slice(1) : value;
257
+ const [integer] = unsigned.split(".");
258
+ if (integer.length > 1 && integer.startsWith("0")) return false;
259
+ const significantDigits = unsigned.replace(".", "").replace(/^0+/, "");
260
+ if (significantDigits.length > 15) return false;
261
+ return Number.isFinite(Number(value));
262
+ }
263
+ function cleanSheetName(raw) {
264
+ return raw.replace(/[[\]:*?/\\]/g, "").trim().slice(0, 31).trim().replace(/^'+|'+$/g, "");
265
+ }
266
+ function sanitizeSheetName(candidate, used, fallback) {
267
+ let base = cleanSheetName(candidate) || cleanSheetName(fallback) || "Sheet";
268
+ let name = base;
269
+ let n = 2;
270
+ while (used.has(name.toLocaleLowerCase("en-US"))) {
271
+ const suffix = String(n++);
272
+ base = base.slice(0, 31 - suffix.length);
273
+ name = `${base}${suffix}`;
274
+ }
275
+ used.add(name.toLocaleLowerCase("en-US"));
276
+ return name;
277
+ }
278
+ var ERROR_VALUE_RE = /^#[A-Z0-9_/]+[!?]?$/;
279
+ function cellXml(cell, ref, inferNumericCells) {
280
+ const { text, formula } = cell;
281
+ if (formula !== void 0 && formula !== "") {
282
+ const f = `<f>${escapeXml(formula)}</f>`;
283
+ if (text === "") return `<c r="${ref}">${f}</c>`;
284
+ if (isSafeNumericCell(text)) return `<c r="${ref}">${f}<v>${escapeXml(text)}</v></c>`;
285
+ if (ERROR_VALUE_RE.test(text)) return `<c r="${ref}" t="e">${f}<v>${escapeXml(text)}</v></c>`;
286
+ return `<c r="${ref}" t="str">${f}<v>${escapeXml(text)}</v></c>`;
287
+ }
288
+ if (inferNumericCells && isSafeNumericCell(text)) {
289
+ return `<c r="${ref}"><v>${escapeXml(text)}</v></c>`;
290
+ }
291
+ if (cell.rich) {
292
+ return `<c r="${ref}" t="inlineStr"><is>${richRunsXml(cell.rich)}</is></c>`;
293
+ }
294
+ return `<c r="${ref}" t="inlineStr"><is><t xml:space="preserve">${escapeXml(text)}</t></is></c>`;
295
+ }
296
+ function richRunsXml(nodes) {
297
+ const runs = [];
298
+ const emit = (text, vertAlign) => {
299
+ if (text === "") return;
300
+ const rPr = vertAlign ? `<rPr><vertAlign val="${vertAlign}"/></rPr>` : "";
301
+ runs.push(`<r>${rPr}<t xml:space="preserve">${escapeXml(text)}</t></r>`);
302
+ };
303
+ const walk = (list, vertAlign) => {
304
+ for (const node of list) {
305
+ if (node.type === "superscript" || node.type === "subscript") {
306
+ walk(node.children, node.type === "superscript" ? "superscript" : "subscript");
307
+ } else if ("children" in node && Array.isArray(node.children)) {
308
+ walk(node.children, vertAlign);
309
+ } else {
310
+ emit(inlineToPlainText(node), vertAlign);
311
+ }
312
+ }
313
+ };
314
+ walk(nodes, null);
315
+ return runs.join("");
316
+ }
317
+ function worksheetXml(sheet, inferNumericCells) {
318
+ const keys = [...sheet.cells.keys()].sort((a, b) => a - b);
319
+ const rows = [];
320
+ let maxRow = 0;
321
+ let maxCol = 0;
322
+ let i = 0;
323
+ while (i < keys.length) {
324
+ const rowIdx = keyRow(keys[i]);
325
+ let cellsXml = "";
326
+ while (i < keys.length && keyRow(keys[i]) === rowIdx) {
327
+ const key = keys[i];
328
+ const col = keyCol(key);
329
+ if (col > maxCol) maxCol = col;
330
+ cellsXml += cellXml(
331
+ sheet.cells.get(key),
332
+ `${columnLetter(col)}${rowIdx + 1}`,
333
+ inferNumericCells
334
+ );
335
+ i++;
336
+ }
337
+ if (rowIdx > maxRow) maxRow = rowIdx;
338
+ rows.push(`<row r="${rowIdx + 1}">${cellsXml}</row>`);
339
+ }
340
+ const dimension = keys.length > 0 ? `A1:${columnLetter(maxCol)}${maxRow + 1}` : "A1";
341
+ return `${xmlDeclaration()}
342
+ <worksheet xmlns="${NS_SML}" xmlns:r="${NS_R}"><dimension ref="${dimension}"/><sheetData>${rows.join("")}</sheetData></worksheet>`;
343
+ }
344
+ function workbookXml(sheets, hasFormulas) {
345
+ const sheetEls = sheets.map(
346
+ (sheet, i) => `<sheet name="${escapeXml(sheet.name)}" sheetId="${i + 1}" r:id="rId${i + 1}"/>`
347
+ ).join("");
348
+ const calcPr = hasFormulas ? `<calcPr calcId="0" fullCalcOnLoad="1"/>` : "";
349
+ return `${xmlDeclaration()}
350
+ <workbook xmlns="${NS_SML}" xmlns:r="${NS_R}"><sheets>${sheetEls}</sheets>${calcPr}</workbook>`;
351
+ }
352
+ function stylesXml() {
353
+ return `${xmlDeclaration()}
354
+ <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>`;
355
+ }
356
+ async function markdownDocToXlsx(doc, options = {}) {
357
+ options.signal?.throwIfAborted();
358
+ const prefix = cleanSheetName(options.sheetNamePrefix ?? "Sheet") || "Sheet";
359
+ const maxCells = options.maxCells ?? 1e5;
360
+ if (!Number.isSafeInteger(maxCells) || maxCells < 0) {
361
+ throw new RangeError("maxCells must be a non-negative safe integer");
362
+ }
363
+ const plan = planWorkbook(doc, { sheetNamePrefix: prefix, sanitize: sanitizeSheetName });
364
+ for (const warning of plan.warnings) options.onWarning?.(warning);
365
+ if (plan.cellCount > maxCells) {
366
+ throw new RangeError(`XLSX export exceeds the ${maxCells}-cell safety limit`);
367
+ }
368
+ let sheets = plan.sheets;
369
+ if (sheets.length === 0) {
370
+ sheets = [
371
+ {
372
+ name: sanitizeSheetName(`${prefix}1`, /* @__PURE__ */ new Set(), "Sheet1"),
373
+ cells: /* @__PURE__ */ new Map(),
374
+ anchored: false
375
+ }
376
+ ];
377
+ }
378
+ const anchored = sheets.some((sheet) => sheet.anchored);
379
+ const inferNumericCells = options.inferNumericCells ?? anchored;
380
+ const hasFormulas = sheets.some((sheet) => {
381
+ for (const cell of sheet.cells.values()) if (cell.formula) return true;
382
+ return false;
383
+ });
384
+ const pkg = createPackage();
385
+ sheets.forEach((sheet, i) => {
386
+ if ((i & 31) === 0) options.signal?.throwIfAborted();
387
+ const sheetPath = `xl/worksheets/sheet${i + 1}.xml`;
388
+ pkg.addPart(sheetPath, worksheetXml(sheet, inferNumericCells), CONTENT_TYPE_XLSX_WORKSHEET);
389
+ pkg.addRelationship("xl/workbook.xml", {
390
+ id: `rId${i + 1}`,
391
+ type: REL_WORKSHEET,
392
+ target: `worksheets/sheet${i + 1}.xml`
393
+ });
394
+ });
395
+ pkg.addPart("xl/styles.xml", stylesXml(), CONTENT_TYPE_XLSX_STYLES);
396
+ pkg.addRelationship("xl/workbook.xml", {
397
+ id: `rId${sheets.length + 1}`,
398
+ type: REL_STYLES,
399
+ target: "styles.xml"
400
+ });
401
+ pkg.addPart("xl/workbook.xml", workbookXml(sheets, hasFormulas), CONTENT_TYPE_XLSX_WORKBOOK);
402
+ pkg.addRelationship("", {
403
+ id: "rId1",
404
+ type: REL_OFFICE_DOCUMENT,
405
+ target: "xl/workbook.xml"
406
+ });
407
+ if (options.title || options.author) {
408
+ pkg.setCoreProperties({
409
+ title: options.title,
410
+ creator: options.author,
411
+ created: (/* @__PURE__ */ new Date()).toISOString(),
412
+ modified: (/* @__PURE__ */ new Date()).toISOString()
413
+ });
414
+ }
415
+ return pkg.toArrayBuffer();
416
+ }
417
+ async function docToXlsx(doc, options) {
418
+ return markdownDocToXlsx(docToMarkdown(doc), options);
419
+ }
420
+
421
+ // src/xlsx/patch.ts
422
+ import JSZip from "jszip";
423
+ import { DOMParser as XmldomDOMParser, XMLSerializer as XmldomXMLSerializer } from "@xmldom/xmldom";
424
+ var XLSX_MAIN_PART = "xl/workbook.xml";
425
+ var XlsxPatchRefusal = class extends Error {
426
+ constructor(code, sheet, ref, message) {
427
+ super(message);
428
+ this.name = "XlsxPatchRefusal";
429
+ this.code = code;
430
+ this.sheet = sheet;
431
+ this.ref = ref;
432
+ }
433
+ };
434
+ function parsePart(text) {
435
+ const doc = new XmldomDOMParser().parseFromString(text, "application/xml");
436
+ const errors = doc.getElementsByTagName("parsererror");
437
+ if (errors.length > 0) {
438
+ throw new Error(`Invalid XLSX XML part: ${errors[0]?.textContent ?? "parse error"}`);
439
+ }
440
+ return doc;
441
+ }
442
+ function serializePart(doc, originalText) {
443
+ const serialized = new XmldomXMLSerializer().serializeToString(
444
+ doc
445
+ );
446
+ if (serialized.startsWith("<?xml")) return serialized;
447
+ const decl = /^\uFEFF?<\?xml[^>]*\?>\s*/.exec(originalText);
448
+ return decl ? decl[0] + serialized : serialized;
449
+ }
450
+ async function readRawPart(pkg, path) {
451
+ const bytes = await getPartBinary(pkg, path);
452
+ if (!bytes) throw new Error(`Invalid XLSX package: part "${path}" is missing.`);
453
+ const text = new TextDecoder().decode(bytes);
454
+ return { text, doc: parsePart(text) };
455
+ }
456
+ function childElementsNS(parent, local) {
457
+ const out = [];
458
+ for (let node = parent.firstChild; node; node = node.nextSibling) {
459
+ if (node.nodeType !== 1) continue;
460
+ const el = node;
461
+ if (el.localName === local && el.namespaceURI === NS_SML) out.push(el);
462
+ }
463
+ return out;
464
+ }
465
+ function firstChildNS(parent, local) {
466
+ return childElementsNS(parent, local)[0] ?? null;
467
+ }
468
+ function findOrCreateRow(doc, sheetData, rowNumber) {
469
+ let insertBefore = null;
470
+ for (const row of childElementsNS(sheetData, "row")) {
471
+ const r = Number.parseInt(row.getAttribute("r") ?? "", 10);
472
+ if (r === rowNumber) return row;
473
+ if (Number.isFinite(r) && r > rowNumber && !insertBefore) insertBefore = row;
474
+ }
475
+ const created = doc.createElementNS(NS_SML, "row");
476
+ created.setAttribute("r", String(rowNumber));
477
+ sheetData.insertBefore(created, insertBefore);
478
+ return created;
479
+ }
480
+ function findOrCreateCell(doc, row, ref) {
481
+ const targetCol = colIndex(ref);
482
+ let insertBefore = null;
483
+ for (const cell of childElementsNS(row, "c")) {
484
+ const cellRef = cell.getAttribute("r");
485
+ if (cellRef === ref) return cell;
486
+ if (cellRef && colIndex(cellRef) > targetCol && !insertBefore) insertBefore = cell;
487
+ }
488
+ const created = doc.createElementNS(NS_SML, "c");
489
+ created.setAttribute("r", ref);
490
+ row.insertBefore(created, insertBefore);
491
+ return created;
492
+ }
493
+ function refuseFormulaCell(cell, sheet, ref) {
494
+ const f = firstChildNS(cell, "f");
495
+ if (!f) return;
496
+ const isSharedFollower = f.getAttribute("t") === "shared" && (f.textContent ?? "").trim() === "";
497
+ throw new XlsxPatchRefusal(
498
+ isSharedFollower ? "shared-formula-follower" : "formula-cell",
499
+ sheet,
500
+ ref,
501
+ isSharedFollower ? `${sheet}!${ref} continues a shared (fill-down) formula; formula cells cannot be patched` : `${sheet}!${ref} holds a formula; formula cells cannot be patched`
502
+ );
503
+ }
504
+ function refuseDateStyled(cell, styles, sheet, ref, value) {
505
+ if (value === null) return;
506
+ const styleIndex = Number.parseInt(cell.getAttribute("s") ?? "", 10);
507
+ if (!Number.isFinite(styleIndex)) return;
508
+ const style = styles[styleIndex];
509
+ if (!style) return;
510
+ const kind = numberFormatKind(style.formatCode);
511
+ if (kind === "date" || kind === "time" || kind === "datetime") {
512
+ throw new XlsxPatchRefusal(
513
+ "date-value-unsupported",
514
+ sheet,
515
+ ref,
516
+ `${sheet}!${ref} is date-formatted; date values are not supported by in-place patching`
517
+ );
518
+ }
519
+ }
520
+ function clearCellContent(cell) {
521
+ for (const local of ["v", "is"]) {
522
+ for (const el of childElementsNS(cell, local)) cell.removeChild(el);
523
+ }
524
+ }
525
+ function writeCellValue(doc, cell, value) {
526
+ clearCellContent(cell);
527
+ if (value === null) {
528
+ cell.removeAttribute("t");
529
+ return;
530
+ }
531
+ if (typeof value === "number") {
532
+ cell.removeAttribute("t");
533
+ const v = doc.createElementNS(NS_SML, "v");
534
+ v.appendChild(doc.createTextNode(String(value)));
535
+ cell.appendChild(v);
536
+ return;
537
+ }
538
+ if (typeof value === "boolean") {
539
+ cell.setAttribute("t", "b");
540
+ const v = doc.createElementNS(NS_SML, "v");
541
+ v.appendChild(doc.createTextNode(value ? "1" : "0"));
542
+ cell.appendChild(v);
543
+ return;
544
+ }
545
+ cell.setAttribute("t", "inlineStr");
546
+ const is = doc.createElementNS(NS_SML, "is");
547
+ const t = doc.createElementNS(NS_SML, "t");
548
+ if (value !== value.trim())
549
+ t.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve");
550
+ t.appendChild(doc.createTextNode(value));
551
+ is.appendChild(t);
552
+ cell.appendChild(is);
553
+ }
554
+ function refuseSharedMaster(cell, sheet, ref) {
555
+ const f = firstChildNS(cell, "f");
556
+ if (!f) return;
557
+ if (f.getAttribute("t") === "shared" && (f.textContent ?? "").trim() !== "") {
558
+ throw new XlsxPatchRefusal(
559
+ "shared-formula-master",
560
+ sheet,
561
+ ref,
562
+ `${sheet}!${ref} is the master of a shared (fill-down) formula group; replacing it would orphan its followers`
563
+ );
564
+ }
565
+ }
566
+ function clearCellFormula(cell) {
567
+ for (const el of childElementsNS(cell, "f")) cell.removeChild(el);
568
+ }
569
+ function writeCellFormula(doc, cell, formula, cachedValue) {
570
+ clearCellFormula(cell);
571
+ clearCellContent(cell);
572
+ cell.removeAttribute("t");
573
+ const f = doc.createElementNS(NS_SML, "f");
574
+ f.appendChild(doc.createTextNode(formula));
575
+ cell.appendChild(f);
576
+ if (cachedValue === void 0) return;
577
+ const v = doc.createElementNS(NS_SML, "v");
578
+ if (typeof cachedValue === "number") {
579
+ v.appendChild(doc.createTextNode(String(cachedValue)));
580
+ } else if (typeof cachedValue === "boolean") {
581
+ cell.setAttribute("t", "b");
582
+ v.appendChild(doc.createTextNode(cachedValue ? "1" : "0"));
583
+ } else {
584
+ cell.setAttribute("t", "str");
585
+ v.appendChild(doc.createTextNode(cachedValue));
586
+ }
587
+ cell.appendChild(v);
588
+ }
589
+ var AFTER_CALC_PR = /* @__PURE__ */ new Set([
590
+ "oleSize",
591
+ "customWorkbookViews",
592
+ "pivotCaches",
593
+ "smartTagPr",
594
+ "smartTagTypes",
595
+ "webPublishing",
596
+ "fileRecoveryPr",
597
+ "webPublishObjects",
598
+ "extLst"
599
+ ]);
600
+ function setFullCalcOnLoad(doc) {
601
+ const root = doc.documentElement;
602
+ if (!root) return;
603
+ const existing = firstChildNS(root, "calcPr");
604
+ if (existing) {
605
+ existing.setAttribute("fullCalcOnLoad", "1");
606
+ return;
607
+ }
608
+ const calcPr = doc.createElementNS(NS_SML, "calcPr");
609
+ calcPr.setAttribute("fullCalcOnLoad", "1");
610
+ let insertBefore = null;
611
+ for (let node = root.firstChild; node; node = node.nextSibling) {
612
+ if (node.nodeType !== 1) continue;
613
+ const el = node;
614
+ if (el.namespaceURI === NS_SML && AFTER_CALC_PR.has(el.localName)) {
615
+ insertBefore = node;
616
+ break;
617
+ }
618
+ }
619
+ root.insertBefore(calcPr, insertBefore);
620
+ }
621
+ async function patchXlsxCellValues(bytes, patches, options = {}) {
622
+ const pkg = await openPackage(bytes, options);
623
+ const mainPart = requireMainPartPath(pkg, XLSX_MAIN_PART, "XLSX");
624
+ const sheets = await listSheetParts(pkg, mainPart);
625
+ const styles = await readCellStyles(pkg);
626
+ const sheetByName = new Map(sheets.map((sheet) => [sheet.name, sheet.path]));
627
+ for (const patch of patches) {
628
+ if (!sheetByName.has(patch.sheet)) {
629
+ throw new XlsxPatchRefusal(
630
+ "sheet-missing",
631
+ patch.sheet,
632
+ patch.ref,
633
+ `workbook has no sheet named "${patch.sheet}"`
634
+ );
635
+ }
636
+ if (!parseCellRef(patch.ref)) {
637
+ throw new XlsxPatchRefusal(
638
+ "cell-ref-invalid",
639
+ patch.sheet,
640
+ patch.ref,
641
+ `"${patch.ref}" is not a valid cell reference`
642
+ );
643
+ }
644
+ const hasValue = patch.value !== void 0;
645
+ const hasFormula = patch.formula !== void 0;
646
+ if (hasValue === hasFormula) {
647
+ throw new XlsxPatchRefusal(
648
+ "patch-invalid",
649
+ patch.sheet,
650
+ patch.ref,
651
+ `${patch.sheet}!${patch.ref}: a patch carries exactly one of value or formula`
652
+ );
653
+ }
654
+ if (hasFormula && patch.formula.trim() === "") {
655
+ throw new XlsxPatchRefusal(
656
+ "patch-invalid",
657
+ patch.sheet,
658
+ patch.ref,
659
+ `${patch.sheet}!${patch.ref}: formula must be non-empty`
660
+ );
661
+ }
662
+ const numericCandidate = hasFormula ? patch.cachedValue : patch.value;
663
+ if (typeof numericCandidate === "number" && !Number.isFinite(numericCandidate)) {
664
+ throw new XlsxPatchRefusal(
665
+ "number-not-finite",
666
+ patch.sheet,
667
+ patch.ref,
668
+ `${patch.sheet}!${patch.ref}: only finite numbers can be written`
669
+ );
670
+ }
671
+ }
672
+ const touched = /* @__PURE__ */ new Map();
673
+ for (const patch of patches) {
674
+ const path = sheetByName.get(patch.sheet);
675
+ let part = touched.get(path);
676
+ if (!part) {
677
+ part = await readRawPart(pkg, path);
678
+ touched.set(path, part);
679
+ }
680
+ const parsed = parseCellRef(patch.ref);
681
+ const normalizedRef = formatCellRef(parsed.row, parsed.col);
682
+ const sheetData = firstChildNS(part.doc.documentElement, "sheetData");
683
+ if (!sheetData) {
684
+ throw new Error(`Invalid worksheet part "${path}": no <sheetData> element.`);
685
+ }
686
+ const row = findOrCreateRow(part.doc, sheetData, parsed.row + 1);
687
+ const cell = findOrCreateCell(part.doc, row, normalizedRef);
688
+ if (patch.formula !== void 0) {
689
+ refuseSharedMaster(cell, patch.sheet, normalizedRef);
690
+ writeCellFormula(part.doc, cell, patch.formula, patch.cachedValue);
691
+ } else {
692
+ refuseFormulaCell(cell, patch.sheet, normalizedRef);
693
+ refuseDateStyled(cell, styles, patch.sheet, normalizedRef, patch.value ?? null);
694
+ writeCellValue(part.doc, cell, patch.value ?? null);
695
+ }
696
+ }
697
+ if (touched.size > 0) {
698
+ const workbook = await readRawPart(pkg, mainPart);
699
+ setFullCalcOnLoad(workbook.doc);
700
+ touched.set(mainPart, workbook);
701
+ }
702
+ const zip = await JSZip.loadAsync(bytes);
703
+ for (const [path, part] of touched) {
704
+ zip.file(path, serializePart(part.doc, part.text));
705
+ }
706
+ return zip.generateAsync({
707
+ type: "arraybuffer",
708
+ compression: "DEFLATE",
709
+ compressionOptions: { level: 6 }
710
+ });
711
+ }
712
+
713
+ // src/xlsx/index.ts
714
+ async function xlsxToDoc(data, options) {
715
+ return markdownToDoc(await xlsxToMarkdownDoc(data, options));
716
+ }
717
+
718
+ export {
719
+ markdownDocToXlsx,
720
+ docToXlsx,
721
+ XlsxPatchRefusal,
722
+ patchXlsxCellValues,
723
+ xlsxToDoc
724
+ };