@stll/folio-core 0.54.2 → 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 +185 -33
- package/dist/ai-edits/headless.js +3 -2
- package/dist/ai-edits/types.d.ts +7 -1
- package/dist/compare/compare.js +1 -0
- package/dist/compare/content-types.d.ts +3 -15
- 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 +53 -0
- package/dist/controller/canonicalComposition.js +296 -0
- package/dist/controller/canonicalInlineProjection.d.ts +113 -0
- package/dist/controller/canonicalInlineProjection.js +393 -0
- package/dist/controller/canonicalInput.d.ts +54 -0
- package/dist/controller/canonicalInput.js +377 -0
- package/dist/controller/canonicalInputTimer.d.ts +7 -0
- package/dist/controller/canonicalInputTimer.js +11 -0
- package/dist/controller/canonicalOperations.d.ts +22 -0
- package/dist/controller/canonicalOperations.js +85 -0
- package/dist/controller/canonicalPublicOperations.d.ts +48 -0
- package/dist/controller/canonicalPublicOperations.js +556 -0
- package/dist/controller/canonicalReview.d.ts +12 -0
- package/dist/controller/canonicalReview.js +19 -0
- package/dist/controller/canonicalSession.d.ts +167 -0
- package/dist/controller/canonicalSession.js +1186 -0
- package/dist/controller/canonicalStoryEditor.d.ts +36 -0
- package/dist/controller/canonicalStoryEditor.js +87 -0
- package/dist/controller/canonicalStructure.d.ts +16 -0
- package/dist/controller/canonicalStructure.js +322 -0
- package/dist/controller/canonicalTocSelection.d.ts +11 -0
- package/dist/controller/canonicalTocSelection.js +43 -0
- package/dist/controller/folioEditor.d.ts +3 -10
- package/dist/controller/folioEditor.js +14 -4
- package/dist/controller/headerFooterEditorManager.d.ts +5 -0
- package/dist/controller/headerFooterEditorManager.js +72 -3
- package/dist/controller/hiddenEditorApi.d.ts +45 -0
- package/dist/controller/hiddenEditorApi.js +29 -8
- package/dist/controller/hiddenEditorManager.d.ts +13 -2
- package/dist/controller/hiddenEditorManager.js +639 -31
- package/dist/controller/layoutPipeline.d.ts +1 -1
- package/dist/controller/layoutPipeline.js +2 -0
- package/dist/controller/noteEditorManager.d.ts +5 -0
- package/dist/controller/noteEditorManager.js +114 -15
- package/dist/document-operations.d.ts +8 -1
- package/dist/document-operations.js +6 -4
- package/dist/docx/attributeRemainder.js +1 -0
- 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/canonicalSessionInput.d.ts +11 -0
- package/dist/docx/canonicalSessionInput.js +27 -0
- package/dist/docx/canonicalStoryRepack.d.ts +10 -0
- package/dist/docx/canonicalStoryRepack.js +74 -0
- package/dist/docx/contentTypeRegistry.d.ts +8 -0
- package/dist/docx/contentTypeRegistry.js +64 -0
- package/dist/docx/documentParser.d.ts +1 -13
- package/dist/docx/documentParser.js +1 -47
- package/dist/docx/ensureParaIds.d.ts +7 -1
- package/dist/docx/ensureParaIds.js +173 -215
- package/dist/docx/foldedListNumberFields.d.ts +85 -0
- package/dist/docx/foldedListNumberFields.js +267 -0
- 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 +39 -1
- package/dist/docx/headerFooterVerbatim.js +173 -2
- 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/noteIds.d.ts +5 -0
- package/dist/docx/noteIds.js +6 -2
- package/dist/docx/noteReferenceMark.d.ts +3 -1
- package/dist/docx/noteReferenceMark.js +15 -14
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +17 -3
- package/dist/docx/packageParts.d.ts +3 -1
- package/dist/docx/packageParts.js +74 -19
- package/dist/docx/paragraphMarkPropertyPresence.d.ts +9 -0
- package/dist/docx/paragraphMarkPropertyPresence.js +21 -0
- package/dist/docx/paragraphParser.js +101 -53
- package/dist/docx/paragraphPropertySource.d.ts +15 -1
- package/dist/docx/paragraphPropertySource.js +77 -22
- package/dist/docx/parser.js +3 -1
- package/dist/docx/removeHeaderFooterParts.js +17 -6
- package/dist/docx/reviewHistoryNamespace.d.ts +4 -0
- package/dist/docx/reviewHistoryNamespace.js +4 -0
- package/dist/docx/reviewResolutionProvenance.d.ts +25 -0
- package/dist/docx/reviewResolutionProvenance.js +153 -0
- package/dist/docx/rezip.d.ts +54 -6
- package/dist/docx/rezip.js +835 -257
- package/dist/docx/runConsolidator.d.ts +2 -58
- package/dist/docx/runConsolidator.js +3 -175
- package/dist/docx/runParser.d.ts +2 -1
- package/dist/docx/runParser.js +156 -116
- package/dist/docx/saveDiagnostics.d.ts +22 -0
- package/dist/docx/saveDiagnostics.js +0 -0
- package/dist/docx/selectiveSave.d.ts +3 -1
- package/dist/docx/selectiveSave.js +36 -4
- package/dist/docx/selectiveXmlPatch.d.ts +16 -8
- package/dist/docx/selectiveXmlPatch.js +81 -7
- package/dist/docx/serializer/documentSerializer.d.ts +9 -2
- package/dist/docx/serializer/documentSerializer.js +29 -10
- package/dist/docx/serializer/headerFooterSerializer.d.ts +5 -1
- package/dist/docx/serializer/headerFooterSerializer.js +19 -11
- package/dist/docx/serializer/noteSerializer.d.ts +2 -2
- package/dist/docx/serializer/noteSerializer.js +24 -8
- package/dist/docx/serializer/paragraphSerializer.js +41 -4
- package/dist/docx/serializer/partNamespaces.js +2 -1
- package/dist/docx/serializer/runSerializer.js +3 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
- package/dist/docx/settingsHeaderFooterUpdate.d.ts +5 -0
- package/dist/docx/settingsHeaderFooterUpdate.js +90 -0
- package/dist/docx/settingsParser.d.ts +1 -2
- package/dist/docx/settingsParser.js +5 -6
- package/dist/docx/storyBlockReplay.d.ts +31 -0
- package/dist/docx/storyBlockReplay.js +471 -0
- package/dist/docx/storyPlainText.d.ts +20 -0
- package/dist/docx/storyPlainText.js +23 -0
- package/dist/docx/streamingXmlParser.d.ts +22 -1
- package/dist/docx/streamingXmlParser.js +49 -3
- package/dist/docx/structuralXmlPatch.js +18 -23
- 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/docx/verbatimCapture.d.ts +3 -1
- package/dist/docx/verbatimCapture.js +49 -6
- package/dist/i18n/messages/ar.gen.d.ts +5 -0
- package/dist/i18n/messages/ar.gen.js +656 -0
- package/dist/i18n/messages/cs.gen.d.ts +5 -0
- package/dist/i18n/messages/cs.gen.js +656 -0
- package/dist/i18n/messages/de.gen.d.ts +5 -0
- package/dist/i18n/messages/de.gen.js +656 -0
- package/dist/i18n/messages/en.gen.d.ts +5 -0
- package/dist/i18n/messages/en.gen.js +656 -0
- package/dist/i18n/messages/es.gen.d.ts +5 -0
- package/dist/i18n/messages/es.gen.js +656 -0
- package/dist/i18n/messages/et.gen.d.ts +5 -0
- package/dist/i18n/messages/et.gen.js +656 -0
- package/dist/i18n/messages/fr.gen.d.ts +5 -0
- package/dist/i18n/messages/fr.gen.js +656 -0
- package/dist/i18n/messages/he.gen.d.ts +5 -0
- package/dist/i18n/messages/he.gen.js +656 -0
- package/dist/i18n/messages/hi.gen.d.ts +5 -0
- package/dist/i18n/messages/hi.gen.js +656 -0
- package/dist/i18n/messages/hu.gen.d.ts +5 -0
- package/dist/i18n/messages/hu.gen.js +656 -0
- package/dist/i18n/messages/locales.d.ts +5 -0
- package/dist/i18n/messages/locales.js +22 -0
- package/dist/i18n/messages/lt.gen.d.ts +5 -0
- package/dist/i18n/messages/lt.gen.js +656 -0
- package/dist/i18n/messages/lv.gen.d.ts +5 -0
- package/dist/i18n/messages/lv.gen.js +656 -0
- package/dist/i18n/messages/pl.gen.d.ts +5 -0
- package/dist/i18n/messages/pl.gen.js +656 -0
- package/dist/i18n/messages/pt-BR.gen.d.ts +5 -0
- package/dist/i18n/messages/pt-BR.gen.js +656 -0
- package/dist/i18n/messages/sk.gen.d.ts +5 -0
- package/dist/i18n/messages/sk.gen.js +656 -0
- package/dist/i18n/messages/tr.gen.d.ts +5 -0
- package/dist/i18n/messages/tr.gen.js +656 -0
- package/dist/i18n/messages/zh-CN.gen.d.ts +5 -0
- package/dist/i18n/messages/zh-CN.gen.js +656 -0
- package/dist/i18n/messages.d.ts +2 -3
- package/dist/i18n/messages.js +1 -19
- package/dist/internal/acceptedBlockProjection.d.ts +12 -0
- package/dist/internal/acceptedBlockProjection.js +45 -0
- package/dist/internal/noteMarkerAttrs.d.ts +8 -0
- package/dist/internal/noteMarkerAttrs.js +16 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +1 -0
- package/dist/internal/prosemirrorAttrBoundary.d.ts +21 -0
- package/dist/internal/prosemirrorAttrBoundary.js +50 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +3 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +1 -0
- package/dist/layout-bridge/convert/noteReferences.d.ts +1 -3
- package/dist/layout-bridge/convert/noteReferences.js +1 -6
- package/dist/layout-bridge/convert/paragraphRuns.js +2 -4
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +2 -2
- package/dist/managers/DocumentLoaderManager.d.ts +1 -0
- package/dist/managers/DocumentLoaderManager.js +9 -1
- package/dist/markdown/escape.d.ts +3 -1
- package/dist/markdown/escape.js +9 -2
- package/dist/markdown/renderBlock.js +20 -121
- package/dist/markdown/renderParagraph.js +13 -15
- package/dist/markdown/renderRuns.d.ts +7 -1
- package/dist/markdown/renderRuns.js +35 -15
- package/dist/markdown/renderTable.js +2 -0
- package/dist/markdown/types.d.ts +3 -9
- package/dist/prosemirror/attrs/index.d.ts +2 -12
- package/dist/prosemirror/attrs/index.js +22 -48
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +2 -1
- package/dist/prosemirror/canonicalCommands.d.ts +121 -0
- package/dist/prosemirror/canonicalCommands.js +35 -0
- 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 +15 -1
- package/dist/prosemirror/commands/pastePlainText.js +2 -1
- package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
- package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
- package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
- package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
- package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +11 -4
- package/dist/prosemirror/conversion/toProseDoc.js +55 -14
- package/dist/prosemirror/executeEditorCommand.d.ts +11 -0
- package/dist/prosemirror/executeEditorCommand.js +26 -0
- package/dist/prosemirror/extensions/StarterKit.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +88 -48
- package/dist/prosemirror/extensions/features/ListExtension.js +18 -5
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +5 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +13 -1
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +56 -28
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +3 -2
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
- package/dist/prosemirror/extensions/marks/markUtils.js +72 -8
- package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.js +36 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +4 -2
- package/dist/prosemirror/insertOperations.js +2 -1
- package/dist/prosemirror/listMarker.d.ts +1 -0
- package/dist/prosemirror/listMarker.js +16 -7
- package/dist/prosemirror/listNumbering.js +26 -5
- package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
- package/dist/prosemirror/listRenderingAttrs.js +3 -0
- package/dist/prosemirror/markupViewNotes.js +3 -2
- package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +2 -1
- package/dist/prosemirror/noteReferenceReview.js +5 -3
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
- package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
- package/dist/prosemirror/plugins/suggestionMode.js +57 -7
- package/dist/prosemirror/rangeAnchorAttrs.d.ts +2 -1
- package/dist/prosemirror/runFormattingFromMarks.d.ts +4 -1
- package/dist/prosemirror/runFormattingFromMarks.js +15 -1
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -1
- package/dist/prosemirror/runFormattingInlineCarriers.js +4 -1
- package/dist/prosemirror/schema/marks.d.ts +2 -0
- package/dist/prosemirror/schema/nodes.d.ts +10 -2
- package/dist/prosemirror/textBoxAnchorAttrs.d.ts +2 -1
- package/dist/prosemirror/textInput.js +5 -1
- package/dist/prosemirror/trackedRevisionPath.js +2 -1
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +1 -0
- package/dist/prosemirror/validation.js +4 -0
- 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/content.d.ts +2 -2
- package/dist/types/docxSerialization.d.ts +14 -0
- package/dist/types/docxSerialization.js +7 -0
- package/dist/utils/createDocument.js +2 -2
- package/package.json +16 -4
package/dist/docx/rezip.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
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";
|
|
6
8
|
import { applyReplyThreadMarkers } from "./commentReplyMarkers.js";
|
|
9
|
+
import { registerContentTypeParts } from "./contentTypeRegistry.js";
|
|
7
10
|
import { readDocumentSectionFacts } from "./documentSectionFacts.js";
|
|
8
11
|
import { normalizeDrawingIds } from "./drawingIdNormalization.js";
|
|
9
12
|
import { rebindDrawingImageRelationship } from "./drawingRelationships.js";
|
|
10
13
|
import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
|
|
14
|
+
import { getDocumentSourceBaseline } from "./headerFooterVerbatim.js";
|
|
11
15
|
import { assertValidFolioDocumentModel } from "./modelValidation.js";
|
|
12
16
|
import { isNewDataUrlDrawing } from "./newImage.js";
|
|
13
17
|
import { missingNoteReferenceStyles, noteReferenceNeeds } from "./noteReferenceStyles.js";
|
|
@@ -15,11 +19,12 @@ import { parseNumbering } from "./numberingParser.js";
|
|
|
15
19
|
import { paragraphNumberingReferenceId as paragraphNumberingReferenceId$1 } from "./numberingReference.js";
|
|
16
20
|
import { isUnsafePackagePath, reconcilePackageReferences, removeUnsafeEntries } from "./packageParts.js";
|
|
17
21
|
import { normalizeParaIdRangeInXmlParts } from "./paraIdRangeNormalization.js";
|
|
18
|
-
import {
|
|
22
|
+
import { cloneDocumentWithParagraphPropertySources, cloneParagraphWithPropertySource, copyDocumentParagraphPropertySourceContract } from "./paragraphPropertySource.js";
|
|
23
|
+
import { BLOCK_TREE_DESCENT, visitBlockTreeRecords, visitInlineContentSlots, visitParagraphRuns } from "./paragraphTraversal.js";
|
|
19
24
|
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
20
25
|
import { removeResolvedHeaderFooterParts } from "./removeHeaderFooterParts.js";
|
|
21
26
|
import { normalizeRevisionIdsInXmlParts } from "./revisionIdNormalization.js";
|
|
22
|
-
import { buildPatchedNotePartXml, collectChangedNoteParaIds, collectParaIds, patchNumberingDefinitions } from "./selectiveXmlPatch.js";
|
|
27
|
+
import { buildPatchedNotePartXml, collectChangedNoteParaIds, collectParaIds, patchNumberingDefinitions, spliceXml } from "./selectiveXmlPatch.js";
|
|
23
28
|
import { planCommentParts, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
24
29
|
import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
25
30
|
import { serializeFontTableXml } from "./serializer/fontTableSerializer.js";
|
|
@@ -30,11 +35,16 @@ import { readRootNamespaceBindings, serializePartElement } from "./serializer/pa
|
|
|
30
35
|
import { serializeSettingsXml } from "./serializer/settingsSerializer.js";
|
|
31
36
|
import { serializeStyle, serializeStylesXml } from "./serializer/stylesSerializer.js";
|
|
32
37
|
import { serializeThemeXml } from "./serializer/themeSerializer.js";
|
|
38
|
+
import { updateEvenAndOddHeaders } from "./settingsHeaderFooterUpdate.js";
|
|
39
|
+
import { parseSettings } from "./settingsParser.js";
|
|
40
|
+
import { getXmlSourceRange, parseStreamingXmlWithSourceRanges } from "./streamingXmlParser.js";
|
|
41
|
+
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
33
42
|
import { hasCanonicalWordprocessingPrefixes } from "./wordprocessingPrefixes.js";
|
|
34
|
-
import { WORDPROCESSINGML_NAMESPACE_URIS, findChild, findChildByNamespaceUri, findChildrenByNamespaceUri, getAttribute, getAttributeByNamespaceUri, getChildElements, getLocalName, getNamespaceUri, matchesName, parseXml, parseXmlDocument } from "./xmlParser.js";
|
|
35
|
-
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";
|
|
36
45
|
import { assertValidOoxmlNumericIds, escapeXmlAttribute, escapeXmlText, validateDocxPackage } from "@stll/docx-core";
|
|
37
46
|
import { mintRelationshipId } from "@stll/docx-core/model";
|
|
47
|
+
import { writeZipPart } from "@stll/docx-core/zip";
|
|
38
48
|
import JSZip from "jszip";
|
|
39
49
|
//#region src/docx/rezip.ts
|
|
40
50
|
/**
|
|
@@ -196,9 +206,14 @@ async function serializeCommentsToZip(doc, zip, compressionLevel) {
|
|
|
196
206
|
}
|
|
197
207
|
const plan = planCommentParts(comments);
|
|
198
208
|
const commentsXml = serializeComments(plan, sourceCommentsXml === void 0 ? void 0 : readRootNamespaceBindings(sourceCommentsXml));
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
209
|
+
writeZipPart({
|
|
210
|
+
zip,
|
|
211
|
+
path: sourceCommentsFile?.name ?? "word/comments.xml",
|
|
212
|
+
data: commentsXml,
|
|
213
|
+
options: {
|
|
214
|
+
compression: "DEFLATE",
|
|
215
|
+
compressionOptions: { level: compressionLevel }
|
|
216
|
+
}
|
|
202
217
|
});
|
|
203
218
|
await ensureCommentsContentType(zip, compressionLevel);
|
|
204
219
|
await ensureCommentsRelationship(zip, compressionLevel);
|
|
@@ -227,9 +242,14 @@ async function syncCommentsExtendedPart(plan, zip, compressionLevel) {
|
|
|
227
242
|
await transformPackagingFile(zip, "word/_rels/document.xml.rels", removeCommentsExtendedRelationship, compressionLevel);
|
|
228
243
|
return;
|
|
229
244
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
245
|
+
writeZipPart({
|
|
246
|
+
zip,
|
|
247
|
+
path: existing?.name ?? "word/commentsExtended.xml",
|
|
248
|
+
data: xml,
|
|
249
|
+
options: {
|
|
250
|
+
compression: "DEFLATE",
|
|
251
|
+
compressionOptions: { level: compressionLevel }
|
|
252
|
+
}
|
|
233
253
|
});
|
|
234
254
|
await transformPackagingFile(zip, "[Content_Types].xml", addCommentsExtendedOverride, compressionLevel);
|
|
235
255
|
await transformPackagingFile(zip, "word/_rels/document.xml.rels", addCommentsExtendedRelationship, compressionLevel);
|
|
@@ -240,9 +260,14 @@ async function transformPackagingFile(zip, path, transform, compressionLevel) {
|
|
|
240
260
|
if (!file) return;
|
|
241
261
|
const xml = await file.async("text");
|
|
242
262
|
const next = transform(xml);
|
|
243
|
-
if (next !== xml)
|
|
244
|
-
|
|
245
|
-
|
|
263
|
+
if (next !== xml) writeZipPart({
|
|
264
|
+
zip,
|
|
265
|
+
path,
|
|
266
|
+
data: next,
|
|
267
|
+
options: {
|
|
268
|
+
compression: "DEFLATE",
|
|
269
|
+
compressionOptions: { level: compressionLevel }
|
|
270
|
+
}
|
|
246
271
|
});
|
|
247
272
|
}
|
|
248
273
|
function findZipEntryCaseInsensitive(zip, lowerPath) {
|
|
@@ -251,7 +276,9 @@ function findZipEntryCaseInsensitive(zip, lowerPath) {
|
|
|
251
276
|
for (const [path, file] of Object.entries(zip.files)) if (!file.dir && path.toLowerCase() === lowerPath) return file;
|
|
252
277
|
return null;
|
|
253
278
|
}
|
|
254
|
-
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>`;
|
|
255
282
|
function headerFooterFilename(target) {
|
|
256
283
|
return target.startsWith("/") ? target.slice(1) : `word/${target}`;
|
|
257
284
|
}
|
|
@@ -348,9 +375,14 @@ async function registerImageExtensions(zip, extensions, compressionLevel) {
|
|
|
348
375
|
changed = true;
|
|
349
376
|
}
|
|
350
377
|
if (!changed) return;
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
378
|
+
writeZipPart({
|
|
379
|
+
zip,
|
|
380
|
+
path: "[Content_Types].xml",
|
|
381
|
+
data: ctXml,
|
|
382
|
+
options: {
|
|
383
|
+
compression: "DEFLATE",
|
|
384
|
+
compressionOptions: { level: compressionLevel }
|
|
385
|
+
}
|
|
354
386
|
});
|
|
355
387
|
}
|
|
356
388
|
function collectNewImages(blocks) {
|
|
@@ -421,9 +453,14 @@ async function processNewImages(parts, zip, compressionLevel) {
|
|
|
421
453
|
maxId++;
|
|
422
454
|
const mediaPath = `word/media/${`image${maxImageNum}.${extension}`}`;
|
|
423
455
|
const newRId = mintRelationshipId(maxId);
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
456
|
+
writeZipPart({
|
|
457
|
+
zip,
|
|
458
|
+
path: mediaPath,
|
|
459
|
+
data,
|
|
460
|
+
options: {
|
|
461
|
+
compression: "DEFLATE",
|
|
462
|
+
compressionOptions: { level: compressionLevel }
|
|
463
|
+
}
|
|
427
464
|
});
|
|
428
465
|
relEntries.push(`<Relationship Id="${newRId}" Type="${RELATIONSHIP_TYPES.image}" Target="${escapeXmlAttribute(relativeTargetForPart(partPath, mediaPath))}"/>`);
|
|
429
466
|
extensionsAdded.add(extension);
|
|
@@ -434,13 +471,15 @@ async function processNewImages(parts, zip, compressionLevel) {
|
|
|
434
471
|
}) ?? panic("A detached drawing lost its embedded image relationship");
|
|
435
472
|
image.rId = newRId;
|
|
436
473
|
}
|
|
437
|
-
if (relEntries.length > 0) {
|
|
438
|
-
|
|
439
|
-
|
|
474
|
+
if (relEntries.length > 0) writeZipPart({
|
|
475
|
+
zip,
|
|
476
|
+
path: relsPath,
|
|
477
|
+
data: relsXml.replace("</Relationships>", `${relEntries.join("")}</Relationships>`),
|
|
478
|
+
options: {
|
|
440
479
|
compression: "DEFLATE",
|
|
441
480
|
compressionOptions: { level: compressionLevel }
|
|
442
|
-
}
|
|
443
|
-
}
|
|
481
|
+
}
|
|
482
|
+
});
|
|
444
483
|
}
|
|
445
484
|
await registerImageExtensions(zip, extensionsAdded, compressionLevel);
|
|
446
485
|
}
|
|
@@ -452,67 +491,259 @@ const materializeEmbeddedMedia = async ({ document, zip, compressionLevel }) =>
|
|
|
452
491
|
if (isUnsafePackagePath(media.path) || !media.path.startsWith("word/media/")) panic("Detached media has an invalid package path");
|
|
453
492
|
const extension = media.path.split(".").at(-1)?.toLowerCase();
|
|
454
493
|
if (!extension || !/^[a-z0-9]+$/u.test(extension)) panic("Embedded media has an invalid extension");
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
494
|
+
writeZipPart({
|
|
495
|
+
zip,
|
|
496
|
+
path: media.path,
|
|
497
|
+
data: media.data,
|
|
498
|
+
options: {
|
|
499
|
+
compression: "DEFLATE",
|
|
500
|
+
compressionOptions: { level: compressionLevel }
|
|
501
|
+
}
|
|
458
502
|
});
|
|
459
503
|
extensions.add(extension);
|
|
460
504
|
}
|
|
461
505
|
await registerImageExtensions(zip, extensions, compressionLevel);
|
|
462
506
|
};
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
if (
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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;
|
|
484
585
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
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] : []);
|
|
490
634
|
}
|
|
491
635
|
/** The selective save boundary must use the same resource census as full repack. */
|
|
492
|
-
const hasUnmaterializedInlineResources = (blocks) => collectNewImages(blocks).length > 0 ||
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
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. */
|
|
498
671
|
async function processNewHyperlinks(parts, zip, compressionLevel) {
|
|
499
672
|
for (const { relsPath, blocks } of parts) {
|
|
500
|
-
const
|
|
501
|
-
if (
|
|
673
|
+
const resources = collectExternalHyperlinkResources(blocks);
|
|
674
|
+
if (resources.length === 0) continue;
|
|
502
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);
|
|
503
683
|
let maxId = findMaxRId(relsXml);
|
|
504
684
|
const relEntries = [];
|
|
505
|
-
for (const
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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
|
+
});
|
|
511
746
|
}
|
|
512
|
-
zip.file(relsPath, relsXml.replace("</Relationships>", `${relEntries.join("")}</Relationships>`), {
|
|
513
|
-
compression: "DEFLATE",
|
|
514
|
-
compressionOptions: { level: compressionLevel }
|
|
515
|
-
});
|
|
516
747
|
}
|
|
517
748
|
}
|
|
518
749
|
/**
|
|
@@ -537,9 +768,14 @@ const normalizePackageIdsInZip = async (zip, compressionLevel) => {
|
|
|
537
768
|
const normalizedParts = normalizeParaIdRangeInXmlParts(normalizeRevisionIdsInXmlParts(xmlParts));
|
|
538
769
|
for (const [path, xml] of normalizedParts) if (xml !== xmlParts.get(path)) {
|
|
539
770
|
assertValidOoxmlNumericIds(xml, path);
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
771
|
+
writeZipPart({
|
|
772
|
+
zip,
|
|
773
|
+
path,
|
|
774
|
+
data: xml,
|
|
775
|
+
options: {
|
|
776
|
+
compression: "DEFLATE",
|
|
777
|
+
compressionOptions: { level: compressionLevel }
|
|
778
|
+
}
|
|
543
779
|
});
|
|
544
780
|
}
|
|
545
781
|
};
|
|
@@ -554,9 +790,14 @@ const normalizeAppVersionInZip = async (zip, compressionLevel) => {
|
|
|
554
790
|
if (!extendedProperties) return;
|
|
555
791
|
const xml = await extendedProperties.async("text");
|
|
556
792
|
const normalized = normalizeAppVersionInExtendedProperties(xml);
|
|
557
|
-
if (normalized !== xml)
|
|
558
|
-
|
|
559
|
-
|
|
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
|
+
}
|
|
560
801
|
});
|
|
561
802
|
};
|
|
562
803
|
/**
|
|
@@ -635,20 +876,37 @@ const normalizeExportDrawingIds = ({ package: docxPackage }) => {
|
|
|
635
876
|
...docxPackage.endnotes !== void 0 ? { endnotes: docxPackage.endnotes } : {}
|
|
636
877
|
});
|
|
637
878
|
};
|
|
638
|
-
|
|
639
|
-
|
|
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);
|
|
640
889
|
await materializeEmbeddedMedia({
|
|
641
890
|
document,
|
|
642
891
|
zip: outputZip,
|
|
643
892
|
compressionLevel
|
|
644
893
|
});
|
|
894
|
+
if (bodyAuthority === "canonical") await publishCanonicalImageResources({
|
|
895
|
+
document,
|
|
896
|
+
zip: outputZip,
|
|
897
|
+
compressionLevel
|
|
898
|
+
});
|
|
645
899
|
const parts = collectDocxParts(document, outputZip);
|
|
646
900
|
normalizeExportDrawingIds(document);
|
|
647
901
|
await processNewImages(parts, outputZip, compressionLevel);
|
|
648
902
|
await processNewHyperlinks(parts, outputZip, compressionLevel);
|
|
649
903
|
assertValidFolioDocumentModel(document, "Cannot repack invalid DOCX document model");
|
|
650
904
|
applyReplyThreadMarkers(document);
|
|
651
|
-
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
|
+
});
|
|
652
910
|
if (originalDocument?.xml) assertDocumentPackageFidelity({
|
|
653
911
|
originalDocumentFacts: originalDocument.sectionFacts(),
|
|
654
912
|
serializedDocumentXml: documentXml,
|
|
@@ -662,12 +920,27 @@ const finishRepack = async ({ document, originalZip, outputZip, originalDocument
|
|
|
662
920
|
removedReferences: [...sectionReferenceRemovals ?? [], ...sectionEndpointRemoval?.removedReferences ?? []],
|
|
663
921
|
compressionLevel
|
|
664
922
|
});
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
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
|
|
937
|
+
});
|
|
938
|
+
await serializeHeadersFootersToZip({
|
|
939
|
+
doc: document,
|
|
940
|
+
zip: outputZip,
|
|
941
|
+
compressionLevel,
|
|
942
|
+
onDiagnostic
|
|
668
943
|
});
|
|
669
|
-
await rebindWatermarkRelIds(document, outputZip, compressionLevel);
|
|
670
|
-
await serializeHeadersFootersToZip(document, outputZip, compressionLevel);
|
|
671
944
|
await serializeNotesToZip({
|
|
672
945
|
doc: document,
|
|
673
946
|
originalZip,
|
|
@@ -677,18 +950,21 @@ const finishRepack = async ({ document, originalZip, outputZip, originalDocument
|
|
|
677
950
|
});
|
|
678
951
|
await serializeNumberingIntoZip(document, originalZip, outputZip, compressionLevel);
|
|
679
952
|
await serializeAddedStylesIntoZip(document, originalZip, outputZip, compressionLevel);
|
|
953
|
+
await serializeHeaderFooterSettingsIntoZip(document, outputZip, compressionLevel);
|
|
680
954
|
await serializeCommentsToZip(document, outputZip, compressionLevel);
|
|
681
955
|
await dropAttachedTemplateReference(outputZip, compressionLevel);
|
|
682
|
-
if (updateModifiedDate && originalCorePropertiesXml) {
|
|
683
|
-
|
|
956
|
+
if (updateModifiedDate && originalCorePropertiesXml) writeZipPart({
|
|
957
|
+
zip: outputZip,
|
|
958
|
+
path: "docProps/core.xml",
|
|
959
|
+
data: updateCoreProperties(originalCorePropertiesXml, {
|
|
684
960
|
updateModifiedDate,
|
|
685
961
|
...modifiedBy !== void 0 ? { modifiedBy } : {}
|
|
686
|
-
})
|
|
687
|
-
|
|
962
|
+
}),
|
|
963
|
+
options: {
|
|
688
964
|
compression: "DEFLATE",
|
|
689
965
|
compressionOptions: { level: compressionLevel }
|
|
690
|
-
}
|
|
691
|
-
}
|
|
966
|
+
}
|
|
967
|
+
});
|
|
692
968
|
return generateDocxZip(outputZip, compressionLevel);
|
|
693
969
|
};
|
|
694
970
|
async function repackDocxWithSectionEndpointRemoval({ document: doc, options, sectionEndpointRemoval, sectionReferenceRemovals }) {
|
|
@@ -707,6 +983,8 @@ async function repackDocxWithSectionEndpointRemoval({ document: doc, options, se
|
|
|
707
983
|
originalCorePropertiesXml,
|
|
708
984
|
compressionLevel,
|
|
709
985
|
updateModifiedDate,
|
|
986
|
+
onDiagnostic: options.onDiagnostic,
|
|
987
|
+
bodyAuthority: options.bodyAuthority,
|
|
710
988
|
...modifiedBy !== void 0 ? { modifiedBy } : {},
|
|
711
989
|
...changedNoteParaIds !== void 0 ? { changedNoteParaIds } : {},
|
|
712
990
|
...sectionEndpointRemoval !== void 0 ? { sectionEndpointRemoval } : {},
|
|
@@ -733,44 +1011,81 @@ function repackDocx(doc, options = {}) {
|
|
|
733
1011
|
*/
|
|
734
1012
|
async function repackDocxFromRaw(doc, rawContent, options = {}) {
|
|
735
1013
|
const { compressionLevel = 6, updateModifiedDate = true, modifiedBy, changedNoteParaIds } = options;
|
|
736
|
-
|
|
1014
|
+
let exportDocument = withoutOrphanCommentRanges(cloneExportDocument(doc));
|
|
737
1015
|
const newZip = new JSZip();
|
|
738
1016
|
for (const [path, file] of Object.entries(rawContent.originalZip.files)) {
|
|
739
1017
|
if (file.dir) {
|
|
740
|
-
|
|
1018
|
+
writeZipPart({
|
|
1019
|
+
zip: newZip,
|
|
1020
|
+
path,
|
|
1021
|
+
data: "",
|
|
1022
|
+
options: {
|
|
1023
|
+
dir: true,
|
|
1024
|
+
date: file.date
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
741
1027
|
continue;
|
|
742
1028
|
}
|
|
743
1029
|
if (isUnsafePackagePath(path)) continue;
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
1030
|
+
writeZipPart({
|
|
1031
|
+
zip: newZip,
|
|
1032
|
+
path,
|
|
1033
|
+
data: await file.async("arraybuffer"),
|
|
1034
|
+
options: {
|
|
1035
|
+
compression: "DEFLATE",
|
|
1036
|
+
compressionOptions: { level: compressionLevel }
|
|
1037
|
+
}
|
|
748
1038
|
});
|
|
749
1039
|
}
|
|
750
|
-
await materializeNewHeaderFooterParts(exportDocument, newZip, compressionLevel);
|
|
1040
|
+
exportDocument = await materializeNewHeaderFooterParts(exportDocument, newZip, compressionLevel);
|
|
751
1041
|
await materializeEmbeddedMedia({
|
|
752
1042
|
document: exportDocument,
|
|
753
1043
|
zip: newZip,
|
|
754
1044
|
compressionLevel
|
|
755
1045
|
});
|
|
1046
|
+
if (options.bodyAuthority === "canonical") await publishCanonicalImageResources({
|
|
1047
|
+
document: exportDocument,
|
|
1048
|
+
zip: newZip,
|
|
1049
|
+
compressionLevel
|
|
1050
|
+
});
|
|
756
1051
|
const parts = collectDocxParts(exportDocument, newZip);
|
|
757
1052
|
normalizeExportDrawingIds(exportDocument);
|
|
758
1053
|
await processNewImages(parts, newZip, compressionLevel);
|
|
759
1054
|
await processNewHyperlinks(parts, newZip, compressionLevel);
|
|
760
1055
|
assertValidFolioDocumentModel(exportDocument, "Cannot repack invalid DOCX document model");
|
|
761
1056
|
applyReplyThreadMarkers(exportDocument);
|
|
762
|
-
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
|
+
});
|
|
763
1062
|
if (rawContent.documentXml) assertDocumentPackageFidelity({
|
|
764
1063
|
originalDocumentFacts: readDocumentSectionFacts(rawContent.documentXml),
|
|
765
1064
|
serializedDocumentXml: documentXml,
|
|
766
1065
|
doc: exportDocument
|
|
767
1066
|
});
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
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
|
|
771
1081
|
});
|
|
772
|
-
await
|
|
773
|
-
|
|
1082
|
+
await serializeHeadersFootersToZip({
|
|
1083
|
+
doc: exportDocument,
|
|
1084
|
+
zip: newZip,
|
|
1085
|
+
compressionLevel,
|
|
1086
|
+
onDiagnostic: options.onDiagnostic
|
|
1087
|
+
});
|
|
1088
|
+
await serializeHeaderFooterSettingsIntoZip(exportDocument, newZip, compressionLevel);
|
|
774
1089
|
await serializeNotesToZip({
|
|
775
1090
|
doc: exportDocument,
|
|
776
1091
|
originalZip: rawContent.originalZip,
|
|
@@ -782,16 +1097,18 @@ async function repackDocxFromRaw(doc, rawContent, options = {}) {
|
|
|
782
1097
|
await serializeAddedStylesIntoZip(exportDocument, rawContent.originalZip, newZip, compressionLevel);
|
|
783
1098
|
await serializeCommentsToZip(exportDocument, newZip, compressionLevel);
|
|
784
1099
|
await dropAttachedTemplateReference(newZip, compressionLevel);
|
|
785
|
-
if (updateModifiedDate && rawContent.corePropsXml) {
|
|
786
|
-
|
|
1100
|
+
if (updateModifiedDate && rawContent.corePropsXml) writeZipPart({
|
|
1101
|
+
zip: newZip,
|
|
1102
|
+
path: "docProps/core.xml",
|
|
1103
|
+
data: updateCoreProperties(rawContent.corePropsXml, {
|
|
787
1104
|
updateModifiedDate,
|
|
788
1105
|
...modifiedBy !== void 0 ? { modifiedBy } : {}
|
|
789
|
-
})
|
|
790
|
-
|
|
1106
|
+
}),
|
|
1107
|
+
options: {
|
|
791
1108
|
compression: "DEFLATE",
|
|
792
1109
|
compressionOptions: { level: compressionLevel }
|
|
793
|
-
}
|
|
794
|
-
}
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
795
1112
|
return generateDocxZip(newZip, compressionLevel);
|
|
796
1113
|
}
|
|
797
1114
|
const COMMENTS_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml";
|
|
@@ -880,13 +1197,23 @@ async function dropAttachedTemplateReference(zip, compressionLevel) {
|
|
|
880
1197
|
if (!settingsFile) return;
|
|
881
1198
|
const relsFile = zip.file(SETTINGS_RELS_PART);
|
|
882
1199
|
const filtered = withoutAttachedTemplate(await settingsFile.async("text"), await relsFile?.async("text"));
|
|
883
|
-
if (filtered.settingsXml !== void 0)
|
|
884
|
-
|
|
885
|
-
|
|
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
|
+
}
|
|
886
1208
|
});
|
|
887
|
-
if (filtered.relsXml !== void 0)
|
|
888
|
-
|
|
889
|
-
|
|
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
|
+
}
|
|
890
1217
|
});
|
|
891
1218
|
}
|
|
892
1219
|
/**
|
|
@@ -899,9 +1226,14 @@ async function ensureCommentsContentType(zip, compressionLevel) {
|
|
|
899
1226
|
let ctXml = await ctFile.async("text");
|
|
900
1227
|
if (ctXml.includes("/word/comments.xml")) return;
|
|
901
1228
|
ctXml = ctXml.replace("</Types>", `<Override PartName="/word/comments.xml" ContentType="${COMMENTS_CONTENT_TYPE}"/></Types>`);
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
1229
|
+
writeZipPart({
|
|
1230
|
+
zip,
|
|
1231
|
+
path: "[Content_Types].xml",
|
|
1232
|
+
data: ctXml,
|
|
1233
|
+
options: {
|
|
1234
|
+
compression: "DEFLATE",
|
|
1235
|
+
compressionOptions: { level: compressionLevel }
|
|
1236
|
+
}
|
|
905
1237
|
});
|
|
906
1238
|
}
|
|
907
1239
|
/**
|
|
@@ -916,9 +1248,14 @@ async function ensureCommentsRelationship(zip, compressionLevel) {
|
|
|
916
1248
|
if (relsXml.includes("comments.xml")) return;
|
|
917
1249
|
const newRId = `rId${findMaxRId(relsXml) + 1}`;
|
|
918
1250
|
relsXml = relsXml.replace("</Relationships>", `<Relationship Id="${newRId}" Type="${RELATIONSHIP_TYPES.comments}" Target="comments.xml"/></Relationships>`);
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1251
|
+
writeZipPart({
|
|
1252
|
+
zip,
|
|
1253
|
+
path: relsPath,
|
|
1254
|
+
data: relsXml,
|
|
1255
|
+
options: {
|
|
1256
|
+
compression: "DEFLATE",
|
|
1257
|
+
compressionOptions: { level: compressionLevel }
|
|
1258
|
+
}
|
|
922
1259
|
});
|
|
923
1260
|
}
|
|
924
1261
|
/**
|
|
@@ -932,9 +1269,14 @@ async function ensureCommentsRelationship(zip, compressionLevel) {
|
|
|
932
1269
|
async function updateDocumentXml(originalBuffer, newDocumentXml, options = {}) {
|
|
933
1270
|
const { compressionLevel = 6 } = options;
|
|
934
1271
|
const zip = await JSZip.loadAsync(originalBuffer);
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1272
|
+
writeZipPart({
|
|
1273
|
+
zip,
|
|
1274
|
+
path: "word/document.xml",
|
|
1275
|
+
data: newDocumentXml,
|
|
1276
|
+
options: {
|
|
1277
|
+
compression: "DEFLATE",
|
|
1278
|
+
compressionOptions: { level: compressionLevel }
|
|
1279
|
+
}
|
|
938
1280
|
});
|
|
939
1281
|
return zip.generateAsync({
|
|
940
1282
|
type: "arraybuffer",
|
|
@@ -954,9 +1296,14 @@ async function updateDocumentXml(originalBuffer, newDocumentXml, options = {}) {
|
|
|
954
1296
|
async function updateXmlFile(originalBuffer, path, content, options = {}) {
|
|
955
1297
|
const { compressionLevel = 6 } = options;
|
|
956
1298
|
const zip = await JSZip.loadAsync(originalBuffer);
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1299
|
+
writeZipPart({
|
|
1300
|
+
zip,
|
|
1301
|
+
path,
|
|
1302
|
+
data: content,
|
|
1303
|
+
options: {
|
|
1304
|
+
compression: "DEFLATE",
|
|
1305
|
+
compressionOptions: { level: compressionLevel }
|
|
1306
|
+
}
|
|
960
1307
|
});
|
|
961
1308
|
return zip.generateAsync({
|
|
962
1309
|
type: "arraybuffer",
|
|
@@ -987,9 +1334,14 @@ async function updateMultipleFiles(originalBuffer, updates, options = {}) {
|
|
|
987
1334
|
*/
|
|
988
1335
|
async function applyUpdatesToZip(zip, updates, options = {}) {
|
|
989
1336
|
const { compressionLevel = 6 } = options;
|
|
990
|
-
for (const [path, content] of updates)
|
|
991
|
-
|
|
992
|
-
|
|
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
|
+
}
|
|
993
1345
|
});
|
|
994
1346
|
await normalizePackageOnSave(zip, compressionLevel);
|
|
995
1347
|
return await zip.generateAsync({
|
|
@@ -1014,8 +1366,11 @@ async function addRelationship(originalBuffer, relationship) {
|
|
|
1014
1366
|
const newRId = `rId${findMaxRId(relsXml) + 1}`;
|
|
1015
1367
|
const targetModeAttr = relationship.targetMode === "External" ? " TargetMode=\"External\"" : "";
|
|
1016
1368
|
const newRelElement = `<Relationship Id="${newRId}" Type="${relationship.type}" Target="${escapeXmlAttribute(relationship.target)}"${targetModeAttr}/>`;
|
|
1017
|
-
|
|
1018
|
-
|
|
1369
|
+
writeZipPart({
|
|
1370
|
+
zip,
|
|
1371
|
+
path: relsPath,
|
|
1372
|
+
data: relsXml.replace("</Relationships>", `${newRelElement}</Relationships>`)
|
|
1373
|
+
});
|
|
1019
1374
|
return {
|
|
1020
1375
|
buffer: await zip.generateAsync({
|
|
1021
1376
|
type: "arraybuffer",
|
|
@@ -1037,7 +1392,11 @@ async function addRelationship(originalBuffer, relationship) {
|
|
|
1037
1392
|
async function addMedia(originalBuffer, filename, data, mimeType) {
|
|
1038
1393
|
const zip = await JSZip.loadAsync(originalBuffer);
|
|
1039
1394
|
const mediaPath = `word/media/${filename}`;
|
|
1040
|
-
|
|
1395
|
+
writeZipPart({
|
|
1396
|
+
zip,
|
|
1397
|
+
path: mediaPath,
|
|
1398
|
+
data
|
|
1399
|
+
});
|
|
1041
1400
|
const relResult = await addRelationship(await zip.generateAsync({ type: "arraybuffer" }), {
|
|
1042
1401
|
type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
1043
1402
|
target: `media/${filename}`
|
|
@@ -1050,7 +1409,11 @@ async function addMedia(originalBuffer, filename, data, mimeType) {
|
|
|
1050
1409
|
const extensionElement = `<Default Extension="${extension}" ContentType="${getContentTypeForExtension(extension, mimeType)}"/>`;
|
|
1051
1410
|
const updatedContentTypes = contentTypesXml.replace("</Types>", `${extensionElement}</Types>`);
|
|
1052
1411
|
const finalZip = await JSZip.loadAsync(relResult.buffer);
|
|
1053
|
-
|
|
1412
|
+
writeZipPart({
|
|
1413
|
+
zip: finalZip,
|
|
1414
|
+
path: "[Content_Types].xml",
|
|
1415
|
+
data: updatedContentTypes
|
|
1416
|
+
});
|
|
1054
1417
|
return {
|
|
1055
1418
|
buffer: await finalZip.generateAsync({
|
|
1056
1419
|
type: "arraybuffer",
|
|
@@ -1115,11 +1478,19 @@ function findMaxHeaderFooterNum(zip, prefix) {
|
|
|
1115
1478
|
* relationship.
|
|
1116
1479
|
*/
|
|
1117
1480
|
async function materializeNewHeaderFooterParts(doc, zip, compressionLevel) {
|
|
1118
|
-
if (!
|
|
1119
|
-
doc
|
|
1120
|
-
|
|
1481
|
+
if (!doc.package.headers?.size && !doc.package.footers?.size) return doc;
|
|
1482
|
+
doc = {
|
|
1483
|
+
...doc,
|
|
1484
|
+
package: {
|
|
1485
|
+
...doc.package,
|
|
1486
|
+
relationships: new Map(doc.package.relationships),
|
|
1487
|
+
...doc.package.headers === void 0 ? {} : { headers: new Map(doc.package.headers) },
|
|
1488
|
+
...doc.package.footers === void 0 ? {} : { footers: new Map(doc.package.footers) }
|
|
1489
|
+
}
|
|
1490
|
+
};
|
|
1491
|
+
const rels = doc.package.relationships ?? panic("The export owns its relationship map.");
|
|
1121
1492
|
const relEntries = [];
|
|
1122
|
-
const
|
|
1493
|
+
const contentTypeParts = [];
|
|
1123
1494
|
let maxHeaderNum = findMaxHeaderFooterNum(zip, "header");
|
|
1124
1495
|
let maxFooterNum = findMaxHeaderFooterNum(zip, "footer");
|
|
1125
1496
|
const relsPath = "word/_rels/document.xml.rels";
|
|
@@ -1142,8 +1513,18 @@ async function materializeNewHeaderFooterParts(doc, zip, compressionLevel) {
|
|
|
1142
1513
|
const materialize = (map, relType, prefix, contentType, isHeader) => {
|
|
1143
1514
|
if (!map) return;
|
|
1144
1515
|
for (const rId of [...map.keys()]) {
|
|
1145
|
-
const
|
|
1146
|
-
|
|
1516
|
+
const registered = zipRels.get(rId);
|
|
1517
|
+
const existing = registered ?? rels.get(rId);
|
|
1518
|
+
if (existing && existing.type === relType && existing.target) {
|
|
1519
|
+
rels.set(rId, existing);
|
|
1520
|
+
const path = resolveRelativePath(relsPath, existing.target);
|
|
1521
|
+
contentTypeParts.push({
|
|
1522
|
+
partName: `/${path}`,
|
|
1523
|
+
contentType
|
|
1524
|
+
});
|
|
1525
|
+
if (!registered) relEntries.push(`<Relationship Id="${escapeXmlAttribute(rId)}" Type="${relType}" Target="${escapeXmlAttribute(existing.target)}"/>`);
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1147
1528
|
let effectiveRId = rId;
|
|
1148
1529
|
if (existing) {
|
|
1149
1530
|
effectiveRId = `rId${++maxRId}`;
|
|
@@ -1152,6 +1533,12 @@ async function materializeNewHeaderFooterParts(doc, zip, compressionLevel) {
|
|
|
1152
1533
|
map.delete(rId);
|
|
1153
1534
|
map.set(effectiveRId, headerFooter);
|
|
1154
1535
|
}
|
|
1536
|
+
const body = doc.package.document;
|
|
1537
|
+
doc.package.document = {
|
|
1538
|
+
...body,
|
|
1539
|
+
content: body.content.map((block) => block.type === "paragraph" && block.sectionProperties !== void 0 ? cloneParagraphWithPropertySource(block, { sectionProperties: structuredClone(block.sectionProperties) }) : block),
|
|
1540
|
+
...body.finalSectionProperties === void 0 ? {} : { finalSectionProperties: structuredClone(body.finalSectionProperties) }
|
|
1541
|
+
};
|
|
1155
1542
|
for (const block of doc.package.document.content) if (block.type === "paragraph") remapRefs(isHeader ? block.sectionProperties?.headerReferences : block.sectionProperties?.footerReferences, rId, effectiveRId);
|
|
1156
1543
|
const finalProps = doc.package.document.finalSectionProperties;
|
|
1157
1544
|
remapRefs(isHeader ? finalProps?.headerReferences : finalProps?.footerReferences, rId, effectiveRId);
|
|
@@ -1163,32 +1550,39 @@ async function materializeNewHeaderFooterParts(doc, zip, compressionLevel) {
|
|
|
1163
1550
|
target: filename
|
|
1164
1551
|
});
|
|
1165
1552
|
relEntries.push(`<Relationship Id="${escapeXmlAttribute(effectiveRId)}" Type="${relType}" Target="${filename}"/>`);
|
|
1166
|
-
|
|
1553
|
+
contentTypeParts.push({
|
|
1554
|
+
partName: `/word/${filename}`,
|
|
1555
|
+
contentType
|
|
1556
|
+
});
|
|
1167
1557
|
}
|
|
1168
1558
|
};
|
|
1169
1559
|
materialize(doc.package.headers, RELATIONSHIP_TYPES.header, "header", HEADER_CONTENT_TYPE, true);
|
|
1170
1560
|
materialize(doc.package.footers, RELATIONSHIP_TYPES.footer, "footer", FOOTER_CONTENT_TYPE, false);
|
|
1171
|
-
if (relEntries.length === 0) return;
|
|
1172
1561
|
const compressionOptions = { level: compressionLevel };
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
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
|
+
}
|
|
1176
1570
|
});
|
|
1177
1571
|
const ctFile = zip.file("[Content_Types].xml");
|
|
1178
1572
|
if (ctFile) {
|
|
1179
|
-
|
|
1180
|
-
const
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
zip.file("[Content_Types].xml", ctXml, {
|
|
1573
|
+
const original = await ctFile.async("text");
|
|
1574
|
+
const updated = registerContentTypeParts(original, contentTypeParts);
|
|
1575
|
+
if (updated !== original) writeZipPart({
|
|
1576
|
+
zip,
|
|
1577
|
+
path: "[Content_Types].xml",
|
|
1578
|
+
data: updated,
|
|
1579
|
+
options: {
|
|
1187
1580
|
compression: "DEFLATE",
|
|
1188
1581
|
compressionOptions
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1582
|
+
}
|
|
1583
|
+
});
|
|
1191
1584
|
}
|
|
1585
|
+
return doc;
|
|
1192
1586
|
}
|
|
1193
1587
|
/**
|
|
1194
1588
|
* A picture watermark is "model-driven" when its raw VML was cleared (so the
|
|
@@ -1204,25 +1598,46 @@ function hasModelDrivenPictureWatermark(doc) {
|
|
|
1204
1598
|
for (const hf of headers.values()) if (hf.watermark?.kind === "picture" && !hf.rawWatermarkXml) return true;
|
|
1205
1599
|
return false;
|
|
1206
1600
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
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 }) {
|
|
1217
1625
|
const rels = doc.package.relationships;
|
|
1218
1626
|
const headers = doc.package.headers;
|
|
1219
|
-
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
|
+
}
|
|
1220
1632
|
const pending = [];
|
|
1221
1633
|
for (const [rId, hf] of headers) {
|
|
1222
1634
|
const watermark = hf.watermark;
|
|
1223
1635
|
if (!watermark || watermark.kind !== "picture") continue;
|
|
1224
1636
|
const rel = rels.get(rId);
|
|
1225
|
-
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
|
+
}
|
|
1226
1641
|
pending.push({
|
|
1227
1642
|
watermark,
|
|
1228
1643
|
header: hf,
|
|
@@ -1255,20 +1670,37 @@ async function rebindWatermarkRelIds(doc, zip, compressionLevel) {
|
|
|
1255
1670
|
const changedPaths = /* @__PURE__ */ new Set();
|
|
1256
1671
|
for (const { watermark, header, relsPath, partPath } of pending) {
|
|
1257
1672
|
let canonical;
|
|
1258
|
-
if (watermark.imageTarget !== void 0) if (watermark.imageTargetExternal)
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
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 = {
|
|
1263
1680
|
mode: "internal",
|
|
1264
1681
|
absolute: watermark.imageTarget
|
|
1265
1682
|
};
|
|
1266
1683
|
else canonical = resolveCanonical(watermark.imageRId);
|
|
1267
|
-
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");
|
|
1268
1689
|
const relsXml = relsXmlByPath.get(relsPath) ?? EMPTY_RELS_XML;
|
|
1269
1690
|
const localRels = parseRelationships(relsXml);
|
|
1270
1691
|
const local = relImage(localRels.get(watermark.imageRId), relsPath);
|
|
1271
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
|
+
}
|
|
1272
1704
|
let resolvedRId;
|
|
1273
1705
|
for (const [id, rel] of localRels) {
|
|
1274
1706
|
const image = relImage(rel, relsPath);
|
|
@@ -1293,19 +1725,18 @@ async function rebindWatermarkRelIds(doc, zip, compressionLevel) {
|
|
|
1293
1725
|
const compressionOptions = { level: compressionLevel };
|
|
1294
1726
|
for (const path of changedPaths) {
|
|
1295
1727
|
const xml = relsXmlByPath.get(path);
|
|
1296
|
-
if (xml)
|
|
1297
|
-
|
|
1298
|
-
|
|
1728
|
+
if (xml) writeZipPart({
|
|
1729
|
+
zip,
|
|
1730
|
+
path,
|
|
1731
|
+
data: xml,
|
|
1732
|
+
options: {
|
|
1733
|
+
compression: "DEFLATE",
|
|
1734
|
+
compressionOptions
|
|
1735
|
+
}
|
|
1299
1736
|
});
|
|
1300
1737
|
}
|
|
1301
1738
|
}
|
|
1302
|
-
|
|
1303
|
-
* Re-serialize every header/footer the model still owns, keyed by part path.
|
|
1304
|
-
*
|
|
1305
|
-
* `sourceZip` supplies each part as it stands before the save so the rebuilt
|
|
1306
|
-
* root can keep any prefix binding only the source document declared.
|
|
1307
|
-
*/
|
|
1308
|
-
async function collectHeaderFooterUpdates(doc, sourceZip) {
|
|
1739
|
+
async function collectHeaderFooterUpdates(doc, { sourceZip, onDiagnostic }) {
|
|
1309
1740
|
const updates = /* @__PURE__ */ new Map();
|
|
1310
1741
|
const rels = doc.package.relationships;
|
|
1311
1742
|
if (!rels) return updates;
|
|
@@ -1327,21 +1758,28 @@ async function collectHeaderFooterUpdates(doc, sourceZip) {
|
|
|
1327
1758
|
const bindings = sourceFile ? readRootNamespaceBindings(await sourceFile.async("text")) : /* @__PURE__ */ new Map();
|
|
1328
1759
|
updates.set(path, serializeHeaderFooter(headerFooter, {
|
|
1329
1760
|
path,
|
|
1330
|
-
bindings
|
|
1761
|
+
bindings,
|
|
1762
|
+
onDiagnostic,
|
|
1763
|
+
originalBuffer: doc.originalBuffer
|
|
1331
1764
|
}));
|
|
1332
1765
|
}
|
|
1333
1766
|
}
|
|
1334
1767
|
}
|
|
1335
1768
|
return updates;
|
|
1336
1769
|
}
|
|
1337
|
-
|
|
1338
|
-
* Serialize modified headers and footers into the ZIP
|
|
1339
|
-
*/
|
|
1340
|
-
async function serializeHeadersFootersToZip(doc, zip, compressionLevel) {
|
|
1770
|
+
async function serializeHeadersFootersToZip({ doc, zip, compressionLevel, onDiagnostic }) {
|
|
1341
1771
|
const compressionOptions = { level: compressionLevel };
|
|
1342
|
-
for (const [filename, xml] of await collectHeaderFooterUpdates(doc,
|
|
1343
|
-
|
|
1344
|
-
|
|
1772
|
+
for (const [filename, xml] of await collectHeaderFooterUpdates(doc, {
|
|
1773
|
+
sourceZip: zip,
|
|
1774
|
+
onDiagnostic
|
|
1775
|
+
})) writeZipPart({
|
|
1776
|
+
zip,
|
|
1777
|
+
path: filename,
|
|
1778
|
+
data: xml,
|
|
1779
|
+
options: {
|
|
1780
|
+
compression: "DEFLATE",
|
|
1781
|
+
compressionOptions
|
|
1782
|
+
}
|
|
1345
1783
|
});
|
|
1346
1784
|
}
|
|
1347
1785
|
async function serializeNotesToZip({ doc, originalZip, newZip, compressionLevel, changedNoteParaIds }) {
|
|
@@ -1350,7 +1788,7 @@ async function serializeNotesToZip({ doc, originalZip, newZip, compressionLevel,
|
|
|
1350
1788
|
if (footnotes.length > 0 || originalFootnotes) if (originalFootnotes) await patchNotePartIntoZip({
|
|
1351
1789
|
conventionalLowerPath: "word/footnotes.xml",
|
|
1352
1790
|
currentXml: serializeFootnotes(footnotes),
|
|
1353
|
-
replacementXml: serializeNewFootnotesPart(footnotes),
|
|
1791
|
+
replacementXml: serializeNewFootnotesPart(footnotes, doc),
|
|
1354
1792
|
baselineFrom: (xml) => serializeFootnotes(parseFootnotes(xml).getNormalFootnotes()),
|
|
1355
1793
|
elementName: "footnote",
|
|
1356
1794
|
changedNoteParaIds,
|
|
@@ -1363,7 +1801,7 @@ async function serializeNotesToZip({ doc, originalZip, newZip, compressionLevel,
|
|
|
1363
1801
|
newZip,
|
|
1364
1802
|
partPath: "word/footnotes.xml",
|
|
1365
1803
|
relationshipType: RELATIONSHIP_TYPES.footnotes,
|
|
1366
|
-
serializedPart: serializeNewFootnotesPart(footnotes),
|
|
1804
|
+
serializedPart: serializeNewFootnotesPart(footnotes, doc),
|
|
1367
1805
|
compressionLevel
|
|
1368
1806
|
});
|
|
1369
1807
|
const endnotes = doc.package.endnotes ?? [];
|
|
@@ -1371,7 +1809,7 @@ async function serializeNotesToZip({ doc, originalZip, newZip, compressionLevel,
|
|
|
1371
1809
|
if (endnotes.length > 0 || originalEndnotes) if (originalEndnotes) await patchNotePartIntoZip({
|
|
1372
1810
|
conventionalLowerPath: "word/endnotes.xml",
|
|
1373
1811
|
currentXml: serializeEndnotes(endnotes),
|
|
1374
|
-
replacementXml: serializeNewEndnotesPart(endnotes),
|
|
1812
|
+
replacementXml: serializeNewEndnotesPart(endnotes, doc),
|
|
1375
1813
|
baselineFrom: (xml) => serializeEndnotes(parseEndnotes(xml).getNormalEndnotes()),
|
|
1376
1814
|
elementName: "endnote",
|
|
1377
1815
|
changedNoteParaIds,
|
|
@@ -1384,7 +1822,7 @@ async function serializeNotesToZip({ doc, originalZip, newZip, compressionLevel,
|
|
|
1384
1822
|
newZip,
|
|
1385
1823
|
partPath: "word/endnotes.xml",
|
|
1386
1824
|
relationshipType: RELATIONSHIP_TYPES.endnotes,
|
|
1387
|
-
serializedPart: serializeNewEndnotesPart(endnotes),
|
|
1825
|
+
serializedPart: serializeNewEndnotesPart(endnotes, doc),
|
|
1388
1826
|
compressionLevel
|
|
1389
1827
|
});
|
|
1390
1828
|
}
|
|
@@ -1395,22 +1833,68 @@ async function materializeNewNotePart({ contentType, newZip, partPath, relations
|
|
|
1395
1833
|
const compressionOptions = { level: compressionLevel };
|
|
1396
1834
|
const contentTypesXml = await contentTypesFile.async("text");
|
|
1397
1835
|
const partName = `/${partPath}`;
|
|
1398
|
-
if (!contentTypesXml.toLowerCase().includes(partName.toLowerCase()))
|
|
1399
|
-
|
|
1400
|
-
|
|
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
|
+
}
|
|
1401
1844
|
});
|
|
1402
1845
|
const relationshipsXml = await relationshipsFile.async("text");
|
|
1403
1846
|
if (!relationshipsXml.includes(relationshipType)) {
|
|
1404
1847
|
const relationshipId = `rId${findMaxRId(relationshipsXml) + 1}`;
|
|
1405
1848
|
const target = partPath.slice(5);
|
|
1406
|
-
|
|
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
|
+
}
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
writeZipPart({
|
|
1860
|
+
zip: newZip,
|
|
1861
|
+
path: partPath,
|
|
1862
|
+
data: serializedPart,
|
|
1863
|
+
options: {
|
|
1407
1864
|
compression: "DEFLATE",
|
|
1408
1865
|
compressionOptions
|
|
1866
|
+
}
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1869
|
+
/** Only this modeled switch changes on story lifecycle edits; preserve all other settings. */
|
|
1870
|
+
async function serializeHeaderFooterSettingsIntoZip(doc, zip, compressionLevel) {
|
|
1871
|
+
if (!doc.package.settings) return;
|
|
1872
|
+
const enabled = doc.package.settings.evenAndOddHeaders;
|
|
1873
|
+
const file = zip.file(SETTINGS_PART);
|
|
1874
|
+
if (!file) {
|
|
1875
|
+
if (enabled === void 0) return;
|
|
1876
|
+
await materializeNewNotePart({
|
|
1877
|
+
contentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml",
|
|
1878
|
+
newZip: zip,
|
|
1879
|
+
partPath: "word/settings.xml",
|
|
1880
|
+
relationshipType: RELATIONSHIP_TYPES.settings,
|
|
1881
|
+
serializedPart: serializeSettingsXml(doc.package.settings),
|
|
1882
|
+
compressionLevel
|
|
1409
1883
|
});
|
|
1884
|
+
return;
|
|
1410
1885
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1886
|
+
const xml = await file.async("text");
|
|
1887
|
+
if (parseSettings(xml).evenAndOddHeaders === enabled) return;
|
|
1888
|
+
const patched = updateEvenAndOddHeaders(xml, enabled);
|
|
1889
|
+
if (patched === null) throw new DocxPackageFidelityError("Cannot update malformed header/footer settings");
|
|
1890
|
+
writeZipPart({
|
|
1891
|
+
zip,
|
|
1892
|
+
path: file.name,
|
|
1893
|
+
data: patched,
|
|
1894
|
+
options: {
|
|
1895
|
+
compression: "DEFLATE",
|
|
1896
|
+
compressionOptions: { level: compressionLevel }
|
|
1897
|
+
}
|
|
1414
1898
|
});
|
|
1415
1899
|
}
|
|
1416
1900
|
const numberingBaselines = /* @__PURE__ */ new WeakMap();
|
|
@@ -1446,9 +1930,14 @@ async function serializeNumberingIntoZip(doc, originalZip, newZip, compressionLe
|
|
|
1446
1930
|
currentXml
|
|
1447
1931
|
});
|
|
1448
1932
|
if (patched === null || patched === baseline.originalXml) return;
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1933
|
+
writeZipPart({
|
|
1934
|
+
zip: newZip,
|
|
1935
|
+
path: file.name,
|
|
1936
|
+
data: patched,
|
|
1937
|
+
options: {
|
|
1938
|
+
compression: "DEFLATE",
|
|
1939
|
+
compressionOptions: { level: compressionLevel }
|
|
1940
|
+
}
|
|
1452
1941
|
});
|
|
1453
1942
|
}
|
|
1454
1943
|
const STYLES_PART_PATH = "word/styles.xml";
|
|
@@ -1556,24 +2045,18 @@ const styleDefinitionsToSerialize = (doc) => {
|
|
|
1556
2045
|
styles: [...styles.styles, ...missing]
|
|
1557
2046
|
};
|
|
1558
2047
|
};
|
|
1559
|
-
|
|
2048
|
+
/** One append-only style owner for full repack and selective overlays. */
|
|
2049
|
+
async function planAddedStyles(doc, originalZip) {
|
|
1560
2050
|
const styles = doc.package.styles;
|
|
1561
|
-
if (!styles || styles.styles.length === 0) return;
|
|
2051
|
+
if (!styles || styles.styles.length === 0) return { type: "unchanged" };
|
|
1562
2052
|
const file = findNotePartEntry(originalZip, STYLES_PART_PATH);
|
|
1563
2053
|
const originalXml = file ? await file.async("text") : null;
|
|
1564
2054
|
const rootName = originalXml === null ? void 0 : /<(?![?!])(?<name>[^\s/>]+)/u.exec(originalXml)?.groups?.["name"];
|
|
1565
2055
|
const rootClose = originalXml !== null && rootName !== void 0 && getLocalName(rootName) === "styles" ? originalXml.lastIndexOf(`</${rootName}>`) : -1;
|
|
1566
|
-
if (file === null || originalXml === null || rootClose < 0) {
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
partPath: STYLES_PART_PATH,
|
|
1571
|
-
relationshipType: RELATIONSHIP_TYPES.styles,
|
|
1572
|
-
serializedPart: serializeStylesXml(styles),
|
|
1573
|
-
compressionLevel
|
|
1574
|
-
});
|
|
1575
|
-
return;
|
|
1576
|
-
}
|
|
2056
|
+
if (file === null || originalXml === null || rootClose < 0) return {
|
|
2057
|
+
type: "materialize",
|
|
2058
|
+
styles
|
|
2059
|
+
};
|
|
1577
2060
|
const existing = new Set(definedStyleIds(originalXml));
|
|
1578
2061
|
const added = [];
|
|
1579
2062
|
for (const style of styles.styles) {
|
|
@@ -1581,13 +2064,42 @@ async function serializeAddedStylesIntoZip(doc, originalZip, newZip, compression
|
|
|
1581
2064
|
existing.add(style.styleId);
|
|
1582
2065
|
added.push(style);
|
|
1583
2066
|
}
|
|
1584
|
-
if (added.length === 0) return;
|
|
2067
|
+
if (added.length === 0) return { type: "unchanged" };
|
|
1585
2068
|
const canonical = hasCanonicalWordprocessingPrefixes(originalXml);
|
|
1586
2069
|
const patched = originalXml.slice(0, rootClose) + added.map((style) => canonical ? serializeStyle(style) : selfBoundFragment(serializeStyle(style), file.name)).join("") + originalXml.slice(rootClose);
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
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
|
+
}
|
|
1591
2103
|
}
|
|
1592
2104
|
/**
|
|
1593
2105
|
* The XML to write for a patched note part, or null to keep the original.
|
|
@@ -1642,9 +2154,14 @@ async function patchNotePartIntoZip({ conventionalLowerPath, currentXml, replace
|
|
|
1642
2154
|
partName: file.name
|
|
1643
2155
|
});
|
|
1644
2156
|
if (patchedXml === null || patchedXml === originalXml) return;
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
2157
|
+
writeZipPart({
|
|
2158
|
+
zip: newZip,
|
|
2159
|
+
path: file.name,
|
|
2160
|
+
data: patchedXml,
|
|
2161
|
+
options: {
|
|
2162
|
+
compression: "DEFLATE",
|
|
2163
|
+
compressionOptions: { level: compressionLevel }
|
|
2164
|
+
}
|
|
1648
2165
|
});
|
|
1649
2166
|
}
|
|
1650
2167
|
/** `word/Footnotes.xml` -> `word/_rels/Footnotes.xml.rels` (casing preserved). */
|
|
@@ -1742,7 +2259,10 @@ function createEmptyDocx(properties = {}) {
|
|
|
1742
2259
|
}
|
|
1743
2260
|
const createEmptyDocxZip = ({ creator, application }) => {
|
|
1744
2261
|
const zip = new JSZip();
|
|
1745
|
-
|
|
2262
|
+
writeZipPart({
|
|
2263
|
+
zip,
|
|
2264
|
+
path: "[Content_Types].xml",
|
|
2265
|
+
data: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1746
2266
|
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
1747
2267
|
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
1748
2268
|
<Default Extension="xml" ContentType="application/xml"/>
|
|
@@ -1750,18 +2270,30 @@ const createEmptyDocxZip = ({ creator, application }) => {
|
|
|
1750
2270
|
<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
|
|
1751
2271
|
<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
|
|
1752
2272
|
<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
|
|
1753
|
-
</Types>`
|
|
1754
|
-
|
|
2273
|
+
</Types>`
|
|
2274
|
+
});
|
|
2275
|
+
writeZipPart({
|
|
2276
|
+
zip,
|
|
2277
|
+
path: "_rels/.rels",
|
|
2278
|
+
data: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1755
2279
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
1756
2280
|
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
|
1757
2281
|
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
|
|
1758
2282
|
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
|
|
1759
|
-
</Relationships>`
|
|
1760
|
-
|
|
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"?>
|
|
1761
2289
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
1762
2290
|
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
|
|
1763
|
-
</Relationships>`
|
|
1764
|
-
|
|
2291
|
+
</Relationships>`
|
|
2292
|
+
});
|
|
2293
|
+
writeZipPart({
|
|
2294
|
+
zip,
|
|
2295
|
+
path: "word/document.xml",
|
|
2296
|
+
data: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1765
2297
|
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
1766
2298
|
<w:body>
|
|
1767
2299
|
<w:p>
|
|
@@ -1774,19 +2306,30 @@ const createEmptyDocxZip = ({ creator, application }) => {
|
|
|
1774
2306
|
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/>
|
|
1775
2307
|
</w:sectPr>
|
|
1776
2308
|
</w:body>
|
|
1777
|
-
</w:document>`
|
|
1778
|
-
|
|
2309
|
+
</w:document>`
|
|
2310
|
+
});
|
|
2311
|
+
writeZipPart({
|
|
2312
|
+
zip,
|
|
2313
|
+
path: STYLES_PART_PATH,
|
|
2314
|
+
data: SEED_STYLES_XML
|
|
2315
|
+
});
|
|
1779
2316
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
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>`}
|
|
1783
2322
|
<dcterms:created xsi:type="dcterms:W3CDTF">${now}</dcterms:created>
|
|
1784
2323
|
<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified>
|
|
1785
|
-
</cp:coreProperties>`
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
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
|
+
});
|
|
1790
2333
|
return zip;
|
|
1791
2334
|
};
|
|
1792
2335
|
/**
|
|
@@ -1807,7 +2350,9 @@ async function createDocx(doc, properties = {}) {
|
|
|
1807
2350
|
originalDocument: source.document,
|
|
1808
2351
|
originalCorePropertiesXml: source.corePropertiesXml,
|
|
1809
2352
|
compressionLevel: 6,
|
|
1810
|
-
updateModifiedDate: true
|
|
2353
|
+
updateModifiedDate: true,
|
|
2354
|
+
onDiagnostic: properties.onDiagnostic,
|
|
2355
|
+
bodyAuthority: properties.bodyAuthority
|
|
1811
2356
|
});
|
|
1812
2357
|
}
|
|
1813
2358
|
const zip = await createDocumentSeedZip(doc, properties);
|
|
@@ -1818,7 +2363,9 @@ async function createDocx(doc, properties = {}) {
|
|
|
1818
2363
|
originalDocument: void 0,
|
|
1819
2364
|
originalCorePropertiesXml: await zip.file("docProps/core.xml")?.async("text"),
|
|
1820
2365
|
compressionLevel: 6,
|
|
1821
|
-
updateModifiedDate: true
|
|
2366
|
+
updateModifiedDate: true,
|
|
2367
|
+
onDiagnostic: properties.onDiagnostic,
|
|
2368
|
+
bodyAuthority: properties.bodyAuthority
|
|
1822
2369
|
});
|
|
1823
2370
|
}
|
|
1824
2371
|
const createDocumentSeedZip = async (doc, properties) => {
|
|
@@ -1829,38 +2376,69 @@ const createDocumentSeedZip = async (doc, properties) => {
|
|
|
1829
2376
|
const styleDefinitions = styleDefinitionsToSerialize(doc);
|
|
1830
2377
|
if (styleDefinitions) {
|
|
1831
2378
|
assertStyleNumberingReferences(doc);
|
|
1832
|
-
|
|
1833
|
-
|
|
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
|
+
});
|
|
1834
2389
|
const numbering = doc.package.numbering;
|
|
1835
2390
|
if (numbering && (numbering.abstractNums.length > 0 || numbering.nums.length > 0)) {
|
|
1836
|
-
|
|
2391
|
+
writeZipPart({
|
|
2392
|
+
zip,
|
|
2393
|
+
path: "word/numbering.xml",
|
|
2394
|
+
data: serializeNumberingXml(numbering)
|
|
2395
|
+
});
|
|
1837
2396
|
relationships.push(relationshipXml(nextRelationshipId, "numbering", "numbering.xml"));
|
|
1838
2397
|
overrides.push(overrideXml("/word/numbering.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"));
|
|
1839
2398
|
nextRelationshipId += 1;
|
|
1840
2399
|
}
|
|
1841
2400
|
if (doc.package.theme) {
|
|
1842
|
-
|
|
2401
|
+
writeZipPart({
|
|
2402
|
+
zip,
|
|
2403
|
+
path: "word/theme/theme1.xml",
|
|
2404
|
+
data: serializeThemeXml(doc.package.theme)
|
|
2405
|
+
});
|
|
1843
2406
|
relationships.push(relationshipXml(nextRelationshipId, "theme", "theme/theme1.xml"));
|
|
1844
2407
|
overrides.push(overrideXml("/word/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml"));
|
|
1845
2408
|
nextRelationshipId += 1;
|
|
1846
2409
|
}
|
|
1847
2410
|
if (doc.package.fontTable && doc.package.fontTable.fonts.length > 0) {
|
|
1848
|
-
|
|
2411
|
+
writeZipPart({
|
|
2412
|
+
zip,
|
|
2413
|
+
path: "word/fontTable.xml",
|
|
2414
|
+
data: serializeFontTableXml(doc.package.fontTable)
|
|
2415
|
+
});
|
|
1849
2416
|
relationships.push(relationshipXml(nextRelationshipId, "fontTable", "fontTable.xml"));
|
|
1850
2417
|
overrides.push(overrideXml("/word/fontTable.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"));
|
|
1851
2418
|
nextRelationshipId += 1;
|
|
1852
2419
|
}
|
|
1853
2420
|
if (doc.package.settings) {
|
|
1854
|
-
|
|
2421
|
+
writeZipPart({
|
|
2422
|
+
zip,
|
|
2423
|
+
path: "word/settings.xml",
|
|
2424
|
+
data: serializeSettingsXml(doc.package.settings)
|
|
2425
|
+
});
|
|
1855
2426
|
relationships.push(relationshipXml(nextRelationshipId, "settings", "settings.xml"));
|
|
1856
2427
|
overrides.push(overrideXml("/word/settings.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"));
|
|
1857
2428
|
}
|
|
1858
|
-
|
|
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
|
+
});
|
|
1859
2434
|
if (overrides.length > 0) {
|
|
1860
2435
|
const contentTypesFile = zip.file("[Content_Types].xml");
|
|
1861
2436
|
if (!contentTypesFile) panic("Fresh DOCX seed is missing [Content_Types].xml");
|
|
1862
|
-
|
|
1863
|
-
|
|
2437
|
+
writeZipPart({
|
|
2438
|
+
zip,
|
|
2439
|
+
path: "[Content_Types].xml",
|
|
2440
|
+
data: (await contentTypesFile.async("string")).replace("</Types>", `${overrides.join("")}\n</Types>`)
|
|
2441
|
+
});
|
|
1864
2442
|
}
|
|
1865
2443
|
return zip;
|
|
1866
2444
|
};
|
|
@@ -1894,4 +2472,4 @@ const assertStyleNumberingReferences = (doc) => {
|
|
|
1894
2472
|
}
|
|
1895
2473
|
};
|
|
1896
2474
|
//#endregion
|
|
1897
|
-
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 };
|