@alosha/xlsx 0.3.0 → 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/README.md +8 -7
- package/dist/{chunk-6XXKAKLS.js → chunk-C67HH2MR.js} +102 -14
- package/dist/chunk-C67HH2MR.js.map +1 -0
- package/dist/compat.cjs +132 -12
- package/dist/compat.cjs.map +1 -1
- package/dist/compat.js +34 -2
- package/dist/compat.js.map +1 -1
- package/dist/index.cjs +100 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-6XXKAKLS.js.map +0 -1
package/README.md
CHANGED
|
@@ -118,7 +118,7 @@ functions accept a `ReadOptions` (reserved for future use).
|
|
|
118
118
|
| Multiple worksheets, sheet state (visible / hidden / veryHidden) | ✅ | ✅ | |
|
|
119
119
|
| Workbook & sheet views (freeze/split, zoom, active tab) | ✅ | ✅ | round-trip as data |
|
|
120
120
|
| Workbook metadata (creator, dates, title, …) | ✅ | ✅ | |
|
|
121
|
-
| Hyperlink cells |
|
|
121
|
+
| Hyperlink cells (external URL/mailto) | ✅ | ✅ | real OOXML relationship, round-trips as `{ text, hyperlink, tooltip? }`; internal `location=` links deferred |
|
|
122
122
|
| Streaming read/write | ❌ | ❌ | deferred |
|
|
123
123
|
| Drawings / images / charts | ❌ | ❌ | deferred |
|
|
124
124
|
| Data validation, conditional formatting, comments | ❌ | ❌ | deferred |
|
|
@@ -138,7 +138,6 @@ behave as you'd expect. Common differences to watch for:
|
|
|
138
138
|
- **Clearer row inheritance.** Instead of ExcelJS's `'i' | 'o' | 'i+' | 'o+'` DSL, `addRow` /
|
|
139
139
|
`insertRow` take `{ inheritFrom: "above" | "below", includeEmpty?: boolean }`.
|
|
140
140
|
- **ESM-first.** The package is ESM with a CJS fallback; prefer `import` over `require`.
|
|
141
|
-
- **Hyperlinks round-trip as text** (see below).
|
|
142
141
|
|
|
143
142
|
Not everything ExcelJS does is implemented yet — check the feature matrix and limitations before
|
|
144
143
|
porting a workbook that leans on drawings, streaming, or data validation.
|
|
@@ -151,16 +150,18 @@ behavioural notes to check before porting.
|
|
|
151
150
|
|
|
152
151
|
## Known limitations
|
|
153
152
|
|
|
154
|
-
- **
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
- **Internal (in-workbook) hyperlinks are deferred.** External `http(s)`/`mailto` cell hyperlinks
|
|
154
|
+
round-trip as real OOXML relationships (`{ text, hyperlink, tooltip? }`). Links to a location
|
|
155
|
+
within the same workbook (ExcelJS's `location="Sheet2!A1"` form, no external relationship) aren't
|
|
156
|
+
written or read yet.
|
|
157
157
|
- **No streaming.** Reading and writing are buffer-based (the whole workbook lives in memory). A
|
|
158
158
|
streaming API for very large sheets is deferred.
|
|
159
159
|
- **No drawings, images, or charts.** These parts are ignored on read and not emitted on write.
|
|
160
160
|
- **No data validation, conditional formatting, or comments** yet.
|
|
161
161
|
|
|
162
|
-
See [`BENCHMARKS.md`](
|
|
163
|
-
|
|
162
|
+
See [`BENCHMARKS.md`](https://github.com/avlisodraude/alosha-xlsx/blob/main/BENCHMARKS.md) for
|
|
163
|
+
write/read throughput and output-size numbers against ExcelJS, and
|
|
164
|
+
[`CHANGELOG.md`](https://github.com/avlisodraude/alosha-xlsx/blob/main/CHANGELOG.md) for release notes.
|
|
164
165
|
|
|
165
166
|
## Development
|
|
166
167
|
|
|
@@ -1692,7 +1692,8 @@ var REL_TYPE = {
|
|
|
1692
1692
|
worksheet: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
|
|
1693
1693
|
styles: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
|
|
1694
1694
|
sharedStrings: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",
|
|
1695
|
-
theme: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
|
|
1695
|
+
theme: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme",
|
|
1696
|
+
hyperlink: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
|
1696
1697
|
};
|
|
1697
1698
|
var PART_PATH = {
|
|
1698
1699
|
contentTypes: "[Content_Types].xml",
|
|
@@ -1993,11 +1994,23 @@ function openPackage(bytes) {
|
|
|
1993
1994
|
relsMap.set(rel.id, { type: rel.type, target: resolveRelTarget(workbookDir, rel.target) });
|
|
1994
1995
|
}
|
|
1995
1996
|
}
|
|
1997
|
+
const partRels = (partPath) => {
|
|
1998
|
+
const dir = dirname(partPath);
|
|
1999
|
+
const relsXml = text(relsPathFor(partPath));
|
|
2000
|
+
const map = /* @__PURE__ */ new Map();
|
|
2001
|
+
if (relsXml === void 0) return map;
|
|
2002
|
+
for (const rel of parseRels(relsXml)) {
|
|
2003
|
+
const target = rel.mode === "External" ? rel.target : resolveRelTarget(dir, rel.target);
|
|
2004
|
+
map.set(rel.id, { type: rel.type, target, mode: rel.mode });
|
|
2005
|
+
}
|
|
2006
|
+
return map;
|
|
2007
|
+
};
|
|
1996
2008
|
return {
|
|
1997
2009
|
entry,
|
|
1998
2010
|
text,
|
|
1999
2011
|
workbookRels: () => relsMap,
|
|
2000
|
-
workbookPath: () => workbookPath
|
|
2012
|
+
workbookPath: () => workbookPath,
|
|
2013
|
+
partRels
|
|
2001
2014
|
};
|
|
2002
2015
|
}
|
|
2003
2016
|
function readZip(bytes) {
|
|
@@ -2019,7 +2032,8 @@ function parseRels(xml) {
|
|
|
2019
2032
|
rels.push({
|
|
2020
2033
|
id: child.attrs.Id ?? "",
|
|
2021
2034
|
type: child.attrs.Type ?? "",
|
|
2022
|
-
target: child.attrs.Target ?? ""
|
|
2035
|
+
target: child.attrs.Target ?? "",
|
|
2036
|
+
mode: child.attrs.TargetMode === "External" ? "External" : "Internal"
|
|
2023
2037
|
});
|
|
2024
2038
|
});
|
|
2025
2039
|
}
|
|
@@ -2923,6 +2937,7 @@ function parseWorksheet(ws, xml, ctx) {
|
|
|
2923
2937
|
while (ev && !(ev.kind === "open" && localName(ev.name) === "worksheet")) ev = c.next();
|
|
2924
2938
|
if (ev?.kind !== "open" || ev.selfClosing) return;
|
|
2925
2939
|
const merges = [];
|
|
2940
|
+
const hyperlinks = [];
|
|
2926
2941
|
c.eachChild(ev.name, (child) => {
|
|
2927
2942
|
switch (localName(child.name)) {
|
|
2928
2943
|
case "cols":
|
|
@@ -2934,11 +2949,17 @@ function parseWorksheet(ws, xml, ctx) {
|
|
|
2934
2949
|
case "mergeCells":
|
|
2935
2950
|
if (!child.selfClosing) collectMerges(c, child.name, merges);
|
|
2936
2951
|
break;
|
|
2952
|
+
case "hyperlinks":
|
|
2953
|
+
if (!child.selfClosing) collectHyperlinks(c, child.name, hyperlinks);
|
|
2954
|
+
break;
|
|
2937
2955
|
default:
|
|
2938
2956
|
if (!child.selfClosing) c.textUntilClose(child.name);
|
|
2939
2957
|
}
|
|
2940
2958
|
});
|
|
2941
2959
|
for (const ref of merges) ws.mergeCells(ref);
|
|
2960
|
+
if (ctx.rels) {
|
|
2961
|
+
for (const link of hyperlinks) applyHyperlink(ws, link, ctx.rels);
|
|
2962
|
+
}
|
|
2942
2963
|
}
|
|
2943
2964
|
function parseCols(c, container, ws, ctx) {
|
|
2944
2965
|
c.eachChild(container, (col) => {
|
|
@@ -3079,6 +3100,35 @@ function collectMerges(c, container, merges) {
|
|
|
3079
3100
|
}
|
|
3080
3101
|
});
|
|
3081
3102
|
}
|
|
3103
|
+
function collectHyperlinks(c, container, hyperlinks) {
|
|
3104
|
+
c.eachChild(container, (child) => {
|
|
3105
|
+
if (localName(child.name) !== "hyperlink") {
|
|
3106
|
+
if (!child.selfClosing) c.textUntilClose(child.name);
|
|
3107
|
+
return;
|
|
3108
|
+
}
|
|
3109
|
+
const ref = child.attrs.ref;
|
|
3110
|
+
const rId = relId2(child);
|
|
3111
|
+
if (ref === void 0 || rId === "") return;
|
|
3112
|
+
const tooltip = child.attrs.tooltip;
|
|
3113
|
+
hyperlinks.push(tooltip !== void 0 ? { ref, rId, tooltip } : { ref, rId });
|
|
3114
|
+
});
|
|
3115
|
+
}
|
|
3116
|
+
function applyHyperlink(ws, link, rels) {
|
|
3117
|
+
const rel = rels.get(link.rId);
|
|
3118
|
+
if (!rel) return;
|
|
3119
|
+
const topLeft = link.ref.split(":")[0] ?? link.ref;
|
|
3120
|
+
const cell = ws.getCell(topLeft);
|
|
3121
|
+
const text = typeof cell.value === "string" ? cell.value : "";
|
|
3122
|
+
cell.value = link.tooltip !== void 0 ? { text, hyperlink: rel.target, tooltip: link.tooltip } : { text, hyperlink: rel.target };
|
|
3123
|
+
}
|
|
3124
|
+
function relId2(el) {
|
|
3125
|
+
const direct = el.attrs["r:id"];
|
|
3126
|
+
if (direct !== void 0) return direct;
|
|
3127
|
+
for (const key of Object.keys(el.attrs)) {
|
|
3128
|
+
if (localName(key) === "id") return el.attrs[key] ?? "";
|
|
3129
|
+
}
|
|
3130
|
+
return "";
|
|
3131
|
+
}
|
|
3082
3132
|
function decodeBool(raw) {
|
|
3083
3133
|
if (raw === "1" || raw === "true" || raw === "TRUE") return true;
|
|
3084
3134
|
if (raw === "0" || raw === "false" || raw === "FALSE") return false;
|
|
@@ -3116,7 +3166,9 @@ function readWorkbookBuffer(bytes, _options) {
|
|
|
3116
3166
|
const target = rels.get(sheet.rId)?.target;
|
|
3117
3167
|
if (target === void 0) continue;
|
|
3118
3168
|
const sheetXml = pkg.text(target);
|
|
3119
|
-
if (sheetXml !== void 0)
|
|
3169
|
+
if (sheetXml !== void 0) {
|
|
3170
|
+
parseWorksheet(ws, sheetXml, { ...ctx, rels: pkg.partRels(target) });
|
|
3171
|
+
}
|
|
3120
3172
|
}
|
|
3121
3173
|
const coreXml = pkg.text(PART_PATH.coreProps);
|
|
3122
3174
|
if (coreXml !== void 0) applyCoreProps(wb, coreXml);
|
|
@@ -3382,6 +3434,22 @@ function renderWorkbookRels(rels) {
|
|
|
3382
3434
|
return w.toString();
|
|
3383
3435
|
}
|
|
3384
3436
|
|
|
3437
|
+
// src/xlsx/parts/worksheet-rels.ts
|
|
3438
|
+
function renderWorksheetRels(rels) {
|
|
3439
|
+
const w = new XmlWriter();
|
|
3440
|
+
w.open("Relationships", { xmlns: NS.packageRels });
|
|
3441
|
+
for (const rel of rels) {
|
|
3442
|
+
w.leaf("Relationship", {
|
|
3443
|
+
Id: rel.rId,
|
|
3444
|
+
Type: REL_TYPE.hyperlink,
|
|
3445
|
+
Target: rel.target,
|
|
3446
|
+
TargetMode: rel.mode
|
|
3447
|
+
});
|
|
3448
|
+
}
|
|
3449
|
+
w.close("Relationships");
|
|
3450
|
+
return w.toString();
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3385
3453
|
// src/xlsx/parts/worksheet.ts
|
|
3386
3454
|
var DEFAULT_DATE_NUMFMT = "mm-dd-yy";
|
|
3387
3455
|
function renderWorksheet(ws, ctx) {
|
|
@@ -3399,11 +3467,13 @@ function renderWorksheet(ws, ctx) {
|
|
|
3399
3467
|
defaultRowHeight: model.properties.defaultRowHeight ?? 15,
|
|
3400
3468
|
defaultColWidth: model.properties.defaultColWidth
|
|
3401
3469
|
});
|
|
3470
|
+
const hyperlinks = [];
|
|
3402
3471
|
renderCols(w, model.columns, ctx);
|
|
3403
|
-
renderSheetData(w, model.rows, ctx);
|
|
3472
|
+
renderSheetData(w, model.rows, ctx, hyperlinks);
|
|
3404
3473
|
renderMergeCells(w, model.merges);
|
|
3474
|
+
const rels = renderHyperlinks(w, hyperlinks);
|
|
3405
3475
|
w.close("worksheet");
|
|
3406
|
-
return w.toString();
|
|
3476
|
+
return { xml: w.toString(), rels };
|
|
3407
3477
|
}
|
|
3408
3478
|
function renderCols(w, columns, ctx) {
|
|
3409
3479
|
if (!columns || columns.length === 0) return;
|
|
@@ -3429,13 +3499,13 @@ function renderCols(w, columns, ctx) {
|
|
|
3429
3499
|
for (const f of fragments) w.raw(f);
|
|
3430
3500
|
w.close("cols");
|
|
3431
3501
|
}
|
|
3432
|
-
function renderSheetData(w, rows, ctx) {
|
|
3502
|
+
function renderSheetData(w, rows, ctx, hyperlinks) {
|
|
3433
3503
|
w.open("sheetData");
|
|
3434
3504
|
for (const row of rows) {
|
|
3435
3505
|
const styleId = row.style ? ctx.styles.addStyle(row.style) : 0;
|
|
3436
3506
|
let cellsXml = "";
|
|
3437
3507
|
for (const cell of row.cells) {
|
|
3438
|
-
cellsXml += renderCell(cell, ctx);
|
|
3508
|
+
cellsXml += renderCell(cell, ctx, hyperlinks);
|
|
3439
3509
|
}
|
|
3440
3510
|
const hasAttrs = row.height !== void 0 || row.hidden || (row.outlineLevel ?? 0) !== 0 || styleId !== 0;
|
|
3441
3511
|
if (cellsXml === "" && !hasAttrs) continue;
|
|
@@ -3453,7 +3523,7 @@ function renderSheetData(w, rows, ctx) {
|
|
|
3453
3523
|
}
|
|
3454
3524
|
w.close("sheetData");
|
|
3455
3525
|
}
|
|
3456
|
-
function renderCell(cell, ctx) {
|
|
3526
|
+
function renderCell(cell, ctx, hyperlinks) {
|
|
3457
3527
|
const styleId = cell.style ? ctx.styles.addStyle(cell.style) : 0;
|
|
3458
3528
|
const r = cell.address;
|
|
3459
3529
|
switch (cell.type) {
|
|
@@ -3472,8 +3542,11 @@ function renderCell(cell, ctx) {
|
|
|
3472
3542
|
return valueCell(r, styleId, "e", cell.value.error);
|
|
3473
3543
|
case 2 /* String */:
|
|
3474
3544
|
return stringCell(r, styleId, cell.value, ctx);
|
|
3475
|
-
case 7 /* Hyperlink */:
|
|
3476
|
-
|
|
3545
|
+
case 7 /* Hyperlink */: {
|
|
3546
|
+
const link = cell.value;
|
|
3547
|
+
hyperlinks.push({ ref: r, target: link.hyperlink, tooltip: link.tooltip });
|
|
3548
|
+
return stringCell(r, styleId, link.text, ctx);
|
|
3549
|
+
}
|
|
3477
3550
|
case 6 /* RichText */:
|
|
3478
3551
|
return richTextCell(r, styleId, cell.value, ctx);
|
|
3479
3552
|
case 8 /* Formula */:
|
|
@@ -3547,6 +3620,18 @@ function renderMergeCells(w, merges) {
|
|
|
3547
3620
|
for (const ref of merges) w.leaf("mergeCell", { ref });
|
|
3548
3621
|
w.close("mergeCells");
|
|
3549
3622
|
}
|
|
3623
|
+
function renderHyperlinks(w, hyperlinks) {
|
|
3624
|
+
if (hyperlinks.length === 0) return void 0;
|
|
3625
|
+
const rels = [];
|
|
3626
|
+
w.open("hyperlinks");
|
|
3627
|
+
hyperlinks.forEach((h, i) => {
|
|
3628
|
+
const rId = `rId${i + 1}`;
|
|
3629
|
+
w.leaf("hyperlink", { ref: h.ref, "r:id": rId, tooltip: h.tooltip });
|
|
3630
|
+
rels.push({ rId, target: h.target, mode: "External" });
|
|
3631
|
+
});
|
|
3632
|
+
w.close("hyperlinks");
|
|
3633
|
+
return renderWorksheetRels(rels);
|
|
3634
|
+
}
|
|
3550
3635
|
|
|
3551
3636
|
// src/xlsx/write-workbook.ts
|
|
3552
3637
|
function writeWorkbookBuffer(wb, options) {
|
|
@@ -3610,7 +3695,10 @@ function writeWorkbookBuffer(wb, options) {
|
|
|
3610
3695
|
put(PART_PATH.styles, styles.toXml());
|
|
3611
3696
|
if (sharedStringsXml !== void 0) put(PART_PATH.sharedStrings, sharedStringsXml);
|
|
3612
3697
|
put(PART_PATH.theme, renderTheme());
|
|
3613
|
-
for (const [file, xml] of worksheetXml)
|
|
3698
|
+
for (const [file, { xml, rels }] of worksheetXml) {
|
|
3699
|
+
put(`xl/worksheets/${file}`, xml);
|
|
3700
|
+
if (rels !== void 0) put(`xl/worksheets/_rels/${file}.rels`, rels);
|
|
3701
|
+
}
|
|
3614
3702
|
return writeZipArchive(entries);
|
|
3615
3703
|
}
|
|
3616
3704
|
async function writeWorkbookFile(wb, path, options) {
|
|
@@ -3659,5 +3747,5 @@ Object.defineProperty(Workbook.prototype, "xlsx", {
|
|
|
3659
3747
|
var version = "0.0.0";
|
|
3660
3748
|
|
|
3661
3749
|
export { AloshaXlsxError, Cell, CellType, Column, DEFAULT_COLUMN_WIDTH, DuplicateWorksheetNameError, FormulaType, InvalidAddressError, InvalidCellValueError, InvalidPackageError, InvalidRangeError, InvalidRowNumberError, InvalidWorksheetNameError, MergeConflictError, Range, ReservedWorksheetNameError, Row, UnsupportedFeatureError, Workbook, Worksheet, WorksheetNameTooLongError, colLetterToNumber, colNumberToLetter, createSharedStrings, createStyles, dateToSerial, decodeAddress, decodeEx, detectType, effectiveType, encodeAddress, fromStored, isAloshaXlsxError, readWorkbookBuffer, readWorkbookFile, resolveCellStyle, serialToDate, toCsv, toStored, toText, validateAddress, version, writeWorkbookBuffer, writeWorkbookFile };
|
|
3662
|
-
//# sourceMappingURL=chunk-
|
|
3663
|
-
//# sourceMappingURL=chunk-
|
|
3750
|
+
//# sourceMappingURL=chunk-C67HH2MR.js.map
|
|
3751
|
+
//# sourceMappingURL=chunk-C67HH2MR.js.map
|