@devmm/puredocs-excel 1.0.0 → 1.0.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/dist/index.js CHANGED
@@ -344,11 +344,22 @@ ${sheetRels}
344
344
  <Relationship Id="rId${sharedId}" Type="${REL_TYPES.sharedStrings}" Target="sharedStrings.xml"/>
345
345
  </Relationships>`;
346
346
  }
347
- function buildWorkbookXml(sheets) {
347
+ function buildWorkbookXml(sheets, definedNames = []) {
348
348
  const sheetElems = sheets.map(({ name, sheetId, relationshipId, state }) => {
349
349
  const stateAttr = state && state !== "visible" ? ` state="${state}"` : "";
350
350
  return ` <sheet name="${escapeAttr(name)}" sheetId="${sheetId}" r:id="${relationshipId}"${stateAttr}/>`;
351
351
  }).join("\n");
352
+ let definedNamesBlock = "";
353
+ if (definedNames.length > 0) {
354
+ const items = definedNames.map(({ name, refersTo, localSheetId }) => {
355
+ const local = localSheetId !== void 0 ? ` localSheetId="${localSheetId}"` : "";
356
+ return ` <definedName name="${escapeAttr(name)}"${local}>${escapeContent(refersTo)}</definedName>`;
357
+ }).join("\n");
358
+ definedNamesBlock = `
359
+ <definedNames>
360
+ ${items}
361
+ </definedNames>`;
362
+ }
352
363
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
353
364
  <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
354
365
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
@@ -359,7 +370,7 @@ function buildWorkbookXml(sheets) {
359
370
  </bookViews>
360
371
  <sheets>
361
372
  ${sheetElems}
362
- </sheets>
373
+ </sheets>${definedNamesBlock}
363
374
  <calcPr calcId="191028" fullCalcOnLoad="1"/>
364
375
  </workbook>`;
365
376
  }
@@ -371,6 +382,9 @@ var EMPTY_WORKSHEET_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"
371
382
  function escapeAttr(s) {
372
383
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
373
384
  }
385
+ function escapeContent(s) {
386
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
387
+ }
374
388
 
375
389
  // src/io/drawing-part.ts
376
390
  var WORKSHEET_DRAWING_REL_ID = "rId1";
@@ -1750,6 +1764,54 @@ var Cell = class {
1750
1764
  __privateGet(this, _data).formula = formula.startsWith("=") ? formula.slice(1) : formula;
1751
1765
  __privateGet(this, _data).rawValue = void 0;
1752
1766
  __privateGet(this, _data).dataType = void 0;
1767
+ __privateGet(this, _data).arrayRef = void 0;
1768
+ return this;
1769
+ }
1770
+ /**
1771
+ * Marks (or unmarks) this cell as a dynamic-array formula anchor. `spillRef`
1772
+ * is the block the array spills over (e.g. "A1:C2"); pass null to revert to a
1773
+ * plain scalar formula. Serialises as `<f t="array" ref="…">`.
1774
+ */
1775
+ setArrayRef(spillRef) {
1776
+ __privateGet(this, _data).arrayRef = spillRef ?? void 0;
1777
+ return this;
1778
+ }
1779
+ /** The dynamic-array spill range, or null if this is not an array anchor. */
1780
+ getArrayRef() {
1781
+ return __privateGet(this, _data).arrayRef ?? null;
1782
+ }
1783
+ /**
1784
+ * Sets the cached/computed result of this cell WITHOUT touching its formula.
1785
+ *
1786
+ * This is what a recalculation engine calls after evaluating the formula: it
1787
+ * stores the value that XLSX serialises into `<v>` alongside the `<f>`. Unlike
1788
+ * setValue(), it does NOT clear the formula, and strings are stored inline
1789
+ * (t="str") the way Excel stores calculated string results — they are not
1790
+ * added to the shared-string table.
1791
+ */
1792
+ setComputedValue(value) {
1793
+ if (value === null || value === void 0) {
1794
+ __privateGet(this, _data).dataType = void 0;
1795
+ __privateGet(this, _data).rawValue = void 0;
1796
+ return this;
1797
+ }
1798
+ if (typeof value === "string") {
1799
+ __privateGet(this, _data).dataType = "str";
1800
+ __privateGet(this, _data).rawValue = value;
1801
+ return this;
1802
+ }
1803
+ if (typeof value === "boolean") {
1804
+ __privateGet(this, _data).dataType = "b";
1805
+ __privateGet(this, _data).rawValue = value ? "1" : "0";
1806
+ return this;
1807
+ }
1808
+ if (value instanceof Date) {
1809
+ __privateGet(this, _data).dataType = "n";
1810
+ __privateGet(this, _data).rawValue = String(toOADate(value));
1811
+ return this;
1812
+ }
1813
+ __privateGet(this, _data).dataType = "n";
1814
+ __privateGet(this, _data).rawValue = String(value);
1753
1815
  return this;
1754
1816
  }
