odf-kit 0.9.9 → 0.10.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/CHANGELOG.md +42 -0
- package/README.md +97 -4
- package/dist/docx/body-reader.d.ts +54 -0
- package/dist/docx/body-reader.d.ts.map +1 -0
- package/dist/docx/body-reader.js +1124 -0
- package/dist/docx/body-reader.js.map +1 -0
- package/dist/docx/converter.d.ts +51 -0
- package/dist/docx/converter.d.ts.map +1 -0
- package/dist/docx/converter.js +799 -0
- package/dist/docx/converter.js.map +1 -0
- package/dist/docx/index.d.ts +81 -0
- package/dist/docx/index.d.ts.map +1 -0
- package/dist/docx/index.js +69 -0
- package/dist/docx/index.js.map +1 -0
- package/dist/docx/numbering.d.ts +42 -0
- package/dist/docx/numbering.d.ts.map +1 -0
- package/dist/docx/numbering.js +236 -0
- package/dist/docx/numbering.js.map +1 -0
- package/dist/docx/reader.d.ts +38 -0
- package/dist/docx/reader.d.ts.map +1 -0
- package/dist/docx/reader.js +512 -0
- package/dist/docx/reader.js.map +1 -0
- package/dist/docx/relationships.d.ts +27 -0
- package/dist/docx/relationships.d.ts.map +1 -0
- package/dist/docx/relationships.js +89 -0
- package/dist/docx/relationships.js.map +1 -0
- package/dist/docx/styles.d.ts +46 -0
- package/dist/docx/styles.d.ts.map +1 -0
- package/dist/docx/styles.js +383 -0
- package/dist/docx/styles.js.map +1 -0
- package/dist/docx/types.d.ts +266 -0
- package/dist/docx/types.d.ts.map +1 -0
- package/dist/docx/types.js +38 -0
- package/dist/docx/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +36 -1
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* odf-kit — DOCX reader
|
|
3
|
+
*
|
|
4
|
+
* Unpacks a .docx ZIP and orchestrates all sub-parsers to produce a
|
|
5
|
+
* DocxDocument. This is the public entry point for the DOCX reading pipeline.
|
|
6
|
+
*
|
|
7
|
+
* Files read (per ECMA-376 Part 1 §11.3):
|
|
8
|
+
* word/document.xml — main body (required)
|
|
9
|
+
* word/_rels/document.xml.rels — relationships: images, hyperlinks, etc.
|
|
10
|
+
* word/styles.xml — paragraph and character style definitions
|
|
11
|
+
* word/numbering.xml — list definitions (optional)
|
|
12
|
+
* word/footnotes.xml — footnote content (optional)
|
|
13
|
+
* word/endnotes.xml — endnote content (optional)
|
|
14
|
+
* word/header*.xml — header content (optional, up to 3 per section)
|
|
15
|
+
* word/footer*.xml — footer content (optional, up to 3 per section)
|
|
16
|
+
* word/settings.xml — page size/margins if not in body sectPr (optional)
|
|
17
|
+
* word/media/* — embedded images
|
|
18
|
+
* docProps/core.xml — document metadata (optional)
|
|
19
|
+
*
|
|
20
|
+
* Relationship type URI suffixes (both openxmlformats.org and purl.oclc.org
|
|
21
|
+
* namespace prefixes are recognised — spec §9.2 permits both):
|
|
22
|
+
* .../relationships/image
|
|
23
|
+
* .../relationships/hyperlink
|
|
24
|
+
* .../relationships/footnotes
|
|
25
|
+
* .../relationships/endnotes
|
|
26
|
+
* .../relationships/header
|
|
27
|
+
* .../relationships/footer
|
|
28
|
+
*/
|
|
29
|
+
import { unzipSync } from "fflate";
|
|
30
|
+
import { parseXml } from "../reader/xml-parser.js";
|
|
31
|
+
import { parseRelationships } from "./relationships.js";
|
|
32
|
+
import { parseStyles } from "./styles.js";
|
|
33
|
+
import { parseNumbering } from "./numbering.js";
|
|
34
|
+
import { readBody, readNotes } from "./body-reader.js";
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Public API
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Parse a .docx file (as raw bytes) into a DocxDocument model.
|
|
40
|
+
*
|
|
41
|
+
* @param input - Raw .docx bytes: Uint8Array or ArrayBuffer.
|
|
42
|
+
* @param warnings - Mutable array to which parsing warnings are appended.
|
|
43
|
+
* @returns Fully populated DocxDocument.
|
|
44
|
+
*/
|
|
45
|
+
export async function readDocx(input, warnings) {
|
|
46
|
+
const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
47
|
+
// Unzip — fflate.unzipSync returns Record<string, Uint8Array>
|
|
48
|
+
let zip;
|
|
49
|
+
try {
|
|
50
|
+
zip = unzipSync(bytes);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
throw new Error(`readDocx: failed to unzip input — is this a valid .docx file? (${err})`);
|
|
54
|
+
}
|
|
55
|
+
// Helper: decode a ZIP entry to a UTF-8 string, return null if absent
|
|
56
|
+
function getText(path) {
|
|
57
|
+
const entry = zip[path] ?? zip[path.replace(/^\//, "")];
|
|
58
|
+
if (!entry)
|
|
59
|
+
return null;
|
|
60
|
+
return new TextDecoder("utf-8").decode(entry);
|
|
61
|
+
}
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// 1. Relationships
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
const relsXml = getText("word/_rels/document.xml.rels");
|
|
66
|
+
const relationships = relsXml ? parseRelationships(relsXml) : new Map();
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// 2. Styles
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
const stylesXml = getText("word/styles.xml");
|
|
71
|
+
const styles = stylesXml ? parseStyles(stylesXml) : new Map();
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// 3. Numbering
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
const numberingXml = getText("word/numbering.xml");
|
|
76
|
+
const numbering = numberingXml ? parseNumbering(numberingXml) : new Map();
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// 4. Images — load all image-type relationships
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
const images = new Map();
|
|
81
|
+
for (const [rId, rel] of relationships) {
|
|
82
|
+
if (!isImageRel(rel.type))
|
|
83
|
+
continue;
|
|
84
|
+
if (rel.external)
|
|
85
|
+
continue; // external image URLs — skip, cannot embed
|
|
86
|
+
const entry = zip[rel.target] ?? zip[rel.target.replace(/^\//, "")];
|
|
87
|
+
if (!entry) {
|
|
88
|
+
warnings.push(`Image rId "${rId}" references "${rel.target}" which is not in the ZIP`);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const imageEntry = {
|
|
92
|
+
bytes: entry,
|
|
93
|
+
mimeType: mimeTypeFromPath(rel.target),
|
|
94
|
+
filename: rel.target.split("/").pop() ?? rel.target,
|
|
95
|
+
};
|
|
96
|
+
images.set(rId, imageEntry);
|
|
97
|
+
}
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// 5. Metadata — docProps/core.xml (Dublin Core / OPC core properties)
|
|
100
|
+
// Spec: ECMA-376-2 §11 (Part 2 defines coreProperties element)
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
const coreXml = getText("docProps/core.xml");
|
|
103
|
+
const metadata = coreXml
|
|
104
|
+
? parseCoreProperties(coreXml, warnings)
|
|
105
|
+
: { title: null, creator: null, description: null, created: null, modified: null };
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// 6. Body reader context — shared across all body walks
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
const bookmarkNames = new Map();
|
|
110
|
+
const ctx = {
|
|
111
|
+
styles,
|
|
112
|
+
numbering,
|
|
113
|
+
relationships,
|
|
114
|
+
bookmarkNames,
|
|
115
|
+
warnings,
|
|
116
|
+
};
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
// 7. Footnotes and endnotes
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
const footnotesXml = getText("word/footnotes.xml");
|
|
121
|
+
const footnotes = footnotesXml ? readNotes(footnotesXml, "footnote", ctx) : new Map();
|
|
122
|
+
const endnotesXml = getText("word/endnotes.xml");
|
|
123
|
+
const endnotes = endnotesXml ? readNotes(endnotesXml, "endnote", ctx) : new Map();
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// 8. Headers and footers
|
|
126
|
+
// Discovered via relationship type; header/footer type (default/first/even)
|
|
127
|
+
// read from the sectPr headerReference/footerReference elements.
|
|
128
|
+
// Spec ref: ECMA-376 §11.3.9, §11.3.6, §17.10.
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Build rId → headerType map from sectPr references in document.xml
|
|
131
|
+
const headerTypeMap = new Map();
|
|
132
|
+
const footerTypeMap = new Map();
|
|
133
|
+
const documentXml = getText("word/document.xml");
|
|
134
|
+
if (documentXml) {
|
|
135
|
+
extractHdrFtrTypes(documentXml, headerTypeMap, footerTypeMap);
|
|
136
|
+
}
|
|
137
|
+
const headers = [];
|
|
138
|
+
const footers = [];
|
|
139
|
+
for (const [rId, rel] of relationships) {
|
|
140
|
+
if (isHeaderRel(rel.type)) {
|
|
141
|
+
const xml = getText(rel.target);
|
|
142
|
+
if (xml) {
|
|
143
|
+
const headerType = headerTypeMap.get(rId) ?? "default";
|
|
144
|
+
const body = readBody(xml, "hdr", ctx);
|
|
145
|
+
headers.push({ headerType, body });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (isFooterRel(rel.type)) {
|
|
149
|
+
const xml = getText(rel.target);
|
|
150
|
+
if (xml) {
|
|
151
|
+
const headerType = footerTypeMap.get(rId) ?? "default";
|
|
152
|
+
const body = readBody(xml, "ftr", ctx);
|
|
153
|
+
footers.push({ headerType, body });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// 9. Page layout — from body sectPr (preferred) or word/settings.xml fallback
|
|
159
|
+
// Spec ref: ECMA-376 §17.6 (sectPr), CT_PageSz, CT_PageMar
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
let pageLayout = emptyPageLayout();
|
|
162
|
+
if (documentXml) {
|
|
163
|
+
pageLayout = extractPageLayout(documentXml, warnings);
|
|
164
|
+
}
|
|
165
|
+
// Fallback to settings.xml if body sectPr had no pgSz/pgMar
|
|
166
|
+
if (!pageLayout.width && !pageLayout.marginTop) {
|
|
167
|
+
const settingsXml = getText("word/settings.xml");
|
|
168
|
+
if (settingsXml) {
|
|
169
|
+
const settingsLayout = extractPageLayoutFromSettings(settingsXml, warnings);
|
|
170
|
+
if (settingsLayout.width)
|
|
171
|
+
pageLayout = settingsLayout;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
// 10. Main document body — last, so all maps are fully populated
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
if (!documentXml) {
|
|
178
|
+
throw new Error("readDocx: word/document.xml is missing — not a valid .docx file");
|
|
179
|
+
}
|
|
180
|
+
const body = readBody(documentXml, "body", ctx);
|
|
181
|
+
// Warn about any referenced footnotes/endnotes not found in their parts
|
|
182
|
+
for (const [, el] of Object.entries({}))
|
|
183
|
+
void el; // no-op; warnings already in ctx
|
|
184
|
+
return {
|
|
185
|
+
metadata,
|
|
186
|
+
pageLayout,
|
|
187
|
+
body,
|
|
188
|
+
footnotes,
|
|
189
|
+
endnotes,
|
|
190
|
+
headers,
|
|
191
|
+
footers,
|
|
192
|
+
styles,
|
|
193
|
+
numbering,
|
|
194
|
+
relationships,
|
|
195
|
+
images,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
// Core properties parser — docProps/core.xml
|
|
200
|
+
// Spec: ECMA-376-2 §11 (OPC Part 2).
|
|
201
|
+
// Elements use Dublin Core (dc:), Dublin Core Terms (dcterms:), and
|
|
202
|
+
// core properties (cp:) namespaces. We strip prefixes and match local names.
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
function parseCoreProperties(xml, warnings) {
|
|
205
|
+
let title = null;
|
|
206
|
+
let creator = null;
|
|
207
|
+
let description = null;
|
|
208
|
+
let created = null;
|
|
209
|
+
let modified = null;
|
|
210
|
+
let root;
|
|
211
|
+
try {
|
|
212
|
+
root = parseXml(xml);
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
warnings.push("docProps/core.xml could not be parsed — metadata unavailable");
|
|
216
|
+
return { title, creator, description, created, modified };
|
|
217
|
+
}
|
|
218
|
+
// The root element is cp:coreProperties; walk its children
|
|
219
|
+
const container = localName(root.tag) === "coreProperties" ? root : (findChild(root, "coreProperties") ?? root);
|
|
220
|
+
for (const child of container.children) {
|
|
221
|
+
if (child.type !== "element")
|
|
222
|
+
continue;
|
|
223
|
+
const tag = localName(child.tag);
|
|
224
|
+
const text = textContent(child);
|
|
225
|
+
switch (tag) {
|
|
226
|
+
case "title":
|
|
227
|
+
title = text || null;
|
|
228
|
+
break;
|
|
229
|
+
case "creator":
|
|
230
|
+
// dc:creator — primary author
|
|
231
|
+
creator = text || null;
|
|
232
|
+
break;
|
|
233
|
+
case "description":
|
|
234
|
+
// dc:description or cp:description
|
|
235
|
+
description = text || null;
|
|
236
|
+
break;
|
|
237
|
+
case "subject":
|
|
238
|
+
// dc:subject — use as description fallback if description absent
|
|
239
|
+
if (!description)
|
|
240
|
+
description = text || null;
|
|
241
|
+
break;
|
|
242
|
+
case "created":
|
|
243
|
+
// dcterms:created — ISO 8601 datetime
|
|
244
|
+
created = text || null;
|
|
245
|
+
break;
|
|
246
|
+
case "modified":
|
|
247
|
+
// dcterms:modified — ISO 8601 datetime
|
|
248
|
+
modified = text || null;
|
|
249
|
+
break;
|
|
250
|
+
case "lastModifiedBy":
|
|
251
|
+
// cp:lastModifiedBy — not in our model, skip
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return { title, creator, description, created, modified };
|
|
256
|
+
}
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
// Page layout extraction — from the final w:sectPr in document.xml
|
|
259
|
+
// Spec ref: ECMA-376 §17.6.17 (sectPr), §17.6.13 (pgSz), §17.6.11 (pgMar)
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
function extractPageLayout(documentXml, warnings) {
|
|
262
|
+
let root;
|
|
263
|
+
try {
|
|
264
|
+
root = parseXml(documentXml);
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
warnings.push("word/document.xml could not be re-parsed for page layout");
|
|
268
|
+
return emptyPageLayout();
|
|
269
|
+
}
|
|
270
|
+
// The final sectPr is a direct child of w:body
|
|
271
|
+
const body = findDescendant(root, "body");
|
|
272
|
+
if (!body)
|
|
273
|
+
return emptyPageLayout();
|
|
274
|
+
// Per spec §17.6.17: the final section's sectPr is the last child of body
|
|
275
|
+
let sectPr = null;
|
|
276
|
+
for (const child of body.children) {
|
|
277
|
+
if (child.type === "element" && localName(child.tag) === "sectPr") {
|
|
278
|
+
sectPr = child;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (!sectPr)
|
|
282
|
+
return emptyPageLayout();
|
|
283
|
+
return parseSectPr(sectPr);
|
|
284
|
+
}
|
|
285
|
+
function extractPageLayoutFromSettings(settingsXml, warnings) {
|
|
286
|
+
let root;
|
|
287
|
+
try {
|
|
288
|
+
root = parseXml(settingsXml);
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
warnings.push("word/settings.xml could not be parsed for page layout");
|
|
292
|
+
return emptyPageLayout();
|
|
293
|
+
}
|
|
294
|
+
// word/settings.xml root is w:settings; sectPr may appear as a child
|
|
295
|
+
const sectPr = findChild(root, "sectPr");
|
|
296
|
+
if (!sectPr)
|
|
297
|
+
return emptyPageLayout();
|
|
298
|
+
return parseSectPr(sectPr);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Parse a w:sectPr element into a DocxPageLayout.
|
|
302
|
+
* Spec ref: CT_PageSz (§17.18.65) and CT_PageMar.
|
|
303
|
+
*
|
|
304
|
+
* w:pgSz attributes:
|
|
305
|
+
* w:w — page width in twips (ST_TwipsMeasure)
|
|
306
|
+
* w:h — page height in twips
|
|
307
|
+
* w:orient — "portrait" | "landscape" (optional; derived from w/h if absent)
|
|
308
|
+
*
|
|
309
|
+
* w:pgMar attributes (all in twips, all required by schema but may be absent
|
|
310
|
+
* in practice):
|
|
311
|
+
* w:top, w:right, w:bottom, w:left, w:header, w:footer, w:gutter
|
|
312
|
+
*/
|
|
313
|
+
function parseSectPr(sectPr) {
|
|
314
|
+
let width = null;
|
|
315
|
+
let height = null;
|
|
316
|
+
let orientation = null;
|
|
317
|
+
let marginTop = null;
|
|
318
|
+
let marginBottom = null;
|
|
319
|
+
let marginLeft = null;
|
|
320
|
+
let marginRight = null;
|
|
321
|
+
for (const child of sectPr.children) {
|
|
322
|
+
if (child.type !== "element")
|
|
323
|
+
continue;
|
|
324
|
+
const tag = localName(child.tag);
|
|
325
|
+
if (tag === "pgSz") {
|
|
326
|
+
const w = child.attrs["w:w"];
|
|
327
|
+
const h = child.attrs["w:h"];
|
|
328
|
+
const orient = child.attrs["w:orient"];
|
|
329
|
+
if (w !== undefined)
|
|
330
|
+
width = twipsToCm(Number(w));
|
|
331
|
+
if (h !== undefined)
|
|
332
|
+
height = twipsToCm(Number(h));
|
|
333
|
+
if (orient === "portrait" || orient === "landscape") {
|
|
334
|
+
orientation = orient;
|
|
335
|
+
}
|
|
336
|
+
else if (width !== null && height !== null) {
|
|
337
|
+
// Derive orientation from dimensions when w:orient is absent
|
|
338
|
+
// Spec §17.18.65: landscape when width > height
|
|
339
|
+
orientation = width > height ? "landscape" : "portrait";
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else if (tag === "pgMar") {
|
|
343
|
+
const top = child.attrs["w:top"];
|
|
344
|
+
const bottom = child.attrs["w:bottom"];
|
|
345
|
+
const left = child.attrs["w:left"];
|
|
346
|
+
const right = child.attrs["w:right"];
|
|
347
|
+
if (top !== undefined)
|
|
348
|
+
marginTop = twipsToCm(Number(top));
|
|
349
|
+
if (bottom !== undefined)
|
|
350
|
+
marginBottom = twipsToCm(Number(bottom));
|
|
351
|
+
if (left !== undefined)
|
|
352
|
+
marginLeft = twipsToCm(Number(left));
|
|
353
|
+
if (right !== undefined)
|
|
354
|
+
marginRight = twipsToCm(Number(right));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return { width, height, orientation, marginTop, marginBottom, marginLeft, marginRight };
|
|
358
|
+
}
|
|
359
|
+
function emptyPageLayout() {
|
|
360
|
+
return {
|
|
361
|
+
width: null,
|
|
362
|
+
height: null,
|
|
363
|
+
orientation: null,
|
|
364
|
+
marginTop: null,
|
|
365
|
+
marginBottom: null,
|
|
366
|
+
marginLeft: null,
|
|
367
|
+
marginRight: null,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
// ---------------------------------------------------------------------------
|
|
371
|
+
// Header / footer type extraction
|
|
372
|
+
// Reads sectPr headerReference / footerReference elements to build
|
|
373
|
+
// rId → "default" | "first" | "even" maps.
|
|
374
|
+
// Spec ref: ECMA-376 §17.10.5 (headerReference), §17.10.2 (footerReference)
|
|
375
|
+
// ---------------------------------------------------------------------------
|
|
376
|
+
function extractHdrFtrTypes(documentXml, headerTypeMap, footerTypeMap) {
|
|
377
|
+
let root;
|
|
378
|
+
try {
|
|
379
|
+
root = parseXml(documentXml);
|
|
380
|
+
}
|
|
381
|
+
catch {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
// Walk all sectPr elements (final body sectPr + any mid-doc sectPr in pPr)
|
|
385
|
+
collectSectPrRefs(root, headerTypeMap, footerTypeMap);
|
|
386
|
+
}
|
|
387
|
+
function collectSectPrRefs(node, headerTypeMap, footerTypeMap) {
|
|
388
|
+
for (const child of node.children) {
|
|
389
|
+
if (child.type !== "element")
|
|
390
|
+
continue;
|
|
391
|
+
const tag = localName(child.tag);
|
|
392
|
+
if (tag === "sectPr") {
|
|
393
|
+
for (const ref of child.children) {
|
|
394
|
+
if (ref.type !== "element")
|
|
395
|
+
continue;
|
|
396
|
+
const refTag = localName(ref.tag);
|
|
397
|
+
if (refTag === "headerReference" || refTag === "footerReference") {
|
|
398
|
+
const rId = ref.attrs["r:id"] ?? ref.attrs["w:id"];
|
|
399
|
+
const rawType = ref.attrs["w:type"] ?? "default";
|
|
400
|
+
const hdrType = normalizeHdrFtrType(rawType);
|
|
401
|
+
if (rId) {
|
|
402
|
+
if (refTag === "headerReference")
|
|
403
|
+
headerTypeMap.set(rId, hdrType);
|
|
404
|
+
else
|
|
405
|
+
footerTypeMap.set(rId, hdrType);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
collectSectPrRefs(child, headerTypeMap, footerTypeMap);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function normalizeHdrFtrType(raw) {
|
|
416
|
+
if (raw === "first")
|
|
417
|
+
return "first";
|
|
418
|
+
if (raw === "even")
|
|
419
|
+
return "even";
|
|
420
|
+
return "default"; // "default" and "odd" both map to default
|
|
421
|
+
}
|
|
422
|
+
// ---------------------------------------------------------------------------
|
|
423
|
+
// Relationship type helpers
|
|
424
|
+
// Both openxmlformats.org and purl.oclc.org URI prefixes are valid per spec §9.2
|
|
425
|
+
// ---------------------------------------------------------------------------
|
|
426
|
+
const REL_SUFFIXES = {
|
|
427
|
+
image: "relationships/image",
|
|
428
|
+
hyperlink: "relationships/hyperlink",
|
|
429
|
+
footnotes: "relationships/footnotes",
|
|
430
|
+
endnotes: "relationships/endnotes",
|
|
431
|
+
header: "relationships/header",
|
|
432
|
+
footer: "relationships/footer",
|
|
433
|
+
};
|
|
434
|
+
function relMatches(type, suffix) {
|
|
435
|
+
return type.endsWith("/" + suffix);
|
|
436
|
+
}
|
|
437
|
+
function isImageRel(type) {
|
|
438
|
+
return relMatches(type, REL_SUFFIXES.image);
|
|
439
|
+
}
|
|
440
|
+
function isHeaderRel(type) {
|
|
441
|
+
return relMatches(type, REL_SUFFIXES.header);
|
|
442
|
+
}
|
|
443
|
+
function isFooterRel(type) {
|
|
444
|
+
return relMatches(type, REL_SUFFIXES.footer);
|
|
445
|
+
}
|
|
446
|
+
// ---------------------------------------------------------------------------
|
|
447
|
+
// MIME type from file extension
|
|
448
|
+
// ---------------------------------------------------------------------------
|
|
449
|
+
const MIME_TYPES = {
|
|
450
|
+
png: "image/png",
|
|
451
|
+
jpg: "image/jpeg",
|
|
452
|
+
jpeg: "image/jpeg",
|
|
453
|
+
gif: "image/gif",
|
|
454
|
+
bmp: "image/bmp",
|
|
455
|
+
tiff: "image/tiff",
|
|
456
|
+
tif: "image/tiff",
|
|
457
|
+
webp: "image/webp",
|
|
458
|
+
svg: "image/svg+xml",
|
|
459
|
+
wmf: "image/x-wmf",
|
|
460
|
+
emf: "image/x-emf",
|
|
461
|
+
};
|
|
462
|
+
function mimeTypeFromPath(path) {
|
|
463
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
464
|
+
return MIME_TYPES[ext] ?? "application/octet-stream";
|
|
465
|
+
}
|
|
466
|
+
// ---------------------------------------------------------------------------
|
|
467
|
+
// Unit conversion
|
|
468
|
+
// ---------------------------------------------------------------------------
|
|
469
|
+
function twipsToCm(twips) {
|
|
470
|
+
return Number(((twips / 1440) * 2.54).toFixed(4));
|
|
471
|
+
}
|
|
472
|
+
// ---------------------------------------------------------------------------
|
|
473
|
+
// XML utility helpers
|
|
474
|
+
// ---------------------------------------------------------------------------
|
|
475
|
+
function localName(tag) {
|
|
476
|
+
const colon = tag.indexOf(":");
|
|
477
|
+
return colon === -1 ? tag : tag.slice(colon + 1);
|
|
478
|
+
}
|
|
479
|
+
/** Find a direct child element by local name. */
|
|
480
|
+
function findChild(el, name) {
|
|
481
|
+
for (const child of el.children) {
|
|
482
|
+
if (child.type === "element" && localName(child.tag) === name)
|
|
483
|
+
return child;
|
|
484
|
+
}
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
/** Find a descendant element by local name (breadth-first). */
|
|
488
|
+
function findDescendant(el, name) {
|
|
489
|
+
const queue = [el];
|
|
490
|
+
while (queue.length > 0) {
|
|
491
|
+
const node = queue.shift();
|
|
492
|
+
if (localName(node.tag) === name)
|
|
493
|
+
return node;
|
|
494
|
+
for (const child of node.children) {
|
|
495
|
+
if (child.type === "element")
|
|
496
|
+
queue.push(child);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
/** Concatenate all text node descendants of an element. */
|
|
502
|
+
function textContent(el) {
|
|
503
|
+
let text = "";
|
|
504
|
+
for (const child of el.children) {
|
|
505
|
+
if (child.type === "text")
|
|
506
|
+
text += child.text;
|
|
507
|
+
else if (child.type === "element")
|
|
508
|
+
text += textContent(child);
|
|
509
|
+
}
|
|
510
|
+
return text.trim();
|
|
511
|
+
}
|
|
512
|
+
//# sourceMappingURL=reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/docx/reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* odf-kit — DOCX relationship parser
|
|
3
|
+
*
|
|
4
|
+
* Parses word/_rels/document.xml.rels (and any other .rels file) into a
|
|
5
|
+
* RelationshipMap keyed by rId.
|
|
6
|
+
*
|
|
7
|
+
* Relationship XML structure:
|
|
8
|
+
*
|
|
9
|
+
* <Relationships xmlns="...">
|
|
10
|
+
* <Relationship Id="rId1"
|
|
11
|
+
* Type="http://…/officeDocument/2006/relationships/image"
|
|
12
|
+
* Target="media/image1.png"/>
|
|
13
|
+
* <Relationship Id="rId2"
|
|
14
|
+
* Type="http://…/officeDocument/2006/relationships/hyperlink"
|
|
15
|
+
* Target="https://example.com"
|
|
16
|
+
* TargetMode="External"/>
|
|
17
|
+
* </Relationships>
|
|
18
|
+
*/
|
|
19
|
+
import type { RelationshipMap } from "./types.js";
|
|
20
|
+
/**
|
|
21
|
+
* Parse a .rels XML string into a RelationshipMap.
|
|
22
|
+
*
|
|
23
|
+
* @param xml - Raw XML content of a .rels file.
|
|
24
|
+
* @returns Map from rId → RelationshipEntry.
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseRelationships(xml: string): RelationshipMap;
|
|
27
|
+
//# sourceMappingURL=relationships.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../src/docx/relationships.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAqB,MAAM,YAAY,CAAC;AAErE;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CA0B/D"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* odf-kit — DOCX relationship parser
|
|
3
|
+
*
|
|
4
|
+
* Parses word/_rels/document.xml.rels (and any other .rels file) into a
|
|
5
|
+
* RelationshipMap keyed by rId.
|
|
6
|
+
*
|
|
7
|
+
* Relationship XML structure:
|
|
8
|
+
*
|
|
9
|
+
* <Relationships xmlns="...">
|
|
10
|
+
* <Relationship Id="rId1"
|
|
11
|
+
* Type="http://…/officeDocument/2006/relationships/image"
|
|
12
|
+
* Target="media/image1.png"/>
|
|
13
|
+
* <Relationship Id="rId2"
|
|
14
|
+
* Type="http://…/officeDocument/2006/relationships/hyperlink"
|
|
15
|
+
* Target="https://example.com"
|
|
16
|
+
* TargetMode="External"/>
|
|
17
|
+
* </Relationships>
|
|
18
|
+
*/
|
|
19
|
+
import { parseXml } from "../reader/xml-parser.js";
|
|
20
|
+
/**
|
|
21
|
+
* Parse a .rels XML string into a RelationshipMap.
|
|
22
|
+
*
|
|
23
|
+
* @param xml - Raw XML content of a .rels file.
|
|
24
|
+
* @returns Map from rId → RelationshipEntry.
|
|
25
|
+
*/
|
|
26
|
+
export function parseRelationships(xml) {
|
|
27
|
+
const map = new Map();
|
|
28
|
+
const root = parseXml(xml);
|
|
29
|
+
for (const child of root.children) {
|
|
30
|
+
if (child.type !== "element")
|
|
31
|
+
continue;
|
|
32
|
+
if (localName(child.tag) !== "Relationship")
|
|
33
|
+
continue;
|
|
34
|
+
const id = child.attrs["Id"];
|
|
35
|
+
const type = child.attrs["Type"] ?? "";
|
|
36
|
+
const rawTarget = child.attrs["Target"] ?? "";
|
|
37
|
+
const targetMode = child.attrs["TargetMode"] ?? "";
|
|
38
|
+
if (!id)
|
|
39
|
+
continue;
|
|
40
|
+
const external = targetMode === "External";
|
|
41
|
+
// Internal targets in document.xml.rels are relative to the word/ folder.
|
|
42
|
+
// Resolve them to full ZIP paths so the reader can look them up directly.
|
|
43
|
+
const target = external ? rawTarget : resolveTarget(rawTarget);
|
|
44
|
+
const entry = { target, external, type };
|
|
45
|
+
map.set(id, entry);
|
|
46
|
+
}
|
|
47
|
+
return map;
|
|
48
|
+
}
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Helpers
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
/**
|
|
53
|
+
* Resolve a relative relationship target to a full ZIP path.
|
|
54
|
+
*
|
|
55
|
+
* Targets in word/_rels/document.xml.rels are relative to the word/ folder:
|
|
56
|
+
* "media/image1.png" → "word/media/image1.png"
|
|
57
|
+
* "footnotes.xml" → "word/footnotes.xml"
|
|
58
|
+
* "../docProps/core.xml" would resolve to "docProps/core.xml" (not used
|
|
59
|
+
* in document.xml.rels but handled for correctness)
|
|
60
|
+
*
|
|
61
|
+
* Targets that already start with a slash or a scheme are returned as-is.
|
|
62
|
+
*/
|
|
63
|
+
function resolveTarget(rawTarget) {
|
|
64
|
+
if (rawTarget.startsWith("/") || /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(rawTarget)) {
|
|
65
|
+
return rawTarget;
|
|
66
|
+
}
|
|
67
|
+
// All document.xml.rels targets are relative to word/
|
|
68
|
+
const base = "word/";
|
|
69
|
+
const parts = (base + rawTarget).split("/");
|
|
70
|
+
const resolved = [];
|
|
71
|
+
for (const part of parts) {
|
|
72
|
+
if (part === "..") {
|
|
73
|
+
resolved.pop();
|
|
74
|
+
}
|
|
75
|
+
else if (part !== ".") {
|
|
76
|
+
resolved.push(part);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return resolved.join("/");
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Extract the local name from a possibly-namespaced element name.
|
|
83
|
+
* e.g. "pkg:Relationship" → "Relationship", "Relationship" → "Relationship"
|
|
84
|
+
*/
|
|
85
|
+
function localName(tag) {
|
|
86
|
+
const colon = tag.indexOf(":");
|
|
87
|
+
return colon === -1 ? tag : tag.slice(colon + 1);
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=relationships.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationships.js","sourceRoot":"","sources":["../../src/docx/relationships.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGnD;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,MAAM,GAAG,GAAoB,IAAI,GAAG,EAAE,CAAC;IACvC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAE3B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;YAAE,SAAS;QACvC,IAAI,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,cAAc;YAAE,SAAS;QAEtD,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACvC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC9C,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QAEnD,IAAI,CAAC,EAAE;YAAE,SAAS;QAElB,MAAM,QAAQ,GAAG,UAAU,KAAK,UAAU,CAAC;QAE3C,0EAA0E;QAC1E,0EAA0E;QAC1E,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QAE/D,MAAM,KAAK,GAAsB,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC5D,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;;;;;;GAUG;AACH,SAAS,aAAa,CAAC,SAAiB;IACtC,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,2BAA2B,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7E,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,sDAAsD;IACtD,MAAM,IAAI,GAAG,OAAO,CAAC;IACrB,MAAM,KAAK,GAAG,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,QAAQ,CAAC,GAAG,EAAE,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;AACnD,CAAC"}
|