@office-open/xlsx 0.8.1 → 0.9.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/README.md +18 -21
- package/dist/context-BXK92u5G.mjs +5055 -0
- package/dist/context-BXK92u5G.mjs.map +1 -0
- package/dist/generate-BLESQtfS.d.mts +26 -0
- package/dist/generate-BLESQtfS.d.mts.map +1 -0
- package/dist/generate-BqlKnMiw.mjs +796 -0
- package/dist/generate-BqlKnMiw.mjs.map +1 -0
- package/dist/generate.d.mts +2 -0
- package/dist/generate.mjs +2 -0
- package/dist/index.d.mts +542 -2113
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +7 -5424
- package/dist/index.mjs.map +1 -1
- package/dist/parse-CZQQuAH5.d.mts +42 -0
- package/dist/parse-CZQQuAH5.d.mts.map +1 -0
- package/dist/parse.d.mts +2 -0
- package/dist/parse.mjs +233 -0
- package/dist/parse.mjs.map +1 -0
- package/dist/patch.d.mts +31 -0
- package/dist/patch.d.mts.map +1 -0
- package/dist/patch.mjs +101 -0
- package/dist/patch.mjs.map +1 -0
- package/dist/worksheet-BbJpRvw2.d.mts +1691 -0
- package/dist/worksheet-BbJpRvw2.d.mts.map +1 -0
- package/package.json +18 -5
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Ct as VolTypeOptions, D as WorksheetOptions, Et as WorkbookProtectionOptions, Tt as WebPublishingOptions, Y as ExternalLinkOptions, bt as FileRecoveryPrOptions, dt as DxfOptions, rt as ChartsheetOptions, vt as CorePropertiesOptions, wt as WebPublishObjectOptions, xt as FileSharingOptions, yt as CustomWorkbookViewOptions } from "./worksheet-BbJpRvw2.mjs";
|
|
2
|
+
import { Element } from "@office-open/xml";
|
|
3
|
+
import { DataType, ParsedArchive, parseArchive } from "@office-open/core";
|
|
4
|
+
|
|
5
|
+
//#region src/shared/file.d.ts
|
|
6
|
+
interface WorkbookOptions extends CorePropertiesOptions {
|
|
7
|
+
worksheets?: WorksheetOptions[];
|
|
8
|
+
chartsheets?: ChartsheetOptions[];
|
|
9
|
+
dxfs?: DxfOptions[];
|
|
10
|
+
workbookProtection?: WorkbookProtectionOptions;
|
|
11
|
+
externalLinks?: ExternalLinkOptions[];
|
|
12
|
+
customWorkbookViews?: CustomWorkbookViewOptions[];
|
|
13
|
+
fileRecoveryPr?: FileRecoveryPrOptions;
|
|
14
|
+
functionGroups?: string[];
|
|
15
|
+
webPublishing?: WebPublishingOptions;
|
|
16
|
+
fileSharing?: FileSharingOptions;
|
|
17
|
+
volTypes?: VolTypeOptions[];
|
|
18
|
+
webPublishObjects?: WebPublishObjectOptions[];
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/parse.d.ts
|
|
22
|
+
interface XlsxPartRefs {
|
|
23
|
+
worksheets: string[];
|
|
24
|
+
charts: string[];
|
|
25
|
+
media: string[];
|
|
26
|
+
drawings: string[];
|
|
27
|
+
}
|
|
28
|
+
interface XlsxDocument {
|
|
29
|
+
doc: ParsedArchive;
|
|
30
|
+
workbook?: Element;
|
|
31
|
+
worksheets: string[];
|
|
32
|
+
styles?: Element;
|
|
33
|
+
sharedStrings?: Element;
|
|
34
|
+
partRefs: XlsxPartRefs;
|
|
35
|
+
coreProps?: string;
|
|
36
|
+
appProps?: string;
|
|
37
|
+
}
|
|
38
|
+
declare function parseXlsx(data: DataType): XlsxDocument;
|
|
39
|
+
declare function parseWorkbook(data: DataType): WorkbookOptions;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { parseXlsx as a, parseWorkbook as i, XlsxPartRefs as n, parseArchive as r, XlsxDocument as t };
|
|
42
|
+
//# sourceMappingURL=parse-CZQQuAH5.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-CZQQuAH5.d.mts","names":[],"sources":["../src/shared/file.ts","../src/parse.ts"],"mappings":";;;;;UAkBiB,eAAA,SAAwB,qBAAA;EACvC,UAAA,GAAa,gBAAA;EAEb,WAAA,GAAc,iBAAA;EAEd,IAAA,GAAO,UAAA;EAEP,kBAAA,GAAqB,yBAAA;EAErB,aAAA,GAAgB,mBAAA;EAEhB,mBAAA,GAFmC,yBAAA;EAInC,cAAA,GAAiB,qBAAA;EAEjB,cAAA;EAEA,aAAA,GAAgB,oBAAA;EAEhB,WAAA,GAAc,kBAAA;EAEd,QAAA,GAFgC,cAAA;EAIhC,iBAAA,GAFmD,uBAAA;AAAA;;;UCNpC,YAAA;EACf,UAAA;EACA,MAAA;EACA,KAAA;EACA,QAAA;AAAA;AAAA,UAGe,YAAA;EACf,GAAA,EAAK,aAAA;EAEL,QAAA,GAAW,OAAA;EAEX,UAAA;EAEA,MAAA,GAAS,OAAA;EAET,aAAA,GAAgB,OAAA;EAChB,QAAA,EAAU,YAAA;EAEV,SAAA;EAEA,QAAA;AAAA;AAAA,iBAcc,SAAA,CAAU,IAAA,EAAM,QAAA,GAAW,YAAY;AAAA,iBAwFvC,aAAA,CAAc,IAAA,EAAM,QAAA,GAAW,eAAe"}
|
package/dist/parse.d.mts
ADDED
package/dist/parse.mjs
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { E as sharedStringsDesc, S as worksheetDesc, _ as commentsDesc, a as workbookDesc, b as calcChainDesc, c as tableDesc, d as pivotTableDesc, g as drawingDesc, h as externalLinkDesc, l as pivotCacheDefDesc, t as XlsxReadContext, u as pivotCacheRecordsDesc, w as stylesDesc, y as chartsheetDesc } from "./context-BXK92u5G.mjs";
|
|
2
|
+
import { attr } from "@office-open/xml";
|
|
3
|
+
import { parseArchive, parseCorePropsElement, toUint8Array } from "@office-open/core";
|
|
4
|
+
//#region src/parse.ts
|
|
5
|
+
/**
|
|
6
|
+
* XLSX parsing — parse .xlsx files into structured data.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
function sortByNumber(paths) {
|
|
11
|
+
return paths.sort((a, b) => {
|
|
12
|
+
return parseInt(a.match(/(\d+)/)?.[1] ?? "0", 10) - parseInt(b.match(/(\d+)/)?.[1] ?? "0", 10);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse raw .xlsx data into a low-level XlsxDocument.
|
|
17
|
+
*/
|
|
18
|
+
function parseXlsx(data) {
|
|
19
|
+
const doc = parseArchive(toUint8Array(data));
|
|
20
|
+
const workbook = doc.get("xl/workbook.xml");
|
|
21
|
+
const styles = doc.get("xl/styles.xml");
|
|
22
|
+
const sharedStrings = doc.get("xl/sharedStrings.xml");
|
|
23
|
+
const worksheets = [];
|
|
24
|
+
const charts = [];
|
|
25
|
+
const drawings = [];
|
|
26
|
+
const media = [];
|
|
27
|
+
const wbRels = doc.get("xl/_rels/workbook.xml.rels");
|
|
28
|
+
if (wbRels) for (const child of wbRels.elements ?? []) {
|
|
29
|
+
if (child.name !== "Relationship") continue;
|
|
30
|
+
const type = attr(child, "Type") ?? "";
|
|
31
|
+
const target = attr(child, "Target") ?? "";
|
|
32
|
+
if (!target) continue;
|
|
33
|
+
if (type.includes("/worksheet")) worksheets.push(target.startsWith("/") ? target.slice(1) : `xl/${target}`);
|
|
34
|
+
}
|
|
35
|
+
sortByNumber(worksheets);
|
|
36
|
+
drawings.push(...doc.keys("xl/drawings/").filter((k) => k.endsWith(".xml")));
|
|
37
|
+
charts.push(...doc.keys("xl/charts/").filter((k) => k.endsWith(".xml")));
|
|
38
|
+
media.push(...doc.keys("xl/media/"));
|
|
39
|
+
sortByNumber(drawings);
|
|
40
|
+
sortByNumber(charts);
|
|
41
|
+
let coreProps;
|
|
42
|
+
let appProps;
|
|
43
|
+
const rootRels = doc.get("_rels/.rels");
|
|
44
|
+
if (rootRels) for (const child of rootRels.elements ?? []) {
|
|
45
|
+
if (child.name !== "Relationship") continue;
|
|
46
|
+
const type = attr(child, "Type") ?? "";
|
|
47
|
+
const target = attr(child, "Target") ?? "";
|
|
48
|
+
if (type.includes("/core-properties")) coreProps = target;
|
|
49
|
+
else if (type.includes("/extended-properties")) appProps = target;
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
doc,
|
|
53
|
+
workbook,
|
|
54
|
+
worksheets,
|
|
55
|
+
styles,
|
|
56
|
+
sharedStrings,
|
|
57
|
+
partRefs: {
|
|
58
|
+
worksheets,
|
|
59
|
+
charts,
|
|
60
|
+
media,
|
|
61
|
+
drawings
|
|
62
|
+
},
|
|
63
|
+
coreProps,
|
|
64
|
+
appProps
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** Extract plain string array from sharedStringsDesc.parse() result. */
|
|
68
|
+
function extractStringsFromEntries(parsed) {
|
|
69
|
+
const strings = [];
|
|
70
|
+
for (const entry of parsed.entries) if (typeof entry === "string") strings.push(entry);
|
|
71
|
+
else {
|
|
72
|
+
const runs = entry.runs;
|
|
73
|
+
if (runs && runs.length > 0) strings.push(runs.map((r) => r.text).join(""));
|
|
74
|
+
}
|
|
75
|
+
return strings;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Parse a .xlsx file and convert it into WorkbookOptions.
|
|
79
|
+
*
|
|
80
|
+
* The returned options can be passed to `new Workbook(parsed)`.
|
|
81
|
+
*/
|
|
82
|
+
function parseWorkbook(data) {
|
|
83
|
+
const xlsx = parseXlsx(data);
|
|
84
|
+
const opts = {};
|
|
85
|
+
if (xlsx.coreProps) {
|
|
86
|
+
const corePropsEl = xlsx.doc.get(xlsx.coreProps);
|
|
87
|
+
if (corePropsEl) {
|
|
88
|
+
const cp = parseCorePropsElement(corePropsEl);
|
|
89
|
+
if (cp.title) opts.title = cp.title;
|
|
90
|
+
if (cp.subject) opts.subject = cp.subject;
|
|
91
|
+
if (cp.creator) opts.creator = cp.creator;
|
|
92
|
+
if (cp.keywords) opts.keywords = cp.keywords;
|
|
93
|
+
if (cp.description) opts.description = cp.description;
|
|
94
|
+
if (cp.lastModifiedBy) opts.lastModifiedBy = cp.lastModifiedBy;
|
|
95
|
+
if (cp.revision) opts.revision = parseInt(cp.revision, 10);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
let strings = [];
|
|
99
|
+
if (xlsx.sharedStrings) strings = extractStringsFromEntries(sharedStringsDesc.parse(xlsx.sharedStrings, {}));
|
|
100
|
+
const readContext = new XlsxReadContext(xlsx, strings);
|
|
101
|
+
if (xlsx.styles) readContext.parsedStyles = stylesDesc.parse(xlsx.styles, readContext);
|
|
102
|
+
let sheetNames = [];
|
|
103
|
+
if (xlsx.workbook) {
|
|
104
|
+
const wbData = workbookDesc.parse(xlsx.workbook, readContext);
|
|
105
|
+
const sheets = wbData.sheets;
|
|
106
|
+
if (sheets) sheetNames = sheets.map((s) => s.name);
|
|
107
|
+
if (wbData.protection) opts.workbookProtection = wbData.protection;
|
|
108
|
+
if (wbData.bookView) opts.bookView = wbData.bookView;
|
|
109
|
+
if (wbData.calcPr) opts.calcPr = wbData.calcPr;
|
|
110
|
+
if (wbData.customViews) opts.customWorkbookViews = wbData.customViews;
|
|
111
|
+
if (wbData.fileRecoveryPr) opts.fileRecoveryPr = wbData.fileRecoveryPr;
|
|
112
|
+
if (wbData.functionGroups) opts.functionGroups = wbData.functionGroups;
|
|
113
|
+
if (wbData.webPublishing) opts.webPublishing = wbData.webPublishing;
|
|
114
|
+
if (wbData.fileSharing) opts.fileSharing = wbData.fileSharing;
|
|
115
|
+
if (wbData.workbookPr) opts.workbookPr = wbData.workbookPr;
|
|
116
|
+
if (wbData.volTypes) opts.volTypes = wbData.volTypes;
|
|
117
|
+
if (wbData.webPublishObjects) opts.webPublishObjects = wbData.webPublishObjects;
|
|
118
|
+
}
|
|
119
|
+
const worksheets = [];
|
|
120
|
+
for (let i = 0; i < xlsx.worksheets.length; i++) {
|
|
121
|
+
const wsPath = xlsx.worksheets[i];
|
|
122
|
+
const wsEl = xlsx.doc.get(wsPath);
|
|
123
|
+
if (!wsEl) continue;
|
|
124
|
+
const wsOpts = worksheetDesc.parse(wsEl, readContext);
|
|
125
|
+
if (sheetNames[i]) wsOpts.name = sheetNames[i];
|
|
126
|
+
const commentRels = readContext.getWorksheetRelsByType(wsPath, "/comments");
|
|
127
|
+
for (const cr of commentRels) {
|
|
128
|
+
const commentEl = xlsx.doc.get(cr.target);
|
|
129
|
+
if (!commentEl) continue;
|
|
130
|
+
const commentData = commentsDesc.parse(commentEl, readContext);
|
|
131
|
+
if (commentData.comments) {
|
|
132
|
+
wsOpts.comments = commentData.comments;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const drawingRels = readContext.getWorksheetRelsByType(wsPath, "/drawing");
|
|
137
|
+
for (const dr of drawingRels) {
|
|
138
|
+
const drawingEl = xlsx.doc.get(dr.target);
|
|
139
|
+
if (!drawingEl) continue;
|
|
140
|
+
const drawingData = drawingDesc.parse(drawingEl, readContext);
|
|
141
|
+
if (drawingData.images) wsOpts.images = drawingData.images;
|
|
142
|
+
if (drawingData.charts) wsOpts.charts = drawingData.charts;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
const tableRels = readContext.getWorksheetRelsByType(wsPath, "/table");
|
|
146
|
+
if (tableRels.length > 0) {
|
|
147
|
+
const tables = [];
|
|
148
|
+
for (const tr of tableRels) {
|
|
149
|
+
const tableEl = xlsx.doc.get(tr.target);
|
|
150
|
+
if (!tableEl) continue;
|
|
151
|
+
const tableData = tableDesc.parse(tableEl, readContext);
|
|
152
|
+
tables.push(tableData);
|
|
153
|
+
}
|
|
154
|
+
if (tables.length > 0) wsOpts.tables = tables;
|
|
155
|
+
}
|
|
156
|
+
const pivotRels = readContext.getWorksheetRelsByType(wsPath, "/pivotTable");
|
|
157
|
+
if (pivotRels.length > 0) {
|
|
158
|
+
const pivotTables = [];
|
|
159
|
+
for (const pr of pivotRels) {
|
|
160
|
+
const pivotEl = xlsx.doc.get(pr.target);
|
|
161
|
+
if (!pivotEl) continue;
|
|
162
|
+
const pivotData = pivotTableDesc.parse(pivotEl, readContext);
|
|
163
|
+
pivotTables.push(pivotData);
|
|
164
|
+
}
|
|
165
|
+
if (pivotTables.length > 0) wsOpts.pivotTables = pivotTables;
|
|
166
|
+
}
|
|
167
|
+
const hyperlinks = wsOpts.hyperlinks;
|
|
168
|
+
if (hyperlinks) for (const hl of hyperlinks) {
|
|
169
|
+
const target = hl.target;
|
|
170
|
+
if (target?.type === "external" && typeof target.url === "string") {
|
|
171
|
+
const resolved = readContext.resolveWorksheetRel(wsPath, target.url);
|
|
172
|
+
if (resolved) target.url = resolved;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
worksheets.push(wsOpts);
|
|
176
|
+
}
|
|
177
|
+
opts.worksheets = worksheets;
|
|
178
|
+
const chartsheetPaths = xlsx.doc.keys("xl/chartsheets/").filter((k) => k.endsWith(".xml"));
|
|
179
|
+
if (chartsheetPaths.length > 0) {
|
|
180
|
+
const chartsheets = [];
|
|
181
|
+
for (let i = 0; i < chartsheetPaths.length; i++) {
|
|
182
|
+
const csEl = xlsx.doc.get(chartsheetPaths[i]);
|
|
183
|
+
if (!csEl) continue;
|
|
184
|
+
const csData = chartsheetDesc.parse(csEl, readContext);
|
|
185
|
+
if (sheetNames[worksheets.length + i]) csData.name = sheetNames[worksheets.length + i];
|
|
186
|
+
chartsheets.push(csData);
|
|
187
|
+
}
|
|
188
|
+
if (chartsheets.length > 0) opts.chartsheets = chartsheets;
|
|
189
|
+
}
|
|
190
|
+
const pivotCacheDefPaths = xlsx.doc.keys("xl/pivotCache/").filter((k) => k.includes("pivotCacheDefinition"));
|
|
191
|
+
if (pivotCacheDefPaths.length > 0) {
|
|
192
|
+
const pivotCaches = [];
|
|
193
|
+
for (const pcdPath of pivotCacheDefPaths) {
|
|
194
|
+
const pcdEl = xlsx.doc.get(pcdPath);
|
|
195
|
+
if (!pcdEl) continue;
|
|
196
|
+
const pcdData = pivotCacheDefDesc.parse(pcdEl, readContext);
|
|
197
|
+
pivotCaches.push(pcdData);
|
|
198
|
+
}
|
|
199
|
+
if (pivotCaches.length > 0) opts.pivotCaches = pivotCaches;
|
|
200
|
+
}
|
|
201
|
+
const pivotCacheRecPaths = xlsx.doc.keys("xl/pivotCache/").filter((k) => k.includes("pivotCacheRecords"));
|
|
202
|
+
if (pivotCacheRecPaths.length > 0) {
|
|
203
|
+
const pivotCacheRecords = [];
|
|
204
|
+
for (const pcrPath of pivotCacheRecPaths) {
|
|
205
|
+
const pcrEl = xlsx.doc.get(pcrPath);
|
|
206
|
+
if (!pcrEl) continue;
|
|
207
|
+
const pcrData = pivotCacheRecordsDesc.parse(pcrEl, readContext);
|
|
208
|
+
pivotCacheRecords.push(pcrData);
|
|
209
|
+
}
|
|
210
|
+
if (pivotCacheRecords.length > 0) opts.pivotCacheRecords = pivotCacheRecords;
|
|
211
|
+
}
|
|
212
|
+
const calcChainEl = xlsx.doc.get("xl/calcChain.xml");
|
|
213
|
+
if (calcChainEl) {
|
|
214
|
+
const calcData = calcChainDesc.parse(calcChainEl, readContext);
|
|
215
|
+
if (calcData.cells) opts.calcChain = calcData.cells;
|
|
216
|
+
}
|
|
217
|
+
const extLinkPaths = xlsx.doc.keys("xl/externalLinks/").filter((k) => k.endsWith(".xml"));
|
|
218
|
+
if (extLinkPaths.length > 0) {
|
|
219
|
+
const externalLinks = [];
|
|
220
|
+
for (const elPath of extLinkPaths) {
|
|
221
|
+
const elEl = xlsx.doc.get(elPath);
|
|
222
|
+
if (!elEl) continue;
|
|
223
|
+
const elData = externalLinkDesc.parse(elEl, readContext);
|
|
224
|
+
externalLinks.push(elData);
|
|
225
|
+
}
|
|
226
|
+
if (externalLinks.length > 0) opts.externalLinks = externalLinks;
|
|
227
|
+
}
|
|
228
|
+
return opts;
|
|
229
|
+
}
|
|
230
|
+
//#endregion
|
|
231
|
+
export { parseArchive, parseWorkbook, parseXlsx };
|
|
232
|
+
|
|
233
|
+
//# sourceMappingURL=parse.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.mjs","names":[],"sources":["../src/parse.ts"],"sourcesContent":["/**\n * XLSX parsing — parse .xlsx files into structured data.\n *\n * @module\n */\nimport { parseArchive, parseCorePropsElement } from \"@office-open/core\";\nimport type { ParsedArchive } from \"@office-open/core\";\nimport { toUint8Array } from \"@office-open/core\";\nimport type { DataType } from \"@office-open/core\";\nimport type { Element } from \"@office-open/xml\";\nimport { attr } from \"@office-open/xml\";\nimport { calcChainDesc } from \"@parts/calc-chain\";\nimport { chartsheetDesc } from \"@parts/chartsheet\";\nimport type { ChartsheetOptions } from \"@parts/chartsheet\";\nimport { commentsDesc } from \"@parts/comments\";\nimport { drawingDesc } from \"@parts/drawing\";\nimport { externalLinkDesc } from \"@parts/external-link\";\nimport { pivotCacheDefDesc, pivotCacheRecordsDesc } from \"@parts/pivot-cache\";\nimport { pivotTableDesc } from \"@parts/pivot-table\";\nimport { sharedStringsDesc } from \"@parts/shared-strings\";\nimport { stylesDesc } from \"@parts/styles\";\nimport { tableDesc } from \"@parts/table\";\nimport { workbookDesc } from \"@parts/workbook\";\nimport { worksheetDesc } from \"@parts/worksheet\";\nimport type { WorksheetOptions } from \"@parts/worksheet\";\nimport type { WorkbookOptions } from \"@shared/file\";\n\nimport { XlsxReadContext } from \"./context\";\n\nexport { parseArchive };\n\n// ── Low-level parse result ──\n\nexport interface XlsxPartRefs {\n worksheets: string[];\n charts: string[];\n media: string[];\n drawings: string[];\n}\n\nexport interface XlsxDocument {\n doc: ParsedArchive;\n /** xl/workbook.xml root element */\n workbook?: Element;\n /** Worksheet paths (xl/worksheets/sheet{n}.xml) */\n worksheets: string[];\n /** xl/styles.xml root element */\n styles?: Element;\n /** xl/sharedStrings.xml root element */\n sharedStrings?: Element;\n partRefs: XlsxPartRefs;\n /** docProps/core.xml path */\n coreProps?: string;\n /** docProps/app.xml path */\n appProps?: string;\n}\n\nfunction sortByNumber(paths: string[]): string[] {\n return paths.sort((a, b) => {\n const numA = parseInt(a.match(/(\\d+)/)?.[1] ?? \"0\", 10);\n const numB = parseInt(b.match(/(\\d+)/)?.[1] ?? \"0\", 10);\n return numA - numB;\n });\n}\n\n/**\n * Parse raw .xlsx data into a low-level XlsxDocument.\n */\nexport function parseXlsx(data: DataType): XlsxDocument {\n const uint8 = toUint8Array(data);\n const doc = parseArchive(uint8);\n\n const workbook = doc.get(\"xl/workbook.xml\");\n const styles = doc.get(\"xl/styles.xml\");\n const sharedStrings = doc.get(\"xl/sharedStrings.xml\");\n\n // Resolve worksheet paths from workbook rels\n const worksheets: string[] = [];\n const charts: string[] = [];\n const drawings: string[] = [];\n const media: string[] = [];\n\n const wbRels = doc.get(\"xl/_rels/workbook.xml.rels\");\n if (wbRels) {\n for (const child of wbRels.elements ?? []) {\n if (child.name !== \"Relationship\") continue;\n const type = attr(child, \"Type\") ?? \"\";\n const target = attr(child, \"Target\") ?? \"\";\n if (!target) continue;\n\n if (type.includes(\"/worksheet\")) {\n worksheets.push(target.startsWith(\"/\") ? target.slice(1) : `xl/${target}`);\n }\n }\n }\n sortByNumber(worksheets);\n\n // Scan for drawings, charts, media\n drawings.push(...doc.keys(\"xl/drawings/\").filter((k) => k.endsWith(\".xml\")));\n charts.push(...doc.keys(\"xl/charts/\").filter((k) => k.endsWith(\".xml\")));\n media.push(...doc.keys(\"xl/media/\"));\n sortByNumber(drawings);\n sortByNumber(charts);\n\n // Root rels → core/app props\n let coreProps: string | undefined;\n let appProps: string | undefined;\n const rootRels = doc.get(\"_rels/.rels\");\n if (rootRels) {\n for (const child of rootRels.elements ?? []) {\n if (child.name !== \"Relationship\") continue;\n const type = attr(child, \"Type\") ?? \"\";\n const target = attr(child, \"Target\") ?? \"\";\n if (type.includes(\"/core-properties\")) coreProps = target;\n else if (type.includes(\"/extended-properties\")) appProps = target;\n }\n }\n\n return {\n doc,\n workbook,\n worksheets,\n styles,\n sharedStrings,\n partRefs: { worksheets, charts, media, drawings },\n coreProps,\n appProps,\n };\n}\n\n// ── Shared strings helper ──\n\n/** Extract plain string array from sharedStringsDesc.parse() result. */\nfunction extractStringsFromEntries(parsed: {\n entries: (string | Record<string, unknown>)[];\n}): string[] {\n const strings: string[] = [];\n for (const entry of parsed.entries) {\n if (typeof entry === \"string\") {\n strings.push(entry);\n } else {\n // Rich text: concatenate run texts\n const runs = entry.runs as { text: string }[] | undefined;\n if (runs && runs.length > 0) {\n strings.push(runs.map((r) => r.text).join(\"\"));\n }\n }\n }\n return strings;\n}\n\n/**\n * Parse a .xlsx file and convert it into WorkbookOptions.\n *\n * The returned options can be passed to `new Workbook(parsed)`.\n */\nexport function parseWorkbook(data: DataType): WorkbookOptions {\n const xlsx = parseXlsx(data);\n\n const opts: Record<string, unknown> = {};\n\n // Core properties\n if (xlsx.coreProps) {\n const corePropsEl = xlsx.doc.get(xlsx.coreProps);\n if (corePropsEl) {\n const cp = parseCorePropsElement(corePropsEl);\n if (cp.title) opts.title = cp.title;\n if (cp.subject) opts.subject = cp.subject;\n if (cp.creator) opts.creator = cp.creator;\n if (cp.keywords) opts.keywords = cp.keywords;\n if (cp.description) opts.description = cp.description;\n if (cp.lastModifiedBy) opts.lastModifiedBy = cp.lastModifiedBy;\n if (cp.revision) opts.revision = parseInt(cp.revision, 10);\n }\n }\n\n // Shared strings — use descriptor.parse() for richer data, then extract strings for lookup\n let strings: string[] = [];\n if (xlsx.sharedStrings) {\n const parsed = sharedStringsDesc.parse(xlsx.sharedStrings, {} as never) as {\n entries: (string | Record<string, unknown>)[];\n };\n strings = extractStringsFromEntries(parsed);\n }\n\n // Create read context for descriptor pipeline\n const readContext = new XlsxReadContext(xlsx, strings);\n\n // Parse styles (fonts, fills, borders, cellXfs)\n if (xlsx.styles) {\n readContext.parsedStyles = stylesDesc.parse(xlsx.styles, readContext) as unknown as Record<\n string,\n unknown\n >;\n }\n\n // Parse workbook via descriptor for richer data\n let sheetNames: string[] = [];\n if (xlsx.workbook) {\n const wbData = workbookDesc.parse(xlsx.workbook, readContext) as unknown as Record<\n string,\n unknown\n >;\n const sheets = wbData.sheets as\n | { name: string; sheetId: number; rId: string; state?: string }[]\n | undefined;\n if (sheets) sheetNames = sheets.map((s) => s.name);\n\n // Workbook-level properties\n if (wbData.protection) opts.workbookProtection = wbData.protection;\n if (wbData.bookView) opts.bookView = wbData.bookView;\n if (wbData.calcPr) opts.calcPr = wbData.calcPr;\n if (wbData.customViews) opts.customWorkbookViews = wbData.customViews;\n if (wbData.fileRecoveryPr) opts.fileRecoveryPr = wbData.fileRecoveryPr;\n if (wbData.functionGroups) opts.functionGroups = wbData.functionGroups;\n if (wbData.webPublishing) opts.webPublishing = wbData.webPublishing;\n if (wbData.fileSharing) opts.fileSharing = wbData.fileSharing;\n if (wbData.workbookPr) opts.workbookPr = wbData.workbookPr;\n if (wbData.volTypes) opts.volTypes = wbData.volTypes;\n if (wbData.webPublishObjects) opts.webPublishObjects = wbData.webPublishObjects;\n }\n\n // Parse worksheets using descriptor pipeline\n const worksheets: WorksheetOptions[] = [];\n for (let i = 0; i < xlsx.worksheets.length; i++) {\n const wsPath = xlsx.worksheets[i];\n const wsEl = xlsx.doc.get(wsPath);\n if (!wsEl) continue;\n\n const wsOpts = worksheetDesc.parse(wsEl, readContext) as Record<string, unknown>;\n if (sheetNames[i]) wsOpts.name = sheetNames[i];\n\n // ── Resolve sub-parts via worksheet relationships ──\n\n // Comments\n const commentRels = readContext.getWorksheetRelsByType(wsPath, \"/comments\");\n for (const cr of commentRels) {\n const commentEl = xlsx.doc.get(cr.target);\n if (!commentEl) continue;\n const commentData = commentsDesc.parse(commentEl, readContext) as unknown as Record<\n string,\n unknown\n >;\n if (commentData.comments) {\n wsOpts.comments = commentData.comments;\n break; // one comments file per worksheet\n }\n }\n\n // Drawings (images + charts)\n const drawingRels = readContext.getWorksheetRelsByType(wsPath, \"/drawing\");\n for (const dr of drawingRels) {\n const drawingEl = xlsx.doc.get(dr.target);\n if (!drawingEl) continue;\n const drawingData = drawingDesc.parse(drawingEl, readContext) as Record<string, unknown>;\n if (drawingData.images) wsOpts.images = drawingData.images;\n if (drawingData.charts) wsOpts.charts = drawingData.charts;\n break;\n }\n\n // Tables\n const tableRels = readContext.getWorksheetRelsByType(wsPath, \"/table\");\n if (tableRels.length > 0) {\n const tables: Record<string, unknown>[] = [];\n for (const tr of tableRels) {\n const tableEl = xlsx.doc.get(tr.target);\n if (!tableEl) continue;\n const tableData = tableDesc.parse(tableEl, readContext) as unknown as Record<\n string,\n unknown\n >;\n tables.push(tableData);\n }\n if (tables.length > 0) wsOpts.tables = tables;\n }\n\n // Pivot tables\n const pivotRels = readContext.getWorksheetRelsByType(wsPath, \"/pivotTable\");\n if (pivotRels.length > 0) {\n const pivotTables: Record<string, unknown>[] = [];\n for (const pr of pivotRels) {\n const pivotEl = xlsx.doc.get(pr.target);\n if (!pivotEl) continue;\n const pivotData = pivotTableDesc.parse(pivotEl, readContext) as unknown as Record<\n string,\n unknown\n >;\n pivotTables.push(pivotData);\n }\n if (pivotTables.length > 0) wsOpts.pivotTables = pivotTables;\n }\n\n // Resolve external hyperlink URLs\n const hyperlinks = wsOpts.hyperlinks as Record<string, unknown>[] | undefined;\n if (hyperlinks) {\n for (const hl of hyperlinks) {\n const target = hl.target as Record<string, unknown> | undefined;\n if (target?.type === \"external\" && typeof target.url === \"string\") {\n const resolved = readContext.resolveWorksheetRel(wsPath, target.url);\n if (resolved) target.url = resolved;\n }\n }\n }\n\n worksheets.push(wsOpts as WorksheetOptions);\n }\n\n opts.worksheets = worksheets;\n\n // Chartsheets — parse chartsheet parts\n const chartsheetPaths = xlsx.doc.keys(\"xl/chartsheets/\").filter((k) => k.endsWith(\".xml\"));\n if (chartsheetPaths.length > 0) {\n const chartsheets: ChartsheetOptions[] = [];\n for (let i = 0; i < chartsheetPaths.length; i++) {\n const csEl = xlsx.doc.get(chartsheetPaths[i]);\n if (!csEl) continue;\n const csData = chartsheetDesc.parse(csEl, readContext) as unknown as Record<string, unknown>;\n if (sheetNames[worksheets.length + i]) csData.name = sheetNames[worksheets.length + i];\n chartsheets.push(csData as unknown as ChartsheetOptions);\n }\n if (chartsheets.length > 0) opts.chartsheets = chartsheets;\n }\n\n // Pivot cache definitions and records\n const pivotCacheDefPaths = xlsx.doc\n .keys(\"xl/pivotCache/\")\n .filter((k) => k.includes(\"pivotCacheDefinition\"));\n if (pivotCacheDefPaths.length > 0) {\n const pivotCaches: Record<string, unknown>[] = [];\n for (const pcdPath of pivotCacheDefPaths) {\n const pcdEl = xlsx.doc.get(pcdPath);\n if (!pcdEl) continue;\n const pcdData = pivotCacheDefDesc.parse(pcdEl, readContext) as unknown as Record<\n string,\n unknown\n >;\n pivotCaches.push(pcdData);\n }\n if (pivotCaches.length > 0) opts.pivotCaches = pivotCaches;\n }\n\n const pivotCacheRecPaths = xlsx.doc\n .keys(\"xl/pivotCache/\")\n .filter((k) => k.includes(\"pivotCacheRecords\"));\n if (pivotCacheRecPaths.length > 0) {\n const pivotCacheRecords: Record<string, unknown>[] = [];\n for (const pcrPath of pivotCacheRecPaths) {\n const pcrEl = xlsx.doc.get(pcrPath);\n if (!pcrEl) continue;\n const pcrData = pivotCacheRecordsDesc.parse(pcrEl, readContext) as unknown as Record<\n string,\n unknown\n >;\n pivotCacheRecords.push(pcrData);\n }\n if (pivotCacheRecords.length > 0) opts.pivotCacheRecords = pivotCacheRecords;\n }\n\n // Calculation chain\n const calcChainEl = xlsx.doc.get(\"xl/calcChain.xml\");\n if (calcChainEl) {\n const calcData = calcChainDesc.parse(calcChainEl, readContext) as unknown as Record<\n string,\n unknown\n >;\n if (calcData.cells) opts.calcChain = calcData.cells;\n }\n\n // External links\n const extLinkPaths = xlsx.doc.keys(\"xl/externalLinks/\").filter((k) => k.endsWith(\".xml\"));\n if (extLinkPaths.length > 0) {\n const externalLinks: Record<string, unknown>[] = [];\n for (const elPath of extLinkPaths) {\n const elEl = xlsx.doc.get(elPath);\n if (!elEl) continue;\n const elData = externalLinkDesc.parse(elEl, readContext) as Record<string, unknown>;\n externalLinks.push(elData);\n }\n if (externalLinks.length > 0) opts.externalLinks = externalLinks;\n }\n\n return opts as WorkbookOptions;\n}\n"],"mappings":"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"}
|
package/dist/patch.d.mts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { OutputByType, OutputType } from "@office-open/core";
|
|
2
|
+
import { Buffer } from "\u0000polyfill-node.buffer";
|
|
3
|
+
|
|
4
|
+
//#region src/patch.d.ts
|
|
5
|
+
type InputDataType = Buffer | string | number[] | Uint8Array | ArrayBuffer | Blob;
|
|
6
|
+
type PatchDocumentOutputType = OutputType;
|
|
7
|
+
declare const PatchType: {
|
|
8
|
+
readonly CELL: "cell";
|
|
9
|
+
};
|
|
10
|
+
interface CellPatch {
|
|
11
|
+
value: string | number | boolean | Date;
|
|
12
|
+
}
|
|
13
|
+
type Patch = CellPatch;
|
|
14
|
+
interface PatchWorkbookOptions<T extends PatchDocumentOutputType = PatchDocumentOutputType> {
|
|
15
|
+
outputType: T;
|
|
16
|
+
data: InputDataType;
|
|
17
|
+
patches: Readonly<Record<string, Patch>>;
|
|
18
|
+
placeholderDelimiters?: Readonly<{
|
|
19
|
+
start: string;
|
|
20
|
+
end: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
declare const patchWorkbook: <T extends PatchDocumentOutputType = PatchDocumentOutputType>({
|
|
24
|
+
outputType,
|
|
25
|
+
data,
|
|
26
|
+
patches,
|
|
27
|
+
placeholderDelimiters
|
|
28
|
+
}: PatchWorkbookOptions<T>) => Promise<OutputByType[T]>;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { CellPatch, InputDataType, Patch, PatchDocumentOutputType, PatchType, PatchWorkbookOptions, patchWorkbook };
|
|
31
|
+
//# sourceMappingURL=patch.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patch.d.mts","names":[],"sources":["../src/patch.ts"],"mappings":";;;;KAkBY,aAAA,GAAgB,MAAA,uBAA6B,UAAA,GAAa,WAAA,GAAc,IAAA;AAAA,KAExE,uBAAA,GAA0B,UAAU;AAAA,cAEnC,SAAA;EAAA,SAEH,IAAA;AAAA;AAAA,UAEO,SAAA;EAEf,KAAA,8BAAmC,IAAI;AAAA;AAAA,KAG7B,KAAA,GAAQ,SAAS;AAAA,UAEZ,oBAAA,WAA+B,uBAAA,GAA0B,uBAAA;EACxE,UAAA,EAAY,CAAA;EACZ,IAAA,EAAM,aAAA;EACN,OAAA,EAAS,QAAA,CAAS,MAAA,SAAe,KAAA;EACjC,qBAAA,GAAwB,QAAA;IACtB,KAAA;IACA,GAAA;EAAA;AAAA;AAAA,cAWS,aAAA,aAAiC,uBAAA,GAA0B,uBAAA;EAAyB,UAAA;EAAA,IAAA;EAAA,OAAA;EAAA;AAAA,GAK9F,oBAAA,CAAqB,CAAA,MAAK,OAAA,CAAQ,YAAA,CAAa,CAAA"}
|
package/dist/patch.mjs
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { js2xml } from "@office-open/xml";
|
|
2
|
+
import { OoxmlMimeType, strFromU8, toJson, toUint8Array, unzipSync, zipAndConvert } from "@office-open/core";
|
|
3
|
+
//#region src/patch.ts
|
|
4
|
+
/**
|
|
5
|
+
* XLSX patching — replace placeholders in existing .xlsx files.
|
|
6
|
+
*
|
|
7
|
+
* Unlike DOCX/PPTX (paragraph-based), XLSX patching targets cell values:
|
|
8
|
+
* - Replaces placeholders in the shared strings table (most common)
|
|
9
|
+
* - Replaces placeholders in inline strings within worksheet cells
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/** Reusable TextEncoder (stateless, safe to share). */
|
|
14
|
+
const encoder = new TextEncoder();
|
|
15
|
+
const PatchType = { CELL: "cell" };
|
|
16
|
+
/**
|
|
17
|
+
* Patch an existing .xlsx workbook by replacing placeholder text in cells.
|
|
18
|
+
*
|
|
19
|
+
* Placeholders are matched in shared strings and inline strings.
|
|
20
|
+
* For string replacements, the shared string value is updated in-place.
|
|
21
|
+
* For non-string replacements, the cell type and value are updated.
|
|
22
|
+
*/
|
|
23
|
+
const patchWorkbook = async ({ outputType, data, patches, placeholderDelimiters = {
|
|
24
|
+
start: "{{",
|
|
25
|
+
end: "}}"
|
|
26
|
+
} }) => {
|
|
27
|
+
const zipContent = unzipSync(toUint8Array(data));
|
|
28
|
+
const xmlMap = /* @__PURE__ */ new Map();
|
|
29
|
+
const binaryMap = /* @__PURE__ */ new Map();
|
|
30
|
+
for (const [key, value] of Object.entries(zipContent)) if (key.endsWith(".xml") || key.endsWith(".rels")) xmlMap.set(key, toJson(strFromU8(value)));
|
|
31
|
+
else binaryMap.set(key, value);
|
|
32
|
+
const { start, end } = placeholderDelimiters;
|
|
33
|
+
const patchMap = /* @__PURE__ */ new Map();
|
|
34
|
+
for (const [key, patch] of Object.entries(patches)) patchMap.set(`${start}${key}${end}`, patch);
|
|
35
|
+
const sst = xmlMap.get("xl/sharedStrings.xml");
|
|
36
|
+
if (sst) patchSharedStrings(sst, patchMap);
|
|
37
|
+
const worksheetKeys = Object.keys(zipContent).filter((k) => k.startsWith("xl/worksheets/sheet") && k.endsWith(".xml"));
|
|
38
|
+
for (const wsKey of worksheetKeys) {
|
|
39
|
+
const ws = xmlMap.get(wsKey);
|
|
40
|
+
if (ws) patchWorksheetInlineStrings(ws, patchMap);
|
|
41
|
+
}
|
|
42
|
+
const files = {};
|
|
43
|
+
for (const [key, value] of xmlMap) files[key] = encoder.encode(js2xml(value));
|
|
44
|
+
for (const [key, value] of binaryMap) files[key] = value;
|
|
45
|
+
return await zipAndConvert(files, outputType, OoxmlMimeType.XLSX);
|
|
46
|
+
};
|
|
47
|
+
function patchSharedStrings(sst, patchMap) {
|
|
48
|
+
const root = sst.name ? sst : sst.elements?.[0];
|
|
49
|
+
if (!root) return;
|
|
50
|
+
for (const si of root.elements ?? []) {
|
|
51
|
+
if (si.name !== "si") continue;
|
|
52
|
+
const t = findLocalChild(si, "t");
|
|
53
|
+
if (t) patchTextElement(t, patchMap);
|
|
54
|
+
else for (const r of si.elements ?? []) {
|
|
55
|
+
if (r.name !== "r") continue;
|
|
56
|
+
const rt = findLocalChild(r, "t");
|
|
57
|
+
if (rt) patchTextElement(rt, patchMap);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function patchWorksheetInlineStrings(ws, patchMap) {
|
|
62
|
+
const root = ws.name ? ws : ws.elements?.[0];
|
|
63
|
+
if (!root) return;
|
|
64
|
+
const sheetData = findLocalChild(root, "sheetData");
|
|
65
|
+
if (!sheetData) return;
|
|
66
|
+
for (const row of sheetData.elements ?? []) {
|
|
67
|
+
if (localName(row) !== "row") continue;
|
|
68
|
+
for (const cell of row.elements ?? []) {
|
|
69
|
+
if (localName(cell) !== "c") continue;
|
|
70
|
+
const isEl = findLocalChild(cell, "is");
|
|
71
|
+
if (isEl) {
|
|
72
|
+
const t = findLocalChild(isEl, "t");
|
|
73
|
+
if (t) patchTextElement(t, patchMap);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function patchTextElement(tEl, patchMap) {
|
|
79
|
+
const text = tEl.elements?.[0]?.text;
|
|
80
|
+
if (typeof text !== "string") return;
|
|
81
|
+
for (const [placeholder, patch] of patchMap) if (text.includes(placeholder)) {
|
|
82
|
+
const newValue = String(patch.value);
|
|
83
|
+
const replaced = text.replace(placeholder, newValue);
|
|
84
|
+
if (tEl.elements) tEl.elements[0] = {
|
|
85
|
+
...tEl.elements[0],
|
|
86
|
+
text: replaced
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function localName(el) {
|
|
91
|
+
const name = el.name ?? "";
|
|
92
|
+
const colonIdx = name.indexOf(":");
|
|
93
|
+
return colonIdx >= 0 ? name.slice(colonIdx + 1) : name;
|
|
94
|
+
}
|
|
95
|
+
function findLocalChild(parent, name) {
|
|
96
|
+
return (parent.elements ?? []).find((el) => localName(el) === name);
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
export { PatchType, patchWorkbook };
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=patch.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patch.mjs","names":[],"sources":["../src/patch.ts"],"sourcesContent":["/**\n * XLSX patching — replace placeholders in existing .xlsx files.\n *\n * Unlike DOCX/PPTX (paragraph-based), XLSX patching targets cell values:\n * - Replaces placeholders in the shared strings table (most common)\n * - Replaces placeholders in inline strings within worksheet cells\n *\n * @module\n */\nimport { OoxmlMimeType, unzipSync, zipAndConvert, strFromU8, toJson } from \"@office-open/core\";\nimport type { OutputByType, OutputType } from \"@office-open/core\";\nimport { toUint8Array } from \"@office-open/core\";\nimport { js2xml } from \"@office-open/xml\";\nimport type { Element } from \"@office-open/xml\";\n\n/** Reusable TextEncoder (stateless, safe to share). */\nconst encoder = new TextEncoder();\n\nexport type InputDataType = Buffer | string | number[] | Uint8Array | ArrayBuffer | Blob;\n\nexport type PatchDocumentOutputType = OutputType;\n\nexport const PatchType = {\n CELL: \"cell\",\n} as const;\n\nexport interface CellPatch {\n /** Replacement value (string, number, boolean, or Date) */\n value: string | number | boolean | Date;\n}\n\nexport type Patch = CellPatch;\n\nexport interface PatchWorkbookOptions<T extends PatchDocumentOutputType = PatchDocumentOutputType> {\n outputType: T;\n data: InputDataType;\n patches: Readonly<Record<string, Patch>>;\n placeholderDelimiters?: Readonly<{\n start: string;\n end: string;\n }>;\n}\n\n/**\n * Patch an existing .xlsx workbook by replacing placeholder text in cells.\n *\n * Placeholders are matched in shared strings and inline strings.\n * For string replacements, the shared string value is updated in-place.\n * For non-string replacements, the cell type and value are updated.\n */\nexport const patchWorkbook = async <T extends PatchDocumentOutputType = PatchDocumentOutputType>({\n outputType,\n data,\n patches,\n placeholderDelimiters = { start: \"{{\", end: \"}}\" } as const,\n}: PatchWorkbookOptions<T>): Promise<OutputByType[T]> => {\n const zipContent = unzipSync(toUint8Array(data));\n\n const xmlMap = new Map<string, Element>();\n const binaryMap = new Map<string, Uint8Array>();\n\n // Separate XML files from binary files\n for (const [key, value] of Object.entries(zipContent)) {\n if (key.endsWith(\".xml\") || key.endsWith(\".rels\")) {\n xmlMap.set(key, toJson(strFromU8(value)));\n } else {\n binaryMap.set(key, value);\n }\n }\n\n const { start, end } = placeholderDelimiters;\n\n // Build placeholder → patch map\n const patchMap = new Map<string, Patch>();\n for (const [key, patch] of Object.entries(patches)) {\n patchMap.set(`${start}${key}${end}`, patch);\n }\n\n // 1. Patch shared strings\n const sst = xmlMap.get(\"xl/sharedStrings.xml\");\n if (sst) {\n patchSharedStrings(sst, patchMap);\n }\n\n // 2. Patch inline strings in worksheets\n const worksheetKeys = Object.keys(zipContent).filter(\n (k) => k.startsWith(\"xl/worksheets/sheet\") && k.endsWith(\".xml\"),\n );\n for (const wsKey of worksheetKeys) {\n const ws = xmlMap.get(wsKey);\n if (ws) patchWorksheetInlineStrings(ws, patchMap);\n }\n\n // Rebuild ZIP\n const files: Record<string, Uint8Array> = {};\n for (const [key, value] of xmlMap) {\n files[key] = encoder.encode(js2xml(value));\n }\n for (const [key, value] of binaryMap) {\n files[key] = value;\n }\n\n return await zipAndConvert(files, outputType, OoxmlMimeType.XLSX);\n};\n\nfunction patchSharedStrings(sst: Element, patchMap: Map<string, Patch>): void {\n // toJson returns {elements: [{name: \"sst\", ...}]} — unwrap to actual root\n const root = sst.name ? sst : sst.elements?.[0];\n if (!root) return;\n\n for (const si of root.elements ?? []) {\n if (si.name !== \"si\") continue;\n\n // Simple: <si><t>text</t></si>\n const t = findLocalChild(si, \"t\");\n if (t) {\n patchTextElement(t, patchMap);\n } else {\n // Rich text: <si><r><t>text</t></r>...</si>\n for (const r of si.elements ?? []) {\n if (r.name !== \"r\") continue;\n const rt = findLocalChild(r, \"t\");\n if (rt) patchTextElement(rt, patchMap);\n }\n }\n }\n}\n\nfunction patchWorksheetInlineStrings(ws: Element, patchMap: Map<string, Patch>): void {\n const root = ws.name ? ws : ws.elements?.[0];\n if (!root) return;\n\n const sheetData = findLocalChild(root, \"sheetData\");\n if (!sheetData) return;\n\n for (const row of sheetData.elements ?? []) {\n if (localName(row) !== \"row\") continue;\n for (const cell of row.elements ?? []) {\n if (localName(cell) !== \"c\") continue;\n\n // Check inline strings: <c t=\"inlineStr\"><is><t>text</t></is></c>\n const isEl = findLocalChild(cell, \"is\");\n if (isEl) {\n const t = findLocalChild(isEl, \"t\");\n if (t) patchTextElement(t, patchMap);\n }\n }\n }\n}\n\nfunction patchTextElement(tEl: Element, patchMap: Map<string, Patch>): void {\n const text = tEl.elements?.[0]?.text;\n if (typeof text !== \"string\") return;\n\n for (const [placeholder, patch] of patchMap) {\n if (text.includes(placeholder)) {\n const newValue = String(patch.value);\n const replaced = text.replace(placeholder, newValue);\n if (tEl.elements) {\n tEl.elements[0] = { ...tEl.elements[0], text: replaced };\n }\n }\n }\n}\n\nfunction localName(el: Element): string {\n const name = el.name ?? \"\";\n const colonIdx = name.indexOf(\":\");\n return colonIdx >= 0 ? name.slice(colonIdx + 1) : name;\n}\n\nfunction findLocalChild(parent: Element, name: string): Element | undefined {\n return (parent.elements ?? []).find((el) => localName(el) === name);\n}\n"],"mappings":"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"}
|