@stll/folio-core 0.55.0 → 0.56.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/dist/ai-edits/apply.js +169 -38
- package/dist/ai-edits/headless.js +2 -2
- package/dist/ai-edits/types.d.ts +7 -1
- package/dist/compare/compare.js +1 -0
- package/dist/compare/reproducible-package.d.ts +0 -17
- package/dist/compare/reproducible-package.js +12 -18
- package/dist/controller/canonicalClipboard.d.ts +23 -0
- package/dist/controller/canonicalClipboard.js +476 -0
- package/dist/controller/canonicalClipboardResources.d.ts +21 -0
- package/dist/controller/canonicalClipboardResources.js +382 -0
- package/dist/controller/canonicalComposition.d.ts +20 -3
- package/dist/controller/canonicalComposition.js +166 -38
- package/dist/controller/canonicalInlineProjection.d.ts +113 -0
- package/dist/controller/canonicalInlineProjection.js +393 -0
- package/dist/controller/canonicalInput.d.ts +13 -4
- package/dist/controller/canonicalInput.js +52 -13
- package/dist/controller/canonicalInputTimer.d.ts +7 -0
- package/dist/controller/canonicalInputTimer.js +11 -0
- package/dist/controller/canonicalPublicOperations.d.ts +48 -0
- package/dist/controller/canonicalPublicOperations.js +556 -0
- package/dist/controller/canonicalSession.d.ts +24 -6
- package/dist/controller/canonicalSession.js +259 -111
- package/dist/controller/canonicalStoryEditor.d.ts +5 -3
- package/dist/controller/canonicalStoryEditor.js +7 -2
- package/dist/controller/canonicalStructure.js +57 -4
- package/dist/controller/canonicalTocSelection.d.ts +11 -0
- package/dist/controller/canonicalTocSelection.js +43 -0
- package/dist/controller/folioEditor.d.ts +2 -9
- package/dist/controller/folioEditor.js +5 -4
- package/dist/controller/headerFooterEditorManager.d.ts +2 -1
- package/dist/controller/headerFooterEditorManager.js +8 -7
- package/dist/controller/hiddenEditorApi.d.ts +12 -2
- package/dist/controller/hiddenEditorApi.js +4 -0
- package/dist/controller/hiddenEditorManager.d.ts +3 -1
- package/dist/controller/hiddenEditorManager.js +216 -34
- package/dist/controller/noteEditorManager.d.ts +2 -1
- package/dist/controller/noteEditorManager.js +8 -7
- package/dist/document-operations.d.ts +8 -1
- package/dist/document-operations.js +6 -4
- package/dist/docx/blockPlainText.d.ts +1 -1
- package/dist/docx/blockPlainText.js +11 -3
- package/dist/docx/canonicalResourceSave.d.ts +16 -0
- package/dist/docx/canonicalResourceSave.js +27 -0
- package/dist/docx/canonicalSave.d.ts +29 -0
- package/dist/docx/canonicalSave.js +101 -0
- package/dist/docx/canonicalStoryRepack.d.ts +1 -1
- package/dist/docx/canonicalStoryRepack.js +38 -5
- package/dist/docx/documentParser.d.ts +1 -13
- package/dist/docx/documentParser.js +1 -47
- package/dist/docx/ensureParaIds.js +10 -4
- package/dist/docx/footnoteParser.d.ts +1 -11
- package/dist/docx/footnoteParser.js +1 -16
- package/dist/docx/headerFooterParser.d.ts +1 -9
- package/dist/docx/headerFooterParser.js +1 -12
- package/dist/docx/headerFooterVerbatim.d.ts +26 -1
- package/dist/docx/headerFooterVerbatim.js +81 -3
- package/dist/docx/imageParser.d.ts +13 -1
- package/dist/docx/imageParser.js +20 -11
- package/dist/docx/metadataPrivacy.js +6 -1
- package/dist/docx/packageParts.js +9 -3
- package/dist/docx/paragraphPropertySource.js +2 -1
- package/dist/docx/parser.js +2 -1
- package/dist/docx/removeHeaderFooterParts.js +17 -6
- package/dist/docx/rezip.d.ts +49 -5
- package/dist/docx/rezip.js +745 -229
- package/dist/docx/saveDiagnostics.d.ts +11 -0
- package/dist/docx/selectiveSave.d.ts +2 -1
- package/dist/docx/selectiveSave.js +32 -3
- package/dist/docx/selectiveXmlPatch.js +7 -5
- package/dist/docx/serializer/documentSerializer.d.ts +9 -2
- package/dist/docx/serializer/documentSerializer.js +29 -10
- package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
- package/dist/docx/storyBlockReplay.d.ts +21 -1
- package/dist/docx/storyBlockReplay.js +113 -9
- package/dist/docx/storyPlainText.d.ts +20 -0
- package/dist/docx/storyPlainText.js +23 -0
- package/dist/docx/structuralXmlPatch.js +10 -22
- package/dist/docx/styleParser.d.ts +5 -1
- package/dist/docx/styleParser.js +1 -1
- package/dist/docx/tableParser.d.ts +1 -8
- package/dist/docx/tableParser.js +1 -28
- package/dist/docx/textBoxParser.d.ts +1 -5
- package/dist/docx/textBoxParser.js +1 -20
- package/dist/docx/unzip.js +6 -1
- package/dist/internal/acceptedBlockProjection.d.ts +12 -0
- package/dist/internal/acceptedBlockProjection.js +45 -0
- package/dist/managers/DocumentLoaderManager.js +2 -1
- package/dist/markdown/escape.d.ts +3 -1
- package/dist/markdown/escape.js +9 -2
- package/dist/markdown/renderBlock.js +5 -120
- package/dist/markdown/renderParagraph.js +4 -2
- package/dist/markdown/renderRuns.d.ts +7 -1
- package/dist/markdown/renderRuns.js +32 -13
- package/dist/prosemirror/canonicalCommands.d.ts +28 -4
- package/dist/prosemirror/canonicalCommands.js +11 -4
- package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
- package/dist/prosemirror/canonicalSelectionRange.js +15 -0
- package/dist/prosemirror/clipboardIntent.d.ts +7 -0
- package/dist/prosemirror/clipboardIntent.js +9 -0
- package/dist/prosemirror/commands/pageBreak.js +2 -2
- package/dist/prosemirror/commands/pastePlainText.js +2 -1
- package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
- package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
- package/dist/prosemirror/conversion/toProseDoc.js +5 -4
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +39 -30
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +56 -28
- package/dist/prosemirror/extensions/marks/markUtils.js +3 -1
- package/dist/prosemirror/insertOperations.js +2 -1
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
- package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
- package/dist/prosemirror/plugins/suggestionMode.js +7 -5
- package/dist/types/canonicalCapabilities.d.ts +215 -0
- package/dist/types/canonicalCapabilities.js +212 -0
- package/dist/types/canonicalSave.d.ts +11 -0
- package/dist/types/canonicalSave.js +0 -0
- package/dist/types/docxSerialization.d.ts +14 -0
- package/dist/types/docxSerialization.js +7 -0
- package/package.json +4 -4
package/dist/docx/rezip.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { consumeTrackedSectionEndpointRemoval } from "../internal/sectionEndpointResolution.js";
|
|
2
2
|
import { consumeSectionReferenceResolution } from "../internal/sectionReferenceResolution.js";
|
|
3
|
+
import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
|
|
4
|
+
import { canonicalJson } from "../utils/canonicalJson.js";
|
|
3
5
|
import { isAllowedExternalWatermarkImageUrl } from "../watermark/index.js";
|
|
4
6
|
import { appVersionInSchemaForm, normalizeAppVersionInExtendedProperties } from "./appVersionNormalization.js";
|
|
5
7
|
import { withoutOrphanCommentRanges } from "./commentRangeIntegrity.js";
|
|
@@ -9,6 +11,7 @@ import { readDocumentSectionFacts } from "./documentSectionFacts.js";
|
|
|
9
11
|
import { normalizeDrawingIds } from "./drawingIdNormalization.js";
|
|
10
12
|
import { rebindDrawingImageRelationship } from "./drawingRelationships.js";
|
|
11
13
|
import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
|
|
14
|
+
import { getDocumentSourceBaseline } from "./headerFooterVerbatim.js";
|
|
12
15
|
import { assertValidFolioDocumentModel } from "./modelValidation.js";
|
|
13
16
|
import { isNewDataUrlDrawing } from "./newImage.js";
|
|
14
17
|
import { missingNoteReferenceStyles, noteReferenceNeeds } from "./noteReferenceStyles.js";
|
|
@@ -16,12 +19,12 @@ import { parseNumbering } from "./numberingParser.js";
|
|
|
16
19
|
import { paragraphNumberingReferenceId as paragraphNumberingReferenceId$1 } from "./numberingReference.js";
|
|
17
20
|
import { isUnsafePackagePath, reconcilePackageReferences, removeUnsafeEntries } from "./packageParts.js";
|
|
18
21
|
import { normalizeParaIdRangeInXmlParts } from "./paraIdRangeNormalization.js";
|
|
19
|
-
import { cloneParagraphWithPropertySource } from "./paragraphPropertySource.js";
|
|
20
|
-
import { BLOCK_TREE_DESCENT, visitBlockTreeRecords } from "./paragraphTraversal.js";
|
|
22
|
+
import { cloneDocumentWithParagraphPropertySources, cloneParagraphWithPropertySource, copyDocumentParagraphPropertySourceContract } from "./paragraphPropertySource.js";
|
|
23
|
+
import { BLOCK_TREE_DESCENT, visitBlockTreeRecords, visitInlineContentSlots, visitParagraphRuns } from "./paragraphTraversal.js";
|
|
21
24
|
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
22
25
|
import { removeResolvedHeaderFooterParts } from "./removeHeaderFooterParts.js";
|
|
23
26
|
import { normalizeRevisionIdsInXmlParts } from "./revisionIdNormalization.js";
|
|
24
|
-
import { buildPatchedNotePartXml, collectChangedNoteParaIds, collectParaIds, patchNumberingDefinitions } from "./selectiveXmlPatch.js";
|
|
27
|
+
import { buildPatchedNotePartXml, collectChangedNoteParaIds, collectParaIds, patchNumberingDefinitions, spliceXml } from "./selectiveXmlPatch.js";
|
|
25
28
|
import { planCommentParts, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
26
29
|
import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
27
30
|
import { serializeFontTableXml } from "./serializer/fontTableSerializer.js";
|
|
@@ -34,11 +37,14 @@ import { serializeStyle, serializeStylesXml } from "./serializer/stylesSerialize
|
|
|
34
37
|
import { serializeThemeXml } from "./serializer/themeSerializer.js";
|
|
35
38
|
import { updateEvenAndOddHeaders } from "./settingsHeaderFooterUpdate.js";
|
|
36
39
|
import { parseSettings } from "./settingsParser.js";
|
|
40
|
+
import { getXmlSourceRange, parseStreamingXmlWithSourceRanges } from "./streamingXmlParser.js";
|
|
41
|
+
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
37
42
|
import { hasCanonicalWordprocessingPrefixes } from "./wordprocessingPrefixes.js";
|
|
38
|
-
import { WORDPROCESSINGML_NAMESPACE_URIS, findChild, findChildByNamespaceUri, findChildrenByNamespaceUri, getAttribute, getAttributeByNamespaceUri, getChildElements, getLocalName, getNamespaceUri, matchesName, parseXml, parseXmlDocument } from "./xmlParser.js";
|
|
39
|
-
import { TaggedError, panic } from "better-result";
|
|
43
|
+
import { OFFICE_RELATIONSHIP_NAMESPACE_URIS, OOXML_NAMESPACE_SCOPE, WORDPROCESSINGML_NAMESPACE_URIS, findAttributeByNamespaceUri, findChild, findChildByNamespaceUri, findChildrenByNamespaceUri, getAttribute, getAttributeByNamespaceUri, getChildElements, getLocalName, getNamespaceUri, matchesName, parseXml, parseXmlDocument } from "./xmlParser.js";
|
|
44
|
+
import { Result, TaggedError, panic } from "better-result";
|
|
40
45
|
import { assertValidOoxmlNumericIds, escapeXmlAttribute, escapeXmlText, validateDocxPackage } from "@stll/docx-core";
|
|
41
46
|
import { mintRelationshipId } from "@stll/docx-core/model";
|
|
47
|
+
import { writeZipPart } from "@stll/docx-core/zip";
|
|
42
48
|
import JSZip from "jszip";
|
|
43
49
|
//#region src/docx/rezip.ts
|
|
44
50
|
/**
|
|
@@ -200,9 +206,14 @@ async function serializeCommentsToZip(doc, zip, compressionLevel) {
|
|
|
200
206
|
}
|
|
201
207
|
const plan = planCommentParts(comments);
|
|
202
208
|
const commentsXml = serializeComments(plan, sourceCommentsXml === void 0 ? void 0 : readRootNamespaceBindings(sourceCommentsXml));
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
209
|
+
writeZipPart({
|
|
210
|
+
zip,
|
|
211
|
+
path: sourceCommentsFile?.name ?? "word/comments.xml",
|
|
212
|
+
data: commentsXml,
|
|
213
|
+
options: {
|
|
214
|
+
compression: "DEFLATE",
|
|
215
|
+
compressionOptions: { level: compressionLevel }
|
|
216
|
+
}
|
|
206
217
|
});
|
|
207
218
|
await ensureCommentsContentType(zip, compressionLevel);
|
|
208
219
|
await ensureCommentsRelationship(zip, compressionLevel);
|
|
@@ -231,9 +242,14 @@ async function syncCommentsExtendedPart(plan, zip, compressionLevel) {
|
|
|
231
242
|
await transformPackagingFile(zip, "word/_rels/document.xml.rels", removeCommentsExtendedRelationship, compressionLevel);
|
|
232
243
|
return;
|
|
233
244
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
245
|
+
writeZipPart({
|
|
246
|
+
zip,
|
|
247
|
+
path: existing?.name ?? "word/commentsExtended.xml",
|
|
248
|
+
data: xml,
|
|
249
|
+
options: {
|
|
250
|
+
compression: "DEFLATE",
|
|
251
|
+
compressionOptions: { level: compressionLevel }
|
|
252
|
+
}
|
|
237
253
|
});
|
|
238
254
|
await transformPackagingFile(zip, "[Content_Types].xml", addCommentsExtendedOverride, compressionLevel);
|
|
239
255
|
await transformPackagingFile(zip, "word/_rels/document.xml.rels", addCommentsExtendedRelationship, compressionLevel);
|
|
@@ -244,9 +260,14 @@ async function transformPackagingFile(zip, path, transform, compressionLevel) {
|
|
|
244
260
|
if (!file) return;
|
|
245
261
|
const xml = await file.async("text");
|
|
246
262
|
const next = transform(xml);
|
|
247
|
-
if (next !== xml)
|
|
248
|
-
|
|
249
|
-
|
|
263
|
+
if (next !== xml) writeZipPart({
|
|
264
|
+
zip,
|
|
265
|
+
path,
|
|
266
|
+
data: next,
|
|
267
|
+
options: {
|
|
268
|
+
compression: "DEFLATE",
|
|
269
|
+
compressionOptions: { level: compressionLevel }
|
|
270
|
+
}
|
|
250
271
|
});
|
|
251
272
|
}
|
|
252
273
|
function findZipEntryCaseInsensitive(zip, lowerPath) {
|
|
@@ -255,7 +276,9 @@ function findZipEntryCaseInsensitive(zip, lowerPath) {
|
|
|
255
276
|
for (const [path, file] of Object.entries(zip.files)) if (!file.dir && path.toLowerCase() === lowerPath) return file;
|
|
256
277
|
return null;
|
|
257
278
|
}
|
|
258
|
-
const
|
|
279
|
+
const PACKAGE_RELATIONSHIPS_NAMESPACE_URI = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
280
|
+
const EMPTY_RELS_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
281
|
+
<Relationships xmlns="${PACKAGE_RELATIONSHIPS_NAMESPACE_URI}"></Relationships>`;
|
|
259
282
|
function headerFooterFilename(target) {
|
|
260
283
|
return target.startsWith("/") ? target.slice(1) : `word/${target}`;
|
|
261
284
|
}
|
|
@@ -352,9 +375,14 @@ async function registerImageExtensions(zip, extensions, compressionLevel) {
|
|
|
352
375
|
changed = true;
|
|
353
376
|
}
|
|
354
377
|
if (!changed) return;
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
378
|
+
writeZipPart({
|
|
379
|
+
zip,
|
|
380
|
+
path: "[Content_Types].xml",
|
|
381
|
+
data: ctXml,
|
|
382
|
+
options: {
|
|
383
|
+
compression: "DEFLATE",
|
|
384
|
+
compressionOptions: { level: compressionLevel }
|
|
385
|
+
}
|
|
358
386
|
});
|
|
359
387
|
}
|
|
360
388
|
function collectNewImages(blocks) {
|
|
@@ -425,9 +453,14 @@ async function processNewImages(parts, zip, compressionLevel) {
|
|
|
425
453
|
maxId++;
|
|
426
454
|
const mediaPath = `word/media/${`image${maxImageNum}.${extension}`}`;
|
|
427
455
|
const newRId = mintRelationshipId(maxId);
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
456
|
+
writeZipPart({
|
|
457
|
+
zip,
|
|
458
|
+
path: mediaPath,
|
|
459
|
+
data,
|
|
460
|
+
options: {
|
|
461
|
+
compression: "DEFLATE",
|
|
462
|
+
compressionOptions: { level: compressionLevel }
|
|
463
|
+
}
|
|
431
464
|
});
|
|
432
465
|
relEntries.push(`<Relationship Id="${newRId}" Type="${RELATIONSHIP_TYPES.image}" Target="${escapeXmlAttribute(relativeTargetForPart(partPath, mediaPath))}"/>`);
|
|
433
466
|
extensionsAdded.add(extension);
|
|
@@ -438,13 +471,15 @@ async function processNewImages(parts, zip, compressionLevel) {
|
|
|
438
471
|
}) ?? panic("A detached drawing lost its embedded image relationship");
|
|
439
472
|
image.rId = newRId;
|
|
440
473
|
}
|
|
441
|
-
if (relEntries.length > 0) {
|
|
442
|
-
|
|
443
|
-
|
|
474
|
+
if (relEntries.length > 0) writeZipPart({
|
|
475
|
+
zip,
|
|
476
|
+
path: relsPath,
|
|
477
|
+
data: relsXml.replace("</Relationships>", `${relEntries.join("")}</Relationships>`),
|
|
478
|
+
options: {
|
|
444
479
|
compression: "DEFLATE",
|
|
445
480
|
compressionOptions: { level: compressionLevel }
|
|
446
|
-
}
|
|
447
|
-
}
|
|
481
|
+
}
|
|
482
|
+
});
|
|
448
483
|
}
|
|
449
484
|
await registerImageExtensions(zip, extensionsAdded, compressionLevel);
|
|
450
485
|
}
|
|
@@ -456,67 +491,259 @@ const materializeEmbeddedMedia = async ({ document, zip, compressionLevel }) =>
|
|
|
456
491
|
if (isUnsafePackagePath(media.path) || !media.path.startsWith("word/media/")) panic("Detached media has an invalid package path");
|
|
457
492
|
const extension = media.path.split(".").at(-1)?.toLowerCase();
|
|
458
493
|
if (!extension || !/^[a-z0-9]+$/u.test(extension)) panic("Embedded media has an invalid extension");
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
494
|
+
writeZipPart({
|
|
495
|
+
zip,
|
|
496
|
+
path: media.path,
|
|
497
|
+
data: media.data,
|
|
498
|
+
options: {
|
|
499
|
+
compression: "DEFLATE",
|
|
500
|
+
compressionOptions: { level: compressionLevel }
|
|
501
|
+
}
|
|
462
502
|
});
|
|
463
503
|
extensions.add(extension);
|
|
464
504
|
}
|
|
465
505
|
await registerImageExtensions(zip, extensions, compressionLevel);
|
|
466
506
|
};
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
if (
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
507
|
+
var CanonicalImageRelationshipRefusalError = class extends TaggedError("CanonicalImageRelationshipRefusalError") {};
|
|
508
|
+
/** Publish allocated pictures into each owning story without rebinding canonical ids. */
|
|
509
|
+
const publishCanonicalImageResources = async ({ document, zip, compressionLevel }) => {
|
|
510
|
+
const baseline = getDocumentSourceBaseline(document);
|
|
511
|
+
for (const { relsPath, blocks } of collectDocxParts(document, zip)) {
|
|
512
|
+
const images = [];
|
|
513
|
+
visitBlockTreeRecords(blocks, (record) => {
|
|
514
|
+
if (record.type !== "paragraph") return BLOCK_TREE_DESCENT.descend;
|
|
515
|
+
visitParagraphRuns(record, (run) => {
|
|
516
|
+
for (const content of run.content) if (content.type === "drawing" && content.image.rId !== void 0) images.push(content.image);
|
|
517
|
+
});
|
|
518
|
+
return BLOCK_TREE_DESCENT.descend;
|
|
519
|
+
});
|
|
520
|
+
if (images.length === 0) continue;
|
|
521
|
+
let xml = await readRelsOrStub(zip, relsPath);
|
|
522
|
+
const local = parseRelationships(xml);
|
|
523
|
+
const partPath = relsPath.replace("/_rels/", "/").replace(/\.rels$/u, "");
|
|
524
|
+
let changed = false;
|
|
525
|
+
for (const image of images) {
|
|
526
|
+
const id = image.rId;
|
|
527
|
+
if (id === void 0) continue;
|
|
528
|
+
const refuse = (reason, message) => {
|
|
529
|
+
throw new CanonicalImageRelationshipRefusalError({
|
|
530
|
+
message,
|
|
531
|
+
gap: CANONICAL_GAP.save,
|
|
532
|
+
part: relsPath,
|
|
533
|
+
relationshipId: id,
|
|
534
|
+
reason
|
|
535
|
+
});
|
|
536
|
+
};
|
|
537
|
+
const source = local.get(id);
|
|
538
|
+
const allocated = document.package.relationships?.get(id);
|
|
539
|
+
const allocatedMediaPath = allocated?.targetMode === "External" || allocated?.type !== RELATIONSHIP_TYPES.image ? void 0 : resolveRelativePath("word/_rels/document.xml.rels", allocated.target);
|
|
540
|
+
const allocatedMedia = allocatedMediaPath === void 0 ? void 0 : document.package.media?.get(allocatedMediaPath);
|
|
541
|
+
const newlyAllocated = allocated?.type === RELATIONSHIP_TYPES.image && (baseline.type !== "captured" || canonicalJson(allocated) !== canonicalJson(baseline.resourceRelationships?.get(id)));
|
|
542
|
+
const desired = relsPath === "word/_rels/document.xml.rels" || newlyAllocated || source === void 0 && image.src !== void 0 && (allocated?.targetMode === "External" ? image.src === allocated.target : image.src === allocatedMedia?.dataUrl) ? allocated : source;
|
|
543
|
+
if (desired?.type !== RELATIONSHIP_TYPES.image) return refuse("unresolved", "A canonical inline picture has no owning image relationship.");
|
|
544
|
+
const desiredRelsPath = desired === allocated ? "word/_rels/document.xml.rels" : relsPath;
|
|
545
|
+
const absolute = desired.targetMode === "External" ? void 0 : resolveRelativePath(desiredRelsPath, desired.target);
|
|
546
|
+
if (desired.targetMode === "External" && !isAllowedExternalWatermarkImageUrl(desired.target)) return refuse("unsafeTarget", "A canonical inline picture has an unsafe external target.");
|
|
547
|
+
if (absolute !== void 0 && isUnsafePackagePath(absolute)) return refuse("unsafeTarget", "A canonical inline picture has an unsafe media target.");
|
|
548
|
+
if (source) {
|
|
549
|
+
const sourceAbsolute = source.targetMode === "External" ? void 0 : resolveRelativePath(relsPath, source.target);
|
|
550
|
+
if (source.type !== RELATIONSHIP_TYPES.image || source.targetMode === "External" !== (desired.targetMode === "External") || (absolute === void 0 ? source.target !== desired.target : sourceAbsolute !== absolute)) return refuse("conflict", "A canonical inline picture relationship conflicts with its owning source binding.");
|
|
551
|
+
}
|
|
552
|
+
if (absolute !== void 0 && !findZipEntryCaseInsensitive(zip, absolute.toLowerCase())) {
|
|
553
|
+
const media = document.package.media?.get(absolute);
|
|
554
|
+
if (!media) return refuse("missingMedia", "A canonical inline picture is missing its media bytes.");
|
|
555
|
+
if (isUnsafePackagePath(media.path) || media.path !== absolute) return refuse("unsafeTarget", "A canonical inline picture media path does not match its relationship.");
|
|
556
|
+
writeZipPart({
|
|
557
|
+
zip,
|
|
558
|
+
path: absolute,
|
|
559
|
+
data: media.data,
|
|
560
|
+
options: {
|
|
561
|
+
compression: "DEFLATE",
|
|
562
|
+
compressionOptions: { level: compressionLevel }
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
const extension = absolute.split(".").at(-1)?.toLowerCase();
|
|
566
|
+
if (!extension || !/^[a-z0-9]+$/u.test(extension)) return refuse("unsafeTarget", "A canonical inline picture media extension is invalid.");
|
|
567
|
+
await registerImageExtensions(zip, /* @__PURE__ */ new Set([extension]), compressionLevel);
|
|
568
|
+
}
|
|
569
|
+
if (source) continue;
|
|
570
|
+
const root = parseXmlDocument(xml);
|
|
571
|
+
const type = root !== null && getChildElements(root).some((element) => getAttribute(element, null, "Type")?.startsWith("http://purl.oclc.org/ooxml/officeDocument/relationships/")) ? "http://purl.oclc.org/ooxml/officeDocument/relationships/image" : RELATIONSHIP_TYPES.image;
|
|
572
|
+
const target = absolute === void 0 ? desired.target : relativeTargetForPart(partPath, absolute);
|
|
573
|
+
xml = appendCanonicalRelationship({
|
|
574
|
+
xml,
|
|
575
|
+
partPath: relsPath,
|
|
576
|
+
relationshipXml: `<Relationship Id="${escapeXmlAttribute(id)}" Type="${type}" Target="${escapeXmlAttribute(target)}"${desired.targetMode === "External" ? " TargetMode=\"External\"" : ""}/>`
|
|
577
|
+
});
|
|
578
|
+
local.set(id, {
|
|
579
|
+
id,
|
|
580
|
+
type: RELATIONSHIP_TYPES.image,
|
|
581
|
+
target,
|
|
582
|
+
...desired.targetMode === "External" ? { targetMode: "External" } : {}
|
|
583
|
+
});
|
|
584
|
+
changed = true;
|
|
488
585
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
586
|
+
if (changed) writeZipPart({
|
|
587
|
+
zip,
|
|
588
|
+
path: relsPath,
|
|
589
|
+
data: xml,
|
|
590
|
+
options: {
|
|
591
|
+
compression: "DEFLATE",
|
|
592
|
+
compressionOptions: { level: compressionLevel }
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
const collectExternalHyperlinkResources = (blocks) => {
|
|
598
|
+
const resources = [];
|
|
599
|
+
visitBlockTreeRecords(blocks, (record) => {
|
|
600
|
+
if (record.type !== "paragraph") return BLOCK_TREE_DESCENT.descend;
|
|
601
|
+
visitInlineContentSlots(record, ({ item }) => {
|
|
602
|
+
if (item.type === "hyperlink" && item.href && !item.anchor) resources.push({
|
|
603
|
+
type: "text",
|
|
604
|
+
hyperlink: item
|
|
605
|
+
});
|
|
606
|
+
});
|
|
607
|
+
visitParagraphRuns(record, (run) => {
|
|
608
|
+
for (const drawing of run.content) if (drawing.type === "drawing" && drawing.rawXmlMode === void 0 && drawing.image.hlinkHref) resources.push({
|
|
609
|
+
type: "drawing",
|
|
610
|
+
image: drawing.image,
|
|
611
|
+
drawing
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
return BLOCK_TREE_DESCENT.descend;
|
|
615
|
+
});
|
|
616
|
+
return resources;
|
|
617
|
+
};
|
|
618
|
+
const externalHyperlinkTarget = (resource) => {
|
|
619
|
+
switch (resource.type) {
|
|
620
|
+
case "text": return {
|
|
621
|
+
id: resource.hyperlink.rId,
|
|
622
|
+
href: resource.hyperlink.href
|
|
623
|
+
};
|
|
624
|
+
case "drawing": return {
|
|
625
|
+
id: resource.image.hlinkRId,
|
|
626
|
+
href: resource.image.hlinkHref
|
|
627
|
+
};
|
|
628
|
+
default: return resource;
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
/** Newly authored text links; the census shares the complete owning-part traversal. */
|
|
632
|
+
function collectHyperlinksWithoutRId(blocks) {
|
|
633
|
+
return collectExternalHyperlinkResources(blocks).flatMap((resource) => resource.type === "text" && !resource.hyperlink.rId ? [resource.hyperlink] : []);
|
|
494
634
|
}
|
|
495
635
|
/** The selective save boundary must use the same resource census as full repack. */
|
|
496
|
-
const hasUnmaterializedInlineResources = (blocks) => collectNewImages(blocks).length > 0 ||
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
636
|
+
const hasUnmaterializedInlineResources = (blocks) => collectNewImages(blocks).length > 0 || collectExternalHyperlinkResources(blocks).some((resource) => externalHyperlinkTarget(resource).id === void 0);
|
|
637
|
+
const matchesExternalHyperlink = (relation, href) => relation?.type === RELATIONSHIP_TYPES.hyperlink && relation.targetMode === "External" && relation.target === href;
|
|
638
|
+
/** Compare against the already loaded source ZIP, without mutating model or package. */
|
|
639
|
+
const hasUnmaterializedHyperlinkBindings = async (document, zip) => {
|
|
640
|
+
for (const { blocks, relsPath } of collectDocxParts(document, zip)) {
|
|
641
|
+
const resources = collectExternalHyperlinkResources(blocks);
|
|
642
|
+
if (resources.length === 0) continue;
|
|
643
|
+
const relationships = parseRelationships(await readRelsOrStub(zip, relsPath));
|
|
644
|
+
for (const resource of resources) {
|
|
645
|
+
const { id, href } = externalHyperlinkTarget(resource);
|
|
646
|
+
if (href && (id === void 0 || !matchesExternalHyperlink(relationships.get(id), href))) return true;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return false;
|
|
650
|
+
};
|
|
651
|
+
const rebindCapturedDrawingLink = ({ xml, previousId, nextId }) => {
|
|
652
|
+
const parsed = Result.try({
|
|
653
|
+
try: () => parseXml(xml, OOXML_NAMESPACE_SCOPE),
|
|
654
|
+
catch: () => new DocxPackageFidelityError("Cannot rebind invalid captured drawing hyperlink XML.")
|
|
655
|
+
});
|
|
656
|
+
if (parsed.isErr()) throw parsed.error;
|
|
657
|
+
let rebound = 0;
|
|
658
|
+
const visit = (element) => {
|
|
659
|
+
const attribute = findAttributeByNamespaceUri(element, OFFICE_RELATIONSHIP_NAMESPACE_URIS, "id");
|
|
660
|
+
if (attribute?.value === previousId && element.attributes !== void 0) {
|
|
661
|
+
element.attributes[attribute.name] = nextId;
|
|
662
|
+
rebound += 1;
|
|
663
|
+
}
|
|
664
|
+
for (const child of element.elements ?? []) visit(child);
|
|
665
|
+
};
|
|
666
|
+
visit(parsed.value);
|
|
667
|
+
if (rebound !== 1) throw new DocxPackageFidelityError("Captured drawing hyperlink must own exactly one click relationship.");
|
|
668
|
+
return (parsed.value.elements ?? []).map(captureVerbatimXml).join("");
|
|
669
|
+
};
|
|
670
|
+
/** Materialize each modeled hyperlink against the actual owning ZIP relationship table. */
|
|
502
671
|
async function processNewHyperlinks(parts, zip, compressionLevel) {
|
|
503
672
|
for (const { relsPath, blocks } of parts) {
|
|
504
|
-
const
|
|
505
|
-
if (
|
|
673
|
+
const resources = collectExternalHyperlinkResources(blocks);
|
|
674
|
+
if (resources.length === 0) continue;
|
|
506
675
|
const relsXml = await readRelsOrStub(zip, relsPath);
|
|
676
|
+
const relationships = parseRelationships(relsXml);
|
|
677
|
+
const root = parseXmlDocument(relsXml);
|
|
678
|
+
if (root?.name === void 0 || getLocalName(root.name) !== "Relationships" || getNamespaceUri(root) !== PACKAGE_RELATIONSHIPS_NAMESPACE_URI) throw new DocxPackageFidelityError("Cannot materialize hyperlinks into an invalid relationship part.");
|
|
679
|
+
const strictRelationshipNamespace = "http://purl.oclc.org/ooxml/officeDocument/relationships";
|
|
680
|
+
const relationshipType = getChildElements(root).some((child) => getAttribute(child, null, "Type")?.startsWith(`${strictRelationshipNamespace}/`)) ? `${strictRelationshipNamespace}/hyperlink` : RELATIONSHIP_TYPES.hyperlink;
|
|
681
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
682
|
+
for (const relation of relationships.values()) if (relation.type === RELATIONSHIP_TYPES.hyperlink && relation.targetMode === "External" && !byTarget.has(relation.target)) byTarget.set(relation.target, relation.id);
|
|
507
683
|
let maxId = findMaxRId(relsXml);
|
|
508
684
|
const relEntries = [];
|
|
509
|
-
for (const
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
685
|
+
for (const resource of resources) {
|
|
686
|
+
const { id, href } = externalHyperlinkTarget(resource);
|
|
687
|
+
if (!href || id !== void 0 && matchesExternalHyperlink(relationships.get(id), href)) continue;
|
|
688
|
+
let nextId = byTarget.get(href);
|
|
689
|
+
if (nextId === void 0) {
|
|
690
|
+
if (id !== void 0 && !relationships.has(id)) nextId = id;
|
|
691
|
+
else do {
|
|
692
|
+
maxId += 1;
|
|
693
|
+
nextId = `rId${maxId}`;
|
|
694
|
+
} while (relationships.has(nextId));
|
|
695
|
+
relationships.set(nextId, {
|
|
696
|
+
id: nextId,
|
|
697
|
+
type: RELATIONSHIP_TYPES.hyperlink,
|
|
698
|
+
target: href,
|
|
699
|
+
targetMode: "External"
|
|
700
|
+
});
|
|
701
|
+
byTarget.set(href, nextId);
|
|
702
|
+
relEntries.push({
|
|
703
|
+
type: "element",
|
|
704
|
+
name: `${root.name.slice(0, -13)}Relationship`,
|
|
705
|
+
attributes: {
|
|
706
|
+
Id: nextId,
|
|
707
|
+
Type: relationshipType,
|
|
708
|
+
Target: href,
|
|
709
|
+
TargetMode: "External"
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
switch (resource.type) {
|
|
714
|
+
case "text":
|
|
715
|
+
resource.hyperlink.rId = nextId;
|
|
716
|
+
break;
|
|
717
|
+
case "drawing": {
|
|
718
|
+
const source = resource.image.hlinkClickSource;
|
|
719
|
+
if (source !== void 0 && source.rId === id && id !== void 0) resource.image.hlinkClickSource = {
|
|
720
|
+
xml: rebindCapturedDrawingLink({
|
|
721
|
+
xml: source.xml,
|
|
722
|
+
previousId: id,
|
|
723
|
+
nextId
|
|
724
|
+
}),
|
|
725
|
+
rId: nextId
|
|
726
|
+
};
|
|
727
|
+
resource.image.hlinkRId = nextId;
|
|
728
|
+
delete resource.drawing.rawXml;
|
|
729
|
+
delete resource.drawing.rawImageFingerprint;
|
|
730
|
+
break;
|
|
731
|
+
}
|
|
732
|
+
default: panic(`Unsupported hyperlink resource ${JSON.stringify(resource)}`);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
if (relEntries.length > 0) {
|
|
736
|
+
(root.elements ??= []).push(...relEntries);
|
|
737
|
+
writeZipPart({
|
|
738
|
+
zip,
|
|
739
|
+
path: relsPath,
|
|
740
|
+
data: captureVerbatimXml(root),
|
|
741
|
+
options: {
|
|
742
|
+
compression: "DEFLATE",
|
|
743
|
+
compressionOptions: { level: compressionLevel }
|
|
744
|
+
}
|
|
745
|
+
});
|
|
515
746
|
}
|
|
516
|
-
zip.file(relsPath, relsXml.replace("</Relationships>", `${relEntries.join("")}</Relationships>`), {
|
|
517
|
-
compression: "DEFLATE",
|
|
518
|
-
compressionOptions: { level: compressionLevel }
|
|
519
|
-
});
|
|
520
747
|
}
|
|
521
748
|
}
|
|
522
749
|
/**
|
|
@@ -541,9 +768,14 @@ const normalizePackageIdsInZip = async (zip, compressionLevel) => {
|
|
|
541
768
|
const normalizedParts = normalizeParaIdRangeInXmlParts(normalizeRevisionIdsInXmlParts(xmlParts));
|
|
542
769
|
for (const [path, xml] of normalizedParts) if (xml !== xmlParts.get(path)) {
|
|
543
770
|
assertValidOoxmlNumericIds(xml, path);
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
771
|
+
writeZipPart({
|
|
772
|
+
zip,
|
|
773
|
+
path,
|
|
774
|
+
data: xml,
|
|
775
|
+
options: {
|
|
776
|
+
compression: "DEFLATE",
|
|
777
|
+
compressionOptions: { level: compressionLevel }
|
|
778
|
+
}
|
|
547
779
|
});
|
|
548
780
|
}
|
|
549
781
|
};
|
|
@@ -558,9 +790,14 @@ const normalizeAppVersionInZip = async (zip, compressionLevel) => {
|
|
|
558
790
|
if (!extendedProperties) return;
|
|
559
791
|
const xml = await extendedProperties.async("text");
|
|
560
792
|
const normalized = normalizeAppVersionInExtendedProperties(xml);
|
|
561
|
-
if (normalized !== xml)
|
|
562
|
-
|
|
563
|
-
|
|
793
|
+
if (normalized !== xml) writeZipPart({
|
|
794
|
+
zip,
|
|
795
|
+
path: EXTENDED_PROPERTIES_PATH,
|
|
796
|
+
data: normalized,
|
|
797
|
+
options: {
|
|
798
|
+
compression: "DEFLATE",
|
|
799
|
+
compressionOptions: { level: compressionLevel }
|
|
800
|
+
}
|
|
564
801
|
});
|
|
565
802
|
};
|
|
566
803
|
/**
|
|
@@ -639,20 +876,37 @@ const normalizeExportDrawingIds = ({ package: docxPackage }) => {
|
|
|
639
876
|
...docxPackage.endnotes !== void 0 ? { endnotes: docxPackage.endnotes } : {}
|
|
640
877
|
});
|
|
641
878
|
};
|
|
642
|
-
|
|
643
|
-
|
|
879
|
+
/** Keep export mutations off authority while retaining the source-buffer cache key. */
|
|
880
|
+
const cloneExportDocument = (sourceDocument) => {
|
|
881
|
+
const { originalBuffer, ...graph } = sourceDocument;
|
|
882
|
+
const document = cloneDocumentWithParagraphPropertySources(graph);
|
|
883
|
+
if (originalBuffer !== void 0) document.originalBuffer = originalBuffer;
|
|
884
|
+
copyDocumentParagraphPropertySourceContract(document, sourceDocument);
|
|
885
|
+
return document;
|
|
886
|
+
};
|
|
887
|
+
const finishRepack = async ({ document: sourceDocument, originalZip, outputZip, originalDocument, originalCorePropertiesXml, compressionLevel, updateModifiedDate, modifiedBy, changedNoteParaIds, onDiagnostic, bodyAuthority, sectionEndpointRemoval, sectionReferenceRemovals }) => {
|
|
888
|
+
const document = await materializeNewHeaderFooterParts(cloneExportDocument(sourceDocument), outputZip, compressionLevel);
|
|
644
889
|
await materializeEmbeddedMedia({
|
|
645
890
|
document,
|
|
646
891
|
zip: outputZip,
|
|
647
892
|
compressionLevel
|
|
648
893
|
});
|
|
894
|
+
if (bodyAuthority === "canonical") await publishCanonicalImageResources({
|
|
895
|
+
document,
|
|
896
|
+
zip: outputZip,
|
|
897
|
+
compressionLevel
|
|
898
|
+
});
|
|
649
899
|
const parts = collectDocxParts(document, outputZip);
|
|
650
900
|
normalizeExportDrawingIds(document);
|
|
651
901
|
await processNewImages(parts, outputZip, compressionLevel);
|
|
652
902
|
await processNewHyperlinks(parts, outputZip, compressionLevel);
|
|
653
903
|
assertValidFolioDocumentModel(document, "Cannot repack invalid DOCX document model");
|
|
654
904
|
applyReplyThreadMarkers(document);
|
|
655
|
-
const documentXml = serializeDocument(document, originalDocument === void 0 ? void 0 : readRootNamespaceBindings(originalDocument.xml)
|
|
905
|
+
const documentXml = serializeDocument(document, originalDocument === void 0 ? void 0 : readRootNamespaceBindings(originalDocument.xml), {
|
|
906
|
+
xml: originalDocument?.xml,
|
|
907
|
+
onDiagnostic,
|
|
908
|
+
bodyAuthority
|
|
909
|
+
});
|
|
656
910
|
if (originalDocument?.xml) assertDocumentPackageFidelity({
|
|
657
911
|
originalDocumentFacts: originalDocument.sectionFacts(),
|
|
658
912
|
serializedDocumentXml: documentXml,
|
|
@@ -666,11 +920,21 @@ const finishRepack = async ({ document, originalZip, outputZip, originalDocument
|
|
|
666
920
|
removedReferences: [...sectionReferenceRemovals ?? [], ...sectionEndpointRemoval?.removedReferences ?? []],
|
|
667
921
|
compressionLevel
|
|
668
922
|
});
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
923
|
+
writeZipPart({
|
|
924
|
+
zip: outputZip,
|
|
925
|
+
path: "word/document.xml",
|
|
926
|
+
data: documentXml,
|
|
927
|
+
options: {
|
|
928
|
+
compression: "DEFLATE",
|
|
929
|
+
compressionOptions: { level: compressionLevel }
|
|
930
|
+
}
|
|
931
|
+
});
|
|
932
|
+
await rebindWatermarkRelIds({
|
|
933
|
+
document,
|
|
934
|
+
zip: outputZip,
|
|
935
|
+
compressionLevel,
|
|
936
|
+
bodyAuthority
|
|
672
937
|
});
|
|
673
|
-
await rebindWatermarkRelIds(document, outputZip, compressionLevel);
|
|
674
938
|
await serializeHeadersFootersToZip({
|
|
675
939
|
doc: document,
|
|
676
940
|
zip: outputZip,
|
|
@@ -689,16 +953,18 @@ const finishRepack = async ({ document, originalZip, outputZip, originalDocument
|
|
|
689
953
|
await serializeHeaderFooterSettingsIntoZip(document, outputZip, compressionLevel);
|
|
690
954
|
await serializeCommentsToZip(document, outputZip, compressionLevel);
|
|
691
955
|
await dropAttachedTemplateReference(outputZip, compressionLevel);
|
|
692
|
-
if (updateModifiedDate && originalCorePropertiesXml) {
|
|
693
|
-
|
|
956
|
+
if (updateModifiedDate && originalCorePropertiesXml) writeZipPart({
|
|
957
|
+
zip: outputZip,
|
|
958
|
+
path: "docProps/core.xml",
|
|
959
|
+
data: updateCoreProperties(originalCorePropertiesXml, {
|
|
694
960
|
updateModifiedDate,
|
|
695
961
|
...modifiedBy !== void 0 ? { modifiedBy } : {}
|
|
696
|
-
})
|
|
697
|
-
|
|
962
|
+
}),
|
|
963
|
+
options: {
|
|
698
964
|
compression: "DEFLATE",
|
|
699
965
|
compressionOptions: { level: compressionLevel }
|
|
700
|
-
}
|
|
701
|
-
}
|
|
966
|
+
}
|
|
967
|
+
});
|
|
702
968
|
return generateDocxZip(outputZip, compressionLevel);
|
|
703
969
|
};
|
|
704
970
|
async function repackDocxWithSectionEndpointRemoval({ document: doc, options, sectionEndpointRemoval, sectionReferenceRemovals }) {
|
|
@@ -718,6 +984,7 @@ async function repackDocxWithSectionEndpointRemoval({ document: doc, options, se
|
|
|
718
984
|
compressionLevel,
|
|
719
985
|
updateModifiedDate,
|
|
720
986
|
onDiagnostic: options.onDiagnostic,
|
|
987
|
+
bodyAuthority: options.bodyAuthority,
|
|
721
988
|
...modifiedBy !== void 0 ? { modifiedBy } : {},
|
|
722
989
|
...changedNoteParaIds !== void 0 ? { changedNoteParaIds } : {},
|
|
723
990
|
...sectionEndpointRemoval !== void 0 ? { sectionEndpointRemoval } : {},
|
|
@@ -744,18 +1011,30 @@ function repackDocx(doc, options = {}) {
|
|
|
744
1011
|
*/
|
|
745
1012
|
async function repackDocxFromRaw(doc, rawContent, options = {}) {
|
|
746
1013
|
const { compressionLevel = 6, updateModifiedDate = true, modifiedBy, changedNoteParaIds } = options;
|
|
747
|
-
let exportDocument = withoutOrphanCommentRanges(doc);
|
|
1014
|
+
let exportDocument = withoutOrphanCommentRanges(cloneExportDocument(doc));
|
|
748
1015
|
const newZip = new JSZip();
|
|
749
1016
|
for (const [path, file] of Object.entries(rawContent.originalZip.files)) {
|
|
750
1017
|
if (file.dir) {
|
|
751
|
-
|
|
1018
|
+
writeZipPart({
|
|
1019
|
+
zip: newZip,
|
|
1020
|
+
path,
|
|
1021
|
+
data: "",
|
|
1022
|
+
options: {
|
|
1023
|
+
dir: true,
|
|
1024
|
+
date: file.date
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
752
1027
|
continue;
|
|
753
1028
|
}
|
|
754
1029
|
if (isUnsafePackagePath(path)) continue;
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
1030
|
+
writeZipPart({
|
|
1031
|
+
zip: newZip,
|
|
1032
|
+
path,
|
|
1033
|
+
data: await file.async("arraybuffer"),
|
|
1034
|
+
options: {
|
|
1035
|
+
compression: "DEFLATE",
|
|
1036
|
+
compressionOptions: { level: compressionLevel }
|
|
1037
|
+
}
|
|
759
1038
|
});
|
|
760
1039
|
}
|
|
761
1040
|
exportDocument = await materializeNewHeaderFooterParts(exportDocument, newZip, compressionLevel);
|
|
@@ -764,23 +1043,42 @@ async function repackDocxFromRaw(doc, rawContent, options = {}) {
|
|
|
764
1043
|
zip: newZip,
|
|
765
1044
|
compressionLevel
|
|
766
1045
|
});
|
|
1046
|
+
if (options.bodyAuthority === "canonical") await publishCanonicalImageResources({
|
|
1047
|
+
document: exportDocument,
|
|
1048
|
+
zip: newZip,
|
|
1049
|
+
compressionLevel
|
|
1050
|
+
});
|
|
767
1051
|
const parts = collectDocxParts(exportDocument, newZip);
|
|
768
1052
|
normalizeExportDrawingIds(exportDocument);
|
|
769
1053
|
await processNewImages(parts, newZip, compressionLevel);
|
|
770
1054
|
await processNewHyperlinks(parts, newZip, compressionLevel);
|
|
771
1055
|
assertValidFolioDocumentModel(exportDocument, "Cannot repack invalid DOCX document model");
|
|
772
1056
|
applyReplyThreadMarkers(exportDocument);
|
|
773
|
-
const documentXml = serializeDocument(exportDocument, rawContent.documentXml ? readRootNamespaceBindings(rawContent.documentXml) : void 0
|
|
1057
|
+
const documentXml = serializeDocument(exportDocument, rawContent.documentXml ? readRootNamespaceBindings(rawContent.documentXml) : void 0, {
|
|
1058
|
+
xml: rawContent.documentXml ?? void 0,
|
|
1059
|
+
onDiagnostic: options.onDiagnostic,
|
|
1060
|
+
bodyAuthority: options.bodyAuthority
|
|
1061
|
+
});
|
|
774
1062
|
if (rawContent.documentXml) assertDocumentPackageFidelity({
|
|
775
1063
|
originalDocumentFacts: readDocumentSectionFacts(rawContent.documentXml),
|
|
776
1064
|
serializedDocumentXml: documentXml,
|
|
777
1065
|
doc: exportDocument
|
|
778
1066
|
});
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
1067
|
+
writeZipPart({
|
|
1068
|
+
zip: newZip,
|
|
1069
|
+
path: "word/document.xml",
|
|
1070
|
+
data: documentXml,
|
|
1071
|
+
options: {
|
|
1072
|
+
compression: "DEFLATE",
|
|
1073
|
+
compressionOptions: { level: compressionLevel }
|
|
1074
|
+
}
|
|
1075
|
+
});
|
|
1076
|
+
await rebindWatermarkRelIds({
|
|
1077
|
+
document: exportDocument,
|
|
1078
|
+
zip: newZip,
|
|
1079
|
+
compressionLevel,
|
|
1080
|
+
bodyAuthority: options.bodyAuthority
|
|
782
1081
|
});
|
|
783
|
-
await rebindWatermarkRelIds(exportDocument, newZip, compressionLevel);
|
|
784
1082
|
await serializeHeadersFootersToZip({
|
|
785
1083
|
doc: exportDocument,
|
|
786
1084
|
zip: newZip,
|
|
@@ -799,16 +1097,18 @@ async function repackDocxFromRaw(doc, rawContent, options = {}) {
|
|
|
799
1097
|
await serializeAddedStylesIntoZip(exportDocument, rawContent.originalZip, newZip, compressionLevel);
|
|
800
1098
|
await serializeCommentsToZip(exportDocument, newZip, compressionLevel);
|
|
801
1099
|
await dropAttachedTemplateReference(newZip, compressionLevel);
|
|
802
|
-
if (updateModifiedDate && rawContent.corePropsXml) {
|
|
803
|
-
|
|
1100
|
+
if (updateModifiedDate && rawContent.corePropsXml) writeZipPart({
|
|
1101
|
+
zip: newZip,
|
|
1102
|
+
path: "docProps/core.xml",
|
|
1103
|
+
data: updateCoreProperties(rawContent.corePropsXml, {
|
|
804
1104
|
updateModifiedDate,
|
|
805
1105
|
...modifiedBy !== void 0 ? { modifiedBy } : {}
|
|
806
|
-
})
|
|
807
|
-
|
|
1106
|
+
}),
|
|
1107
|
+
options: {
|
|
808
1108
|
compression: "DEFLATE",
|
|
809
1109
|
compressionOptions: { level: compressionLevel }
|
|
810
|
-
}
|
|
811
|
-
}
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
812
1112
|
return generateDocxZip(newZip, compressionLevel);
|
|
813
1113
|
}
|
|
814
1114
|
const COMMENTS_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml";
|
|
@@ -897,13 +1197,23 @@ async function dropAttachedTemplateReference(zip, compressionLevel) {
|
|
|
897
1197
|
if (!settingsFile) return;
|
|
898
1198
|
const relsFile = zip.file(SETTINGS_RELS_PART);
|
|
899
1199
|
const filtered = withoutAttachedTemplate(await settingsFile.async("text"), await relsFile?.async("text"));
|
|
900
|
-
if (filtered.settingsXml !== void 0)
|
|
901
|
-
|
|
902
|
-
|
|
1200
|
+
if (filtered.settingsXml !== void 0) writeZipPart({
|
|
1201
|
+
zip,
|
|
1202
|
+
path: SETTINGS_PART,
|
|
1203
|
+
data: filtered.settingsXml,
|
|
1204
|
+
options: {
|
|
1205
|
+
compression: "DEFLATE",
|
|
1206
|
+
compressionOptions: { level: compressionLevel }
|
|
1207
|
+
}
|
|
903
1208
|
});
|
|
904
|
-
if (filtered.relsXml !== void 0)
|
|
905
|
-
|
|
906
|
-
|
|
1209
|
+
if (filtered.relsXml !== void 0) writeZipPart({
|
|
1210
|
+
zip,
|
|
1211
|
+
path: SETTINGS_RELS_PART,
|
|
1212
|
+
data: filtered.relsXml,
|
|
1213
|
+
options: {
|
|
1214
|
+
compression: "DEFLATE",
|
|
1215
|
+
compressionOptions: { level: compressionLevel }
|
|
1216
|
+
}
|
|
907
1217
|
});
|
|
908
1218
|
}
|
|
909
1219
|
/**
|
|
@@ -916,9 +1226,14 @@ async function ensureCommentsContentType(zip, compressionLevel) {
|
|
|
916
1226
|
let ctXml = await ctFile.async("text");
|
|
917
1227
|
if (ctXml.includes("/word/comments.xml")) return;
|
|
918
1228
|
ctXml = ctXml.replace("</Types>", `<Override PartName="/word/comments.xml" ContentType="${COMMENTS_CONTENT_TYPE}"/></Types>`);
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1229
|
+
writeZipPart({
|
|
1230
|
+
zip,
|
|
1231
|
+
path: "[Content_Types].xml",
|
|
1232
|
+
data: ctXml,
|
|
1233
|
+
options: {
|
|
1234
|
+
compression: "DEFLATE",
|
|
1235
|
+
compressionOptions: { level: compressionLevel }
|
|
1236
|
+
}
|
|
922
1237
|
});
|
|
923
1238
|
}
|
|
924
1239
|
/**
|
|
@@ -933,9 +1248,14 @@ async function ensureCommentsRelationship(zip, compressionLevel) {
|
|
|
933
1248
|
if (relsXml.includes("comments.xml")) return;
|
|
934
1249
|
const newRId = `rId${findMaxRId(relsXml) + 1}`;
|
|
935
1250
|
relsXml = relsXml.replace("</Relationships>", `<Relationship Id="${newRId}" Type="${RELATIONSHIP_TYPES.comments}" Target="comments.xml"/></Relationships>`);
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1251
|
+
writeZipPart({
|
|
1252
|
+
zip,
|
|
1253
|
+
path: relsPath,
|
|
1254
|
+
data: relsXml,
|
|
1255
|
+
options: {
|
|
1256
|
+
compression: "DEFLATE",
|
|
1257
|
+
compressionOptions: { level: compressionLevel }
|
|
1258
|
+
}
|
|
939
1259
|
});
|
|
940
1260
|
}
|
|
941
1261
|
/**
|
|
@@ -949,9 +1269,14 @@ async function ensureCommentsRelationship(zip, compressionLevel) {
|
|
|
949
1269
|
async function updateDocumentXml(originalBuffer, newDocumentXml, options = {}) {
|
|
950
1270
|
const { compressionLevel = 6 } = options;
|
|
951
1271
|
const zip = await JSZip.loadAsync(originalBuffer);
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1272
|
+
writeZipPart({
|
|
1273
|
+
zip,
|
|
1274
|
+
path: "word/document.xml",
|
|
1275
|
+
data: newDocumentXml,
|
|
1276
|
+
options: {
|
|
1277
|
+
compression: "DEFLATE",
|
|
1278
|
+
compressionOptions: { level: compressionLevel }
|
|
1279
|
+
}
|
|
955
1280
|
});
|
|
956
1281
|
return zip.generateAsync({
|
|
957
1282
|
type: "arraybuffer",
|
|
@@ -971,9 +1296,14 @@ async function updateDocumentXml(originalBuffer, newDocumentXml, options = {}) {
|
|
|
971
1296
|
async function updateXmlFile(originalBuffer, path, content, options = {}) {
|
|
972
1297
|
const { compressionLevel = 6 } = options;
|
|
973
1298
|
const zip = await JSZip.loadAsync(originalBuffer);
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1299
|
+
writeZipPart({
|
|
1300
|
+
zip,
|
|
1301
|
+
path,
|
|
1302
|
+
data: content,
|
|
1303
|
+
options: {
|
|
1304
|
+
compression: "DEFLATE",
|
|
1305
|
+
compressionOptions: { level: compressionLevel }
|
|
1306
|
+
}
|
|
977
1307
|
});
|
|
978
1308
|
return zip.generateAsync({
|
|
979
1309
|
type: "arraybuffer",
|
|
@@ -1004,9 +1334,14 @@ async function updateMultipleFiles(originalBuffer, updates, options = {}) {
|
|
|
1004
1334
|
*/
|
|
1005
1335
|
async function applyUpdatesToZip(zip, updates, options = {}) {
|
|
1006
1336
|
const { compressionLevel = 6 } = options;
|
|
1007
|
-
for (const [path, content] of updates)
|
|
1008
|
-
|
|
1009
|
-
|
|
1337
|
+
for (const [path, content] of updates) writeZipPart({
|
|
1338
|
+
zip,
|
|
1339
|
+
path,
|
|
1340
|
+
data: content,
|
|
1341
|
+
options: {
|
|
1342
|
+
compression: "DEFLATE",
|
|
1343
|
+
compressionOptions: { level: compressionLevel }
|
|
1344
|
+
}
|
|
1010
1345
|
});
|
|
1011
1346
|
await normalizePackageOnSave(zip, compressionLevel);
|
|
1012
1347
|
return await zip.generateAsync({
|
|
@@ -1031,8 +1366,11 @@ async function addRelationship(originalBuffer, relationship) {
|
|
|
1031
1366
|
const newRId = `rId${findMaxRId(relsXml) + 1}`;
|
|
1032
1367
|
const targetModeAttr = relationship.targetMode === "External" ? " TargetMode=\"External\"" : "";
|
|
1033
1368
|
const newRelElement = `<Relationship Id="${newRId}" Type="${relationship.type}" Target="${escapeXmlAttribute(relationship.target)}"${targetModeAttr}/>`;
|
|
1034
|
-
|
|
1035
|
-
|
|
1369
|
+
writeZipPart({
|
|
1370
|
+
zip,
|
|
1371
|
+
path: relsPath,
|
|
1372
|
+
data: relsXml.replace("</Relationships>", `${newRelElement}</Relationships>`)
|
|
1373
|
+
});
|
|
1036
1374
|
return {
|
|
1037
1375
|
buffer: await zip.generateAsync({
|
|
1038
1376
|
type: "arraybuffer",
|
|
@@ -1054,7 +1392,11 @@ async function addRelationship(originalBuffer, relationship) {
|
|
|
1054
1392
|
async function addMedia(originalBuffer, filename, data, mimeType) {
|
|
1055
1393
|
const zip = await JSZip.loadAsync(originalBuffer);
|
|
1056
1394
|
const mediaPath = `word/media/${filename}`;
|
|
1057
|
-
|
|
1395
|
+
writeZipPart({
|
|
1396
|
+
zip,
|
|
1397
|
+
path: mediaPath,
|
|
1398
|
+
data
|
|
1399
|
+
});
|
|
1058
1400
|
const relResult = await addRelationship(await zip.generateAsync({ type: "arraybuffer" }), {
|
|
1059
1401
|
type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
1060
1402
|
target: `media/${filename}`
|
|
@@ -1067,7 +1409,11 @@ async function addMedia(originalBuffer, filename, data, mimeType) {
|
|
|
1067
1409
|
const extensionElement = `<Default Extension="${extension}" ContentType="${getContentTypeForExtension(extension, mimeType)}"/>`;
|
|
1068
1410
|
const updatedContentTypes = contentTypesXml.replace("</Types>", `${extensionElement}</Types>`);
|
|
1069
1411
|
const finalZip = await JSZip.loadAsync(relResult.buffer);
|
|
1070
|
-
|
|
1412
|
+
writeZipPart({
|
|
1413
|
+
zip: finalZip,
|
|
1414
|
+
path: "[Content_Types].xml",
|
|
1415
|
+
data: updatedContentTypes
|
|
1416
|
+
});
|
|
1071
1417
|
return {
|
|
1072
1418
|
buffer: await finalZip.generateAsync({
|
|
1073
1419
|
type: "arraybuffer",
|
|
@@ -1213,17 +1559,27 @@ async function materializeNewHeaderFooterParts(doc, zip, compressionLevel) {
|
|
|
1213
1559
|
materialize(doc.package.headers, RELATIONSHIP_TYPES.header, "header", HEADER_CONTENT_TYPE, true);
|
|
1214
1560
|
materialize(doc.package.footers, RELATIONSHIP_TYPES.footer, "footer", FOOTER_CONTENT_TYPE, false);
|
|
1215
1561
|
const compressionOptions = { level: compressionLevel };
|
|
1216
|
-
if (relEntries.length > 0)
|
|
1217
|
-
|
|
1218
|
-
|
|
1562
|
+
if (relEntries.length > 0) writeZipPart({
|
|
1563
|
+
zip,
|
|
1564
|
+
path: relsPath,
|
|
1565
|
+
data: relsXml.replace("</Relationships>", `${relEntries.join("")}</Relationships>`),
|
|
1566
|
+
options: {
|
|
1567
|
+
compression: "DEFLATE",
|
|
1568
|
+
compressionOptions
|
|
1569
|
+
}
|
|
1219
1570
|
});
|
|
1220
1571
|
const ctFile = zip.file("[Content_Types].xml");
|
|
1221
1572
|
if (ctFile) {
|
|
1222
1573
|
const original = await ctFile.async("text");
|
|
1223
1574
|
const updated = registerContentTypeParts(original, contentTypeParts);
|
|
1224
|
-
if (updated !== original)
|
|
1225
|
-
|
|
1226
|
-
|
|
1575
|
+
if (updated !== original) writeZipPart({
|
|
1576
|
+
zip,
|
|
1577
|
+
path: "[Content_Types].xml",
|
|
1578
|
+
data: updated,
|
|
1579
|
+
options: {
|
|
1580
|
+
compression: "DEFLATE",
|
|
1581
|
+
compressionOptions
|
|
1582
|
+
}
|
|
1227
1583
|
});
|
|
1228
1584
|
}
|
|
1229
1585
|
return doc;
|
|
@@ -1242,25 +1598,46 @@ function hasModelDrivenPictureWatermark(doc) {
|
|
|
1242
1598
|
for (const hf of headers.values()) if (hf.watermark?.kind === "picture" && !hf.rawWatermarkXml) return true;
|
|
1243
1599
|
return false;
|
|
1244
1600
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1601
|
+
const appendCanonicalRelationship = ({ xml, relationshipXml, partPath }) => {
|
|
1602
|
+
const parsed = parseStreamingXmlWithSourceRanges(xml);
|
|
1603
|
+
if (parsed.status !== "parsed") throw new DocxPackageFidelityError(`Cannot read canonical relationships in ${partPath}`);
|
|
1604
|
+
const root = getChildElements(parsed.value).find((element) => getLocalName(element.name ?? "") === "Relationships" && getNamespaceUri(element) === PACKAGE_RELATIONSHIPS_NAMESPACE_URI);
|
|
1605
|
+
const range = root ? getXmlSourceRange(root) : void 0;
|
|
1606
|
+
if (!root?.name || !range) throw new DocxPackageFidelityError(`Cannot find canonical relationship root in ${partPath}`);
|
|
1607
|
+
const sourceRoot = xml.slice(range.start, range.end);
|
|
1608
|
+
const bound = relationshipXml.replace("<Relationship ", `<Relationship xmlns="${PACKAGE_RELATIONSHIPS_NAMESPACE_URI}" `);
|
|
1609
|
+
const selfClosing = sourceRoot.endsWith("/>");
|
|
1610
|
+
const close = xml.lastIndexOf("</", range.end);
|
|
1611
|
+
if (!selfClosing && close < range.start) throw new DocxPackageFidelityError(`Cannot extend canonical relationships in ${partPath}`);
|
|
1612
|
+
const result = spliceXml(xml, [selfClosing ? {
|
|
1613
|
+
start: range.end - 2,
|
|
1614
|
+
end: range.end,
|
|
1615
|
+
newXml: ">" + bound + `</${root.name}>`
|
|
1616
|
+
} : {
|
|
1617
|
+
start: close,
|
|
1618
|
+
end: close,
|
|
1619
|
+
newXml: bound
|
|
1620
|
+
}]);
|
|
1621
|
+
if (result === null) throw new DocxPackageFidelityError(`Cannot splice canonical relationships in ${partPath}`);
|
|
1622
|
+
return result;
|
|
1623
|
+
};
|
|
1624
|
+
async function rebindWatermarkRelIds({ document: doc, zip, compressionLevel, bodyAuthority }) {
|
|
1255
1625
|
const rels = doc.package.relationships;
|
|
1256
1626
|
const headers = doc.package.headers;
|
|
1257
|
-
if (!
|
|
1627
|
+
if (!headers) return;
|
|
1628
|
+
if (!rels) {
|
|
1629
|
+
if (bodyAuthority === "canonical" && [...headers.values()].some(({ watermark }) => watermark?.kind === "picture")) throw new DocxPackageFidelityError("A canonical picture watermark has no header relationship map");
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1258
1632
|
const pending = [];
|
|
1259
1633
|
for (const [rId, hf] of headers) {
|
|
1260
1634
|
const watermark = hf.watermark;
|
|
1261
1635
|
if (!watermark || watermark.kind !== "picture") continue;
|
|
1262
1636
|
const rel = rels.get(rId);
|
|
1263
|
-
if (!rel?.target)
|
|
1637
|
+
if (!rel?.target) {
|
|
1638
|
+
if (bodyAuthority === "canonical") throw new DocxPackageFidelityError(`A canonical picture watermark has no header target for ${rId}`);
|
|
1639
|
+
continue;
|
|
1640
|
+
}
|
|
1264
1641
|
pending.push({
|
|
1265
1642
|
watermark,
|
|
1266
1643
|
header: hf,
|
|
@@ -1293,20 +1670,37 @@ async function rebindWatermarkRelIds(doc, zip, compressionLevel) {
|
|
|
1293
1670
|
const changedPaths = /* @__PURE__ */ new Set();
|
|
1294
1671
|
for (const { watermark, header, relsPath, partPath } of pending) {
|
|
1295
1672
|
let canonical;
|
|
1296
|
-
if (watermark.imageTarget !== void 0) if (watermark.imageTargetExternal)
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1673
|
+
if (watermark.imageTarget !== void 0) if (watermark.imageTargetExternal) {
|
|
1674
|
+
if (bodyAuthority === "canonical" && !isAllowedExternalWatermarkImageUrl(watermark.imageTarget)) throw new DocxPackageFidelityError("A canonical picture watermark has an unsafe external target");
|
|
1675
|
+
canonical = isAllowedExternalWatermarkImageUrl(watermark.imageTarget) ? {
|
|
1676
|
+
mode: "external",
|
|
1677
|
+
url: watermark.imageTarget
|
|
1678
|
+
} : resolveCanonical(watermark.imageRId);
|
|
1679
|
+
} else canonical = {
|
|
1301
1680
|
mode: "internal",
|
|
1302
1681
|
absolute: watermark.imageTarget
|
|
1303
1682
|
};
|
|
1304
1683
|
else canonical = resolveCanonical(watermark.imageRId);
|
|
1305
|
-
if (!canonical)
|
|
1684
|
+
if (!canonical) {
|
|
1685
|
+
if (bodyAuthority === "canonical") throw new DocxPackageFidelityError("A canonical picture watermark image cannot be resolved");
|
|
1686
|
+
continue;
|
|
1687
|
+
}
|
|
1688
|
+
if (bodyAuthority === "canonical" && canonical.mode === "internal" && !zip.file(canonical.absolute)) throw new DocxPackageFidelityError("A canonical picture watermark image part is missing");
|
|
1306
1689
|
const relsXml = relsXmlByPath.get(relsPath) ?? EMPTY_RELS_XML;
|
|
1307
1690
|
const localRels = parseRelationships(relsXml);
|
|
1308
1691
|
const local = relImage(localRels.get(watermark.imageRId), relsPath);
|
|
1309
1692
|
if (local && sameImage(local, canonical)) continue;
|
|
1693
|
+
if (bodyAuthority === "canonical") {
|
|
1694
|
+
if (localRels.has(watermark.imageRId)) throw new DocxPackageFidelityError(`A canonical picture watermark relationship ${watermark.imageRId} has a conflicting target`);
|
|
1695
|
+
const relXml = canonical.mode === "external" ? `<Relationship Id="${escapeXmlAttribute(watermark.imageRId)}" Type="${RELATIONSHIP_TYPES.image}" Target="${escapeXmlAttribute(canonical.url)}" TargetMode="External"/>` : `<Relationship Id="${escapeXmlAttribute(watermark.imageRId)}" Type="${RELATIONSHIP_TYPES.image}" Target="${escapeXmlAttribute(relativeTargetForPart(partPath, canonical.absolute))}"/>`;
|
|
1696
|
+
relsXmlByPath.set(relsPath, appendCanonicalRelationship({
|
|
1697
|
+
xml: relsXml,
|
|
1698
|
+
relationshipXml: relXml,
|
|
1699
|
+
partPath: relsPath
|
|
1700
|
+
}));
|
|
1701
|
+
changedPaths.add(relsPath);
|
|
1702
|
+
continue;
|
|
1703
|
+
}
|
|
1310
1704
|
let resolvedRId;
|
|
1311
1705
|
for (const [id, rel] of localRels) {
|
|
1312
1706
|
const image = relImage(rel, relsPath);
|
|
@@ -1331,9 +1725,14 @@ async function rebindWatermarkRelIds(doc, zip, compressionLevel) {
|
|
|
1331
1725
|
const compressionOptions = { level: compressionLevel };
|
|
1332
1726
|
for (const path of changedPaths) {
|
|
1333
1727
|
const xml = relsXmlByPath.get(path);
|
|
1334
|
-
if (xml)
|
|
1335
|
-
|
|
1336
|
-
|
|
1728
|
+
if (xml) writeZipPart({
|
|
1729
|
+
zip,
|
|
1730
|
+
path,
|
|
1731
|
+
data: xml,
|
|
1732
|
+
options: {
|
|
1733
|
+
compression: "DEFLATE",
|
|
1734
|
+
compressionOptions
|
|
1735
|
+
}
|
|
1337
1736
|
});
|
|
1338
1737
|
}
|
|
1339
1738
|
}
|
|
@@ -1373,9 +1772,14 @@ async function serializeHeadersFootersToZip({ doc, zip, compressionLevel, onDiag
|
|
|
1373
1772
|
for (const [filename, xml] of await collectHeaderFooterUpdates(doc, {
|
|
1374
1773
|
sourceZip: zip,
|
|
1375
1774
|
onDiagnostic
|
|
1376
|
-
}))
|
|
1377
|
-
|
|
1378
|
-
|
|
1775
|
+
})) writeZipPart({
|
|
1776
|
+
zip,
|
|
1777
|
+
path: filename,
|
|
1778
|
+
data: xml,
|
|
1779
|
+
options: {
|
|
1780
|
+
compression: "DEFLATE",
|
|
1781
|
+
compressionOptions
|
|
1782
|
+
}
|
|
1379
1783
|
});
|
|
1380
1784
|
}
|
|
1381
1785
|
async function serializeNotesToZip({ doc, originalZip, newZip, compressionLevel, changedNoteParaIds }) {
|
|
@@ -1429,22 +1833,37 @@ async function materializeNewNotePart({ contentType, newZip, partPath, relations
|
|
|
1429
1833
|
const compressionOptions = { level: compressionLevel };
|
|
1430
1834
|
const contentTypesXml = await contentTypesFile.async("text");
|
|
1431
1835
|
const partName = `/${partPath}`;
|
|
1432
|
-
if (!contentTypesXml.toLowerCase().includes(partName.toLowerCase()))
|
|
1433
|
-
|
|
1434
|
-
|
|
1836
|
+
if (!contentTypesXml.toLowerCase().includes(partName.toLowerCase())) writeZipPart({
|
|
1837
|
+
zip: newZip,
|
|
1838
|
+
path: contentTypesFile.name,
|
|
1839
|
+
data: contentTypesXml.replace("</Types>", () => `<Override PartName="${partName}" ContentType="${contentType}"/></Types>`),
|
|
1840
|
+
options: {
|
|
1841
|
+
compression: "DEFLATE",
|
|
1842
|
+
compressionOptions
|
|
1843
|
+
}
|
|
1435
1844
|
});
|
|
1436
1845
|
const relationshipsXml = await relationshipsFile.async("text");
|
|
1437
1846
|
if (!relationshipsXml.includes(relationshipType)) {
|
|
1438
1847
|
const relationshipId = `rId${findMaxRId(relationshipsXml) + 1}`;
|
|
1439
1848
|
const target = partPath.slice(5);
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1849
|
+
writeZipPart({
|
|
1850
|
+
zip: newZip,
|
|
1851
|
+
path: relationshipsFile.name,
|
|
1852
|
+
data: relationshipsXml.replace("</Relationships>", () => `<Relationship Id="${relationshipId}" Type="${relationshipType}" Target="${target}"/></Relationships>`),
|
|
1853
|
+
options: {
|
|
1854
|
+
compression: "DEFLATE",
|
|
1855
|
+
compressionOptions
|
|
1856
|
+
}
|
|
1443
1857
|
});
|
|
1444
1858
|
}
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1859
|
+
writeZipPart({
|
|
1860
|
+
zip: newZip,
|
|
1861
|
+
path: partPath,
|
|
1862
|
+
data: serializedPart,
|
|
1863
|
+
options: {
|
|
1864
|
+
compression: "DEFLATE",
|
|
1865
|
+
compressionOptions
|
|
1866
|
+
}
|
|
1448
1867
|
});
|
|
1449
1868
|
}
|
|
1450
1869
|
/** Only this modeled switch changes on story lifecycle edits; preserve all other settings. */
|
|
@@ -1468,9 +1887,14 @@ async function serializeHeaderFooterSettingsIntoZip(doc, zip, compressionLevel)
|
|
|
1468
1887
|
if (parseSettings(xml).evenAndOddHeaders === enabled) return;
|
|
1469
1888
|
const patched = updateEvenAndOddHeaders(xml, enabled);
|
|
1470
1889
|
if (patched === null) throw new DocxPackageFidelityError("Cannot update malformed header/footer settings");
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1890
|
+
writeZipPart({
|
|
1891
|
+
zip,
|
|
1892
|
+
path: file.name,
|
|
1893
|
+
data: patched,
|
|
1894
|
+
options: {
|
|
1895
|
+
compression: "DEFLATE",
|
|
1896
|
+
compressionOptions: { level: compressionLevel }
|
|
1897
|
+
}
|
|
1474
1898
|
});
|
|
1475
1899
|
}
|
|
1476
1900
|
const numberingBaselines = /* @__PURE__ */ new WeakMap();
|
|
@@ -1506,9 +1930,14 @@ async function serializeNumberingIntoZip(doc, originalZip, newZip, compressionLe
|
|
|
1506
1930
|
currentXml
|
|
1507
1931
|
});
|
|
1508
1932
|
if (patched === null || patched === baseline.originalXml) return;
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1933
|
+
writeZipPart({
|
|
1934
|
+
zip: newZip,
|
|
1935
|
+
path: file.name,
|
|
1936
|
+
data: patched,
|
|
1937
|
+
options: {
|
|
1938
|
+
compression: "DEFLATE",
|
|
1939
|
+
compressionOptions: { level: compressionLevel }
|
|
1940
|
+
}
|
|
1512
1941
|
});
|
|
1513
1942
|
}
|
|
1514
1943
|
const STYLES_PART_PATH = "word/styles.xml";
|
|
@@ -1616,24 +2045,18 @@ const styleDefinitionsToSerialize = (doc) => {
|
|
|
1616
2045
|
styles: [...styles.styles, ...missing]
|
|
1617
2046
|
};
|
|
1618
2047
|
};
|
|
1619
|
-
|
|
2048
|
+
/** One append-only style owner for full repack and selective overlays. */
|
|
2049
|
+
async function planAddedStyles(doc, originalZip) {
|
|
1620
2050
|
const styles = doc.package.styles;
|
|
1621
|
-
if (!styles || styles.styles.length === 0) return;
|
|
2051
|
+
if (!styles || styles.styles.length === 0) return { type: "unchanged" };
|
|
1622
2052
|
const file = findNotePartEntry(originalZip, STYLES_PART_PATH);
|
|
1623
2053
|
const originalXml = file ? await file.async("text") : null;
|
|
1624
2054
|
const rootName = originalXml === null ? void 0 : /<(?![?!])(?<name>[^\s/>]+)/u.exec(originalXml)?.groups?.["name"];
|
|
1625
2055
|
const rootClose = originalXml !== null && rootName !== void 0 && getLocalName(rootName) === "styles" ? originalXml.lastIndexOf(`</${rootName}>`) : -1;
|
|
1626
|
-
if (file === null || originalXml === null || rootClose < 0) {
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
partPath: STYLES_PART_PATH,
|
|
1631
|
-
relationshipType: RELATIONSHIP_TYPES.styles,
|
|
1632
|
-
serializedPart: serializeStylesXml(styles),
|
|
1633
|
-
compressionLevel
|
|
1634
|
-
});
|
|
1635
|
-
return;
|
|
1636
|
-
}
|
|
2056
|
+
if (file === null || originalXml === null || rootClose < 0) return {
|
|
2057
|
+
type: "materialize",
|
|
2058
|
+
styles
|
|
2059
|
+
};
|
|
1637
2060
|
const existing = new Set(definedStyleIds(originalXml));
|
|
1638
2061
|
const added = [];
|
|
1639
2062
|
for (const style of styles.styles) {
|
|
@@ -1641,13 +2064,42 @@ async function serializeAddedStylesIntoZip(doc, originalZip, newZip, compression
|
|
|
1641
2064
|
existing.add(style.styleId);
|
|
1642
2065
|
added.push(style);
|
|
1643
2066
|
}
|
|
1644
|
-
if (added.length === 0) return;
|
|
2067
|
+
if (added.length === 0) return { type: "unchanged" };
|
|
1645
2068
|
const canonical = hasCanonicalWordprocessingPrefixes(originalXml);
|
|
1646
2069
|
const patched = originalXml.slice(0, rootClose) + added.map((style) => canonical ? serializeStyle(style) : selfBoundFragment(serializeStyle(style), file.name)).join("") + originalXml.slice(rootClose);
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
2070
|
+
return {
|
|
2071
|
+
type: "patch",
|
|
2072
|
+
path: file.name,
|
|
2073
|
+
xml: patched
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
async function serializeAddedStylesIntoZip(doc, originalZip, newZip, compressionLevel) {
|
|
2077
|
+
const plan = await planAddedStyles(doc, originalZip);
|
|
2078
|
+
switch (plan.type) {
|
|
2079
|
+
case "unchanged": return;
|
|
2080
|
+
case "materialize":
|
|
2081
|
+
await materializeNewNotePart({
|
|
2082
|
+
contentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml",
|
|
2083
|
+
newZip,
|
|
2084
|
+
partPath: STYLES_PART_PATH,
|
|
2085
|
+
relationshipType: RELATIONSHIP_TYPES.styles,
|
|
2086
|
+
serializedPart: serializeStylesXml(plan.styles),
|
|
2087
|
+
compressionLevel
|
|
2088
|
+
});
|
|
2089
|
+
return;
|
|
2090
|
+
case "patch":
|
|
2091
|
+
writeZipPart({
|
|
2092
|
+
zip: newZip,
|
|
2093
|
+
path: plan.path,
|
|
2094
|
+
data: plan.xml,
|
|
2095
|
+
options: {
|
|
2096
|
+
compression: "DEFLATE",
|
|
2097
|
+
compressionOptions: { level: compressionLevel }
|
|
2098
|
+
}
|
|
2099
|
+
});
|
|
2100
|
+
return;
|
|
2101
|
+
default: return plan;
|
|
2102
|
+
}
|
|
1651
2103
|
}
|
|
1652
2104
|
/**
|
|
1653
2105
|
* The XML to write for a patched note part, or null to keep the original.
|
|
@@ -1702,9 +2154,14 @@ async function patchNotePartIntoZip({ conventionalLowerPath, currentXml, replace
|
|
|
1702
2154
|
partName: file.name
|
|
1703
2155
|
});
|
|
1704
2156
|
if (patchedXml === null || patchedXml === originalXml) return;
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
2157
|
+
writeZipPart({
|
|
2158
|
+
zip: newZip,
|
|
2159
|
+
path: file.name,
|
|
2160
|
+
data: patchedXml,
|
|
2161
|
+
options: {
|
|
2162
|
+
compression: "DEFLATE",
|
|
2163
|
+
compressionOptions: { level: compressionLevel }
|
|
2164
|
+
}
|
|
1708
2165
|
});
|
|
1709
2166
|
}
|
|
1710
2167
|
/** `word/Footnotes.xml` -> `word/_rels/Footnotes.xml.rels` (casing preserved). */
|
|
@@ -1802,7 +2259,10 @@ function createEmptyDocx(properties = {}) {
|
|
|
1802
2259
|
}
|
|
1803
2260
|
const createEmptyDocxZip = ({ creator, application }) => {
|
|
1804
2261
|
const zip = new JSZip();
|
|
1805
|
-
|
|
2262
|
+
writeZipPart({
|
|
2263
|
+
zip,
|
|
2264
|
+
path: "[Content_Types].xml",
|
|
2265
|
+
data: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1806
2266
|
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
1807
2267
|
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
1808
2268
|
<Default Extension="xml" ContentType="application/xml"/>
|
|
@@ -1810,18 +2270,30 @@ const createEmptyDocxZip = ({ creator, application }) => {
|
|
|
1810
2270
|
<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
|
|
1811
2271
|
<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
|
|
1812
2272
|
<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
|
|
1813
|
-
</Types>`
|
|
1814
|
-
|
|
2273
|
+
</Types>`
|
|
2274
|
+
});
|
|
2275
|
+
writeZipPart({
|
|
2276
|
+
zip,
|
|
2277
|
+
path: "_rels/.rels",
|
|
2278
|
+
data: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1815
2279
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
1816
2280
|
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
|
1817
2281
|
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
|
|
1818
2282
|
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
|
|
1819
|
-
</Relationships>`
|
|
1820
|
-
|
|
2283
|
+
</Relationships>`
|
|
2284
|
+
});
|
|
2285
|
+
writeZipPart({
|
|
2286
|
+
zip,
|
|
2287
|
+
path: "word/_rels/document.xml.rels",
|
|
2288
|
+
data: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1821
2289
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
1822
2290
|
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
|
|
1823
|
-
</Relationships>`
|
|
1824
|
-
|
|
2291
|
+
</Relationships>`
|
|
2292
|
+
});
|
|
2293
|
+
writeZipPart({
|
|
2294
|
+
zip,
|
|
2295
|
+
path: "word/document.xml",
|
|
2296
|
+
data: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1825
2297
|
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
1826
2298
|
<w:body>
|
|
1827
2299
|
<w:p>
|
|
@@ -1834,19 +2306,30 @@ const createEmptyDocxZip = ({ creator, application }) => {
|
|
|
1834
2306
|
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/>
|
|
1835
2307
|
</w:sectPr>
|
|
1836
2308
|
</w:body>
|
|
1837
|
-
</w:document>`
|
|
1838
|
-
|
|
2309
|
+
</w:document>`
|
|
2310
|
+
});
|
|
2311
|
+
writeZipPart({
|
|
2312
|
+
zip,
|
|
2313
|
+
path: STYLES_PART_PATH,
|
|
2314
|
+
data: SEED_STYLES_XML
|
|
2315
|
+
});
|
|
1839
2316
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
2317
|
+
writeZipPart({
|
|
2318
|
+
zip,
|
|
2319
|
+
path: "docProps/core.xml",
|
|
2320
|
+
data: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
2321
|
+
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">${creator === void 0 ? "" : `\n <dc:creator>${escapeXmlText(creator)}</dc:creator>`}
|
|
1843
2322
|
<dcterms:created xsi:type="dcterms:W3CDTF">${now}</dcterms:created>
|
|
1844
2323
|
<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified>
|
|
1845
|
-
</cp:coreProperties>`
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
2324
|
+
</cp:coreProperties>`
|
|
2325
|
+
});
|
|
2326
|
+
writeZipPart({
|
|
2327
|
+
zip,
|
|
2328
|
+
path: "docProps/app.xml",
|
|
2329
|
+
data: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
2330
|
+
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">${application === void 0 ? "" : `\n <Application>${escapeXmlText(application)}</Application>\n <AppVersion>${CREATED_APP_VERSION}</AppVersion>`}
|
|
2331
|
+
</Properties>`
|
|
2332
|
+
});
|
|
1850
2333
|
return zip;
|
|
1851
2334
|
};
|
|
1852
2335
|
/**
|
|
@@ -1868,7 +2351,8 @@ async function createDocx(doc, properties = {}) {
|
|
|
1868
2351
|
originalCorePropertiesXml: source.corePropertiesXml,
|
|
1869
2352
|
compressionLevel: 6,
|
|
1870
2353
|
updateModifiedDate: true,
|
|
1871
|
-
onDiagnostic: properties.onDiagnostic
|
|
2354
|
+
onDiagnostic: properties.onDiagnostic,
|
|
2355
|
+
bodyAuthority: properties.bodyAuthority
|
|
1872
2356
|
});
|
|
1873
2357
|
}
|
|
1874
2358
|
const zip = await createDocumentSeedZip(doc, properties);
|
|
@@ -1880,7 +2364,8 @@ async function createDocx(doc, properties = {}) {
|
|
|
1880
2364
|
originalCorePropertiesXml: await zip.file("docProps/core.xml")?.async("text"),
|
|
1881
2365
|
compressionLevel: 6,
|
|
1882
2366
|
updateModifiedDate: true,
|
|
1883
|
-
onDiagnostic: properties.onDiagnostic
|
|
2367
|
+
onDiagnostic: properties.onDiagnostic,
|
|
2368
|
+
bodyAuthority: properties.bodyAuthority
|
|
1884
2369
|
});
|
|
1885
2370
|
}
|
|
1886
2371
|
const createDocumentSeedZip = async (doc, properties) => {
|
|
@@ -1891,38 +2376,69 @@ const createDocumentSeedZip = async (doc, properties) => {
|
|
|
1891
2376
|
const styleDefinitions = styleDefinitionsToSerialize(doc);
|
|
1892
2377
|
if (styleDefinitions) {
|
|
1893
2378
|
assertStyleNumberingReferences(doc);
|
|
1894
|
-
|
|
1895
|
-
|
|
2379
|
+
writeZipPart({
|
|
2380
|
+
zip,
|
|
2381
|
+
path: STYLES_PART_PATH,
|
|
2382
|
+
data: serializeStylesXml(styleDefinitions)
|
|
2383
|
+
});
|
|
2384
|
+
} else writeZipPart({
|
|
2385
|
+
zip,
|
|
2386
|
+
path: STYLES_PART_PATH,
|
|
2387
|
+
data: seedStylesXmlWith(missingNoteReferenceStyles(void 0, noteReferenceNeeds(doc.package)))
|
|
2388
|
+
});
|
|
1896
2389
|
const numbering = doc.package.numbering;
|
|
1897
2390
|
if (numbering && (numbering.abstractNums.length > 0 || numbering.nums.length > 0)) {
|
|
1898
|
-
|
|
2391
|
+
writeZipPart({
|
|
2392
|
+
zip,
|
|
2393
|
+
path: "word/numbering.xml",
|
|
2394
|
+
data: serializeNumberingXml(numbering)
|
|
2395
|
+
});
|
|
1899
2396
|
relationships.push(relationshipXml(nextRelationshipId, "numbering", "numbering.xml"));
|
|
1900
2397
|
overrides.push(overrideXml("/word/numbering.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"));
|
|
1901
2398
|
nextRelationshipId += 1;
|
|
1902
2399
|
}
|
|
1903
2400
|
if (doc.package.theme) {
|
|
1904
|
-
|
|
2401
|
+
writeZipPart({
|
|
2402
|
+
zip,
|
|
2403
|
+
path: "word/theme/theme1.xml",
|
|
2404
|
+
data: serializeThemeXml(doc.package.theme)
|
|
2405
|
+
});
|
|
1905
2406
|
relationships.push(relationshipXml(nextRelationshipId, "theme", "theme/theme1.xml"));
|
|
1906
2407
|
overrides.push(overrideXml("/word/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml"));
|
|
1907
2408
|
nextRelationshipId += 1;
|
|
1908
2409
|
}
|
|
1909
2410
|
if (doc.package.fontTable && doc.package.fontTable.fonts.length > 0) {
|
|
1910
|
-
|
|
2411
|
+
writeZipPart({
|
|
2412
|
+
zip,
|
|
2413
|
+
path: "word/fontTable.xml",
|
|
2414
|
+
data: serializeFontTableXml(doc.package.fontTable)
|
|
2415
|
+
});
|
|
1911
2416
|
relationships.push(relationshipXml(nextRelationshipId, "fontTable", "fontTable.xml"));
|
|
1912
2417
|
overrides.push(overrideXml("/word/fontTable.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"));
|
|
1913
2418
|
nextRelationshipId += 1;
|
|
1914
2419
|
}
|
|
1915
2420
|
if (doc.package.settings) {
|
|
1916
|
-
|
|
2421
|
+
writeZipPart({
|
|
2422
|
+
zip,
|
|
2423
|
+
path: "word/settings.xml",
|
|
2424
|
+
data: serializeSettingsXml(doc.package.settings)
|
|
2425
|
+
});
|
|
1917
2426
|
relationships.push(relationshipXml(nextRelationshipId, "settings", "settings.xml"));
|
|
1918
2427
|
overrides.push(overrideXml("/word/settings.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"));
|
|
1919
2428
|
}
|
|
1920
|
-
|
|
2429
|
+
writeZipPart({
|
|
2430
|
+
zip,
|
|
2431
|
+
path: "word/_rels/document.xml.rels",
|
|
2432
|
+
data: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${relationships.join("")}</Relationships>`
|
|
2433
|
+
});
|
|
1921
2434
|
if (overrides.length > 0) {
|
|
1922
2435
|
const contentTypesFile = zip.file("[Content_Types].xml");
|
|
1923
2436
|
if (!contentTypesFile) panic("Fresh DOCX seed is missing [Content_Types].xml");
|
|
1924
|
-
|
|
1925
|
-
|
|
2437
|
+
writeZipPart({
|
|
2438
|
+
zip,
|
|
2439
|
+
path: "[Content_Types].xml",
|
|
2440
|
+
data: (await contentTypesFile.async("string")).replace("</Types>", `${overrides.join("")}\n</Types>`)
|
|
2441
|
+
});
|
|
1926
2442
|
}
|
|
1927
2443
|
return zip;
|
|
1928
2444
|
};
|
|
@@ -1956,4 +2472,4 @@ const assertStyleNumberingReferences = (doc) => {
|
|
|
1956
2472
|
}
|
|
1957
2473
|
};
|
|
1958
2474
|
//#endregion
|
|
1959
|
-
export { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_CONTENT_TYPE, COMMENTS_EXTENDED_PART, COMMENTS_EXTENDED_PART_LOWER, DocxDuplicateSectionCarrierError, DocxPackageFidelityError, addCommentsExtendedOverride, addCommentsExtendedRelationship, addMedia, addRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, collectHyperlinksWithoutRId, createDocx, createEmptyDocx, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, hasUnmaterializedInlineResources, isDocxBuffer, notePartRelsPath, removeCommentsExtendedOverride, removeCommentsExtendedRelationship, repackDocx, repackDocxFromRaw, updateCoreProperties, updateDocumentXml, updateMultipleFiles, updateXmlFile, validateDocx, withoutAttachedTemplate };
|
|
2475
|
+
export { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_CONTENT_TYPE, COMMENTS_EXTENDED_PART, COMMENTS_EXTENDED_PART_LOWER, CanonicalImageRelationshipRefusalError, DocxDuplicateSectionCarrierError, DocxPackageFidelityError, addCommentsExtendedOverride, addCommentsExtendedRelationship, addMedia, addRelationship, applyUpdatesToZip, assertSectionCarriersMatchModel, collectHeaderFooterUpdates, collectHyperlinksWithoutRId, createDocx, createEmptyDocx, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, hasUnmaterializedHyperlinkBindings, hasUnmaterializedInlineResources, isDocxBuffer, notePartRelsPath, planAddedStyles, publishCanonicalImageResources, removeCommentsExtendedOverride, removeCommentsExtendedRelationship, repackDocx, repackDocxFromRaw, updateCoreProperties, updateDocumentXml, updateMultipleFiles, updateXmlFile, validateDocx, withoutAttachedTemplate };
|