1755
1817
  /** Returns the formula text (without leading '='), or null if no formula. */
@@ -1822,6 +1884,7 @@ var Cell = class {
1822
1884
  __privateGet(this, _data).rawValue = void 0;
1823
1885
  __privateGet(this, _data).dataType = void 0;
1824
1886
  __privateGet(this, _data).formula = void 0;
1887
+ __privateGet(this, _data).arrayRef = void 0;
1825
1888
  }
1826
1889
  /** Clears the cell value, formula, AND style. */
1827
1890
  clearAll() {
@@ -1834,7 +1897,7 @@ var Cell = class {
1834
1897
  const ref = __privateGet(this, _data).reference;
1835
1898
  const style = __privateGet(this, _data).styleIndex > 0 ? ` s="${__privateGet(this, _data).styleIndex}"` : "";
1836
1899
  const type = __privateGet(this, _data).dataType ? ` t="${__privateGet(this, _data).dataType}"` : "";
1837
- const formulaXml = __privateGet(this, _data).formula ? `<f>${escXml(__privateGet(this, _data).formula)}</f>` : "";
1900
+ const formulaXml = __privateGet(this, _data).formula ? __privateGet(this, _data).arrayRef ? `<f t="array" ref="${__privateGet(this, _data).arrayRef}" aca="1" ca="1">${escXml(__privateGet(this, _data).formula)}</f>` : `<f>${escXml(__privateGet(this, _data).formula)}</f>` : "";
1838
1901
  const valueXml = __privateGet(this, _data).rawValue !== void 0 && __privateGet(this, _data).rawValue !== "" ? `<v>${escXml(__privateGet(this, _data).rawValue)}</v>` : "";
1839
1902
  if (!formulaXml && !valueXml && __privateGet(this, _data).styleIndex === 0) return "";
1840
1903
  return `<c r="${ref}"${style}${type}>${formulaXml}${valueXml}</c>`;
@@ -1845,12 +1908,18 @@ var Cell = class {
1845
1908
  const styleIndex = parseInt(el.attributes["s"] ?? "0", 10);
1846
1909
  let rawValue;
1847
1910
  let formula;
1911
+ let arrayRef;
1848
1912
  for (const child of el.children) {
1849
1913
  const tag = child.tagName.replace(/^.*:/, "");
1850
1914
  if (tag === "v") rawValue = child.textContent;
1851
- if (tag === "f") formula = child.textContent;
1915
+ if (tag === "f") {
1916
+ formula = child.textContent;
1917
+ if (child.attributes && child.attributes["t"] === "array" && child.attributes["ref"]) {
1918
+ arrayRef = child.attributes["ref"];
1919
+ }
1920
+ }
1852
1921
  }
1853
- return { reference: ref, dataType, rawValue, formula, styleIndex };
1922
+ return { reference: ref, dataType, rawValue, formula, arrayRef, styleIndex };
1854
1923
  }
1855
1924
  };
1856
1925
  _data = new WeakMap();
@@ -2073,6 +2142,14 @@ var Worksheet = class {
2073
2142
  getCellValue(reference) {
2074
2143
  return this.tryGetCell(reference)?.getValue() ?? null;
2075
2144
  }
2145
+ /** Formula text (without leading '=') of a cell, or null if it has none. */
2146
+ getCellFormula(reference) {
2147
+ return this.tryGetCell(reference)?.getFormula() ?? null;
2148
+ }
2149
+ /** Spill range (e.g. "A1:A3") of a dynamic-array anchor, or null. Supports A1#. */
2150
+ getSpillRange(reference) {
2151
+ return this.tryGetCell(reference)?.getArrayRef() ?? null;
2152
+ }
2076
2153
  /**
2077
2154
  * Returns the 1-based extent of populated cells (largest row and column that
2078
2155
  * contain data). Returns zeros for an empty sheet. Useful for snapshotting a
@@ -2123,6 +2200,15 @@ var Worksheet = class {
2123
2200
  row.height = height;
2124
2201
  row.customHeight = true;
2125
2202
  }
2203
+ /** Shows or hides a row (1-based index). Hidden rows affect SUBTOTAL(101-111). */
2204
+ setRowHidden(rowIndex, hidden = true) {
2205
+ if (rowIndex < 1) throw new RangeError("Row index must be >= 1.");
2206
+ __privateMethod(this, _Worksheet_instances, getOrCreateRow_fn).call(this, rowIndex).hidden = hidden;
2207
+ }
2208
+ /** True if the given 1-based row is hidden. */
2209
+ isRowHidden(rowIndex) {
2210
+ return __privateGet(this, _rows).get(rowIndex)?.hidden === true;
2211
+ }
2126
2212
  /** Merges cells in the given range (e.g. "A1:B2"). */
2127
2213
  mergeCells(rangeReference) {
2128
2214
  if (!rangeReference) throw new Error("Range reference cannot be empty.");
@@ -2222,6 +2308,7 @@ ${colsXml}${sheetDataXml}${filterXml}${mergeXml}${validXml}${drawingXml}
2222
2308
  rowData.height = parseFloat(ht);
2223
2309
  rowData.customHeight = true;
2224
2310
  }
2311
+ if (getAttr(rowEl, "hidden") === "1") rowData.hidden = true;
2225
2312
  for (const cellEl of rowEl.children) {
2226
2313
  const tag = cellEl.tagName.replace(/^.*:/, "");
2227
2314
  if (tag !== "c") continue;
@@ -2287,14 +2374,15 @@ buildSheetDataXml_fn = function() {
2287
2374
  if (sortedRows.length === 0) return "<sheetData/>";
2288
2375
  const rowsXml = sortedRows.map((row) => {
2289
2376
  const ht = row.height !== void 0 && row.customHeight ? ` ht="${row.height}" customHeight="1"` : "";
2377
+ const hidden = row.hidden ? ' hidden="1"' : "";
2290
2378
  const sortedCells = [...row.cells.values()].sort((a, b) => {
2291
2379
  const ra = parseCellRef(a.reference);
2292
2380
  const rb = parseCellRef(b.reference);
2293
2381
  return ra.column - rb.column;
2294
2382
  });
2295
2383
  const cellsXml = sortedCells.map((cd) => new Cell(cd, __privateGet(this, _sharedStrings2), __privateGet(this, _styles2)).toXml()).filter(Boolean).join("");
2296
- if (!cellsXml && !ht) return "";
2297
- return `<row r="${row.rowIndex}"${ht}>${cellsXml}</row>`;
2384
+ if (!cellsXml && !ht && !hidden) return "";
2385
+ return `<row r="${row.rowIndex}"${ht}${hidden}>${cellsXml}</row>`;
2298
2386
  }).filter(Boolean).join("");
2299
2387
  return `<sheetData>${rowsXml}</sheetData>`;
2300
2388
  };
@@ -2333,14 +2421,77 @@ function escXml2(s) {
2333
2421
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
2334
2422
  }
2335
2423
 
2424
+ // src/model/defined-name.ts
2425
+ var _names, _DefinedNameManager_instances, indexOf_fn;
2426
+ var DefinedNameManager = class {
2427
+ constructor() {
2428
+ __privateAdd(this, _DefinedNameManager_instances);
2429
+ __privateAdd(this, _names, []);
2430
+ }
2431
+ /** All defined names, in insertion order. */
2432
+ get all() {
2433
+ return __privateGet(this, _names);
2434
+ }
2435
+ get size() {
2436
+ return __privateGet(this, _names).length;
2437
+ }
2438
+ /**
2439
+ * Adds or replaces a defined name. A name is uniquely identified by the pair
2440
+ * (identifier, scope): the same identifier may exist once globally and once
2441
+ * per worksheet. The leading '=' of refersTo is stripped.
2442
+ */
2443
+ define(name, refersTo, scope) {
2444
+ if (!name) throw new Error("Defined name cannot be empty.");
2445
+ if (!refersTo) throw new Error("Defined name refersTo cannot be empty.");
2446
+ const cleaned = refersTo.startsWith("=") ? refersTo.slice(1) : refersTo;
2447
+ const idx = __privateMethod(this, _DefinedNameManager_instances, indexOf_fn).call(this, name, scope);
2448
+ const entry = { name, refersTo: cleaned, scope };
2449
+ if (idx >= 0) __privateGet(this, _names)[idx] = entry;
2450
+ else __privateGet(this, _names).push(entry);
2451
+ }
2452
+ /** Removes a defined name by identifier and scope. Returns true if removed. */
2453
+ remove(name, scope) {
2454
+ const idx = __privateMethod(this, _DefinedNameManager_instances, indexOf_fn).call(this, name, scope);
2455
+ if (idx < 0) return false;
2456
+ __privateGet(this, _names).splice(idx, 1);
2457
+ return true;
2458
+ }
2459
+ /**
2460
+ * Resolves a name to its refers-to expression following Excel scoping:
2461
+ * a name scoped to `sheetName` takes precedence over the workbook-global
2462
+ * name of the same identifier. Returns undefined if no name matches.
2463
+ */
2464
+ resolve(name, sheetName) {
2465
+ const key = name.toUpperCase();
2466
+ if (sheetName) {
2467
+ const local = __privateGet(this, _names).find(
2468
+ (n) => n.name.toUpperCase() === key && n.scope?.toUpperCase() === sheetName.toUpperCase()
2469
+ );
2470
+ if (local) return local.refersTo;
2471
+ }
2472
+ const global = __privateGet(this, _names).find((n) => n.name.toUpperCase() === key && n.scope === void 0);
2473
+ return global?.refersTo;
2474
+ }
2475
+ };
2476
+ _names = new WeakMap();
2477
+ _DefinedNameManager_instances = new WeakSet();
2478
+ indexOf_fn = function(name, scope) {
2479
+ const key = name.toUpperCase();
2480
+ const scopeKey = scope?.toUpperCase();
2481
+ return __privateGet(this, _names).findIndex(
2482
+ (n) => n.name.toUpperCase() === key && n.scope?.toUpperCase() === scopeKey
2483
+ );
2484
+ };
2485
+
2336
2486
  // src/model/workbook.ts
2337
- var _sharedStrings3, _styles3, _sheets, _closed, _Workbook_instances, assertOpen_fn, buildZipEntries_fn;
2487
+ var _sharedStrings3, _styles3, _sheets, _definedNames, _closed, _Workbook_instances, assertOpen_fn, buildZipEntries_fn;
2338
2488
  var _Workbook = class _Workbook {
2339
2489
  constructor(sharedStrings, styles) {
2340
2490
  __privateAdd(this, _Workbook_instances);
2341
2491
  __privateAdd(this, _sharedStrings3);
2342
2492
  __privateAdd(this, _styles3);
2343
2493
  __privateAdd(this, _sheets, []);
2494
+ __privateAdd(this, _definedNames, new DefinedNameManager());
2344
2495
  __privateAdd(this, _closed, false);
2345
2496
  __privateSet(this, _sharedStrings3, sharedStrings);
2346
2497
  __privateSet(this, _styles3, styles);
@@ -2384,6 +2535,19 @@ var _Workbook = class _Workbook {
2384
2535
  ws.loadFromXml(wsXml);
2385
2536
  __privateGet(wb, _sheets).push({ worksheet: ws, sheetId, relId });
2386
2537
  }
2538
+ for (const dn of getElementsByTagName(wbRoot, "definedName")) {
2539
+ const name = getAttr(dn, "name");
2540
+ if (!name) continue;
2541
+ const refersTo = dn.textContent.trim();
2542
+ if (!refersTo) continue;
2543
+ const localSheetId = getAttr(dn, "localSheetId");
2544
+ let scope;
2545
+ if (localSheetId !== void 0) {
2546
+ const idx = parseInt(localSheetId, 10);
2547
+ scope = __privateGet(wb, _sheets)[idx]?.worksheet.name;
2548
+ }
2549
+ __privateGet(wb, _definedNames).define(name, refersTo, scope);
2550
+ }
2387
2551
  return wb;
2388
2552
  }
2389
2553
  /**
@@ -2428,6 +2592,43 @@ var _Workbook = class _Workbook {
2428
2592
  if (!entry) throw new Error(`Worksheet "${name}" not found.`);
2429
2593
  return entry.worksheet;
2430
2594
  }
2595
+ // ── Defined names (named ranges) ─────────────────────────────────────────────
2596
+ /**
2597
+ * Defines (or replaces) a named range.
2598
+ *
2599
+ * @param name The name identifier (case-insensitive when resolved).
2600
+ * @param refersTo The refers-to expression, e.g. "Sheet1!$A$1:$B$10". A
2601
+ * leading '=' is optional and stripped.
2602
+ * @param options `scope` restricts the name to a single worksheet; omit for
2603
+ * a workbook-global name.
2604
+ */
2605
+ defineName(name, refersTo, options) {
2606
+ __privateMethod(this, _Workbook_instances, assertOpen_fn).call(this);
2607
+ const scope = options?.scope;
2608
+ if (scope !== void 0 && !__privateGet(this, _sheets).some((e) => e.worksheet.name === scope)) {
2609
+ throw new Error(`Cannot scope defined name "${name}" to unknown worksheet "${scope}".`);
2610
+ }
2611
+ __privateGet(this, _definedNames).define(name, refersTo, scope);
2612
+ }
2613
+ /**
2614
+ * Resolves a defined name to its refers-to expression (without leading '=').
2615
+ * Follows Excel scoping: a name scoped to `sheetName` wins over the global
2616
+ * name of the same identifier. Returns undefined if no name matches.
2617
+ *
2618
+ * This is the seam the formula engine calls to resolve NamedRangeNode.
2619
+ */
2620
+ getDefinedName(name, sheetName) {
2621
+ return __privateGet(this, _definedNames).resolve(name, sheetName);
2622
+ }
2623
+ /** Removes a defined name. Returns true if a matching name was removed. */
2624
+ removeName(name, scope) {
2625
+ __privateMethod(this, _Workbook_instances, assertOpen_fn).call(this);
2626
+ return __privateGet(this, _definedNames).remove(name, scope);
2627
+ }
2628
+ /** All defined names in the workbook, in insertion order. */
2629
+ get definedNames() {
2630
+ return __privateGet(this, _definedNames).all;
2631
+ }
2431
2632
  // ── Serialisation ──────────────────────────────────────────────────────────
2432
2633
  /**
2433
2634
  * Serialises the workbook to a Uint8Array (xlsx binary).
@@ -2465,6 +2666,7 @@ var _Workbook = class _Workbook {
2465
2666
  _sharedStrings3 = new WeakMap();
2466
2667
  _styles3 = new WeakMap();
2467
2668
  _sheets = new WeakMap();
2669
+ _definedNames = new WeakMap();
2468
2670
  _closed = new WeakMap();
2469
2671
  _Workbook_instances = new WeakSet();
2470
2672
  // ── Private helpers ────────────────────────────────────────────────────────
@@ -2481,7 +2683,15 @@ buildZipEntries_fn = function() {
2481
2683
  relationshipId: e.relId,
2482
2684
  state: e.worksheet.visibility !== "visible" ? e.worksheet.visibility : void 0
2483
2685
  }));
2484
- entries.set("xl/workbook.xml", buildWorkbookXml(sheetMetas));
2686
+ const definedNameMetas = __privateGet(this, _definedNames).all.map((dn) => {
2687
+ let localSheetId;
2688
+ if (dn.scope !== void 0) {
2689
+ const idx = __privateGet(this, _sheets).findIndex((e) => e.worksheet.name === dn.scope);
2690
+ if (idx >= 0) localSheetId = idx;
2691
+ }
2692
+ return { name: dn.name, refersTo: dn.refersTo, localSheetId };
2693
+ });
2694
+ entries.set("xl/workbook.xml", buildWorkbookXml(sheetMetas, definedNameMetas));
2485
2695
  entries.set("xl/_rels/workbook.xml.rels", buildWorkbookRels(sheetCount));
2486
2696
  entries.set("xl/styles.xml", __privateGet(this, _styles3).buildStylesXml());
2487
2697
  entries.set("xl/sharedStrings.xml", __privateGet(this, _sharedStrings3).buildXml());
@@ -2539,6 +2749,6 @@ function resolveWorksheetPath(relsXml, relId) {
2539
2749
  return void 0;
2540
2750
  }
2541
2751
 
2542
- export { CONTENT_TYPES, Cell, CellStyle, ExcelAlignment, ExcelBorder, ExcelBorderEdge, ExcelBorderStyle, ExcelColor, ExcelFill, ExcelFont, ExcelHorizontalAlignment, ExcelNumberFormat, ExcelPatternType, ExcelReadingOrder, ExcelUnderline, ExcelVerticalAlignRun, ExcelVerticalAlignment, NS, REL_TYPES, Range, StyleManager, WORKSHEET_DRAWING_REL_ID, Workbook, Worksheet, XmlBuilder, buildDrawingXml, buildRelsXml, cellRefFromRowCol, columnLetter, columnNumber, decodeUtf8, encodeUtf8, escapeXml, fromOADate, getAttr, getElementsByTagName, isDateFormatCode, isDateFormatId, listEntries, parseCellRef, parseRangeRef, parseXml, readXmlEntry, requireXmlEntry, setBinaryEntry, setXmlEntry, toOADate, unzipXlsx, xml, zipXlsx };
2752
+ export { CONTENT_TYPES, Cell, CellStyle, DefinedNameManager, ExcelAlignment, ExcelBorder, ExcelBorderEdge, ExcelBorderStyle, ExcelColor, ExcelFill, ExcelFont, ExcelHorizontalAlignment, ExcelNumberFormat, ExcelPatternType, ExcelReadingOrder, ExcelUnderline, ExcelVerticalAlignRun, ExcelVerticalAlignment, NS, REL_TYPES, Range, StyleManager, WORKSHEET_DRAWING_REL_ID, Workbook, Worksheet, XmlBuilder, buildDrawingXml, buildRelsXml, cellRefFromRowCol, columnLetter, columnNumber, decodeUtf8, encodeUtf8, escapeXml, fromOADate, getAttr, getElementsByTagName, isDateFormatCode, isDateFormatId, listEntries, parseCellRef, parseRangeRef, parseXml, readXmlEntry, requireXmlEntry, setBinaryEntry, setXmlEntry, toOADate, unzipXlsx, xml, zipXlsx };
2543
2753
  //# sourceMappingURL=index.js.map
2544
2754
  //# sourceMappingURL=index.js.map