ooxml.js 0.0.0 → 1.1.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/LICENSE +21 -0
- package/README.md +204 -0
- package/dist/index.cjs +944 -0
- package/dist/index.d.cts +581 -0
- package/dist/index.d.ts +581 -0
- package/dist/index.js +886 -0
- package/package.json +83 -2
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,944 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let zod = require("zod");
|
|
3
|
+
let fast_xml_parser = require("fast-xml-parser");
|
|
4
|
+
let fflate = require("fflate");
|
|
5
|
+
//#region src/model/node.ts
|
|
6
|
+
const AttributeSchema = zod.z.object({
|
|
7
|
+
name: zod.z.string(),
|
|
8
|
+
value: zod.z.string()
|
|
9
|
+
});
|
|
10
|
+
const XmlTextSchema = zod.z.object({
|
|
11
|
+
type: zod.z.literal("text"),
|
|
12
|
+
value: zod.z.string()
|
|
13
|
+
});
|
|
14
|
+
const XmlCdataSchema = zod.z.object({
|
|
15
|
+
type: zod.z.literal("cdata"),
|
|
16
|
+
value: zod.z.string()
|
|
17
|
+
});
|
|
18
|
+
const XmlCommentSchema = zod.z.object({
|
|
19
|
+
type: zod.z.literal("comment"),
|
|
20
|
+
value: zod.z.string()
|
|
21
|
+
});
|
|
22
|
+
const XmlDeclarationSchema = zod.z.object({
|
|
23
|
+
type: zod.z.literal("declaration"),
|
|
24
|
+
attributes: zod.z.array(AttributeSchema)
|
|
25
|
+
});
|
|
26
|
+
const XmlPiSchema = zod.z.object({
|
|
27
|
+
type: zod.z.literal("pi"),
|
|
28
|
+
target: zod.z.string(),
|
|
29
|
+
content: zod.z.string()
|
|
30
|
+
});
|
|
31
|
+
function isRecord$1(value) {
|
|
32
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33
|
+
}
|
|
34
|
+
function isAttribute(value) {
|
|
35
|
+
return isRecord$1(value) && typeof value.name === "string" && typeof value.value === "string";
|
|
36
|
+
}
|
|
37
|
+
function isXmlNode(value) {
|
|
38
|
+
if (!isRecord$1(value)) return false;
|
|
39
|
+
const t = value.type;
|
|
40
|
+
if (t === "text" || t === "cdata" || t === "comment") return typeof value.value === "string";
|
|
41
|
+
if (t === "declaration") return Array.isArray(value.attributes) && value.attributes.every(isAttribute);
|
|
42
|
+
if (t === "pi") return typeof value.target === "string" && typeof value.content === "string";
|
|
43
|
+
if (t === "element") return typeof value.tag === "string" && Array.isArray(value.attributes) && value.attributes.every(isAttribute) && Array.isArray(value.children) && value.children.every(isXmlNode);
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const XmlElementSchema = zod.z.object({
|
|
47
|
+
type: zod.z.literal("element"),
|
|
48
|
+
tag: zod.z.string(),
|
|
49
|
+
attributes: zod.z.array(AttributeSchema),
|
|
50
|
+
children: zod.z.array(zod.z.custom(isXmlNode))
|
|
51
|
+
});
|
|
52
|
+
const XmlNodeSchema = zod.z.discriminatedUnion("type", [
|
|
53
|
+
XmlTextSchema,
|
|
54
|
+
XmlCdataSchema,
|
|
55
|
+
XmlCommentSchema,
|
|
56
|
+
XmlDeclarationSchema,
|
|
57
|
+
XmlPiSchema,
|
|
58
|
+
XmlElementSchema
|
|
59
|
+
]);
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/model/package.ts
|
|
62
|
+
const XmlPartSchema = zod.z.object({
|
|
63
|
+
kind: zod.z.literal("xml"),
|
|
64
|
+
nodes: zod.z.array(XmlNodeSchema)
|
|
65
|
+
});
|
|
66
|
+
const BinaryPartSchema = zod.z.object({
|
|
67
|
+
kind: zod.z.literal("binary"),
|
|
68
|
+
base64: zod.z.string()
|
|
69
|
+
});
|
|
70
|
+
const PartSchema = zod.z.discriminatedUnion("kind", [XmlPartSchema, BinaryPartSchema]);
|
|
71
|
+
const PackageSchema = zod.z.object({ parts: zod.z.record(zod.z.string(), PartSchema) });
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/util/base64.ts
|
|
74
|
+
const TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
75
|
+
const DECODE = (() => {
|
|
76
|
+
const map = (/* @__PURE__ */ new Uint8Array(256)).fill(255);
|
|
77
|
+
for (let i = 0; i < 64; i = i + 1) map[TABLE.charCodeAt(i)] = i;
|
|
78
|
+
return map;
|
|
79
|
+
})();
|
|
80
|
+
function bytesToBase64(bytes) {
|
|
81
|
+
let out = "";
|
|
82
|
+
const len = bytes.length;
|
|
83
|
+
for (let i = 0; i < len; i = i + 3) {
|
|
84
|
+
const b0 = bytes[i];
|
|
85
|
+
const b1 = i + 1 < len ? bytes[i + 1] : 0;
|
|
86
|
+
const b2 = i + 2 < len ? bytes[i + 2] : 0;
|
|
87
|
+
out += TABLE[b0 >> 2];
|
|
88
|
+
out += TABLE[(b0 & 3) << 4 | b1 >> 4];
|
|
89
|
+
out += i + 1 < len ? TABLE[(b1 & 15) << 2 | b2 >> 6] : "=";
|
|
90
|
+
out += i + 2 < len ? TABLE[b2 & 63] : "=";
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
function base64ToBytes(b64) {
|
|
95
|
+
const clean = b64.replace(/[^A-Za-z0-9+/=]/g, "");
|
|
96
|
+
const len = clean.length;
|
|
97
|
+
const out = new Uint8Array(len * 3 / 4 | 0);
|
|
98
|
+
let p = 0;
|
|
99
|
+
for (let i = 0; i < len; i = i + 4) {
|
|
100
|
+
const c0 = DECODE[clean.charCodeAt(i)];
|
|
101
|
+
const c1 = DECODE[clean.charCodeAt(i + 1)];
|
|
102
|
+
const c2 = clean.charCodeAt(i + 2);
|
|
103
|
+
const c3 = clean.charCodeAt(i + 3);
|
|
104
|
+
if (c0 === 255 || c1 === 255) throw new Error("invalid base64 input");
|
|
105
|
+
out[p++] = c0 << 2 | c1 >> 4;
|
|
106
|
+
if (c2 !== 61) {
|
|
107
|
+
const d2 = DECODE[c2];
|
|
108
|
+
out[p++] = (c1 & 15) << 4 | d2 >> 2;
|
|
109
|
+
if (c3 !== 61) {
|
|
110
|
+
const d3 = DECODE[c3];
|
|
111
|
+
out[p++] = (d2 & 3) << 6 | d3;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return out.subarray(0, p);
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/xml/parse.ts
|
|
119
|
+
const PARSER = new fast_xml_parser.XMLParser({
|
|
120
|
+
preserveOrder: true,
|
|
121
|
+
attributeNamePrefix: "@_",
|
|
122
|
+
ignoreAttributes: false,
|
|
123
|
+
textNodeName: "#text",
|
|
124
|
+
cdataPropName: "__cdata",
|
|
125
|
+
commentPropName: "__comment",
|
|
126
|
+
processEntities: false,
|
|
127
|
+
parseTagValue: false,
|
|
128
|
+
trimValues: false
|
|
129
|
+
});
|
|
130
|
+
function parseXml(xml) {
|
|
131
|
+
return parseNodes(PARSER.parse(xml));
|
|
132
|
+
}
|
|
133
|
+
function isRecord(value) {
|
|
134
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
135
|
+
}
|
|
136
|
+
function isUnknownArray$1(value) {
|
|
137
|
+
return Array.isArray(value);
|
|
138
|
+
}
|
|
139
|
+
function asString(value) {
|
|
140
|
+
if (typeof value !== "string") throw new Error(`expected string while parsing XML, got ${typeof value}`);
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
function parseNodes(raw) {
|
|
144
|
+
if (!isUnknownArray$1(raw)) throw new Error("fast-xml-parser output was not an ordered array");
|
|
145
|
+
return raw.map(parseNode);
|
|
146
|
+
}
|
|
147
|
+
function parseNode(raw) {
|
|
148
|
+
if (!isRecord(raw)) throw new Error("fast-xml-parser node was not an object");
|
|
149
|
+
let tagKey;
|
|
150
|
+
for (const key of Object.keys(raw)) if (key !== ":@") {
|
|
151
|
+
if (tagKey !== void 0) throw new Error("XML node had multiple tag keys");
|
|
152
|
+
tagKey = key;
|
|
153
|
+
}
|
|
154
|
+
if (tagKey === void 0) throw new Error("XML node had no tag key");
|
|
155
|
+
const attributes = parseAttributes(raw[":@"]);
|
|
156
|
+
if (tagKey === "#text") return {
|
|
157
|
+
type: "text",
|
|
158
|
+
value: asString(raw["#text"])
|
|
159
|
+
};
|
|
160
|
+
if (tagKey === "__comment") return {
|
|
161
|
+
type: "comment",
|
|
162
|
+
value: scalarText(raw.__comment)
|
|
163
|
+
};
|
|
164
|
+
if (tagKey === "__cdata") return {
|
|
165
|
+
type: "cdata",
|
|
166
|
+
value: scalarText(raw.__cdata)
|
|
167
|
+
};
|
|
168
|
+
if (tagKey === "?xml") return {
|
|
169
|
+
type: "declaration",
|
|
170
|
+
attributes
|
|
171
|
+
};
|
|
172
|
+
if (tagKey.startsWith("?")) return {
|
|
173
|
+
type: "pi",
|
|
174
|
+
target: tagKey.slice(1),
|
|
175
|
+
content: scalarText(raw[tagKey])
|
|
176
|
+
};
|
|
177
|
+
return {
|
|
178
|
+
type: "element",
|
|
179
|
+
tag: tagKey,
|
|
180
|
+
attributes,
|
|
181
|
+
children: parseNodes(raw[tagKey])
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function parseAttributes(raw) {
|
|
185
|
+
if (raw === void 0) return [];
|
|
186
|
+
if (!isRecord(raw)) throw new Error("XML attributes were not an object");
|
|
187
|
+
const attrs = [];
|
|
188
|
+
for (const key of Object.keys(raw)) {
|
|
189
|
+
if (!key.startsWith("@_")) throw new Error(`unexpected attribute key without @_ prefix: ${key}`);
|
|
190
|
+
attrs.push({
|
|
191
|
+
name: key.slice(2),
|
|
192
|
+
value: asString(raw[key])
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return attrs;
|
|
196
|
+
}
|
|
197
|
+
function scalarText(raw) {
|
|
198
|
+
if (!isUnknownArray$1(raw) || raw.length === 0) throw new Error("expected a scalar-text wrapper array");
|
|
199
|
+
const first = raw[0];
|
|
200
|
+
if (!isRecord(first)) throw new Error("scalar-text wrapper was not an object");
|
|
201
|
+
return asString(first["#text"]);
|
|
202
|
+
}
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region src/zip.ts
|
|
205
|
+
function unzipPackage(bytes) {
|
|
206
|
+
return (0, fflate.unzipSync)(bytes);
|
|
207
|
+
}
|
|
208
|
+
function zipPackage(parts) {
|
|
209
|
+
return (0, fflate.zipSync)(parts);
|
|
210
|
+
}
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/package-io/read.ts
|
|
213
|
+
function parsePackage(bytes) {
|
|
214
|
+
const entries = unzipPackage(bytes);
|
|
215
|
+
const parts = {};
|
|
216
|
+
for (const [path, partBytes] of Object.entries(entries)) if (looksLikeXml(partBytes)) parts[path] = {
|
|
217
|
+
kind: "xml",
|
|
218
|
+
nodes: parseXml(new TextDecoder("utf-8").decode(partBytes))
|
|
219
|
+
};
|
|
220
|
+
else parts[path] = {
|
|
221
|
+
kind: "binary",
|
|
222
|
+
base64: bytesToBase64(partBytes)
|
|
223
|
+
};
|
|
224
|
+
return { parts };
|
|
225
|
+
}
|
|
226
|
+
function looksLikeXml(bytes) {
|
|
227
|
+
let i = 0;
|
|
228
|
+
if (bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) i = 3;
|
|
229
|
+
while (i < bytes.length) {
|
|
230
|
+
const b = bytes[i];
|
|
231
|
+
if (b === 32 || b === 9 || b === 10 || b === 13) {
|
|
232
|
+
i = i + 1;
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
return b === 60;
|
|
236
|
+
}
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/xml/build.ts
|
|
241
|
+
const BUILDER = new fast_xml_parser.XMLBuilder({
|
|
242
|
+
preserveOrder: true,
|
|
243
|
+
attributeNamePrefix: "@_",
|
|
244
|
+
ignoreAttributes: false,
|
|
245
|
+
textNodeName: "#text",
|
|
246
|
+
cdataPropName: "__cdata",
|
|
247
|
+
commentPropName: "__comment",
|
|
248
|
+
processEntities: false,
|
|
249
|
+
format: false,
|
|
250
|
+
suppressEmptyNode: false
|
|
251
|
+
});
|
|
252
|
+
function buildXml(nodes) {
|
|
253
|
+
const out = BUILDER.build(toOrdered(nodes));
|
|
254
|
+
if (typeof out !== "string") throw new Error("XMLBuilder did not return a string");
|
|
255
|
+
return out;
|
|
256
|
+
}
|
|
257
|
+
function toOrdered(nodes) {
|
|
258
|
+
return nodes.map(toOrderedNode);
|
|
259
|
+
}
|
|
260
|
+
function attrsObject(attributes) {
|
|
261
|
+
const obj = {};
|
|
262
|
+
for (const a of attributes) obj[`@_${a.name}`] = a.value;
|
|
263
|
+
return obj;
|
|
264
|
+
}
|
|
265
|
+
function toOrderedNode(node) {
|
|
266
|
+
switch (node.type) {
|
|
267
|
+
case "text": return { "#text": node.value };
|
|
268
|
+
case "comment": return { __comment: [{ "#text": node.value }] };
|
|
269
|
+
case "cdata": return { __cdata: [{ "#text": node.value }] };
|
|
270
|
+
case "pi": return { [`?${node.target}`]: [{ "#text": node.content }] };
|
|
271
|
+
case "declaration": return {
|
|
272
|
+
"?xml": [{ "#text": "" }],
|
|
273
|
+
":@": attrsObject(node.attributes)
|
|
274
|
+
};
|
|
275
|
+
case "element": {
|
|
276
|
+
const obj = { [node.tag]: toOrdered(node.children) };
|
|
277
|
+
const attrs = attrsObject(node.attributes);
|
|
278
|
+
if (Object.keys(attrs).length > 0) obj[":@"] = attrs;
|
|
279
|
+
return obj;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/package-io/write.ts
|
|
285
|
+
function serializePackage(pkg) {
|
|
286
|
+
const entries = {};
|
|
287
|
+
for (const [path, part] of Object.entries(pkg.parts)) entries[path] = partToBytes(part);
|
|
288
|
+
return zipPackage(entries);
|
|
289
|
+
}
|
|
290
|
+
function partToBytes(part) {
|
|
291
|
+
switch (part.kind) {
|
|
292
|
+
case "xml": return new TextEncoder().encode(buildXml(part.nodes));
|
|
293
|
+
case "binary": return base64ToBytes(part.base64);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/codec.ts
|
|
298
|
+
const xmlCodec = zod.z.codec(zod.z.string(), zod.z.array(XmlNodeSchema), {
|
|
299
|
+
decode: (xml) => parseXml(xml),
|
|
300
|
+
encode: (nodes) => buildXml(nodes)
|
|
301
|
+
});
|
|
302
|
+
const packageCodec = zod.z.codec(zod.z.instanceof(Uint8Array), PackageSchema, {
|
|
303
|
+
decode: (bytes) => parsePackage(bytes),
|
|
304
|
+
encode: (pkg) => serializePackage(pkg)
|
|
305
|
+
});
|
|
306
|
+
function decodePackage(bytes) {
|
|
307
|
+
return zod.z.decode(packageCodec, bytes);
|
|
308
|
+
}
|
|
309
|
+
function encodePackage(pkg) {
|
|
310
|
+
return zod.z.encode(packageCodec, pkg);
|
|
311
|
+
}
|
|
312
|
+
//#endregion
|
|
313
|
+
//#region src/compact.ts
|
|
314
|
+
function isUnknownArray(value) {
|
|
315
|
+
return Array.isArray(value);
|
|
316
|
+
}
|
|
317
|
+
function isCompactAttrPairs(value) {
|
|
318
|
+
return isUnknownArray(value) && value.every((v) => typeof v === "number");
|
|
319
|
+
}
|
|
320
|
+
function isCompactXmlNode(value) {
|
|
321
|
+
if (!isUnknownArray(value)) return false;
|
|
322
|
+
const code = value[0];
|
|
323
|
+
if (code === 1 || code === 2 || code === 3) return value.length === 2 && typeof value[1] === "number";
|
|
324
|
+
if (code === 4) return value.length === 2 && isCompactAttrPairs(value[1]);
|
|
325
|
+
if (code === 5) return value.length === 3 && typeof value[1] === "number" && typeof value[2] === "number";
|
|
326
|
+
if (code === 0) return value.length === 4 && typeof value[1] === "number" && isCompactAttrPairs(value[2]) && Array.isArray(value[3]) && value[3].every(isCompactXmlNode);
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
const CompactXmlNodeSchema = zod.z.custom(isCompactXmlNode);
|
|
330
|
+
const CompactPartSchema = zod.z.union([zod.z.array(CompactXmlNodeSchema), zod.z.number()]);
|
|
331
|
+
const CompactPackageSchema = zod.z.object({
|
|
332
|
+
s: zod.z.array(zod.z.string()),
|
|
333
|
+
p: zod.z.record(zod.z.string(), CompactPartSchema)
|
|
334
|
+
});
|
|
335
|
+
var StringTable = class {
|
|
336
|
+
indices = /* @__PURE__ */ new Map();
|
|
337
|
+
strings = [];
|
|
338
|
+
intern(value) {
|
|
339
|
+
const existing = this.indices.get(value);
|
|
340
|
+
if (existing !== void 0) return existing;
|
|
341
|
+
const index = this.strings.length;
|
|
342
|
+
this.indices.set(value, index);
|
|
343
|
+
this.strings.push(value);
|
|
344
|
+
return index;
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
function encodeAttrs(attributes, table) {
|
|
348
|
+
const pairs = [];
|
|
349
|
+
for (const attribute of attributes) pairs.push(table.intern(attribute.name), table.intern(attribute.value));
|
|
350
|
+
return pairs;
|
|
351
|
+
}
|
|
352
|
+
function encodeNode(node, table) {
|
|
353
|
+
switch (node.type) {
|
|
354
|
+
case "text": return [1, table.intern(node.value)];
|
|
355
|
+
case "cdata": return [2, table.intern(node.value)];
|
|
356
|
+
case "comment": return [3, table.intern(node.value)];
|
|
357
|
+
case "declaration": return [4, encodeAttrs(node.attributes, table)];
|
|
358
|
+
case "pi": return [
|
|
359
|
+
5,
|
|
360
|
+
table.intern(node.target),
|
|
361
|
+
table.intern(node.content)
|
|
362
|
+
];
|
|
363
|
+
case "element": return [
|
|
364
|
+
0,
|
|
365
|
+
table.intern(node.tag),
|
|
366
|
+
encodeAttrs(node.attributes, table),
|
|
367
|
+
node.children.map((child) => encodeNode(child, table))
|
|
368
|
+
];
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function packageToCompact(pkg) {
|
|
372
|
+
const table = new StringTable();
|
|
373
|
+
const p = {};
|
|
374
|
+
for (const [path, part] of Object.entries(pkg.parts)) p[path] = part.kind === "binary" ? table.intern(part.base64) : part.nodes.map((node) => encodeNode(node, table));
|
|
375
|
+
return {
|
|
376
|
+
s: table.strings,
|
|
377
|
+
p
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function stringAt(strings, index) {
|
|
381
|
+
const value = strings[index];
|
|
382
|
+
if (value === void 0) throw new Error(`fromCompact: string table index ${index} is out of range`);
|
|
383
|
+
return value;
|
|
384
|
+
}
|
|
385
|
+
function decodeAttrs(pairs, strings) {
|
|
386
|
+
const attributes = [];
|
|
387
|
+
for (let i = 0; i < pairs.length; i += 2) {
|
|
388
|
+
const nameIdx = pairs[i];
|
|
389
|
+
const valueIdx = pairs[i + 1];
|
|
390
|
+
if (nameIdx === void 0 || valueIdx === void 0) throw new Error("fromCompact: attribute index pairs array has odd length");
|
|
391
|
+
attributes.push({
|
|
392
|
+
name: stringAt(strings, nameIdx),
|
|
393
|
+
value: stringAt(strings, valueIdx)
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return attributes;
|
|
397
|
+
}
|
|
398
|
+
function decodeNode(node, strings) {
|
|
399
|
+
switch (node[0]) {
|
|
400
|
+
case 1: return {
|
|
401
|
+
type: "text",
|
|
402
|
+
value: stringAt(strings, node[1])
|
|
403
|
+
};
|
|
404
|
+
case 2: return {
|
|
405
|
+
type: "cdata",
|
|
406
|
+
value: stringAt(strings, node[1])
|
|
407
|
+
};
|
|
408
|
+
case 3: return {
|
|
409
|
+
type: "comment",
|
|
410
|
+
value: stringAt(strings, node[1])
|
|
411
|
+
};
|
|
412
|
+
case 4: return {
|
|
413
|
+
type: "declaration",
|
|
414
|
+
attributes: decodeAttrs(node[1], strings)
|
|
415
|
+
};
|
|
416
|
+
case 5: return {
|
|
417
|
+
type: "pi",
|
|
418
|
+
target: stringAt(strings, node[1]),
|
|
419
|
+
content: stringAt(strings, node[2])
|
|
420
|
+
};
|
|
421
|
+
case 0: return {
|
|
422
|
+
type: "element",
|
|
423
|
+
tag: stringAt(strings, node[1]),
|
|
424
|
+
attributes: decodeAttrs(node[2], strings),
|
|
425
|
+
children: node[3].map((child) => decodeNode(child, strings))
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function compactToPackage(cpkg) {
|
|
430
|
+
const parts = {};
|
|
431
|
+
for (const [path, part] of Object.entries(cpkg.p)) parts[path] = typeof part === "number" ? {
|
|
432
|
+
kind: "binary",
|
|
433
|
+
base64: stringAt(cpkg.s, part)
|
|
434
|
+
} : {
|
|
435
|
+
kind: "xml",
|
|
436
|
+
nodes: part.map((node) => decodeNode(node, cpkg.s))
|
|
437
|
+
};
|
|
438
|
+
return { parts };
|
|
439
|
+
}
|
|
440
|
+
const compactCodec = zod.z.codec(PackageSchema, CompactPackageSchema, {
|
|
441
|
+
decode: (pkg) => packageToCompact(pkg),
|
|
442
|
+
encode: (cpkg) => compactToPackage(cpkg)
|
|
443
|
+
});
|
|
444
|
+
function toCompact(pkg) {
|
|
445
|
+
return zod.z.decode(compactCodec, pkg);
|
|
446
|
+
}
|
|
447
|
+
function fromCompact(cpkg) {
|
|
448
|
+
return zod.z.encode(compactCodec, cpkg);
|
|
449
|
+
}
|
|
450
|
+
const compactPackageCodec = zod.z.codec(zod.z.instanceof(Uint8Array), CompactPackageSchema, {
|
|
451
|
+
decode: (bytes) => toCompact(decodePackage(bytes)),
|
|
452
|
+
encode: (cpkg) => encodePackage(fromCompact(cpkg))
|
|
453
|
+
});
|
|
454
|
+
function decodeCompactPackage(bytes) {
|
|
455
|
+
return zod.z.decode(compactPackageCodec, bytes);
|
|
456
|
+
}
|
|
457
|
+
function encodeCompactPackage(cpkg) {
|
|
458
|
+
return zod.z.encode(compactPackageCodec, cpkg);
|
|
459
|
+
}
|
|
460
|
+
//#endregion
|
|
461
|
+
//#region src/typed/util.ts
|
|
462
|
+
function* walk(nodes) {
|
|
463
|
+
for (const node of nodes) {
|
|
464
|
+
yield node;
|
|
465
|
+
if (node.type === "element") yield* walk(node.children);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
function elementsWithTag(nodes, tag) {
|
|
469
|
+
const out = [];
|
|
470
|
+
for (const node of walk(nodes)) if (node.type === "element" && node.tag === tag) out.push(node);
|
|
471
|
+
return out;
|
|
472
|
+
}
|
|
473
|
+
function childrenWithTag(element, tag) {
|
|
474
|
+
const out = [];
|
|
475
|
+
for (const child of element.children) if (child.type === "element" && child.tag === tag) out.push(child);
|
|
476
|
+
return out;
|
|
477
|
+
}
|
|
478
|
+
function attr(element, name) {
|
|
479
|
+
for (const a of element.attributes) if (a.name === name) return a.value;
|
|
480
|
+
}
|
|
481
|
+
function rootElement(part) {
|
|
482
|
+
if (part?.kind !== "xml") return;
|
|
483
|
+
for (const node of part.nodes) if (node.type === "element") return node;
|
|
484
|
+
}
|
|
485
|
+
function decodeEntities(value) {
|
|
486
|
+
return value.replace(/&(?:amp|lt|gt|quot|apos);/g, (entity) => {
|
|
487
|
+
switch (entity) {
|
|
488
|
+
case "&": return "&";
|
|
489
|
+
case "<": return "<";
|
|
490
|
+
case ">": return ">";
|
|
491
|
+
case """: return "\"";
|
|
492
|
+
case "'": return "'";
|
|
493
|
+
default: return entity;
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
function textContent(element) {
|
|
498
|
+
let text = "";
|
|
499
|
+
for (const node of walk(element.children)) if (node.type === "text" || node.type === "cdata") text += node.value;
|
|
500
|
+
return decodeEntities(text);
|
|
501
|
+
}
|
|
502
|
+
function relsPathFor(partPath) {
|
|
503
|
+
const lastSlash = partPath.lastIndexOf("/");
|
|
504
|
+
return `${lastSlash === -1 ? "" : partPath.slice(0, lastSlash)}/_rels/${lastSlash === -1 ? partPath : partPath.slice(lastSlash + 1)}.rels`;
|
|
505
|
+
}
|
|
506
|
+
function resolveRelTarget$1(partPath, target) {
|
|
507
|
+
if (target.startsWith("/")) return target.slice(1);
|
|
508
|
+
const lastSlash = partPath.lastIndexOf("/");
|
|
509
|
+
const baseDir = lastSlash === -1 ? "" : partPath.slice(0, lastSlash);
|
|
510
|
+
const resolved = [];
|
|
511
|
+
for (const segment of `${baseDir}/${target}`.split("/")) {
|
|
512
|
+
if (segment === "" || segment === ".") continue;
|
|
513
|
+
if (segment === "..") resolved.pop();
|
|
514
|
+
else resolved.push(segment);
|
|
515
|
+
}
|
|
516
|
+
return resolved.join("/");
|
|
517
|
+
}
|
|
518
|
+
function resolveRelationships(pkg, partPath) {
|
|
519
|
+
const map = /* @__PURE__ */ new Map();
|
|
520
|
+
const rels = rootElement(pkg.parts[relsPathFor(partPath)]);
|
|
521
|
+
if (rels === void 0) return map;
|
|
522
|
+
for (const rel of childrenWithTag(rels, "Relationship")) {
|
|
523
|
+
const id = attr(rel, "Id");
|
|
524
|
+
const type = attr(rel, "Type");
|
|
525
|
+
const target = attr(rel, "Target");
|
|
526
|
+
if (id === void 0 || type === void 0 || target === void 0) continue;
|
|
527
|
+
const targetMode = attr(rel, "TargetMode");
|
|
528
|
+
map.set(id, {
|
|
529
|
+
type,
|
|
530
|
+
target: targetMode === "External" ? target : resolveRelTarget$1(partPath, target),
|
|
531
|
+
targetMode
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
return map;
|
|
535
|
+
}
|
|
536
|
+
//#endregion
|
|
537
|
+
//#region src/typed/docx.ts
|
|
538
|
+
const RunSchema = zod.z.object({
|
|
539
|
+
text: zod.z.string(),
|
|
540
|
+
bold: zod.z.boolean().optional(),
|
|
541
|
+
italic: zod.z.boolean().optional()
|
|
542
|
+
});
|
|
543
|
+
const ListMembershipSchema = zod.z.object({
|
|
544
|
+
numId: zod.z.string(),
|
|
545
|
+
level: zod.z.number()
|
|
546
|
+
});
|
|
547
|
+
const ParagraphSchema = zod.z.object({
|
|
548
|
+
runs: zod.z.array(RunSchema),
|
|
549
|
+
list: ListMembershipSchema.optional()
|
|
550
|
+
});
|
|
551
|
+
const TableCellSchema = zod.z.object({ paragraphs: zod.z.array(ParagraphSchema) });
|
|
552
|
+
const TableRowSchema = zod.z.object({ cells: zod.z.array(TableCellSchema) });
|
|
553
|
+
const TableSchema = zod.z.object({ rows: zod.z.array(TableRowSchema) });
|
|
554
|
+
const HyperlinkSchema = zod.z.object({
|
|
555
|
+
text: zod.z.string(),
|
|
556
|
+
target: zod.z.string()
|
|
557
|
+
});
|
|
558
|
+
const CommentSchema = zod.z.object({
|
|
559
|
+
author: zod.z.string().optional(),
|
|
560
|
+
text: zod.z.string()
|
|
561
|
+
});
|
|
562
|
+
const FootnoteSchema = zod.z.object({
|
|
563
|
+
type: zod.z.string().optional(),
|
|
564
|
+
text: zod.z.string()
|
|
565
|
+
});
|
|
566
|
+
const DocxDocumentSchema = zod.z.object({
|
|
567
|
+
paragraphs: zod.z.array(ParagraphSchema),
|
|
568
|
+
tables: zod.z.array(TableSchema),
|
|
569
|
+
hyperlinks: zod.z.array(HyperlinkSchema),
|
|
570
|
+
comments: zod.z.array(CommentSchema),
|
|
571
|
+
footnotes: zod.z.array(FootnoteSchema),
|
|
572
|
+
headers: zod.z.array(zod.z.string()),
|
|
573
|
+
footers: zod.z.array(zod.z.string())
|
|
574
|
+
});
|
|
575
|
+
function runPropertyOn(run, tag) {
|
|
576
|
+
const rPr = run.children.find((child) => child.type === "element" && child.tag === "w:rPr");
|
|
577
|
+
return rPr !== void 0 && elementsWithTag(rPr.children, tag).length > 0;
|
|
578
|
+
}
|
|
579
|
+
function readRun(run) {
|
|
580
|
+
const result = { text: elementsWithTag(run.children, "w:t").map(textContent).join("") };
|
|
581
|
+
if (runPropertyOn(run, "w:b")) result.bold = true;
|
|
582
|
+
if (runPropertyOn(run, "w:i")) result.italic = true;
|
|
583
|
+
return result;
|
|
584
|
+
}
|
|
585
|
+
function readListMembership(paragraph) {
|
|
586
|
+
const pPr = childrenWithTag(paragraph, "w:pPr")[0];
|
|
587
|
+
if (pPr === void 0) return;
|
|
588
|
+
const numPr = childrenWithTag(pPr, "w:numPr")[0];
|
|
589
|
+
if (numPr === void 0) return;
|
|
590
|
+
const numIdEl = childrenWithTag(numPr, "w:numId")[0];
|
|
591
|
+
const numId = numIdEl !== void 0 ? attr(numIdEl, "w:val") : void 0;
|
|
592
|
+
if (numId === void 0) return;
|
|
593
|
+
const ilvlEl = childrenWithTag(numPr, "w:ilvl")[0];
|
|
594
|
+
const ilvlVal = ilvlEl !== void 0 ? attr(ilvlEl, "w:val") : void 0;
|
|
595
|
+
return {
|
|
596
|
+
numId,
|
|
597
|
+
level: ilvlVal !== void 0 ? Number(ilvlVal) : 0
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
function readParagraph(paragraph) {
|
|
601
|
+
const result = { runs: elementsWithTag(paragraph.children, "w:r").map(readRun) };
|
|
602
|
+
const list = readListMembership(paragraph);
|
|
603
|
+
if (list !== void 0) result.list = list;
|
|
604
|
+
return result;
|
|
605
|
+
}
|
|
606
|
+
function readCell$1(cell) {
|
|
607
|
+
return { paragraphs: childrenWithTag(cell, "w:p").map(readParagraph) };
|
|
608
|
+
}
|
|
609
|
+
function readRow(row) {
|
|
610
|
+
return { cells: childrenWithTag(row, "w:tc").map(readCell$1) };
|
|
611
|
+
}
|
|
612
|
+
function readTable$1(table) {
|
|
613
|
+
return { rows: childrenWithTag(table, "w:tr").map(readRow) };
|
|
614
|
+
}
|
|
615
|
+
function readHyperlink(hyperlink, rels) {
|
|
616
|
+
const text = elementsWithTag(hyperlink.children, "w:t").map(textContent).join("");
|
|
617
|
+
const rid = attr(hyperlink, "r:id");
|
|
618
|
+
return {
|
|
619
|
+
text,
|
|
620
|
+
target: rid !== void 0 ? rels.get(rid)?.target ?? "" : ""
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function readComment(comment) {
|
|
624
|
+
const author = attr(comment, "w:author");
|
|
625
|
+
const result = { text: elementsWithTag(comment.children, "w:t").map(textContent).join("") };
|
|
626
|
+
if (author !== void 0) result.author = author;
|
|
627
|
+
return result;
|
|
628
|
+
}
|
|
629
|
+
function readFootnote(footnote) {
|
|
630
|
+
const type = attr(footnote, "w:type");
|
|
631
|
+
const result = { text: elementsWithTag(footnote.children, "w:t").map(textContent).join("") };
|
|
632
|
+
if (type !== void 0) result.type = type;
|
|
633
|
+
return result;
|
|
634
|
+
}
|
|
635
|
+
function readComments(pkg) {
|
|
636
|
+
const root = rootElement(pkg.parts["word/comments.xml"]);
|
|
637
|
+
if (root === void 0) return [];
|
|
638
|
+
return childrenWithTag(root, "w:comment").map(readComment);
|
|
639
|
+
}
|
|
640
|
+
function readFootnotes(pkg) {
|
|
641
|
+
const root = rootElement(pkg.parts["word/footnotes.xml"]);
|
|
642
|
+
if (root === void 0) return [];
|
|
643
|
+
const out = [];
|
|
644
|
+
for (const fn of childrenWithTag(root, "w:footnote")) {
|
|
645
|
+
const type = attr(fn, "w:type");
|
|
646
|
+
if (type === "separator" || type === "continuationSeparator") continue;
|
|
647
|
+
out.push(readFootnote(fn));
|
|
648
|
+
}
|
|
649
|
+
return out;
|
|
650
|
+
}
|
|
651
|
+
function readHeaderFooterText(pkg, prefix) {
|
|
652
|
+
const out = [];
|
|
653
|
+
for (const path of Object.keys(pkg.parts)) {
|
|
654
|
+
if (!path.startsWith(prefix) || !path.endsWith(".xml")) continue;
|
|
655
|
+
const part = pkg.parts[path];
|
|
656
|
+
if (part?.kind !== "xml") continue;
|
|
657
|
+
out.push(elementsWithTag(part.nodes, "w:t").map(textContent).join(""));
|
|
658
|
+
}
|
|
659
|
+
return out;
|
|
660
|
+
}
|
|
661
|
+
function readDocx(pkg) {
|
|
662
|
+
const part = pkg.parts["word/document.xml"];
|
|
663
|
+
if (part === void 0) throw new Error("readDocx: package has no word/document.xml part");
|
|
664
|
+
if (part.kind !== "xml") throw new Error("readDocx: word/document.xml is not an XML part");
|
|
665
|
+
const rels = resolveRelationships(pkg, "word/document.xml");
|
|
666
|
+
return {
|
|
667
|
+
paragraphs: elementsWithTag(part.nodes, "w:p").map(readParagraph),
|
|
668
|
+
tables: elementsWithTag(part.nodes, "w:tbl").map(readTable$1),
|
|
669
|
+
hyperlinks: elementsWithTag(part.nodes, "w:hyperlink").map((h) => readHyperlink(h, rels)),
|
|
670
|
+
comments: readComments(pkg),
|
|
671
|
+
footnotes: readFootnotes(pkg),
|
|
672
|
+
headers: readHeaderFooterText(pkg, "word/header"),
|
|
673
|
+
footers: readHeaderFooterText(pkg, "word/footer")
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
//#endregion
|
|
677
|
+
//#region src/typed/pptx.ts
|
|
678
|
+
const ShapeSchema = zod.z.object({ text: zod.z.string() });
|
|
679
|
+
const PptxTableCellSchema = zod.z.object({ text: zod.z.string() });
|
|
680
|
+
const PptxTableRowSchema = zod.z.object({ cells: zod.z.array(PptxTableCellSchema) });
|
|
681
|
+
const PptxTableSchema = zod.z.object({ rows: zod.z.array(PptxTableRowSchema) });
|
|
682
|
+
const SlideSchema = zod.z.object({
|
|
683
|
+
index: zod.z.number().int(),
|
|
684
|
+
text: zod.z.string(),
|
|
685
|
+
shapes: zod.z.array(ShapeSchema),
|
|
686
|
+
tables: zod.z.array(PptxTableSchema),
|
|
687
|
+
notes: zod.z.string()
|
|
688
|
+
});
|
|
689
|
+
const PptxPresentationSchema = zod.z.object({ slides: zod.z.array(SlideSchema) });
|
|
690
|
+
const SLIDE_PATH = /^ppt\/slides\/slide(\d+)\.xml$/;
|
|
691
|
+
function txBodyText(parent, txBodyTag) {
|
|
692
|
+
const txBody = childrenWithTag(parent, txBodyTag)[0];
|
|
693
|
+
if (txBody === void 0) return "";
|
|
694
|
+
return elementsWithTag(txBody.children, "a:t").map(textContent).join("");
|
|
695
|
+
}
|
|
696
|
+
function readShape(shape) {
|
|
697
|
+
return { text: txBodyText(shape, "p:txBody") };
|
|
698
|
+
}
|
|
699
|
+
function readTableCell(cell) {
|
|
700
|
+
return { text: txBodyText(cell, "a:txBody") };
|
|
701
|
+
}
|
|
702
|
+
function readTableRow(row) {
|
|
703
|
+
return { cells: childrenWithTag(row, "a:tc").map(readTableCell) };
|
|
704
|
+
}
|
|
705
|
+
function readTable(table) {
|
|
706
|
+
return { rows: childrenWithTag(table, "a:tr").map(readTableRow) };
|
|
707
|
+
}
|
|
708
|
+
function readNotes(pkg, slidePath) {
|
|
709
|
+
const rels = resolveRelationships(pkg, slidePath);
|
|
710
|
+
let notesPath;
|
|
711
|
+
for (const rel of rels.values()) if (rel.type.endsWith("/notesSlide")) {
|
|
712
|
+
notesPath = rel.target;
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
if (notesPath === void 0) return "";
|
|
716
|
+
const part = pkg.parts[notesPath];
|
|
717
|
+
if (part?.kind !== "xml") return "";
|
|
718
|
+
return elementsWithTag(part.nodes, "a:t").map(textContent).join("");
|
|
719
|
+
}
|
|
720
|
+
function readPptx(pkg) {
|
|
721
|
+
const found = [];
|
|
722
|
+
for (const [path, part] of Object.entries(pkg.parts)) {
|
|
723
|
+
const match = SLIDE_PATH.exec(path);
|
|
724
|
+
if (match === null) continue;
|
|
725
|
+
const captured = match[1];
|
|
726
|
+
if (captured === void 0) continue;
|
|
727
|
+
if (part.kind !== "xml") continue;
|
|
728
|
+
const index = Number(captured);
|
|
729
|
+
const text = elementsWithTag(part.nodes, "a:t").map(textContent).join("");
|
|
730
|
+
const shapes = elementsWithTag(part.nodes, "p:sp").map(readShape);
|
|
731
|
+
const tables = elementsWithTag(part.nodes, "a:tbl").map(readTable);
|
|
732
|
+
const notes = readNotes(pkg, path);
|
|
733
|
+
found.push({
|
|
734
|
+
index,
|
|
735
|
+
text,
|
|
736
|
+
shapes,
|
|
737
|
+
tables,
|
|
738
|
+
notes
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
found.sort((a, b) => a.index - b.index);
|
|
742
|
+
return { slides: found };
|
|
743
|
+
}
|
|
744
|
+
//#endregion
|
|
745
|
+
//#region src/typed/xlsx.ts
|
|
746
|
+
const XlsxCellSchema = zod.z.object({
|
|
747
|
+
reference: zod.z.string(),
|
|
748
|
+
value: zod.z.string(),
|
|
749
|
+
formula: zod.z.string().optional()
|
|
750
|
+
});
|
|
751
|
+
const XlsxSheetSchema = zod.z.object({
|
|
752
|
+
name: zod.z.string(),
|
|
753
|
+
cells: zod.z.array(XlsxCellSchema),
|
|
754
|
+
mergedRanges: zod.z.array(zod.z.string())
|
|
755
|
+
});
|
|
756
|
+
const DefinedNameSchema = zod.z.object({
|
|
757
|
+
name: zod.z.string(),
|
|
758
|
+
refersTo: zod.z.string()
|
|
759
|
+
});
|
|
760
|
+
const XlsxWorkbookSchema = zod.z.object({
|
|
761
|
+
sheets: zod.z.array(XlsxSheetSchema),
|
|
762
|
+
definedNames: zod.z.array(DefinedNameSchema)
|
|
763
|
+
});
|
|
764
|
+
const SHEET_PATH_RE = /^xl\/worksheets\/sheet(\d+)\.xml$/;
|
|
765
|
+
function loadSharedStrings(pkg) {
|
|
766
|
+
const root = rootElement(pkg.parts["xl/sharedStrings.xml"]);
|
|
767
|
+
if (root === void 0) return [];
|
|
768
|
+
const strings = [];
|
|
769
|
+
for (const si of childrenWithTag(root, "si")) {
|
|
770
|
+
let value = "";
|
|
771
|
+
for (const t of elementsWithTag(si.children, "t")) value += textContent(t);
|
|
772
|
+
strings.push(value);
|
|
773
|
+
}
|
|
774
|
+
return strings;
|
|
775
|
+
}
|
|
776
|
+
function resolveRelTarget(target) {
|
|
777
|
+
if (target.startsWith("/")) return target.slice(1);
|
|
778
|
+
return `xl/${target}`;
|
|
779
|
+
}
|
|
780
|
+
function relTargets(pkg) {
|
|
781
|
+
const map = /* @__PURE__ */ new Map();
|
|
782
|
+
const rels = rootElement(pkg.parts["xl/_rels/workbook.xml.rels"]);
|
|
783
|
+
if (rels === void 0) return map;
|
|
784
|
+
for (const rel of childrenWithTag(rels, "Relationship")) {
|
|
785
|
+
const id = attr(rel, "Id");
|
|
786
|
+
const target = attr(rel, "Target");
|
|
787
|
+
if (id !== void 0 && target !== void 0) map.set(id, resolveRelTarget(target));
|
|
788
|
+
}
|
|
789
|
+
return map;
|
|
790
|
+
}
|
|
791
|
+
function resolveSheetNames(pkg) {
|
|
792
|
+
const names = /* @__PURE__ */ new Map();
|
|
793
|
+
const workbook = rootElement(pkg.parts["xl/workbook.xml"]);
|
|
794
|
+
if (workbook === void 0) return names;
|
|
795
|
+
const targets = relTargets(pkg);
|
|
796
|
+
for (const sheet of elementsWithTag(workbook.children, "sheet")) {
|
|
797
|
+
const name = attr(sheet, "name");
|
|
798
|
+
const rid = attr(sheet, "r:id");
|
|
799
|
+
if (name !== void 0 && rid !== void 0) {
|
|
800
|
+
const partName = targets.get(rid);
|
|
801
|
+
if (partName !== void 0) names.set(partName, name);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return names;
|
|
805
|
+
}
|
|
806
|
+
function readDefinedNames(pkg) {
|
|
807
|
+
const names = [];
|
|
808
|
+
const workbook = rootElement(pkg.parts["xl/workbook.xml"]);
|
|
809
|
+
if (workbook === void 0) return names;
|
|
810
|
+
for (const container of elementsWithTag(workbook.children, "definedNames")) for (const definedName of childrenWithTag(container, "definedName")) {
|
|
811
|
+
const name = attr(definedName, "name");
|
|
812
|
+
if (name === void 0) continue;
|
|
813
|
+
names.push({
|
|
814
|
+
name,
|
|
815
|
+
refersTo: textContent(definedName)
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
return names;
|
|
819
|
+
}
|
|
820
|
+
function sheetNumberOf(path) {
|
|
821
|
+
const match = SHEET_PATH_RE.exec(path);
|
|
822
|
+
const digits = match === null ? void 0 : match[1];
|
|
823
|
+
if (digits === void 0) return;
|
|
824
|
+
return Number.parseInt(digits, 10);
|
|
825
|
+
}
|
|
826
|
+
function readCell(cell, sharedStrings) {
|
|
827
|
+
const reference = attr(cell, "r");
|
|
828
|
+
if (reference === void 0) return;
|
|
829
|
+
const valueEl = childrenWithTag(cell, "v")[0];
|
|
830
|
+
if (valueEl === void 0) return;
|
|
831
|
+
const raw = textContent(valueEl);
|
|
832
|
+
let value;
|
|
833
|
+
if (attr(cell, "t") === "s") {
|
|
834
|
+
const index = Number.parseInt(raw, 10);
|
|
835
|
+
value = Number.isInteger(index) ? sharedStrings[index] : void 0;
|
|
836
|
+
} else value = raw;
|
|
837
|
+
if (value === void 0) return;
|
|
838
|
+
const projected = {
|
|
839
|
+
reference,
|
|
840
|
+
value
|
|
841
|
+
};
|
|
842
|
+
const formulaEl = childrenWithTag(cell, "f")[0];
|
|
843
|
+
if (formulaEl !== void 0) projected.formula = textContent(formulaEl);
|
|
844
|
+
return projected;
|
|
845
|
+
}
|
|
846
|
+
function readCells(worksheet, sharedStrings) {
|
|
847
|
+
const cells = [];
|
|
848
|
+
for (const row of elementsWithTag(worksheet.children, "row")) for (const cell of childrenWithTag(row, "c")) {
|
|
849
|
+
const projected = readCell(cell, sharedStrings);
|
|
850
|
+
if (projected !== void 0) cells.push(projected);
|
|
851
|
+
}
|
|
852
|
+
return cells;
|
|
853
|
+
}
|
|
854
|
+
function readMergedRanges(worksheet) {
|
|
855
|
+
const ranges = [];
|
|
856
|
+
for (const mergeCells of elementsWithTag(worksheet.children, "mergeCells")) for (const mergeCell of childrenWithTag(mergeCells, "mergeCell")) {
|
|
857
|
+
const ref = attr(mergeCell, "ref");
|
|
858
|
+
if (ref !== void 0) ranges.push(ref);
|
|
859
|
+
}
|
|
860
|
+
return ranges;
|
|
861
|
+
}
|
|
862
|
+
function readXlsx(pkg) {
|
|
863
|
+
const sharedStrings = loadSharedStrings(pkg);
|
|
864
|
+
const names = resolveSheetNames(pkg);
|
|
865
|
+
const definedNames = readDefinedNames(pkg);
|
|
866
|
+
const worksheets = Object.keys(pkg.parts).map((path) => ({
|
|
867
|
+
path,
|
|
868
|
+
number: sheetNumberOf(path)
|
|
869
|
+
})).filter((entry) => entry.number !== void 0).sort((a, b) => a.number - b.number);
|
|
870
|
+
const sheets = [];
|
|
871
|
+
for (const { path, number } of worksheets) {
|
|
872
|
+
const root = rootElement(pkg.parts[path]);
|
|
873
|
+
if (root === void 0) continue;
|
|
874
|
+
const name = names.get(path) ?? `Sheet${number}`;
|
|
875
|
+
sheets.push({
|
|
876
|
+
name,
|
|
877
|
+
cells: readCells(root, sharedStrings),
|
|
878
|
+
mergedRanges: readMergedRanges(root)
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
sheets,
|
|
883
|
+
definedNames
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
//#endregion
|
|
887
|
+
exports.AttributeSchema = AttributeSchema;
|
|
888
|
+
exports.BinaryPartSchema = BinaryPartSchema;
|
|
889
|
+
exports.CommentSchema = CommentSchema;
|
|
890
|
+
exports.CompactPackageSchema = CompactPackageSchema;
|
|
891
|
+
exports.CompactPartSchema = CompactPartSchema;
|
|
892
|
+
exports.CompactXmlNodeSchema = CompactXmlNodeSchema;
|
|
893
|
+
exports.DefinedNameSchema = DefinedNameSchema;
|
|
894
|
+
exports.DocxDocumentSchema = DocxDocumentSchema;
|
|
895
|
+
exports.FootnoteSchema = FootnoteSchema;
|
|
896
|
+
exports.HyperlinkSchema = HyperlinkSchema;
|
|
897
|
+
exports.ListMembershipSchema = ListMembershipSchema;
|
|
898
|
+
exports.PackageSchema = PackageSchema;
|
|
899
|
+
exports.ParagraphSchema = ParagraphSchema;
|
|
900
|
+
exports.PartSchema = PartSchema;
|
|
901
|
+
exports.PptxPresentationSchema = PptxPresentationSchema;
|
|
902
|
+
exports.PptxTableCellSchema = PptxTableCellSchema;
|
|
903
|
+
exports.PptxTableRowSchema = PptxTableRowSchema;
|
|
904
|
+
exports.PptxTableSchema = PptxTableSchema;
|
|
905
|
+
exports.RunSchema = RunSchema;
|
|
906
|
+
exports.ShapeSchema = ShapeSchema;
|
|
907
|
+
exports.SlideSchema = SlideSchema;
|
|
908
|
+
exports.TableCellSchema = TableCellSchema;
|
|
909
|
+
exports.TableRowSchema = TableRowSchema;
|
|
910
|
+
exports.TableSchema = TableSchema;
|
|
911
|
+
exports.XlsxCellSchema = XlsxCellSchema;
|
|
912
|
+
exports.XlsxSheetSchema = XlsxSheetSchema;
|
|
913
|
+
exports.XlsxWorkbookSchema = XlsxWorkbookSchema;
|
|
914
|
+
exports.XmlCdataSchema = XmlCdataSchema;
|
|
915
|
+
exports.XmlCommentSchema = XmlCommentSchema;
|
|
916
|
+
exports.XmlDeclarationSchema = XmlDeclarationSchema;
|
|
917
|
+
exports.XmlElementSchema = XmlElementSchema;
|
|
918
|
+
exports.XmlNodeSchema = XmlNodeSchema;
|
|
919
|
+
exports.XmlPartSchema = XmlPartSchema;
|
|
920
|
+
exports.XmlPiSchema = XmlPiSchema;
|
|
921
|
+
exports.XmlTextSchema = XmlTextSchema;
|
|
922
|
+
exports.base64ToBytes = base64ToBytes;
|
|
923
|
+
exports.buildXml = buildXml;
|
|
924
|
+
exports.bytesToBase64 = bytesToBase64;
|
|
925
|
+
exports.compactCodec = compactCodec;
|
|
926
|
+
exports.compactPackageCodec = compactPackageCodec;
|
|
927
|
+
exports.decodeCompactPackage = decodeCompactPackage;
|
|
928
|
+
exports.decodePackage = decodePackage;
|
|
929
|
+
exports.encodeCompactPackage = encodeCompactPackage;
|
|
930
|
+
exports.encodePackage = encodePackage;
|
|
931
|
+
exports.fromCompact = fromCompact;
|
|
932
|
+
exports.isCompactXmlNode = isCompactXmlNode;
|
|
933
|
+
exports.isXmlNode = isXmlNode;
|
|
934
|
+
exports.packageCodec = packageCodec;
|
|
935
|
+
exports.parsePackage = parsePackage;
|
|
936
|
+
exports.parseXml = parseXml;
|
|
937
|
+
exports.readDocx = readDocx;
|
|
938
|
+
exports.readPptx = readPptx;
|
|
939
|
+
exports.readXlsx = readXlsx;
|
|
940
|
+
exports.serializePackage = serializePackage;
|
|
941
|
+
exports.toCompact = toCompact;
|
|
942
|
+
exports.unzipPackage = unzipPackage;
|
|
943
|
+
exports.xmlCodec = xmlCodec;
|
|
944
|
+
exports.zipPackage = zipPackage;
|