@alosha/xlsx 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/compat.cjs CHANGED
@@ -1743,7 +1743,8 @@ var REL_TYPE = {
1743
1743
  worksheet: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
1744
1744
  styles: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
1745
1745
  sharedStrings: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",
1746
- theme: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
1746
+ theme: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme",
1747
+ hyperlink: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
1747
1748
  };
1748
1749
  var PART_PATH = {
1749
1750
  contentTypes: "[Content_Types].xml",
@@ -2044,11 +2045,23 @@ function openPackage(bytes) {
2044
2045
  relsMap.set(rel.id, { type: rel.type, target: resolveRelTarget(workbookDir, rel.target) });
2045
2046
  }
2046
2047
  }
2048
+ const partRels = (partPath) => {
2049
+ const dir = dirname(partPath);
2050
+ const relsXml = text(relsPathFor(partPath));
2051
+ const map = /* @__PURE__ */ new Map();
2052
+ if (relsXml === void 0) return map;
2053
+ for (const rel of parseRels(relsXml)) {
2054
+ const target = rel.mode === "External" ? rel.target : resolveRelTarget(dir, rel.target);
2055
+ map.set(rel.id, { type: rel.type, target, mode: rel.mode });
2056
+ }
2057
+ return map;
2058
+ };
2047
2059
  return {
2048
2060
  entry,
2049
2061
  text,
2050
2062
  workbookRels: () => relsMap,
2051
- workbookPath: () => workbookPath
2063
+ workbookPath: () => workbookPath,
2064
+ partRels
2052
2065
  };
2053
2066
  }
2054
2067
  function readZip(bytes) {
@@ -2070,7 +2083,8 @@ function parseRels(xml) {
2070
2083
  rels.push({
2071
2084
  id: child.attrs.Id ?? "",
2072
2085
  type: child.attrs.Type ?? "",
2073
- target: child.attrs.Target ?? ""
2086
+ target: child.attrs.Target ?? "",
2087
+ mode: child.attrs.TargetMode === "External" ? "External" : "Internal"
2074
2088
  });
2075
2089
  });
2076
2090
  }
