ooxml.js 4.1.1 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/{codec-DxnbKt4O.d.ts → codec-BrTMlL0a.d.ts} +2 -2
- package/dist/{codec-DO0MNF45.d.cts → codec-DNjHjEDm.d.cts} +2 -2
- package/dist/codec.d.cts +1 -1
- package/dist/codec.d.ts +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/{read-Legu2Pt-.js → read-BQoFiqsb.js} +31 -6
- package/dist/{read-DY3Sm5T3.d.cts → read-BoV9SZy4.d.cts} +34 -0
- package/dist/{read-ClIHv1ef.d.cts → read-CDX1WbiF.d.cts} +17 -0
- package/dist/{read-gB0H2bff.d.ts → read-CxMli3Om.d.ts} +17 -0
- package/dist/{read-DPAy4uu8.cjs → read-Di5UfiSh.cjs} +29 -4
- package/dist/{read-DcJZITV9.d.ts → read-ZWJPDvG-.d.ts} +34 -0
- package/dist/typed/document-package.cjs +2 -2
- package/dist/typed/document-package.js +2 -2
- package/dist/typed/docx/constructs.cjs +59 -5
- package/dist/typed/docx/constructs.d.cts +10 -2
- package/dist/typed/docx/constructs.d.ts +10 -2
- package/dist/typed/docx/constructs.js +59 -6
- package/dist/typed/docx/read.cjs +1 -1
- package/dist/typed/docx/read.d.cts +1 -1
- package/dist/typed/docx/read.d.ts +1 -1
- package/dist/typed/docx/read.js +1 -1
- package/dist/typed/docx/write.cjs +139 -6
- package/dist/typed/docx/write.js +140 -7
- package/dist/typed/embedded.cjs +1 -1
- package/dist/typed/embedded.js +1 -1
- package/dist/typed/pptx/read.cjs +1 -1
- package/dist/typed/pptx/read.d.cts +1 -1
- package/dist/typed/pptx/read.d.ts +1 -1
- package/dist/typed/pptx/read.js +1 -1
- package/package.json +3 -3
package/dist/typed/docx/write.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { bytesToBase64 } from "../../util/base64.js";
|
|
2
|
+
import { parseXml } from "../../xml/parse.js";
|
|
3
|
+
import { encodePackage } from "../../codec.js";
|
|
1
4
|
import { el, txt } from "../../xml/fragment.js";
|
|
2
5
|
import { encodeXmlText } from "../../xml/entities.js";
|
|
3
6
|
import { ptToEighthPoints, ptToEmu, ptToHalfPoints, ptToTwips } from "../shared/units.js";
|
|
4
7
|
import { TABLE_OF_CONTENTS_GALLERY, isDeletedChange } from "./constructs.js";
|
|
5
|
-
import {
|
|
8
|
+
import { buildXlsxPackageFromContent } from "../xlsx/build.js";
|
|
9
|
+
import { colorToRgbHex, findConstructMarkerImbalance, findRunConstructFault } from "document-schema.js";
|
|
6
10
|
//#region src/typed/docx/write.ts
|
|
7
11
|
const WML_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
|
8
12
|
const REL_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
@@ -19,14 +23,18 @@ const DRAWING_PIC_NS = "http://schemas.openxmlformats.org/drawingml/2006/picture
|
|
|
19
23
|
const MARKUP_COMPAT_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006";
|
|
20
24
|
const W14_NS = "http://schemas.microsoft.com/office/word/2010/wordml";
|
|
21
25
|
const W15_NS = "http://schemas.microsoft.com/office/word/2012/wordml";
|
|
26
|
+
const VML_OFFICE_NS = "urn:schemas-microsoft-com:office:office";
|
|
22
27
|
const CT_DOCUMENT = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml";
|
|
23
28
|
const CT_CORE_PROPS = "application/vnd.openxmlformats-package.core-properties+xml";
|
|
24
29
|
const CT_EXTENDED_PROPS = "application/vnd.openxmlformats-officedocument.extended-properties+xml";
|
|
30
|
+
const CT_EMBEDDED_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
31
|
+
const CT_EMBEDDED_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
25
32
|
const REL_OFFICE_DOCUMENT = `${REL_NS}/officeDocument`;
|
|
26
33
|
const REL_CORE_PROPS = `${PKG_RELS_NS}/metadata/core-properties`;
|
|
27
34
|
const REL_EXTENDED_PROPS = `${REL_NS}/extended-properties`;
|
|
28
35
|
const REL_HYPERLINK = `${REL_NS}/hyperlink`;
|
|
29
36
|
const REL_IMAGE = `${REL_NS}/image`;
|
|
37
|
+
const REL_OLE_OBJECT = `${REL_NS}/oleObject`;
|
|
30
38
|
const DOCUMENT_PART_PATH = "word/document.xml";
|
|
31
39
|
function newWriteState() {
|
|
32
40
|
return {
|
|
@@ -34,6 +42,8 @@ function newWriteState() {
|
|
|
34
42
|
hyperlinkIds: /* @__PURE__ */ new Map(),
|
|
35
43
|
mediaIds: /* @__PURE__ */ new Map(),
|
|
36
44
|
mediaParts: /* @__PURE__ */ new Map(),
|
|
45
|
+
embeddingIds: /* @__PURE__ */ new Map(),
|
|
46
|
+
embeddingParts: /* @__PURE__ */ new Map(),
|
|
37
47
|
nextDrawingId: 1,
|
|
38
48
|
nextMarkerId: 1
|
|
39
49
|
};
|
|
@@ -168,10 +178,49 @@ function buildParagraph(paragraph, state, pageBreakBefore, deleted, provenance)
|
|
|
168
178
|
const changeTag = provenance === void 0 ? void 0 : TRACKED_CHANGE_TAG_BY_CHANGE[provenance.change];
|
|
169
179
|
const pPr = properties === void 0 && changeTag !== void 0 ? el("w:pPr", {}, []) : properties;
|
|
170
180
|
if (pPr !== void 0 && changeTag !== void 0 && provenance !== void 0) pPr.children.push(el("w:rPr", {}, [el(changeTag, trackChangeAttrs(state, provenance))]));
|
|
171
|
-
const runs = paragraph.runs.map((run) => buildRun(run, state, deleted));
|
|
181
|
+
const runs = interleaveRunConstructExtents(paragraph.runs.map((run) => buildRun(run, state, deleted)), paragraph, state);
|
|
172
182
|
const content = changeTag === void 0 || provenance === void 0 ? runs : [el(changeTag, trackChangeAttrs(state, provenance), runs)];
|
|
173
183
|
return el("w:p", {}, [...pPr === void 0 ? [] : [pPr], ...content]);
|
|
174
184
|
}
|
|
185
|
+
function interleaveRunConstructExtents(runElements, paragraph, state) {
|
|
186
|
+
if (paragraph.constructs === void 0) return [...runElements];
|
|
187
|
+
const fault = findRunConstructFault(paragraph);
|
|
188
|
+
if (fault !== void 0) throw new Error(`buildDocxPackageFromContent: run-level construct extent at index ${String(fault.index)} of a paragraph does not name real runs (${fault.kind})`);
|
|
189
|
+
const bookmarks = paragraph.constructs.filter((extent) => extent.descriptor.kind === "anchor" && extent.descriptor.anchorType === "bookmark");
|
|
190
|
+
if (bookmarks.length === 0) return [...runElements];
|
|
191
|
+
const closingAt = /* @__PURE__ */ new Map();
|
|
192
|
+
const openingAt = /* @__PURE__ */ new Map();
|
|
193
|
+
const pointAt = /* @__PURE__ */ new Map();
|
|
194
|
+
const push = (map, position, element) => {
|
|
195
|
+
const existing = map.get(position);
|
|
196
|
+
if (existing === void 0) map.set(position, [element]);
|
|
197
|
+
else existing.push(element);
|
|
198
|
+
};
|
|
199
|
+
for (const bookmark of bookmarks) {
|
|
200
|
+
const id = String(state.nextMarkerId++);
|
|
201
|
+
const open = el("w:bookmarkStart", {
|
|
202
|
+
"w:id": id,
|
|
203
|
+
"w:name": encodeXmlText(bookmark.descriptor.name)
|
|
204
|
+
});
|
|
205
|
+
const close = el("w:bookmarkEnd", { "w:id": id });
|
|
206
|
+
if (bookmark.startRun === bookmark.endRun) {
|
|
207
|
+
push(pointAt, bookmark.startRun, open);
|
|
208
|
+
push(pointAt, bookmark.startRun, close);
|
|
209
|
+
} else {
|
|
210
|
+
push(openingAt, bookmark.startRun, open);
|
|
211
|
+
push(closingAt, bookmark.endRun, close);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const out = [];
|
|
215
|
+
for (let position = 0; position <= runElements.length; position++) {
|
|
216
|
+
for (const close of closingAt.get(position) ?? []) out.push(close);
|
|
217
|
+
for (const open of openingAt.get(position) ?? []) out.push(open);
|
|
218
|
+
for (const half of pointAt.get(position) ?? []) out.push(half);
|
|
219
|
+
const run = runElements[position];
|
|
220
|
+
if (run !== void 0) out.push(run);
|
|
221
|
+
}
|
|
222
|
+
return out;
|
|
223
|
+
}
|
|
175
224
|
function trailingEmptyRunElements(paragraph, element) {
|
|
176
225
|
const runElements = [];
|
|
177
226
|
for (const child of element.children) if (child.type === "element" && (child.tag === "w:r" || child.tag === "w:hyperlink")) runElements.push(child);
|
|
@@ -296,6 +345,43 @@ function buildDrawing(image, state) {
|
|
|
296
345
|
el("a:graphic", { "xmlns:a": DRAWINGML_NS }, [el("a:graphicData", { uri: DRAWING_PIC_NS }, [picture])])
|
|
297
346
|
])]);
|
|
298
347
|
}
|
|
348
|
+
function embeddedPayloadOf(document) {
|
|
349
|
+
switch (document.kind) {
|
|
350
|
+
case "wordprocessing": return {
|
|
351
|
+
extension: "docx",
|
|
352
|
+
progId: "Word.Document.12",
|
|
353
|
+
base64: bytesToBase64(encodePackage(buildDocxPackageFromContent(document)))
|
|
354
|
+
};
|
|
355
|
+
case "spreadsheet": return {
|
|
356
|
+
extension: "xlsx",
|
|
357
|
+
progId: "Excel.Sheet.12",
|
|
358
|
+
base64: bytesToBase64(encodePackage(buildXlsxPackageFromContent(document)))
|
|
359
|
+
};
|
|
360
|
+
default: throw new Error(`buildDocxPackageFromContent: an embedded object carrying a ${document.kind} document has no OOXML OLE payload this writer can produce (embedded wordprocessing and spreadsheet documents serialise through their own builders; presentation is read-only in this package, and drawing/formula are ODF/MathML spellings)`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function embeddedObjectRelationshipId(state, payload) {
|
|
364
|
+
const existing = state.embeddingIds.get(payload.base64);
|
|
365
|
+
if (existing !== void 0) return existing;
|
|
366
|
+
const name = `oleObject${state.embeddingParts.size + 1}.${payload.extension}`;
|
|
367
|
+
state.embeddingParts.set(name, payload);
|
|
368
|
+
const id = addRelationship(state, REL_OLE_OBJECT, `embeddings/${name}`, false);
|
|
369
|
+
state.embeddingIds.set(payload.base64, id);
|
|
370
|
+
return id;
|
|
371
|
+
}
|
|
372
|
+
function buildObjectElement(block, state) {
|
|
373
|
+
const payload = embeddedPayloadOf(block.document);
|
|
374
|
+
const relId = embeddedObjectRelationshipId(state, payload);
|
|
375
|
+
return el("w:object", {
|
|
376
|
+
"w:dxaOrig": String(ptToTwips(block.frame.widthPt)),
|
|
377
|
+
"w:dyaOrig": String(ptToTwips(block.frame.heightPt))
|
|
378
|
+
}, [el("o:OLEObject", {
|
|
379
|
+
Type: "Embed",
|
|
380
|
+
ProgID: payload.progId,
|
|
381
|
+
DrawAspect: "Content",
|
|
382
|
+
"r:id": relId
|
|
383
|
+
})]);
|
|
384
|
+
}
|
|
299
385
|
const TRACKED_CHANGE_TAG_BY_CHANGE = {
|
|
300
386
|
insertion: "w:ins",
|
|
301
387
|
deletion: "w:del",
|
|
@@ -356,10 +442,29 @@ function buildSdtProperties(descriptor) {
|
|
|
356
442
|
children.push(el("w:date", descriptor.value === void 0 ? {} : { "w:fullDate": encodeXmlText(descriptor.value) }));
|
|
357
443
|
return el("w:sdtPr", {}, children);
|
|
358
444
|
}
|
|
445
|
+
const restored = restoreGalleryElement(descriptor);
|
|
446
|
+
if (restored !== void 0) {
|
|
447
|
+
children.push(restored);
|
|
448
|
+
return el("w:sdtPr", {}, children);
|
|
449
|
+
}
|
|
359
450
|
const typeTag = SDT_TYPE_ELEMENT[descriptor.controlType];
|
|
360
451
|
children.push(el(typeTag ?? "w:richText"));
|
|
361
452
|
return el("w:sdtPr", {}, children);
|
|
362
453
|
}
|
|
454
|
+
function restoreGalleryElement(descriptor) {
|
|
455
|
+
if (descriptor.controlType !== "richText") return;
|
|
456
|
+
const source = descriptor.source;
|
|
457
|
+
if (source?.format !== "docx") return;
|
|
458
|
+
let nodes;
|
|
459
|
+
try {
|
|
460
|
+
nodes = parseXml(source.xml);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
throw new Error(`buildDocxPackageFromContent: a content control carries docx residue that does not parse as XML: ${source.xml}`, { cause: error });
|
|
463
|
+
}
|
|
464
|
+
const first = nodes[0];
|
|
465
|
+
if (nodes.length !== 1 || first?.type !== "element" || first.tag !== "w:docPartObj" && first.tag !== "w:docPartList") return;
|
|
466
|
+
return first;
|
|
467
|
+
}
|
|
363
468
|
function parseFlow(blocks) {
|
|
364
469
|
const imbalance = findConstructMarkerImbalance(blocks);
|
|
365
470
|
if (imbalance !== void 0) throw new Error(`buildDocxPackageFromContent: construct markers do not balance (${imbalance.kind} at block ${String(imbalance.index)})`);
|
|
@@ -503,8 +608,25 @@ function buildFlowItems(items, state, deleted, provenance) {
|
|
|
503
608
|
availableImageRuns = [];
|
|
504
609
|
continue;
|
|
505
610
|
}
|
|
506
|
-
|
|
507
|
-
|
|
611
|
+
if (block.kind === "embeddedObject") {
|
|
612
|
+
if (pendingPageBreak) {
|
|
613
|
+
const breakParagraph = el("w:p", {}, [el("w:pPr", {}, [el("w:pageBreakBefore")])]);
|
|
614
|
+
nodes.push(breakParagraph);
|
|
615
|
+
lastParagraph = breakParagraph;
|
|
616
|
+
availableImageRuns = [];
|
|
617
|
+
pendingPageBreak = false;
|
|
618
|
+
}
|
|
619
|
+
const object = buildObjectElement(block, state);
|
|
620
|
+
const reusable = availableImageRuns.shift();
|
|
621
|
+
if (reusable !== void 0) reusable.children.push(object);
|
|
622
|
+
else if (lastParagraph !== void 0) lastParagraph.children.push(el("w:r", {}, [object]));
|
|
623
|
+
else {
|
|
624
|
+
const paragraph = el("w:p", {}, [el("w:r", {}, [object])]);
|
|
625
|
+
lastParagraph = paragraph;
|
|
626
|
+
nodes.push(paragraph);
|
|
627
|
+
}
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
508
630
|
}
|
|
509
631
|
if (pendingPageBreak) nodes.push(el("w:p", {}, [el("w:pPr", {}, [el("w:pageBreakBefore")])]));
|
|
510
632
|
return nodes;
|
|
@@ -554,12 +676,14 @@ function buildDocumentPart(sections, state) {
|
|
|
554
676
|
"xmlns:wp": DRAWING_WP_NS,
|
|
555
677
|
"xmlns:pic": DRAWING_PIC_NS,
|
|
556
678
|
"xmlns:mc": MARKUP_COMPAT_NS,
|
|
679
|
+
"xmlns:o": VML_OFFICE_NS,
|
|
557
680
|
"xmlns:w14": W14_NS,
|
|
558
681
|
"xmlns:w15": W15_NS,
|
|
559
682
|
"mc:Ignorable": "w14 w15"
|
|
560
683
|
}, [el("w:body", {}, bodyChildren)]));
|
|
561
684
|
}
|
|
562
|
-
function buildContentTypesPart(
|
|
685
|
+
function buildContentTypesPart(state) {
|
|
686
|
+
const mediaFormats = new Set([...state.mediaParts.values()].map((media) => media.format));
|
|
563
687
|
const defaults = [el("Default", {
|
|
564
688
|
Extension: "rels",
|
|
565
689
|
ContentType: "application/vnd.openxmlformats-package.relationships+xml"
|
|
@@ -575,6 +699,10 @@ function buildContentTypesPart(mediaFormats) {
|
|
|
575
699
|
Extension: "jpeg",
|
|
576
700
|
ContentType: "image/jpeg"
|
|
577
701
|
}));
|
|
702
|
+
const embeddingOverrides = [...state.embeddingParts].map(([name, payload]) => el("Override", {
|
|
703
|
+
PartName: `/word/embeddings/${name}`,
|
|
704
|
+
ContentType: payload.extension === "docx" ? CT_EMBEDDED_DOCX : CT_EMBEDDED_XLSX
|
|
705
|
+
}));
|
|
578
706
|
return xmlPart(el("Types", { xmlns: CONTENT_TYPES_NS }, [
|
|
579
707
|
...defaults,
|
|
580
708
|
el("Override", {
|
|
@@ -588,7 +716,8 @@ function buildContentTypesPart(mediaFormats) {
|
|
|
588
716
|
el("Override", {
|
|
589
717
|
PartName: "/docProps/app.xml",
|
|
590
718
|
ContentType: CT_EXTENDED_PROPS
|
|
591
|
-
})
|
|
719
|
+
}),
|
|
720
|
+
...embeddingOverrides
|
|
592
721
|
]));
|
|
593
722
|
}
|
|
594
723
|
function buildPackageRelsPart() {
|
|
@@ -660,7 +789,7 @@ function buildDocxPackageFromContent(content) {
|
|
|
660
789
|
}] : content.sections, state);
|
|
661
790
|
const metadata = content.metadata ?? {};
|
|
662
791
|
const parts = {
|
|
663
|
-
"[Content_Types].xml": buildContentTypesPart(
|
|
792
|
+
"[Content_Types].xml": buildContentTypesPart(state),
|
|
664
793
|
"_rels/.rels": buildPackageRelsPart(),
|
|
665
794
|
[DOCUMENT_PART_PATH]: documentPart,
|
|
666
795
|
"word/_rels/document.xml.rels": buildDocumentRelsPart(state),
|
|
@@ -671,6 +800,10 @@ function buildDocxPackageFromContent(content) {
|
|
|
671
800
|
kind: "binary",
|
|
672
801
|
base64: media.base64
|
|
673
802
|
};
|
|
803
|
+
for (const [name, payload] of state.embeddingParts) parts[`word/embeddings/${name}`] = {
|
|
804
|
+
kind: "binary",
|
|
805
|
+
base64: payload.base64
|
|
806
|
+
};
|
|
674
807
|
return { parts };
|
|
675
808
|
}
|
|
676
809
|
//#endregion
|
package/dist/typed/embedded.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_read = require("../read-
|
|
2
|
+
const require_read = require("../read-Di5UfiSh.cjs");
|
|
3
3
|
exports.readEmbeddedOoxmlPayload = require_read.readEmbeddedOoxmlPayload;
|
|
4
4
|
exports.readEmbeddedPayloadPart = require_read.readEmbeddedPayloadPart;
|
package/dist/typed/embedded.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as readEmbeddedOoxmlPayload, o as readEmbeddedPayloadPart } from "../read-
|
|
1
|
+
import { a as readEmbeddedOoxmlPayload, o as readEmbeddedPayloadPart } from "../read-BQoFiqsb.js";
|
|
2
2
|
export { readEmbeddedOoxmlPayload, readEmbeddedPayloadPart };
|
package/dist/typed/pptx/read.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_read = require("../../read-
|
|
2
|
+
const require_read = require("../../read-Di5UfiSh.cjs");
|
|
3
3
|
exports.PptxDocumentSchema = require_read.PptxDocumentSchema;
|
|
4
4
|
exports.readPptxContent = require_read.readPptxContent;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as PptxDocumentSchema, r as readPptxContent, t as PptxDocument } from "../../read-
|
|
1
|
+
import { n as PptxDocumentSchema, r as readPptxContent, t as PptxDocument } from "../../read-BoV9SZy4.cjs";
|
|
2
2
|
export { PptxDocument, PptxDocumentSchema, readPptxContent };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as PptxDocumentSchema, r as readPptxContent, t as PptxDocument } from "../../read-
|
|
1
|
+
import { n as PptxDocumentSchema, r as readPptxContent, t as PptxDocument } from "../../read-ZWJPDvG-.js";
|
|
2
2
|
export { PptxDocument, PptxDocumentSchema, readPptxContent };
|
package/dist/typed/pptx/read.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { c as readPptxContent, s as PptxDocumentSchema } from "../../read-
|
|
1
|
+
import { c as readPptxContent, s as PptxDocumentSchema } from "../../read-BQoFiqsb.js";
|
|
2
2
|
export { PptxDocumentSchema, readPptxContent };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ooxml.js",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "Type-safe, lossless round-trip conversion between OOXML packages (docx, pptx, xlsx) and JSON, built on Zod 4 codecs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"license": "MIT",
|
|
81
81
|
"packageManager": "pnpm@11.6.0",
|
|
82
82
|
"dependencies": {
|
|
83
|
-
"archive-codec": "^1.0
|
|
84
|
-
"document-schema.js": "^4.
|
|
83
|
+
"archive-codec": "^1.1.0",
|
|
84
|
+
"document-schema.js": "^4.5.0",
|
|
85
85
|
"fast-xml-parser": "^5.10.1",
|
|
86
86
|
"fflate": "^0.8.3",
|
|
87
87
|
"zod": "^4.4.3"
|