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