@@ -2974,6 +2988,7 @@ function parseWorksheet(ws, xml, ctx) {
2974
2988
  while (ev && !(ev.kind === "open" && localName(ev.name) === "worksheet")) ev = c.next();
2975
2989
  if (ev?.kind !== "open" || ev.selfClosing) return;
2976
2990
  const merges = [];
2991
+ const hyperlinks = [];
2977
2992
  c.eachChild(ev.name, (child) => {
2978
2993
  switch (localName(child.name)) {
2979
2994
  case "cols":
@@ -2985,11 +3000,17 @@ function parseWorksheet(ws, xml, ctx) {
2985
3000
  case "mergeCells":
2986
3001
  if (!child.selfClosing) collectMerges(c, child.name, merges);
2987
3002
  break;
3003
+ case "hyperlinks":
3004
+ if (!child.selfClosing) collectHyperlinks(c, child.name, hyperlinks);
3005
+ break;
2988
3006
  default:
2989
3007
  if (!child.selfClosing) c.textUntilClose(child.name);
2990
3008
  }
2991
3009
  });
2992
3010
  for (const ref of merges) ws.mergeCells(ref);
3011
+ if (ctx.rels) {
3012
+ for (const link of hyperlinks) applyHyperlink(ws, link, ctx.rels);
3013
+ }
2993
3014
  }
2994
3015
  function parseCols(c, container, ws, ctx) {
2995
3016
  c.eachChild(container, (col) => {
@@ -3130,6 +3151,35 @@ function collectMerges(c, container, merges) {
3130
3151
  }
3131
3152
  });
3132
3153
  }
3154
+ function collectHyperlinks(c, container, hyperlinks) {
3155
+ c.eachChild(container, (child) => {
3156
+ if (localName(child.name) !== "hyperlink") {
3157
+ if (!child.selfClosing) c.textUntilClose(child.name);
3158
+ return;
3159
+ }
3160
+ const ref = child.attrs.ref;
3161
+ const rId = relId2(child);
3162
+ if (ref === void 0 || rId === "") return;
3163
+ const tooltip = child.attrs.tooltip;
3164
+ hyperlinks.push(tooltip !== void 0 ? { ref, rId, tooltip } : { ref, rId });
3165
+ });
3166
+ }
3167
+ function applyHyperlink(ws, link, rels) {
3168
+ const rel = rels.get(link.rId);
3169
+ if (!rel) return;
3170
+ const topLeft = link.ref.split(":")[0] ?? link.ref;
3171
+ const cell = ws.getCell(topLeft);
3172
+ const text = typeof cell.value === "string" ? cell.value : "";
3173
+ cell.value = link.tooltip !== void 0 ? { text, hyperlink: rel.target, tooltip: link.tooltip } : { text, hyperlink: rel.target };
3174
+ }
3175
+ function relId2(el) {
3176
+ const direct = el.attrs["r:id"];
3177
+ if (direct !== void 0) return direct;
3178
+ for (const key of Object.keys(el.attrs)) {
3179
+ if (localName(key) === "id") return el.attrs[key] ?? "";
3180
+ }
3181
+ return "";
3182
+ }
3133
3183
  function decodeBool(raw) {
3134
3184
  if (raw === "1" || raw === "true" || raw === "TRUE") return true;
3135
3185
  if (raw === "0" || raw === "false" || raw === "FALSE") return false;
@@ -3167,7 +3217,9 @@ function readWorkbookBuffer(bytes, _options) {
3167
3217
  const target = rels.get(sheet.rId)?.target;
3168
3218
  if (target === void 0) continue;
3169
3219
  const sheetXml = pkg.text(target);
3170
- if (sheetXml !== void 0) parseWorksheet(ws, sheetXml, ctx);
3220
+ if (sheetXml !== void 0) {
3221
+ parseWorksheet(ws, sheetXml, { ...ctx, rels: pkg.partRels(target) });
3222
+ }
3171
3223
  }
3172
3224
  const coreXml = pkg.text(PART_PATH.coreProps);
3173
3225
  if (coreXml !== void 0) applyCoreProps(wb, coreXml);
@@ -3433,6 +3485,22 @@ function renderWorkbookRels(rels) {
3433
3485
  return w.toString();
3434
3486
  }
3435
3487
 
3488
+ // src/xlsx/parts/worksheet-rels.ts
3489
+ function renderWorksheetRels(rels) {
3490
+ const w = new XmlWriter();
3491
+ w.open("Relationships", { xmlns: NS.packageRels });
3492
+ for (const rel of rels) {
3493
+ w.leaf("Relationship", {
3494
+ Id: rel.rId,
3495
+ Type: REL_TYPE.hyperlink,
3496
+ Target: rel.target,
3497
+ TargetMode: rel.mode
3498
+ });
3499
+ }
3500
+ w.close("Relationships");
3501
+ return w.toString();
3502
+ }
3503
+
3436
3504
  // src/xlsx/parts/worksheet.ts
3437
3505
  var DEFAULT_DATE_NUMFMT = "mm-dd-yy";
3438
3506
  function renderWorksheet(ws, ctx) {
@@ -3450,11 +3518,13 @@ function renderWorksheet(ws, ctx) {
3450
3518
  defaultRowHeight: model.properties.defaultRowHeight ?? 15,
3451
3519
  defaultColWidth: model.properties.defaultColWidth
3452
3520
  });
3521
+ const hyperlinks = [];
3453
3522
  renderCols(w, model.columns, ctx);
3454
- renderSheetData(w, model.rows, ctx);
3523
+ renderSheetData(w, model.rows, ctx, hyperlinks);
3455
3524
  renderMergeCells(w, model.merges);
3525
+ const rels = renderHyperlinks(w, hyperlinks);
3456
3526
  w.close("worksheet");
3457
- return w.toString();
3527
+ return { xml: w.toString(), rels };
3458
3528
  }
3459
3529
  function renderCols(w, columns, ctx) {
3460
3530
  if (!columns || columns.length === 0) return;
@@ -3480,13 +3550,13 @@ function renderCols(w, columns, ctx) {
3480
3550
  for (const f of fragments) w.raw(f);
3481
3551
  w.close("cols");
3482
3552
  }
3483
- function renderSheetData(w, rows, ctx) {
3553
+ function renderSheetData(w, rows, ctx, hyperlinks) {
3484
3554
  w.open("sheetData");
3485
3555
  for (const row of rows) {
3486
3556
  const styleId = row.style ? ctx.styles.addStyle(row.style) : 0;
3487
3557
  let cellsXml = "";
3488
3558
  for (const cell of row.cells) {
3489
- cellsXml += renderCell(cell, ctx);
3559
+ cellsXml += renderCell(cell, ctx, hyperlinks);
3490
3560
  }
3491
3561
  const hasAttrs = row.height !== void 0 || row.hidden || (row.outlineLevel ?? 0) !== 0 || styleId !== 0;
3492
3562
  if (cellsXml === "" && !hasAttrs) continue;
@@ -3504,7 +3574,7 @@ function renderSheetData(w, rows, ctx) {
3504
3574
  }
3505
3575
  w.close("sheetData");
3506
3576
  }
3507
- function renderCell(cell, ctx) {
3577
+ function renderCell(cell, ctx, hyperlinks) {
3508
3578
  const styleId = cell.style ? ctx.styles.addStyle(cell.style) : 0;
3509
3579
  const r = cell.address;
3510
3580
  switch (cell.type) {
@@ -3523,8 +3593,11 @@ function renderCell(cell, ctx) {
3523
3593
  return valueCell(r, styleId, "e", cell.value.error);
3524
3594
  case 2 /* String */:
3525
3595
  return stringCell(r, styleId, cell.value, ctx);
3526
- case 7 /* Hyperlink */:
3527
- return stringCell(r, styleId, cell.value.text, ctx);
3596
+ case 7 /* Hyperlink */: {
3597
+ const link = cell.value;
3598
+ hyperlinks.push({ ref: r, target: link.hyperlink, tooltip: link.tooltip });
3599
+ return stringCell(r, styleId, link.text, ctx);
3600
+ }
3528
3601
  case 6 /* RichText */:
3529
3602
  return richTextCell(r, styleId, cell.value, ctx);
3530
3603
  case 8 /* Formula */:
@@ -3598,6 +3671,18 @@ function renderMergeCells(w, merges) {
3598
3671
  for (const ref of merges) w.leaf("mergeCell", { ref });
3599
3672
  w.close("mergeCells");
3600
3673
  }
3674
+ function renderHyperlinks(w, hyperlinks) {
3675
+ if (hyperlinks.length === 0) return void 0;
3676
+ const rels = [];
3677
+ w.open("hyperlinks");
3678
+ hyperlinks.forEach((h, i) => {
3679
+ const rId = `rId${i + 1}`;
3680
+ w.leaf("hyperlink", { ref: h.ref, "r:id": rId, tooltip: h.tooltip });
3681
+ rels.push({ rId, target: h.target, mode: "External" });
3682
+ });
3683
+ w.close("hyperlinks");
3684
+ return renderWorksheetRels(rels);
3685
+ }
3601
3686
 
3602
3687
  // src/xlsx/write-workbook.ts
3603
3688
  function writeWorkbookBuffer(wb, options) {
@@ -3661,7 +3746,10 @@ function writeWorkbookBuffer(wb, options) {
3661
3746
  put(PART_PATH.styles, styles.toXml());
3662
3747
  if (sharedStringsXml !== void 0) put(PART_PATH.sharedStrings, sharedStringsXml);
3663
3748
  put(PART_PATH.theme, renderTheme());
3664
- for (const [file, xml] of worksheetXml) put(`xl/worksheets/${file}`, xml);
3749
+ for (const [file, { xml, rels }] of worksheetXml) {
3750
+ put(`xl/worksheets/${file}`, xml);
3751
+ if (rels !== void 0) put(`xl/worksheets/_rels/${file}.rels`, rels);
3752
+ }
3665
3753
  return writeZipArchive(entries);
3666
3754
  }
3667
3755
  async function writeWorkbookFile(wb, path, options) {