@stll/folio-core 0.0.1-placeholder.0 → 0.1.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/LICENSE +202 -0
- package/NOTICE.md +29 -0
- package/README.md +41 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/ai-edits/apply.d.ts +35 -0
- package/dist/ai-edits/apply.js +683 -0
- package/dist/ai-edits/clean-text.d.ts +28 -0
- package/dist/ai-edits/clean-text.js +23 -0
- package/dist/ai-edits/headless.d.ts +225 -0
- package/dist/ai-edits/headless.js +513 -0
- package/dist/ai-edits/index.d.ts +6 -0
- package/dist/ai-edits/index.js +5 -0
- package/dist/ai-edits/inline-emphasis.d.ts +38 -0
- package/dist/ai-edits/inline-emphasis.js +78 -0
- package/dist/ai-edits/snapshot.d.ts +9 -0
- package/dist/ai-edits/snapshot.js +195 -0
- package/dist/ai-edits/types.d.ts +156 -0
- package/dist/ai-edits/types.js +0 -0
- package/dist/ai-edits/word-diff.d.ts +20 -0
- package/dist/ai-edits/word-diff.js +77 -0
- package/dist/ai-suggestions/apply.d.ts +17 -0
- package/dist/ai-suggestions/apply.js +64 -0
- package/dist/ai-suggestions/conflict.d.ts +22 -0
- package/dist/ai-suggestions/conflict.js +67 -0
- package/dist/ai-suggestions/text-positions.d.ts +21 -0
- package/dist/ai-suggestions/text-positions.js +48 -0
- package/dist/ai-suggestions/types.d.ts +199 -0
- package/dist/ai-suggestions/types.js +59 -0
- package/dist/content-controls/errors.d.ts +52 -0
- package/dist/content-controls/errors.js +36 -0
- package/dist/content-controls/findContentControls.d.ts +55 -0
- package/dist/content-controls/findContentControls.js +75 -0
- package/dist/content-controls/index.d.ts +4 -0
- package/dist/content-controls/index.js +4 -0
- package/dist/content-controls/mutateContentControls.d.ts +51 -0
- package/dist/content-controls/mutateContentControls.js +377 -0
- package/dist/controller/folioEditor.d.ts +21 -0
- package/dist/controller/folioEditor.js +29 -0
- package/dist/controller/folioEditorEvents.d.ts +23 -0
- package/dist/controller/folioEditorEvents.js +24 -0
- package/dist/controller/hiddenEditorApi.d.ts +35 -0
- package/dist/controller/hiddenEditorApi.js +112 -0
- package/dist/controller/hiddenEditorManager.d.ts +93 -0
- package/dist/controller/hiddenEditorManager.js +308 -0
- package/dist/controller/layoutPipeline.d.ts +63 -0
- package/dist/controller/layoutPipeline.js +406 -0
- package/dist/controller/layoutScheduler.d.ts +41 -0
- package/dist/controller/layoutScheduler.js +59 -0
- package/dist/controller/layoutSession.d.ts +24 -0
- package/dist/controller/layoutSession.js +13 -0
- package/dist/docx/blockContentParser.d.ts +13 -0
- package/dist/docx/blockContentParser.js +289 -0
- package/dist/docx/bookmarkParser.d.ts +178 -0
- package/dist/docx/bookmarkParser.js +246 -0
- package/dist/docx/bookmarkPlacement.d.ts +10 -0
- package/dist/docx/bookmarkPlacement.js +50 -0
- package/dist/docx/bulletMarkers.d.ts +4 -0
- package/dist/docx/bulletMarkers.js +42 -0
- package/dist/docx/commentParser.d.ts +34 -0
- package/dist/docx/commentParser.js +127 -0
- package/dist/docx/commentReferenceNormalization.d.ts +25 -0
- package/dist/docx/commentReferenceNormalization.js +97 -0
- package/dist/docx/commentReplyMarkers.d.ts +20 -0
- package/dist/docx/commentReplyMarkers.js +123 -0
- package/dist/docx/compatibility.d.ts +12 -0
- package/dist/docx/compatibility.js +77 -0
- package/dist/docx/documentParser.d.ts +65 -0
- package/dist/docx/documentParser.js +209 -0
- package/dist/docx/drawingUtils.d.ts +56 -0
- package/dist/docx/drawingUtils.js +305 -0
- package/dist/docx/fieldParser.d.ts +228 -0
- package/dist/docx/fieldParser.js +559 -0
- package/dist/docx/footnoteParser.d.ts +109 -0
- package/dist/docx/footnoteParser.js +270 -0
- package/dist/docx/headerFooterParser.d.ts +119 -0
- package/dist/docx/headerFooterParser.js +266 -0
- package/dist/docx/headerFooterRefParser.d.ts +22 -0
- package/dist/docx/headerFooterRefParser.js +52 -0
- package/dist/docx/headerFooterReferenceNormalization.d.ts +19 -0
- package/dist/docx/headerFooterReferenceNormalization.js +64 -0
- package/dist/docx/hyperlinkParser.d.ts +108 -0
- package/dist/docx/hyperlinkParser.js +230 -0
- package/dist/docx/imageParser.d.ts +93 -0
- package/dist/docx/imageParser.js +522 -0
- package/dist/docx/mathToMathml.d.ts +15 -0
- package/dist/docx/mathToMathml.js +357 -0
- package/dist/docx/modelValidation.d.ts +13 -0
- package/dist/docx/modelValidation.js +21 -0
- package/dist/docx/normalizeBaseDirection.d.ts +12 -0
- package/dist/docx/normalizeBaseDirection.js +81 -0
- package/dist/docx/notePropertiesParser.d.ts +16 -0
- package/dist/docx/notePropertiesParser.js +99 -0
- package/dist/docx/numberingParser.d.ts +86 -0
- package/dist/docx/numberingParser.js +735 -0
- package/dist/docx/numberingReferenceNormalization.d.ts +25 -0
- package/dist/docx/numberingReferenceNormalization.js +22 -0
- package/dist/docx/paragraphParser.d.ts +86 -0
- package/dist/docx/paragraphParser.js +1132 -0
- package/dist/docx/paragraphTraversal.d.ts +19 -0
- package/dist/docx/paragraphTraversal.js +76 -0
- package/dist/docx/parser.d.ts +67 -0
- package/dist/docx/parser.js +391 -0
- package/dist/docx/parserEnums.d.ts +45 -0
- package/dist/docx/parserEnums.js +70 -0
- package/dist/docx/relsParser.d.ts +160 -0
- package/dist/docx/relsParser.js +235 -0
- package/dist/docx/replyToComment.d.ts +29 -0
- package/dist/docx/replyToComment.js +73 -0
- package/dist/docx/rezip.d.ts +166 -0
- package/dist/docx/rezip.js +1194 -0
- package/dist/docx/runConsolidator.d.ts +57 -0
- package/dist/docx/runConsolidator.js +224 -0
- package/dist/docx/runParser.d.ts +78 -0
- package/dist/docx/runParser.js +661 -0
- package/dist/docx/sdtProperties.d.ts +15 -0
- package/dist/docx/sdtProperties.js +290 -0
- package/dist/docx/sdtPropertiesPatch.d.ts +16 -0
- package/dist/docx/sdtPropertiesPatch.js +144 -0
- package/dist/docx/sectionParser.d.ts +95 -0
- package/dist/docx/sectionParser.js +534 -0
- package/dist/docx/selectiveSave.d.ts +25 -0
- package/dist/docx/selectiveSave.js +247 -0
- package/dist/docx/selectiveSaveFlags.d.ts +33 -0
- package/dist/docx/selectiveSaveFlags.js +11 -0
- package/dist/docx/selectiveSaveTripwire.d.ts +33 -0
- package/dist/docx/selectiveSaveTripwire.js +79 -0
- package/dist/docx/selectiveXmlPatch.d.ts +103 -0
- package/dist/docx/selectiveXmlPatch.js +493 -0
- package/dist/docx/serializer/blockSdtSerializer.d.ts +6 -0
- package/dist/docx/serializer/blockSdtSerializer.js +88 -0
- package/dist/docx/serializer/borderSerializer.d.ts +25 -0
- package/dist/docx/serializer/borderSerializer.js +44 -0
- package/dist/docx/serializer/commentSerializer.d.ts +31 -0
- package/dist/docx/serializer/commentSerializer.js +184 -0
- package/dist/docx/serializer/documentSerializer.d.ts +65 -0
- package/dist/docx/serializer/documentSerializer.js +199 -0
- package/dist/docx/serializer/headerFooterSerializer.d.ts +12 -0
- package/dist/docx/serializer/headerFooterSerializer.js +84 -0
- package/dist/docx/serializer/noteSerializer.d.ts +19 -0
- package/dist/docx/serializer/noteSerializer.js +70 -0
- package/dist/docx/serializer/numberingSerializer.d.ts +12 -0
- package/dist/docx/serializer/numberingSerializer.js +93 -0
- package/dist/docx/serializer/paragraphSerializer.d.ts +48 -0
- package/dist/docx/serializer/paragraphSerializer.js +559 -0
- package/dist/docx/serializer/runSerializer.d.ts +56 -0
- package/dist/docx/serializer/runSerializer.js +621 -0
- package/dist/docx/serializer/sectionPropertiesSerializer.d.ts +6 -0
- package/dist/docx/serializer/sectionPropertiesSerializer.js +187 -0
- package/dist/docx/serializer/tableSerializer.d.ts +79 -0
- package/dist/docx/serializer/tableSerializer.js +422 -0
- package/dist/docx/serializer/xmlUtils.d.ts +20 -0
- package/dist/docx/serializer/xmlUtils.js +25 -0
- package/dist/docx/settingsParser.d.ts +8 -0
- package/dist/docx/settingsParser.js +36 -0
- package/dist/docx/shapeParser.d.ts +20 -0
- package/dist/docx/shapeParser.js +272 -0
- package/dist/docx/styleParser.d.ts +50 -0
- package/dist/docx/styleParser.js +905 -0
- package/dist/docx/tableParser.d.ts +202 -0
- package/dist/docx/tableParser.js +811 -0
- package/dist/docx/textBoxParser.d.ts +117 -0
- package/dist/docx/textBoxParser.js +262 -0
- package/dist/docx/themeParser.d.ts +77 -0
- package/dist/docx/themeParser.js +330 -0
- package/dist/docx/trackedMoveRangeNormalization.d.ts +22 -0
- package/dist/docx/trackedMoveRangeNormalization.js +100 -0
- package/dist/docx/unzip.d.ts +118 -0
- package/dist/docx/unzip.js +383 -0
- package/dist/docx/vmlImageParser.d.ts +16 -0
- package/dist/docx/vmlImageParser.js +100 -0
- package/dist/docx/watermarkParser.d.ts +45 -0
- package/dist/docx/watermarkParser.js +348 -0
- package/dist/docx/wrapTypes.d.ts +29 -0
- package/dist/docx/wrapTypes.js +48 -0
- package/dist/docx/xmlParser.d.ts +297 -0
- package/dist/docx/xmlParser.js +527 -0
- package/dist/fields/bookmarkPages.d.ts +13 -0
- package/dist/fields/bookmarkPages.js +66 -0
- package/dist/fields/bookmarkText.d.ts +16 -0
- package/dist/fields/bookmarkText.js +61 -0
- package/dist/fields/evaluateField.d.ts +23 -0
- package/dist/fields/evaluateField.js +77 -0
- package/dist/fields/fieldContext.d.ts +21 -0
- package/dist/fields/fieldContext.js +0 -0
- package/dist/fields/resolveFieldValues.d.ts +44 -0
- package/dist/fields/resolveFieldValues.js +204 -0
- package/dist/fields/sectionPageCounts.d.ts +11 -0
- package/dist/fields/sectionPageCounts.js +16 -0
- package/dist/fields/seqValues.d.ts +14 -0
- package/dist/fields/seqValues.js +36 -0
- package/dist/fonts/embeddedFontTable.d.ts +42 -0
- package/dist/fonts/embeddedFontTable.js +80 -0
- package/dist/fonts/embeddedFonts.d.ts +46 -0
- package/dist/fonts/embeddedFonts.js +112 -0
- package/dist/fonts/fontDeobfuscation.d.ts +30 -0
- package/dist/fonts/fontDeobfuscation.js +57 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +23 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +57 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +316 -0
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +74 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +432 -0
- package/dist/layout-bridge/convert/templatePreviewFlow.d.ts +36 -0
- package/dist/layout-bridge/convert/templatePreviewFlow.js +176 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +65 -0
- package/dist/layout-bridge/convert/toFlowBlocks.js +1309 -0
- package/dist/layout-bridge/convert/wrapEditorViewAsSurface.d.ts +17 -0
- package/dist/layout-bridge/convert/wrapEditorViewAsSurface.js +36 -0
- package/dist/layout-bridge/dom/clickToPositionDom.d.ts +66 -0
- package/dist/layout-bridge/dom/clickToPositionDom.js +304 -0
- package/dist/layout-bridge/dom/findBodyPmSpans.d.ts +7 -0
- package/dist/layout-bridge/dom/findBodyPmSpans.js +17 -0
- package/dist/layout-bridge/dom/findHfPmSpans.d.ts +62 -0
- package/dist/layout-bridge/dom/findHfPmSpans.js +197 -0
- package/dist/layout-bridge/engine/clickToPosition.d.ts +66 -0
- package/dist/layout-bridge/engine/clickToPosition.js +403 -0
- package/dist/layout-bridge/engine/hitTest.d.ts +135 -0
- package/dist/layout-bridge/engine/hitTest.js +375 -0
- package/dist/layout-bridge/engine/measuring/index.d.ts +10 -0
- package/dist/layout-bridge/engine/measuring/index.js +9 -0
- package/dist/layout-bridge/engine/selectionRects.d.ts +59 -0
- package/dist/layout-bridge/engine/selectionRects.js +485 -0
- package/dist/layout-bridge/engine/tableWidthUtils.d.ts +7 -0
- package/dist/layout-bridge/engine/tableWidthUtils.js +25 -0
- package/dist/layout-engine/index.d.ts +44 -0
- package/dist/layout-engine/index.js +691 -0
- package/dist/layout-engine/keep-together.d.ts +43 -0
- package/dist/layout-engine/keep-together.js +98 -0
- package/dist/layout-engine/layoutInstrumentation.d.ts +50 -0
- package/dist/layout-engine/layoutInstrumentation.js +43 -0
- package/dist/layout-engine/lineFlow.d.ts +8 -0
- package/dist/layout-engine/lineFlow.js +17 -0
- package/dist/layout-engine/measure/cache.d.ts +93 -0
- package/dist/layout-engine/measure/cache.js +245 -0
- package/dist/layout-engine/measure/clampFloatingWrapMargins.d.ts +20 -0
- package/dist/layout-engine/measure/clampFloatingWrapMargins.js +29 -0
- package/dist/layout-engine/measure/featureFlags.d.ts +44 -0
- package/dist/layout-engine/measure/featureFlags.js +19 -0
- package/dist/layout-engine/measure/floatingZones.d.ts +89 -0
- package/dist/layout-engine/measure/floatingZones.js +152 -0
- package/dist/layout-engine/measure/font-metrics.worker.d.ts +17 -0
- package/dist/layout-engine/measure/font-metrics.worker.js +104 -0
- package/dist/layout-engine/measure/index.d.ts +9 -0
- package/dist/layout-engine/measure/index.js +8 -0
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +40 -0
- package/dist/layout-engine/measure/listMarkerWidth.js +76 -0
- package/dist/layout-engine/measure/measureBlocks.d.ts +25 -0
- package/dist/layout-engine/measure/measureBlocks.js +450 -0
- package/dist/layout-engine/measure/measureContainer.d.ts +24 -0
- package/dist/layout-engine/measure/measureContainer.js +280 -0
- package/dist/layout-engine/measure/measureHelpers.d.ts +82 -0
- package/dist/layout-engine/measure/measureHelpers.js +156 -0
- package/dist/layout-engine/measure/measureParagraph.d.ts +61 -0
- package/dist/layout-engine/measure/measureParagraph.js +724 -0
- package/dist/layout-engine/measure/measureProvider.d.ts +23 -0
- package/dist/layout-engine/measure/measureProvider.js +35 -0
- package/dist/layout-engine/measure/measureTypes.d.ts +61 -0
- package/dist/layout-engine/measure/measureTypes.js +0 -0
- package/dist/layout-engine/measure/measureWorker.d.ts +54 -0
- package/dist/layout-engine/measure/measureWorker.js +249 -0
- package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +88 -0
- package/dist/layout-engine/measure/measureWorkerProtocol.js +20 -0
- package/dist/layout-engine/measure/tableCellFloating.d.ts +26 -0
- package/dist/layout-engine/measure/tableCellFloating.js +99 -0
- package/dist/layout-engine/paginator.d.ts +84 -0
- package/dist/layout-engine/paginator.js +348 -0
- package/dist/layout-engine/paragraphFragmentRange.d.ts +9 -0
- package/dist/layout-engine/paragraphFragmentRange.js +40 -0
- package/dist/layout-engine/section-breaks.d.ts +78 -0
- package/dist/layout-engine/section-breaks.js +182 -0
- package/dist/layout-engine/tableRowBreak.d.ts +23 -0
- package/dist/layout-engine/tableRowBreak.js +147 -0
- package/dist/layout-engine/textBoxFlow.d.ts +50 -0
- package/dist/layout-engine/textBoxFlow.js +160 -0
- package/dist/layout-engine/types.d.ts +1031 -0
- package/dist/layout-engine/types.js +100 -0
- package/dist/layout-painter/documentColors.d.ts +4 -0
- package/dist/layout-painter/documentColors.js +40 -0
- package/dist/layout-painter/index.d.ts +110 -0
- package/dist/layout-painter/index.js +182 -0
- package/dist/layout-painter/registry/modules/image.d.ts +6 -0
- package/dist/layout-painter/registry/modules/image.js +17 -0
- package/dist/layout-painter/registry/modules/paragraph.d.ts +6 -0
- package/dist/layout-painter/registry/modules/paragraph.js +18 -0
- package/dist/layout-painter/registry/modules/table.d.ts +6 -0
- package/dist/layout-painter/registry/modules/table.js +16 -0
- package/dist/layout-painter/registry/modules/textBox.d.ts +6 -0
- package/dist/layout-painter/registry/modules/textBox.js +13 -0
- package/dist/layout-painter/registry/modules.d.ts +6 -0
- package/dist/layout-painter/registry/modules.js +26 -0
- package/dist/layout-painter/registry/registry.d.ts +24 -0
- package/dist/layout-painter/registry/registry.js +53 -0
- package/dist/layout-painter/registry/types.d.ts +61 -0
- package/dist/layout-painter/registry/types.js +0 -0
- package/dist/layout-painter/renderFragment.d.ts +32 -0
- package/dist/layout-painter/renderFragment.js +114 -0
- package/dist/layout-painter/renderImage.d.ts +88 -0
- package/dist/layout-painter/renderImage.js +130 -0
- package/dist/layout-painter/renderPage.d.ts +264 -0
- package/dist/layout-painter/renderPage.js +1795 -0
- package/dist/layout-painter/renderParagraph.d.ts +93 -0
- package/dist/layout-painter/renderParagraph.js +1300 -0
- package/dist/layout-painter/renderTable.d.ts +36 -0
- package/dist/layout-painter/renderTable.js +432 -0
- package/dist/layout-painter/renderTextBox.d.ts +22 -0
- package/dist/layout-painter/renderTextBox.js +67 -0
- package/dist/layout-painter/renderUtils.d.ts +42 -0
- package/dist/layout-painter/renderUtils.js +30 -0
- package/dist/layout-painter/renderWatermark.d.ts +16 -0
- package/dist/layout-painter/renderWatermark.js +61 -0
- package/dist/layout-painter/sdtBoundary.d.ts +6 -0
- package/dist/layout-painter/sdtBoundary.js +28 -0
- package/dist/managers/ContextMenuManager.d.ts +28 -0
- package/dist/managers/ContextMenuManager.js +48 -0
- package/dist/managers/DocumentLoaderManager.d.ts +47 -0
- package/dist/managers/DocumentLoaderManager.js +69 -0
- package/dist/managers/EditorModeManager.d.ts +28 -0
- package/dist/managers/EditorModeManager.js +50 -0
- package/dist/managers/ErrorManager.d.ts +26 -0
- package/dist/managers/ErrorManager.js +85 -0
- package/dist/managers/FindReplaceManager.d.ts +54 -0
- package/dist/managers/FindReplaceManager.js +104 -0
- package/dist/managers/HistoryManager.d.ts +92 -0
- package/dist/managers/HistoryManager.js +193 -0
- package/dist/managers/Subscribable.d.ts +34 -0
- package/dist/managers/Subscribable.js +46 -0
- package/dist/managers/TableSelectionManager.d.ts +74 -0
- package/dist/managers/TableSelectionManager.js +225 -0
- package/dist/managers/editorShortcuts.d.ts +42 -0
- package/dist/managers/editorShortcuts.js +60 -0
- package/dist/managers/types.d.ts +41 -0
- package/dist/managers/types.js +0 -0
- package/dist/markdown/annotations.d.ts +14 -0
- package/dist/markdown/annotations.js +42 -0
- package/dist/markdown/escape.d.ts +36 -0
- package/dist/markdown/escape.js +59 -0
- package/dist/markdown/fromMarkdown.d.ts +11 -0
- package/dist/markdown/fromMarkdown.js +223 -0
- package/dist/markdown/headings.d.ts +13 -0
- package/dist/markdown/headings.js +20 -0
- package/dist/markdown/images.d.ts +13 -0
- package/dist/markdown/images.js +63 -0
- package/dist/markdown/index.d.ts +18 -0
- package/dist/markdown/index.js +33 -0
- package/dist/markdown/internals.d.ts +15 -0
- package/dist/markdown/internals.js +35 -0
- package/dist/markdown/renderBlock.d.ts +7 -0
- package/dist/markdown/renderBlock.js +68 -0
- package/dist/markdown/renderParagraph.d.ts +11 -0
- package/dist/markdown/renderParagraph.js +64 -0
- package/dist/markdown/renderRuns.d.ts +11 -0
- package/dist/markdown/renderRuns.js +265 -0
- package/dist/markdown/renderTable.d.ts +8 -0
- package/dist/markdown/renderTable.js +229 -0
- package/dist/markdown/trailers.d.ts +13 -0
- package/dist/markdown/trailers.js +54 -0
- package/dist/markdown/types.d.ts +118 -0
- package/dist/markdown/types.js +0 -0
- package/dist/model.d.ts +13 -0
- package/dist/model.js +4 -0
- package/dist/paged-layout/LayoutSelectionGate.d.ts +80 -0
- package/dist/paged-layout/LayoutSelectionGate.js +131 -0
- package/dist/paged-layout/headerFooterMargins.d.ts +73 -0
- package/dist/paged-layout/headerFooterMargins.js +120 -0
- package/dist/paged-layout/hiddenEditorScroll.d.ts +4 -0
- package/dist/paged-layout/hiddenEditorScroll.js +4 -0
- package/dist/paged-layout/incrementalMeasure.d.ts +33 -0
- package/dist/paged-layout/incrementalMeasure.js +56 -0
- package/dist/paged-layout/rangeProjection.d.ts +51 -0
- package/dist/paged-layout/rangeProjection.js +153 -0
- package/dist/paged-layout/readOnlyEditAttempt.d.ts +5 -0
- package/dist/paged-layout/readOnlyEditAttempt.js +22 -0
- package/dist/paged-layout/scrollNavigation.d.ts +23 -0
- package/dist/paged-layout/scrollNavigation.js +31 -0
- package/dist/paged-layout/scrollPageInfo.d.ts +41 -0
- package/dist/paged-layout/scrollPageInfo.js +34 -0
- package/dist/paged-layout/scrollToPmPosition.d.ts +17 -0
- package/dist/paged-layout/scrollToPmPosition.js +95 -0
- package/dist/paged-layout/sectionBlockWidths.d.ts +35 -0
- package/dist/paged-layout/sectionBlockWidths.js +52 -0
- package/dist/paged-layout/sectionGeometry.d.ts +21 -0
- package/dist/paged-layout/sectionGeometry.js +36 -0
- package/dist/paged-layout/selectionViewportRect.d.ts +29 -0
- package/dist/paged-layout/selectionViewportRect.js +55 -0
- package/dist/paged-layout/tableColumnResize.d.ts +19 -0
- package/dist/paged-layout/tableColumnResize.js +28 -0
- package/dist/paged-layout/tableInsertButtonGeometry.d.ts +15 -0
- package/dist/paged-layout/tableInsertButtonGeometry.js +15 -0
- package/dist/paged-layout/transactionDirtyRange.d.ts +7 -0
- package/dist/paged-layout/transactionDirtyRange.js +27 -0
- package/dist/paged-layout/zoomScrollAnchor.d.ts +40 -0
- package/dist/paged-layout/zoomScrollAnchor.js +25 -0
- package/dist/prosemirror/attrs/index.d.ts +80 -0
- package/dist/prosemirror/attrs/index.js +1218 -0
- package/dist/prosemirror/autospacingBase.d.ts +11 -0
- package/dist/prosemirror/autospacingBase.js +16 -0
- package/dist/prosemirror/commands/comments.d.ts +93 -0
- package/dist/prosemirror/commands/comments.js +435 -0
- package/dist/prosemirror/commands/contentControls.d.ts +45 -0
- package/dist/prosemirror/commands/contentControls.js +294 -0
- package/dist/prosemirror/commands/contentControlsBlockFill.d.ts +15 -0
- package/dist/prosemirror/commands/contentControlsBlockFill.js +19 -0
- package/dist/prosemirror/commands/formatPainter.d.ts +31 -0
- package/dist/prosemirror/commands/formatPainter.js +130 -0
- package/dist/prosemirror/commands/formatting.d.ts +32 -0
- package/dist/prosemirror/commands/formatting.js +45 -0
- package/dist/prosemirror/commands/hyperlink.d.ts +31 -0
- package/dist/prosemirror/commands/hyperlink.js +79 -0
- package/dist/prosemirror/commands/image.d.ts +59 -0
- package/dist/prosemirror/commands/image.js +219 -0
- package/dist/prosemirror/commands/index.d.ts +13 -0
- package/dist/prosemirror/commands/index.js +13 -0
- package/dist/prosemirror/commands/pageBreak.d.ts +10 -0
- package/dist/prosemirror/commands/pageBreak.js +47 -0
- package/dist/prosemirror/commands/paragraph.d.ts +39 -0
- package/dist/prosemirror/commands/paragraph.js +64 -0
- package/dist/prosemirror/commands/pastePlainText.d.ts +39 -0
- package/dist/prosemirror/commands/pastePlainText.js +67 -0
- package/dist/prosemirror/commands/table.d.ts +83 -0
- package/dist/prosemirror/commands/table.js +105 -0
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +27 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +1550 -0
- package/dist/prosemirror/conversion/index.d.ts +4 -0
- package/dist/prosemirror/conversion/index.js +4 -0
- package/dist/prosemirror/conversion/runShadingMark.d.ts +16 -0
- package/dist/prosemirror/conversion/runShadingMark.js +39 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +39 -0
- package/dist/prosemirror/conversion/toProseDoc.js +1404 -0
- package/dist/prosemirror/extensions/ExtensionManager.d.ts +43 -0
- package/dist/prosemirror/extensions/ExtensionManager.js +86 -0
- package/dist/prosemirror/extensions/StarterKit.d.ts +16 -0
- package/dist/prosemirror/extensions/StarterKit.js +132 -0
- package/dist/prosemirror/extensions/core/DocExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/core/DocExtension.js +12 -0
- package/dist/prosemirror/extensions/core/HistoryExtension.d.ts +13 -0
- package/dist/prosemirror/extensions/core/HistoryExtension.js +28 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +25 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +619 -0
- package/dist/prosemirror/extensions/core/TextExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/core/TextExtension.js +12 -0
- package/dist/prosemirror/extensions/create.d.ts +17 -0
- package/dist/prosemirror/extensions/create.js +129 -0
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +23 -0
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +106 -0
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.d.ts +8 -0
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +172 -0
- package/dist/prosemirror/extensions/features/BidiShortcutExtension.d.ts +16 -0
- package/dist/prosemirror/extensions/features/BidiShortcutExtension.js +38 -0
- package/dist/prosemirror/extensions/features/ContentControlWidgetsExtension.d.ts +16 -0
- package/dist/prosemirror/extensions/features/ContentControlWidgetsExtension.js +21 -0
- package/dist/prosemirror/extensions/features/DropCursorExtension.d.ts +12 -0
- package/dist/prosemirror/extensions/features/DropCursorExtension.js +20 -0
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts +8 -0
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +44 -0
- package/dist/prosemirror/extensions/features/GapCursorExtension.d.ts +19 -0
- package/dist/prosemirror/extensions/features/GapCursorExtension.js +24 -0
- package/dist/prosemirror/extensions/features/ImageDragExtension.d.ts +15 -0
- package/dist/prosemirror/extensions/features/ImageDragExtension.js +66 -0
- package/dist/prosemirror/extensions/features/ImagePasteExtension.d.ts +12 -0
- package/dist/prosemirror/extensions/features/ImagePasteExtension.js +91 -0
- package/dist/prosemirror/extensions/features/ListExtension.d.ts +14 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +340 -0
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +60 -0
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +35 -0
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +188 -0
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +20 -0
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +34 -0
- package/dist/prosemirror/extensions/features/PasteStyleInlinerExtension.d.ts +20 -0
- package/dist/prosemirror/extensions/features/PasteStyleInlinerExtension.js +145 -0
- package/dist/prosemirror/extensions/features/SelectionTrackerExtension.d.ts +10 -0
- package/dist/prosemirror/extensions/features/SelectionTrackerExtension.js +17 -0
- package/dist/prosemirror/extensions/features/bidiShortcutController.d.ts +31 -0
- package/dist/prosemirror/extensions/features/bidiShortcutController.js +27 -0
- package/dist/prosemirror/extensions/features/pasteCleanup.d.ts +31 -0
- package/dist/prosemirror/extensions/features/pasteCleanup.js +159 -0
- package/dist/prosemirror/extensions/marks/AllCapsExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/AllCapsExtension.js +24 -0
- package/dist/prosemirror/extensions/marks/BoldExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/BoldExtension.js +41 -0
- package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.d.ts +14 -0
- package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +64 -0
- package/dist/prosemirror/extensions/marks/CharacterStyleExtension.d.ts +23 -0
- package/dist/prosemirror/extensions/marks/CharacterStyleExtension.js +47 -0
- package/dist/prosemirror/extensions/marks/CommentExtension.d.ts +12 -0
- package/dist/prosemirror/extensions/marks/CommentExtension.js +38 -0
- package/dist/prosemirror/extensions/marks/FontFamilyExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/FontFamilyExtension.js +55 -0
- package/dist/prosemirror/extensions/marks/FontSizeExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/FontSizeExtension.js +47 -0
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.d.ts +11 -0
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +92 -0
- package/dist/prosemirror/extensions/marks/HiddenTextExtension.d.ts +23 -0
- package/dist/prosemirror/extensions/marks/HiddenTextExtension.js +35 -0
- package/dist/prosemirror/extensions/marks/HighlightExtension.d.ts +10 -0
- package/dist/prosemirror/extensions/marks/HighlightExtension.js +115 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.d.ts +13 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +146 -0
- package/dist/prosemirror/extensions/marks/ItalicExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/ItalicExtension.js +34 -0
- package/dist/prosemirror/extensions/marks/RtlExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/marks/RtlExtension.js +21 -0
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +11 -0
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +75 -0
- package/dist/prosemirror/extensions/marks/RunShadingExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/marks/RunShadingExtension.js +38 -0
- package/dist/prosemirror/extensions/marks/SmallCapsExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/SmallCapsExtension.js +24 -0
- package/dist/prosemirror/extensions/marks/StrikeExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/StrikeExtension.js +33 -0
- package/dist/prosemirror/extensions/marks/SubscriptExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/SubscriptExtension.js +25 -0
- package/dist/prosemirror/extensions/marks/SuperscriptExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/SuperscriptExtension.js +25 -0
- package/dist/prosemirror/extensions/marks/TextColorExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +50 -0
- package/dist/prosemirror/extensions/marks/TextEffectExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/marks/TextEffectExtension.js +35 -0
- package/dist/prosemirror/extensions/marks/TextEffectsExtensions.d.ts +31 -0
- package/dist/prosemirror/extensions/marks/TextEffectsExtensions.js +134 -0
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +22 -0
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +113 -0
- package/dist/prosemirror/extensions/marks/UnderlineExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/marks/UnderlineExtension.js +60 -0
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +34 -0
- package/dist/prosemirror/extensions/marks/markUtils.js +233 -0
- package/dist/prosemirror/extensions/nodes/BlockSdtExtension.d.ts +22 -0
- package/dist/prosemirror/extensions/nodes/BlockSdtExtension.js +122 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +12 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +87 -0
- package/dist/prosemirror/extensions/nodes/HardBreakExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +38 -0
- package/dist/prosemirror/extensions/nodes/HorizontalRuleExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/nodes/HorizontalRuleExtension.js +18 -0
- package/dist/prosemirror/extensions/nodes/ImageExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +132 -0
- package/dist/prosemirror/extensions/nodes/MathExtension.d.ts +13 -0
- package/dist/prosemirror/extensions/nodes/MathExtension.js +56 -0
- package/dist/prosemirror/extensions/nodes/PageBreakExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/nodes/PageBreakExtension.js +20 -0
- package/dist/prosemirror/extensions/nodes/SdtExtension.d.ts +12 -0
- package/dist/prosemirror/extensions/nodes/SdtExtension.js +107 -0
- package/dist/prosemirror/extensions/nodes/ShapeExtension.d.ts +30 -0
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +502 -0
- package/dist/prosemirror/extensions/nodes/TabExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/nodes/TabExtension.js +27 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +34 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +1972 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +34 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +150 -0
- package/dist/prosemirror/extensions/types.d.ts +101 -0
- package/dist/prosemirror/extensions/types.js +10 -0
- package/dist/prosemirror/findReplaceSelection.d.ts +23 -0
- package/dist/prosemirror/findReplaceSelection.js +86 -0
- package/dist/prosemirror/index.d.ts +25 -0
- package/dist/prosemirror/index.js +23 -0
- package/dist/prosemirror/insertOperations.d.ts +12 -0
- package/dist/prosemirror/insertOperations.js +19 -0
- package/dist/prosemirror/paragraphDirection.d.ts +42 -0
- package/dist/prosemirror/paragraphDirection.js +33 -0
- package/dist/prosemirror/plugins/aiCitationDecorations.d.ts +40 -0
- package/dist/prosemirror/plugins/aiCitationDecorations.js +90 -0
- package/dist/prosemirror/plugins/aiSuggestionDecorations.d.ts +42 -0
- package/dist/prosemirror/plugins/aiSuggestionDecorations.js +135 -0
- package/dist/prosemirror/plugins/anonymizationDecorations.d.ts +60 -0
- package/dist/prosemirror/plugins/anonymizationDecorations.js +120 -0
- package/dist/prosemirror/plugins/autocompleteSuggestion.d.ts +123 -0
- package/dist/prosemirror/plugins/autocompleteSuggestion.js +283 -0
- package/dist/prosemirror/plugins/contentControlWidgets.d.ts +56 -0
- package/dist/prosemirror/plugins/contentControlWidgets.js +192 -0
- package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +37 -0
- package/dist/prosemirror/plugins/createDocScanPlugin.js +55 -0
- package/dist/prosemirror/plugins/documentStyles.d.ts +18 -0
- package/dist/prosemirror/plugins/documentStyles.js +46 -0
- package/dist/prosemirror/plugins/index.d.ts +3 -0
- package/dist/prosemirror/plugins/index.js +3 -0
- package/dist/prosemirror/plugins/pmTextScan.d.ts +19 -0
- package/dist/prosemirror/plugins/pmTextScan.js +39 -0
- package/dist/prosemirror/plugins/selectionTracker.d.ts +43 -0
- package/dist/prosemirror/plugins/selectionTracker.js +179 -0
- package/dist/prosemirror/plugins/suggestionMode.d.ts +70 -0
- package/dist/prosemirror/plugins/suggestionMode.js +489 -0
- package/dist/prosemirror/plugins/templateDirectives.d.ts +25 -0
- package/dist/prosemirror/plugins/templateDirectives.js +67 -0
- package/dist/prosemirror/plugins/templatePreviewValues.d.ts +49 -0
- package/dist/prosemirror/plugins/templatePreviewValues.js +117 -0
- package/dist/prosemirror/plugins/templateSlashMenu.d.ts +57 -0
- package/dist/prosemirror/plugins/templateSlashMenu.js +184 -0
- package/dist/prosemirror/schema/index.d.ts +15 -0
- package/dist/prosemirror/schema/index.js +20 -0
- package/dist/prosemirror/schema/marks.d.ts +118 -0
- package/dist/prosemirror/schema/marks.js +0 -0
- package/dist/prosemirror/schema/nodes.d.ts +389 -0
- package/dist/prosemirror/schema/nodes.js +0 -0
- package/dist/prosemirror/selectionState.d.ts +23 -0
- package/dist/prosemirror/selectionState.js +111 -0
- package/dist/prosemirror/styles/index.d.ts +2 -0
- package/dist/prosemirror/styles/index.js +2 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +32 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +108 -0
- package/dist/prosemirror/styles/styleResolver.d.ts +94 -0
- package/dist/prosemirror/styles/styleResolver.js +200 -0
- package/dist/prosemirror/utils/findParagraphByParaId.d.ts +26 -0
- package/dist/prosemirror/utils/findParagraphByParaId.js +37 -0
- package/dist/prosemirror/utils/tabCalculator.d.ts +110 -0
- package/dist/prosemirror/utils/tabCalculator.js +137 -0
- package/dist/prosemirror/validation.d.ts +20 -0
- package/dist/prosemirror/validation.js +177 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +6 -0
- package/dist/style-engine/index.d.ts +3 -0
- package/dist/style-engine/index.js +2 -0
- package/dist/style-engine/styleEngine.d.ts +67 -0
- package/dist/style-engine/styleEngine.js +70 -0
- package/dist/types/block-id.d.ts +58 -0
- package/dist/types/block-id.js +61 -0
- package/dist/types/colors.d.ts +2 -0
- package/dist/types/colors.js +0 -0
- package/dist/types/content.d.ts +2 -0
- package/dist/types/content.js +0 -0
- package/dist/types/document.d.ts +7 -0
- package/dist/types/document.js +0 -0
- package/dist/types/documentEnumValues.d.ts +89 -0
- package/dist/types/documentEnumValues.js +693 -0
- package/dist/types/formatting.d.ts +2 -0
- package/dist/types/formatting.js +0 -0
- package/dist/types/index.d.ts +107 -0
- package/dist/types/index.js +0 -0
- package/dist/utils/authorColors.d.ts +16 -0
- package/dist/utils/authorColors.js +30 -0
- package/dist/utils/baseDirection.d.ts +23 -0
- package/dist/utils/baseDirection.js +34 -0
- package/dist/utils/clipboard.d.ts +126 -0
- package/dist/utils/clipboard.js +622 -0
- package/dist/utils/colorResolver.d.ts +158 -0
- package/dist/utils/colorResolver.js +557 -0
- package/dist/utils/createDocument.d.ts +50 -0
- package/dist/utils/createDocument.js +262 -0
- package/dist/utils/documentLoaderBehavior.d.ts +22 -0
- package/dist/utils/documentLoaderBehavior.js +14 -0
- package/dist/utils/docxInput.d.ts +22 -0
- package/dist/utils/docxInput.js +16 -0
- package/dist/utils/domGuards.d.ts +59 -0
- package/dist/utils/domGuards.js +82 -0
- package/dist/utils/fontFamilyMerge.d.ts +7 -0
- package/dist/utils/fontFamilyMerge.js +31 -0
- package/dist/utils/fontLoader.d.ts +50 -0
- package/dist/utils/fontLoader.js +177 -0
- package/dist/utils/fontResolver.d.ts +61 -0
- package/dist/utils/fontResolver.js +651 -0
- package/dist/utils/fontWeights.d.ts +4 -0
- package/dist/utils/fontWeights.js +4 -0
- package/dist/utils/formatToStyle.d.ts +103 -0
- package/dist/utils/formatToStyle.js +289 -0
- package/dist/utils/headerFooter.d.ts +74 -0
- package/dist/utils/headerFooter.js +257 -0
- package/dist/utils/headingCollector.d.ts +22 -0
- package/dist/utils/headingCollector.js +36 -0
- package/dist/utils/hexId.d.ts +33 -0
- package/dist/utils/hexId.js +37 -0
- package/dist/utils/imageValidation.d.ts +5 -0
- package/dist/utils/imageValidation.js +31 -0
- package/dist/utils/paragraphFormattingMerge.d.ts +14 -0
- package/dist/utils/paragraphFormattingMerge.js +68 -0
- package/dist/utils/replaceText.d.ts +17 -0
- package/dist/utils/replaceText.js +161 -0
- package/dist/utils/rotationBoundingBox.d.ts +12 -0
- package/dist/utils/rotationBoundingBox.js +36 -0
- package/dist/utils/scriptSegments.d.ts +36 -0
- package/dist/utils/scriptSegments.js +52 -0
- package/dist/utils/tableOperations.d.ts +87 -0
- package/dist/utils/tableOperations.js +259 -0
- package/dist/utils/textFormattingMerge.d.ts +6 -0
- package/dist/utils/textFormattingMerge.js +31 -0
- package/dist/utils/tiffConverter.d.ts +18 -0
- package/dist/utils/tiffConverter.js +83 -0
- package/dist/utils/units.d.ts +99 -0
- package/dist/utils/units.js +139 -0
- package/dist/utils/urlSecurity.d.ts +7 -0
- package/dist/utils/urlSecurity.js +65 -0
- package/dist/watermark/index.d.ts +39 -0
- package/dist/watermark/index.js +149 -0
- package/package.json +122 -2
|
@@ -0,0 +1,1194 @@
|
|
|
1
|
+
import { applyReplyThreadMarkers } from "./commentReplyMarkers.js";
|
|
2
|
+
import { RELATIONSHIP_TYPES, parseRelationships, resolveRelativePath } from "./relsParser.js";
|
|
3
|
+
import { parseEndnotes, parseFootnotes } from "./footnoteParser.js";
|
|
4
|
+
import { assertValidFolioDocumentModel } from "./modelValidation.js";
|
|
5
|
+
import { parseNumbering } from "./numberingParser.js";
|
|
6
|
+
import { buildPatchedNoteXml, buildPatchedNumberingXml, collectChangedNumberingDefs, collectParaIds, extractParagraphXml } from "./selectiveXmlPatch.js";
|
|
7
|
+
import { escapeXml } from "./serializer/xmlUtils.js";
|
|
8
|
+
import { ensureThreadedCommentParaIds, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
9
|
+
import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
10
|
+
import { serializeHeaderFooter } from "./serializer/headerFooterSerializer.js";
|
|
11
|
+
import { serializeEndnotes, serializeFootnotes } from "./serializer/noteSerializer.js";
|
|
12
|
+
import { serializeNumberingXml } from "./serializer/numberingSerializer.js";
|
|
13
|
+
import { isPreservableDocxEntry } from "./unzip.js";
|
|
14
|
+
import { panic } from "better-result";
|
|
15
|
+
import JSZip from "jszip";
|
|
16
|
+
//#region src/docx/rezip.ts
|
|
17
|
+
/**
|
|
18
|
+
* DOCX Repacker - Repack modified document into valid DOCX
|
|
19
|
+
*
|
|
20
|
+
* Takes a Document with modified content and creates a new DOCX file
|
|
21
|
+
* by updating document.xml while preserving all other files from
|
|
22
|
+
* the original ZIP archive.
|
|
23
|
+
*
|
|
24
|
+
* This ensures round-trip fidelity:
|
|
25
|
+
* - styles.xml, theme1.xml, fontTable.xml remain untouched
|
|
26
|
+
* - Media files preserved
|
|
27
|
+
* - Relationships preserved
|
|
28
|
+
* - Only document.xml is updated with new content
|
|
29
|
+
*
|
|
30
|
+
* OOXML Package Structure:
|
|
31
|
+
* - [Content_Types].xml - Content type declarations
|
|
32
|
+
* - _rels/.rels - Package relationships
|
|
33
|
+
* - word/document.xml - Main document (modified)
|
|
34
|
+
* - word/styles.xml - Styles (preserved)
|
|
35
|
+
* - word/theme/theme1.xml - Theme (preserved)
|
|
36
|
+
* - word/numbering.xml - Numbering (preserved)
|
|
37
|
+
* - word/fontTable.xml - Font table (preserved)
|
|
38
|
+
* - word/settings.xml - Settings (preserved)
|
|
39
|
+
* - word/header*.xml - Headers (preserved)
|
|
40
|
+
* - word/footer*.xml - Footers (preserved)
|
|
41
|
+
* - word/footnotes.xml - Footnotes (preserved)
|
|
42
|
+
* - word/endnotes.xml - Endnotes (preserved)
|
|
43
|
+
* - word/media/* - Media files (preserved)
|
|
44
|
+
* - word/_rels/document.xml.rels - Document relationships (preserved)
|
|
45
|
+
* - docProps/* - Document properties (preserved)
|
|
46
|
+
*/
|
|
47
|
+
var DocxPackageFidelityError = class extends Error {
|
|
48
|
+
constructor(message) {
|
|
49
|
+
super(message);
|
|
50
|
+
this.name = "DocxPackageFidelityError";
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Find the highest rId number in a relationships XML string.
|
|
55
|
+
*/
|
|
56
|
+
function findMaxRId(relsXml) {
|
|
57
|
+
let maxId = 0;
|
|
58
|
+
for (const match of relsXml.matchAll(/Id="rId(?<id>\d+)"/gu)) {
|
|
59
|
+
const id = Number.parseInt(match.groups["id"], 10);
|
|
60
|
+
if (id > maxId) maxId = id;
|
|
61
|
+
}
|
|
62
|
+
return maxId;
|
|
63
|
+
}
|
|
64
|
+
const countDocumentSections = (xml) => Array.from(xml.matchAll(/<w:sectPr\b/gu)).length;
|
|
65
|
+
const extractHeaderFooterReferences = (xml) => {
|
|
66
|
+
const references = [];
|
|
67
|
+
for (const match of xml.matchAll(/<w:(?<element>headerReference|footerReference)\b[^>]*>/gu)) {
|
|
68
|
+
const tag = match[0];
|
|
69
|
+
const type = /\bw:type="(?<type>[^"]+)"/u.exec(tag)?.groups?.["type"] ?? "default";
|
|
70
|
+
const rId = /\br:id="(?<rId>[^"]+)"/u.exec(tag)?.groups?.["rId"];
|
|
71
|
+
const element = match.groups?.["element"];
|
|
72
|
+
if (!rId || element !== "headerReference" && element !== "footerReference") continue;
|
|
73
|
+
references.push({
|
|
74
|
+
element,
|
|
75
|
+
type,
|
|
76
|
+
rId
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return references;
|
|
80
|
+
};
|
|
81
|
+
const hasParsedHeaderFooterPart = (doc, ref) => {
|
|
82
|
+
return (ref.element === "headerReference" ? doc.package.headers : doc.package.footers)?.has(ref.rId) ?? false;
|
|
83
|
+
};
|
|
84
|
+
function assertDocumentPackageFidelity(originalDocumentXml, serializedDocumentXml, doc) {
|
|
85
|
+
const originalSectionCount = countDocumentSections(originalDocumentXml);
|
|
86
|
+
if (countDocumentSections(serializedDocumentXml) < originalSectionCount) throw new DocxPackageFidelityError("Full DOCX repack would drop section properties. Use selective patching instead.");
|
|
87
|
+
const serializedRefs = new Set(extractHeaderFooterReferences(serializedDocumentXml).map((ref) => `${ref.element}:${ref.type}:${ref.rId}`));
|
|
88
|
+
if (extractHeaderFooterReferences(originalDocumentXml).filter((ref) => hasParsedHeaderFooterPart(doc, ref) && !serializedRefs.has(`${ref.element}:${ref.type}:${ref.rId}`)).length > 0) throw new DocxPackageFidelityError("Full DOCX repack would drop header/footer references. Use selective patching instead.");
|
|
89
|
+
}
|
|
90
|
+
async function serializeCommentsToZip(doc, zip, compressionLevel) {
|
|
91
|
+
const comments = doc.package.document.comments ?? [];
|
|
92
|
+
const hadCommentsFile = zip.file("word/comments.xml") !== null;
|
|
93
|
+
if (comments.length === 0 && !hadCommentsFile) return;
|
|
94
|
+
ensureThreadedCommentParaIds(comments);
|
|
95
|
+
const commentsXml = serializeComments(comments);
|
|
96
|
+
zip.file("word/comments.xml", commentsXml, {
|
|
97
|
+
compression: "DEFLATE",
|
|
98
|
+
compressionOptions: { level: compressionLevel }
|
|
99
|
+
});
|
|
100
|
+
await ensureCommentsContentType(zip, compressionLevel);
|
|
101
|
+
await ensureCommentsRelationship(zip, compressionLevel);
|
|
102
|
+
await syncCommentsExtendedPart(comments, zip, compressionLevel);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Bring `word/commentsExtended.xml` and its packaging (content-type override +
|
|
106
|
+
* relationship) in line with the model: write the part when there is thread /
|
|
107
|
+
* resolved state to record, or remove the part AND its override AND its
|
|
108
|
+
* relationship together when there is none. Managing all three consistently
|
|
109
|
+
* keeps the package valid (a dangling override or a relationship pointing at a
|
|
110
|
+
* removed part triggers Word's repair prompt). The reply-thread markers in
|
|
111
|
+
* `document.xml` are synthesized separately (see {@link applyReplyThreadMarkers}).
|
|
112
|
+
*/
|
|
113
|
+
async function syncCommentsExtendedPart(comments, zip, compressionLevel) {
|
|
114
|
+
const xml = serializeCommentsExtended(comments);
|
|
115
|
+
const existing = findZipEntryCaseInsensitive(zip, COMMENTS_EXTENDED_PART_LOWER);
|
|
116
|
+
if (!xml) {
|
|
117
|
+
if (!existing) return;
|
|
118
|
+
zip.remove(existing.name);
|
|
119
|
+
await transformPackagingFile(zip, "[Content_Types].xml", removeCommentsExtendedOverride, compressionLevel);
|
|
120
|
+
await transformPackagingFile(zip, "word/_rels/document.xml.rels", removeCommentsExtendedRelationship, compressionLevel);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
zip.file(existing?.name ?? "word/commentsExtended.xml", xml, {
|
|
124
|
+
compression: "DEFLATE",
|
|
125
|
+
compressionOptions: { level: compressionLevel }
|
|
126
|
+
});
|
|
127
|
+
await transformPackagingFile(zip, "[Content_Types].xml", addCommentsExtendedOverride, compressionLevel);
|
|
128
|
+
await transformPackagingFile(zip, "word/_rels/document.xml.rels", addCommentsExtendedRelationship, compressionLevel);
|
|
129
|
+
}
|
|
130
|
+
/** Read a packaging file, apply a pure transform, and write it back if it changed. */
|
|
131
|
+
async function transformPackagingFile(zip, path, transform, compressionLevel) {
|
|
132
|
+
const file = zip.file(path);
|
|
133
|
+
if (!file) return;
|
|
134
|
+
const xml = await file.async("text");
|
|
135
|
+
const next = transform(xml);
|
|
136
|
+
if (next !== xml) zip.file(path, next, {
|
|
137
|
+
compression: "DEFLATE",
|
|
138
|
+
compressionOptions: { level: compressionLevel }
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function findZipEntryCaseInsensitive(zip, lowerPath) {
|
|
142
|
+
const direct = zip.file(lowerPath);
|
|
143
|
+
if (direct) return direct;
|
|
144
|
+
for (const [path, file] of Object.entries(zip.files)) if (!file.dir && path.toLowerCase() === lowerPath) return file;
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
const EMPTY_RELS_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"></Relationships>";
|
|
148
|
+
function headerFooterFilename(target) {
|
|
149
|
+
return target.startsWith("/") ? target.slice(1) : `word/${target}`;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* The relationships part for a header/footer. A part at `<dir>/<name>` keeps its
|
|
153
|
+
* rels at `<dir>/_rels/<name>.rels` — e.g. `word/headers/header1.xml` ->
|
|
154
|
+
* `word/headers/_rels/header1.xml.rels`, not a flattened `word/_rels/...`.
|
|
155
|
+
*/
|
|
156
|
+
function headerFooterRelsPath(target) {
|
|
157
|
+
const partPath = headerFooterFilename(target);
|
|
158
|
+
const lastSlash = partPath.lastIndexOf("/");
|
|
159
|
+
const directory = lastSlash === -1 ? "" : partPath.slice(0, lastSlash);
|
|
160
|
+
const name = lastSlash === -1 ? partPath : partPath.slice(lastSlash + 1);
|
|
161
|
+
return `${directory ? `${directory}/` : ""}_rels/${name}.rels`;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Express an absolute package path as a relationship target relative to the
|
|
165
|
+
* part at `partPath`. e.g. media `word/media/image1.png` for a part at
|
|
166
|
+
* `word/headers/header2.xml` -> `../media/image1.png` (and `media/image1.png`
|
|
167
|
+
* for a part at the `word/` root). The inverse of `resolveRelativePath`.
|
|
168
|
+
*/
|
|
169
|
+
function relativeTargetForPart(partPath, absoluteTarget) {
|
|
170
|
+
const lastSlash = partPath.lastIndexOf("/");
|
|
171
|
+
const fromDir = lastSlash === -1 ? [] : partPath.slice(0, lastSlash).split("/");
|
|
172
|
+
const to = absoluteTarget.split("/");
|
|
173
|
+
let shared = 0;
|
|
174
|
+
while (shared < fromDir.length && shared < to.length - 1 && fromDir[shared] === to[shared]) shared += 1;
|
|
175
|
+
return `${"../".repeat(fromDir.length - shared)}${to.slice(shared).join("/")}`;
|
|
176
|
+
}
|
|
177
|
+
function collectImageParts(doc) {
|
|
178
|
+
const parts = [{
|
|
179
|
+
relsPath: "word/_rels/document.xml.rels",
|
|
180
|
+
blocks: doc.package.document.content
|
|
181
|
+
}];
|
|
182
|
+
const rels = doc.package.relationships;
|
|
183
|
+
if (!rels) return parts;
|
|
184
|
+
const addHeaderFooterParts = (map, type) => {
|
|
185
|
+
if (!map) return;
|
|
186
|
+
for (const [rId, headerFooter] of map.entries()) {
|
|
187
|
+
const rel = rels.get(rId);
|
|
188
|
+
if (!rel || rel.type !== type || !rel.target) continue;
|
|
189
|
+
parts.push({
|
|
190
|
+
relsPath: headerFooterRelsPath(rel.target),
|
|
191
|
+
blocks: headerFooter.content
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
addHeaderFooterParts(doc.package.headers, RELATIONSHIP_TYPES.header);
|
|
196
|
+
addHeaderFooterParts(doc.package.footers, RELATIONSHIP_TYPES.footer);
|
|
197
|
+
return parts;
|
|
198
|
+
}
|
|
199
|
+
async function readRelsOrStub(zip, relsPath) {
|
|
200
|
+
const file = zip.file(relsPath);
|
|
201
|
+
return (file ? await file.async("text") : EMPTY_RELS_XML).replace(/<Relationships(?<attrs>[^>]*)\/>/u, "<Relationships$<attrs>></Relationships>");
|
|
202
|
+
}
|
|
203
|
+
function findMaxImageNum(zip) {
|
|
204
|
+
let maxImageNum = 0;
|
|
205
|
+
zip.forEach((relativePath) => {
|
|
206
|
+
const m = /^word\/media\/image(?<num>\d+)\./u.exec(relativePath);
|
|
207
|
+
if (m) {
|
|
208
|
+
const num = Number.parseInt(m.groups["num"], 10);
|
|
209
|
+
if (num > maxImageNum) maxImageNum = num;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
return maxImageNum;
|
|
213
|
+
}
|
|
214
|
+
async function registerImageExtensions(zip, extensions, compressionLevel) {
|
|
215
|
+
if (extensions.size === 0) return;
|
|
216
|
+
const ctFile = zip.file("[Content_Types].xml");
|
|
217
|
+
if (!ctFile) return;
|
|
218
|
+
let ctXml = await ctFile.async("text");
|
|
219
|
+
let changed = false;
|
|
220
|
+
for (const ext of extensions) {
|
|
221
|
+
if (ctXml.includes(`Extension="${ext}"`)) continue;
|
|
222
|
+
const contentType = getContentTypeForExtension(ext, "");
|
|
223
|
+
ctXml = ctXml.replace("</Types>", `<Default Extension="${ext}" ContentType="${contentType}"/></Types>`);
|
|
224
|
+
changed = true;
|
|
225
|
+
}
|
|
226
|
+
if (!changed) return;
|
|
227
|
+
zip.file("[Content_Types].xml", ctXml, {
|
|
228
|
+
compression: "DEFLATE",
|
|
229
|
+
compressionOptions: { level: compressionLevel }
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Collect all newly inserted images with data-URL src from the document content.
|
|
234
|
+
* Existing DOCX images may also have a resolved data URL for preview; those must
|
|
235
|
+
* continue to reference their original media part. Editor-created images use a
|
|
236
|
+
* synthetic rId until they are assigned a real DOCX relationship here.
|
|
237
|
+
*/
|
|
238
|
+
const SYNTHETIC_IMAGE_RID_PREFIX = "rId_img_";
|
|
239
|
+
const isNewDataUrlImage = (image) => image.src?.startsWith("data:") && (!image.rId || image.rId.startsWith(SYNTHETIC_IMAGE_RID_PREFIX));
|
|
240
|
+
function collectNewImages(blocks) {
|
|
241
|
+
const images = [];
|
|
242
|
+
const collectFromRun = (run) => {
|
|
243
|
+
for (const c of run.content) if (c.type === "drawing" && c.image && isNewDataUrlImage(c.image)) images.push(c.image);
|
|
244
|
+
};
|
|
245
|
+
for (const block of blocks) if (block.type === "paragraph") {
|
|
246
|
+
for (const item of block.content) if (item.type === "run") collectFromRun(item);
|
|
247
|
+
else if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
|
|
248
|
+
for (const sub of item.content) if (sub.type === "run") collectFromRun(sub);
|
|
249
|
+
}
|
|
250
|
+
} else if (block.type === "table") for (const row of block.rows) for (const cell of row.cells) images.push(...collectNewImages(cell.content));
|
|
251
|
+
return images;
|
|
252
|
+
}
|
|
253
|
+
/** Map MIME type to file extension (inverse of getContentTypeForExtension) */
|
|
254
|
+
const MIME_TO_EXT = {
|
|
255
|
+
"image/png": "png",
|
|
256
|
+
"image/jpeg": "jpeg",
|
|
257
|
+
"image/gif": "gif",
|
|
258
|
+
"image/bmp": "bmp",
|
|
259
|
+
"image/tiff": "tiff",
|
|
260
|
+
"image/webp": "webp",
|
|
261
|
+
"image/svg+xml": "svg"
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Decode a data URL to binary ArrayBuffer and file extension.
|
|
265
|
+
*/
|
|
266
|
+
function decodeDataUrl(dataUrl) {
|
|
267
|
+
const match = /^data:(?<mime>[^;]+);base64,(?<data>.+)$/u.exec(dataUrl);
|
|
268
|
+
if (!match) panic("Invalid data URL");
|
|
269
|
+
const binary = atob(match.groups["data"]);
|
|
270
|
+
const bytes = new Uint8Array(binary.length);
|
|
271
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.codePointAt(i) ?? 0;
|
|
272
|
+
return {
|
|
273
|
+
data: bytes.buffer,
|
|
274
|
+
extension: MIME_TO_EXT[match.groups["mime"]] ?? "png"
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Process newly inserted images: add binary data to ZIP, create relationships,
|
|
279
|
+
* update content types, and rewrite rIds in the document model so the serializer
|
|
280
|
+
* outputs correct references.
|
|
281
|
+
*
|
|
282
|
+
* Mutates the images' rId fields in-place.
|
|
283
|
+
*/
|
|
284
|
+
async function processNewImages(parts, zip, compressionLevel) {
|
|
285
|
+
let maxImageNum = findMaxImageNum(zip);
|
|
286
|
+
const extensionsAdded = /* @__PURE__ */ new Set();
|
|
287
|
+
for (const { relsPath, blocks } of parts) {
|
|
288
|
+
const newImages = collectNewImages(blocks);
|
|
289
|
+
if (newImages.length === 0) continue;
|
|
290
|
+
const relsXml = await readRelsOrStub(zip, relsPath);
|
|
291
|
+
let maxId = findMaxRId(relsXml);
|
|
292
|
+
const relEntries = [];
|
|
293
|
+
const partPath = relsPath.replace("/_rels/", "/").replace(/\.rels$/u, "");
|
|
294
|
+
for (const image of newImages) {
|
|
295
|
+
if (!image.src) continue;
|
|
296
|
+
const { data, extension } = decodeDataUrl(image.src);
|
|
297
|
+
maxImageNum++;
|
|
298
|
+
maxId++;
|
|
299
|
+
const mediaPath = `word/media/${`image${maxImageNum}.${extension}`}`;
|
|
300
|
+
const newRId = `rId${maxId}`;
|
|
301
|
+
zip.file(mediaPath, data, {
|
|
302
|
+
compression: "DEFLATE",
|
|
303
|
+
compressionOptions: { level: compressionLevel }
|
|
304
|
+
});
|
|
305
|
+
relEntries.push(`<Relationship Id="${newRId}" Type="${RELATIONSHIP_TYPES.image}" Target="${escapeXml(relativeTargetForPart(partPath, mediaPath))}"/>`);
|
|
306
|
+
extensionsAdded.add(extension);
|
|
307
|
+
image.rId = newRId;
|
|
308
|
+
}
|
|
309
|
+
if (relEntries.length > 0) {
|
|
310
|
+
const updatedRelsXml = relsXml.replace("</Relationships>", `${relEntries.join("")}</Relationships>`);
|
|
311
|
+
zip.file(relsPath, updatedRelsXml, {
|
|
312
|
+
compression: "DEFLATE",
|
|
313
|
+
compressionOptions: { level: compressionLevel }
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
await registerImageExtensions(zip, extensionsAdded, compressionLevel);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Collect all hyperlinks that have an href but no rId from block content.
|
|
321
|
+
* These are newly created hyperlinks that need relationship entries.
|
|
322
|
+
*/
|
|
323
|
+
function collectHyperlinksWithoutRId(blocks) {
|
|
324
|
+
const hyperlinks = [];
|
|
325
|
+
for (const block of blocks) if (block.type === "paragraph") {
|
|
326
|
+
for (const item of block.content) if (item.type === "hyperlink" && item.href && !item.rId && !item.anchor) hyperlinks.push(item);
|
|
327
|
+
} else if (block.type === "table") for (const row of block.rows) for (const cell of row.cells) hyperlinks.push(...collectHyperlinksWithoutRId(cell.content));
|
|
328
|
+
return hyperlinks;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Process newly created hyperlinks: assign rIds and add relationship entries.
|
|
332
|
+
* Mutates the hyperlinks' rId fields in-place.
|
|
333
|
+
*/
|
|
334
|
+
async function processNewHyperlinks(newHyperlinks, zip, compressionLevel) {
|
|
335
|
+
if (newHyperlinks.length === 0) return;
|
|
336
|
+
const relsPath = "word/_rels/document.xml.rels";
|
|
337
|
+
const relsFile = zip.file(relsPath);
|
|
338
|
+
if (!relsFile) return;
|
|
339
|
+
let relsXml = await relsFile.async("text");
|
|
340
|
+
let maxId = findMaxRId(relsXml);
|
|
341
|
+
const relEntries = [];
|
|
342
|
+
for (const hyperlink of newHyperlinks) {
|
|
343
|
+
maxId++;
|
|
344
|
+
const newRId = `rId${maxId}`;
|
|
345
|
+
if (!hyperlink.href) continue;
|
|
346
|
+
relEntries.push(`<Relationship Id="${newRId}" Type="${RELATIONSHIP_TYPES.hyperlink}" Target="${escapeXml(hyperlink.href)}" TargetMode="External"/>`);
|
|
347
|
+
hyperlink.rId = newRId;
|
|
348
|
+
}
|
|
349
|
+
if (relEntries.length > 0) {
|
|
350
|
+
relsXml = relsXml.replace("</Relationships>", `${relEntries.join("")}</Relationships>`);
|
|
351
|
+
zip.file(relsPath, relsXml, {
|
|
352
|
+
compression: "DEFLATE",
|
|
353
|
+
compressionOptions: { level: compressionLevel }
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Repack a Document into a valid DOCX file
|
|
359
|
+
*
|
|
360
|
+
* @param doc - Document with modified content
|
|
361
|
+
* @param options - Optional repack options
|
|
362
|
+
* @returns Promise resolving to DOCX as ArrayBuffer
|
|
363
|
+
* @throws {Error} if document has no original buffer for round-trip
|
|
364
|
+
*/
|
|
365
|
+
async function repackDocx(doc, options = {}) {
|
|
366
|
+
if (!doc.originalBuffer) panic("Cannot repack document: no original buffer for round-trip. Use createDocx() for new documents.");
|
|
367
|
+
const { compressionLevel = 6, updateModifiedDate = true, modifiedBy } = options;
|
|
368
|
+
const exportDocument = doc;
|
|
369
|
+
const originalZip = await JSZip.loadAsync(doc.originalBuffer);
|
|
370
|
+
const newZip = new JSZip();
|
|
371
|
+
for (const [path, file] of Object.entries(originalZip.files)) {
|
|
372
|
+
if (file.dir) {
|
|
373
|
+
newZip.folder(path.replace(/\/$/u, ""));
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
if (!isPreservableDocxEntry(path)) continue;
|
|
377
|
+
const content = await file.async("arraybuffer");
|
|
378
|
+
newZip.file(path, content, {
|
|
379
|
+
compression: "DEFLATE",
|
|
380
|
+
compressionOptions: { level: compressionLevel }
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
await materializeNewHeaderFooterParts(exportDocument, newZip, compressionLevel);
|
|
384
|
+
await processNewImages(collectImageParts(exportDocument), newZip, compressionLevel);
|
|
385
|
+
await processNewHyperlinks(collectHyperlinksWithoutRId(exportDocument.package.document.content), newZip, compressionLevel);
|
|
386
|
+
assertValidFolioDocumentModel(exportDocument, "Cannot repack invalid DOCX document model");
|
|
387
|
+
applyReplyThreadMarkers(exportDocument);
|
|
388
|
+
const documentXml = serializeDocument(exportDocument);
|
|
389
|
+
const originalDocumentXml = await originalZip.file("word/document.xml")?.async("text");
|
|
390
|
+
if (originalDocumentXml) assertDocumentPackageFidelity(originalDocumentXml, documentXml, exportDocument);
|
|
391
|
+
newZip.file("word/document.xml", documentXml, {
|
|
392
|
+
compression: "DEFLATE",
|
|
393
|
+
compressionOptions: { level: compressionLevel }
|
|
394
|
+
});
|
|
395
|
+
await rebindWatermarkRelIds(exportDocument, newZip, compressionLevel);
|
|
396
|
+
serializeHeadersFootersToZip(exportDocument, newZip, compressionLevel);
|
|
397
|
+
await serializeNotesToZip(exportDocument, originalZip, newZip, compressionLevel);
|
|
398
|
+
await serializeNumberingIntoZip(exportDocument, originalZip, newZip, compressionLevel);
|
|
399
|
+
await serializeCommentsToZip(exportDocument, newZip, compressionLevel);
|
|
400
|
+
if (updateModifiedDate) {
|
|
401
|
+
const corePropsPath = "docProps/core.xml";
|
|
402
|
+
const corePropsFile = originalZip.file(corePropsPath);
|
|
403
|
+
if (corePropsFile) {
|
|
404
|
+
const updatedCoreProps = updateCoreProperties(await corePropsFile.async("text"), {
|
|
405
|
+
updateModifiedDate,
|
|
406
|
+
...modifiedBy !== void 0 ? { modifiedBy } : {}
|
|
407
|
+
});
|
|
408
|
+
newZip.file(corePropsPath, updatedCoreProps, {
|
|
409
|
+
compression: "DEFLATE",
|
|
410
|
+
compressionOptions: { level: compressionLevel }
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return await newZip.generateAsync({
|
|
415
|
+
type: "arraybuffer",
|
|
416
|
+
compression: "DEFLATE",
|
|
417
|
+
compressionOptions: { level: compressionLevel }
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Repack a Document using raw content for more control
|
|
422
|
+
*
|
|
423
|
+
* @param doc - Document with modified content
|
|
424
|
+
* @param rawContent - Original raw content from unzipDocx
|
|
425
|
+
* @param options - Optional repack options
|
|
426
|
+
* @returns Promise resolving to DOCX as ArrayBuffer
|
|
427
|
+
*/
|
|
428
|
+
async function repackDocxFromRaw(doc, rawContent, options = {}) {
|
|
429
|
+
const { compressionLevel = 6, updateModifiedDate = true, modifiedBy } = options;
|
|
430
|
+
const exportDocument = doc;
|
|
431
|
+
const newZip = new JSZip();
|
|
432
|
+
for (const [path, file] of Object.entries(rawContent.originalZip.files)) {
|
|
433
|
+
if (file.dir) {
|
|
434
|
+
newZip.folder(path.replace(/\/$/u, ""));
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
if (!isPreservableDocxEntry(path)) continue;
|
|
438
|
+
const content = await file.async("arraybuffer");
|
|
439
|
+
newZip.file(path, content, {
|
|
440
|
+
compression: "DEFLATE",
|
|
441
|
+
compressionOptions: { level: compressionLevel }
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
await materializeNewHeaderFooterParts(exportDocument, newZip, compressionLevel);
|
|
445
|
+
await processNewImages(collectImageParts(exportDocument), newZip, compressionLevel);
|
|
446
|
+
await processNewHyperlinks(collectHyperlinksWithoutRId(exportDocument.package.document.content), newZip, compressionLevel);
|
|
447
|
+
assertValidFolioDocumentModel(exportDocument, "Cannot repack invalid DOCX document model");
|
|
448
|
+
applyReplyThreadMarkers(exportDocument);
|
|
449
|
+
const documentXml = serializeDocument(exportDocument);
|
|
450
|
+
if (rawContent.documentXml) assertDocumentPackageFidelity(rawContent.documentXml, documentXml, exportDocument);
|
|
451
|
+
newZip.file("word/document.xml", documentXml, {
|
|
452
|
+
compression: "DEFLATE",
|
|
453
|
+
compressionOptions: { level: compressionLevel }
|
|
454
|
+
});
|
|
455
|
+
await rebindWatermarkRelIds(exportDocument, newZip, compressionLevel);
|
|
456
|
+
serializeHeadersFootersToZip(exportDocument, newZip, compressionLevel);
|
|
457
|
+
await serializeNotesToZip(exportDocument, rawContent.originalZip, newZip, compressionLevel);
|
|
458
|
+
await serializeNumberingIntoZip(exportDocument, rawContent.originalZip, newZip, compressionLevel);
|
|
459
|
+
await serializeCommentsToZip(exportDocument, newZip, compressionLevel);
|
|
460
|
+
if (updateModifiedDate && rawContent.corePropsXml) {
|
|
461
|
+
const updatedCoreProps = updateCoreProperties(rawContent.corePropsXml, {
|
|
462
|
+
updateModifiedDate,
|
|
463
|
+
...modifiedBy !== void 0 ? { modifiedBy } : {}
|
|
464
|
+
});
|
|
465
|
+
newZip.file("docProps/core.xml", updatedCoreProps, {
|
|
466
|
+
compression: "DEFLATE",
|
|
467
|
+
compressionOptions: { level: compressionLevel }
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
return await newZip.generateAsync({
|
|
471
|
+
type: "arraybuffer",
|
|
472
|
+
compression: "DEFLATE",
|
|
473
|
+
compressionOptions: { level: compressionLevel }
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
const COMMENTS_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml";
|
|
477
|
+
const COMMENTS_EXTENDED_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml";
|
|
478
|
+
const COMMENTS_EXTENDED_PART = "word/commentsExtended.xml";
|
|
479
|
+
const COMMENTS_EXTENDED_PART_LOWER = "word/commentsextended.xml";
|
|
480
|
+
function addCommentsExtendedOverride(contentTypesXml) {
|
|
481
|
+
if (contentTypesXml.toLowerCase().includes("/word/commentsextended.xml")) return contentTypesXml;
|
|
482
|
+
return contentTypesXml.replace("</Types>", `<Override PartName="/word/commentsExtended.xml" ContentType="${COMMENTS_EXTENDED_CONTENT_TYPE}"/></Types>`);
|
|
483
|
+
}
|
|
484
|
+
function removeCommentsExtendedOverride(contentTypesXml) {
|
|
485
|
+
return contentTypesXml.replace(/<Override\b[^>]*commentsExtended\.xml[^>]*\/>/giu, "");
|
|
486
|
+
}
|
|
487
|
+
function addCommentsExtendedRelationship(relsXml) {
|
|
488
|
+
if (relsXml.toLowerCase().includes("commentsextended.xml")) return relsXml;
|
|
489
|
+
const newRId = `rId${findMaxRId(relsXml) + 1}`;
|
|
490
|
+
return relsXml.replace("</Relationships>", `<Relationship Id="${newRId}" Type="${RELATIONSHIP_TYPES.commentsExtended}" Target="commentsExtended.xml"/></Relationships>`);
|
|
491
|
+
}
|
|
492
|
+
function removeCommentsExtendedRelationship(relsXml) {
|
|
493
|
+
return relsXml.replace(/<Relationship\b[^>]*commentsExtended\.xml[^>]*\/>/giu, "");
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Ensure [Content_Types].xml contains an Override for word/comments.xml.
|
|
497
|
+
* If the document already had comments, this is a no-op.
|
|
498
|
+
*/
|
|
499
|
+
async function ensureCommentsContentType(zip, compressionLevel) {
|
|
500
|
+
const ctFile = zip.file("[Content_Types].xml");
|
|
501
|
+
if (!ctFile) return;
|
|
502
|
+
let ctXml = await ctFile.async("text");
|
|
503
|
+
if (ctXml.includes("/word/comments.xml")) return;
|
|
504
|
+
ctXml = ctXml.replace("</Types>", `<Override PartName="/word/comments.xml" ContentType="${COMMENTS_CONTENT_TYPE}"/></Types>`);
|
|
505
|
+
zip.file("[Content_Types].xml", ctXml, {
|
|
506
|
+
compression: "DEFLATE",
|
|
507
|
+
compressionOptions: { level: compressionLevel }
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Ensure word/_rels/document.xml.rels contains a Relationship for comments.xml.
|
|
512
|
+
* If the document already had comments, this is a no-op.
|
|
513
|
+
*/
|
|
514
|
+
async function ensureCommentsRelationship(zip, compressionLevel) {
|
|
515
|
+
const relsPath = "word/_rels/document.xml.rels";
|
|
516
|
+
const relsFile = zip.file(relsPath);
|
|
517
|
+
if (!relsFile) return;
|
|
518
|
+
let relsXml = await relsFile.async("text");
|
|
519
|
+
if (relsXml.includes("comments.xml")) return;
|
|
520
|
+
const newRId = `rId${findMaxRId(relsXml) + 1}`;
|
|
521
|
+
relsXml = relsXml.replace("</Relationships>", `<Relationship Id="${newRId}" Type="${RELATIONSHIP_TYPES.comments}" Target="comments.xml"/></Relationships>`);
|
|
522
|
+
zip.file(relsPath, relsXml, {
|
|
523
|
+
compression: "DEFLATE",
|
|
524
|
+
compressionOptions: { level: compressionLevel }
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Update only document.xml in a DOCX buffer (minimal changes)
|
|
529
|
+
*
|
|
530
|
+
* @param originalBuffer - Original DOCX as ArrayBuffer
|
|
531
|
+
* @param newDocumentXml - New document.xml content
|
|
532
|
+
* @param options - Optional repack options
|
|
533
|
+
* @returns Promise resolving to DOCX as ArrayBuffer
|
|
534
|
+
*/
|
|
535
|
+
async function updateDocumentXml(originalBuffer, newDocumentXml, options = {}) {
|
|
536
|
+
const { compressionLevel = 6 } = options;
|
|
537
|
+
const zip = await JSZip.loadAsync(originalBuffer);
|
|
538
|
+
zip.file("word/document.xml", newDocumentXml, {
|
|
539
|
+
compression: "DEFLATE",
|
|
540
|
+
compressionOptions: { level: compressionLevel }
|
|
541
|
+
});
|
|
542
|
+
return zip.generateAsync({
|
|
543
|
+
type: "arraybuffer",
|
|
544
|
+
compression: "DEFLATE",
|
|
545
|
+
compressionOptions: { level: compressionLevel }
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Update a specific XML file in a DOCX buffer
|
|
550
|
+
*
|
|
551
|
+
* @param originalBuffer - Original DOCX as ArrayBuffer
|
|
552
|
+
* @param path - Path within the ZIP (e.g., "word/styles.xml")
|
|
553
|
+
* @param content - New XML content
|
|
554
|
+
* @param options - Optional repack options
|
|
555
|
+
* @returns Promise resolving to DOCX as ArrayBuffer
|
|
556
|
+
*/
|
|
557
|
+
async function updateXmlFile(originalBuffer, path, content, options = {}) {
|
|
558
|
+
const { compressionLevel = 6 } = options;
|
|
559
|
+
const zip = await JSZip.loadAsync(originalBuffer);
|
|
560
|
+
zip.file(path, content, {
|
|
561
|
+
compression: "DEFLATE",
|
|
562
|
+
compressionOptions: { level: compressionLevel }
|
|
563
|
+
});
|
|
564
|
+
return zip.generateAsync({
|
|
565
|
+
type: "arraybuffer",
|
|
566
|
+
compression: "DEFLATE",
|
|
567
|
+
compressionOptions: { level: compressionLevel }
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Update multiple files in a DOCX buffer
|
|
572
|
+
*
|
|
573
|
+
* @param originalBuffer - Original DOCX as ArrayBuffer
|
|
574
|
+
* @param updates - Map of path -> content for files to update
|
|
575
|
+
* @param options - Optional repack options
|
|
576
|
+
* @returns Promise resolving to DOCX as ArrayBuffer
|
|
577
|
+
*/
|
|
578
|
+
async function updateMultipleFiles(originalBuffer, updates, options = {}) {
|
|
579
|
+
return applyUpdatesToZip(await JSZip.loadAsync(originalBuffer), updates, options);
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Apply file updates to an already-loaded JSZip instance and generate the output.
|
|
583
|
+
* Use this when the zip is already loaded to avoid a redundant decompression pass.
|
|
584
|
+
*/
|
|
585
|
+
function applyUpdatesToZip(zip, updates, options = {}) {
|
|
586
|
+
const { compressionLevel = 6 } = options;
|
|
587
|
+
for (const [path, content] of updates) zip.file(path, content, {
|
|
588
|
+
compression: "DEFLATE",
|
|
589
|
+
compressionOptions: { level: compressionLevel }
|
|
590
|
+
});
|
|
591
|
+
return zip.generateAsync({
|
|
592
|
+
type: "arraybuffer",
|
|
593
|
+
compression: "DEFLATE",
|
|
594
|
+
compressionOptions: { level: compressionLevel }
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Add a new relationship to document.xml.rels
|
|
599
|
+
*
|
|
600
|
+
* @param originalBuffer - Original DOCX as ArrayBuffer
|
|
601
|
+
* @param relationship - New relationship to add
|
|
602
|
+
* @returns Promise resolving to { buffer: ArrayBuffer, rId: string }
|
|
603
|
+
*/
|
|
604
|
+
async function addRelationship(originalBuffer, relationship) {
|
|
605
|
+
const zip = await JSZip.loadAsync(originalBuffer);
|
|
606
|
+
const relsPath = "word/_rels/document.xml.rels";
|
|
607
|
+
const relsFile = zip.file(relsPath);
|
|
608
|
+
if (!relsFile) panic("document.xml.rels not found in DOCX");
|
|
609
|
+
const relsXml = await relsFile.async("text");
|
|
610
|
+
const newRId = `rId${findMaxRId(relsXml) + 1}`;
|
|
611
|
+
const targetModeAttr = relationship.targetMode === "External" ? " TargetMode=\"External\"" : "";
|
|
612
|
+
const newRelElement = `<Relationship Id="${newRId}" Type="${relationship.type}" Target="${escapeXml(relationship.target)}"${targetModeAttr}/>`;
|
|
613
|
+
const updatedRelsXml = relsXml.replace("</Relationships>", `${newRelElement}</Relationships>`);
|
|
614
|
+
zip.file(relsPath, updatedRelsXml);
|
|
615
|
+
return {
|
|
616
|
+
buffer: await zip.generateAsync({
|
|
617
|
+
type: "arraybuffer",
|
|
618
|
+
compression: "DEFLATE",
|
|
619
|
+
compressionOptions: { level: 6 }
|
|
620
|
+
}),
|
|
621
|
+
rId: newRId
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Add a media file to the DOCX
|
|
626
|
+
*
|
|
627
|
+
* @param originalBuffer - Original DOCX as ArrayBuffer
|
|
628
|
+
* @param filename - Filename for the media (e.g., "image1.png")
|
|
629
|
+
* @param data - Binary data for the media file
|
|
630
|
+
* @param mimeType - MIME type (e.g., "image/png")
|
|
631
|
+
* @returns Promise resolving to { buffer: ArrayBuffer, rId: string, path: string }
|
|
632
|
+
*/
|
|
633
|
+
async function addMedia(originalBuffer, filename, data, mimeType) {
|
|
634
|
+
const zip = await JSZip.loadAsync(originalBuffer);
|
|
635
|
+
const mediaPath = `word/media/${filename}`;
|
|
636
|
+
zip.file(mediaPath, data);
|
|
637
|
+
const relResult = await addRelationship(await zip.generateAsync({ type: "arraybuffer" }), {
|
|
638
|
+
type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
639
|
+
target: `media/${filename}`
|
|
640
|
+
});
|
|
641
|
+
const contentTypesFile = zip.file("[Content_Types].xml");
|
|
642
|
+
if (contentTypesFile) {
|
|
643
|
+
const contentTypesXml = await contentTypesFile.async("text");
|
|
644
|
+
const extension = filename.split(".").pop()?.toLowerCase() || "";
|
|
645
|
+
if (!contentTypesXml.includes(`Extension="${extension}"`) && extension) {
|
|
646
|
+
const extensionElement = `<Default Extension="${extension}" ContentType="${getContentTypeForExtension(extension, mimeType)}"/>`;
|
|
647
|
+
const updatedContentTypes = contentTypesXml.replace("</Types>", `${extensionElement}</Types>`);
|
|
648
|
+
const finalZip = await JSZip.loadAsync(relResult.buffer);
|
|
649
|
+
finalZip.file("[Content_Types].xml", updatedContentTypes);
|
|
650
|
+
return {
|
|
651
|
+
buffer: await finalZip.generateAsync({
|
|
652
|
+
type: "arraybuffer",
|
|
653
|
+
compression: "DEFLATE",
|
|
654
|
+
compressionOptions: { level: 6 }
|
|
655
|
+
}),
|
|
656
|
+
rId: relResult.rId,
|
|
657
|
+
path: mediaPath
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return {
|
|
662
|
+
buffer: relResult.buffer,
|
|
663
|
+
rId: relResult.rId,
|
|
664
|
+
path: mediaPath
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Collect serialized header/footer XML updates from the document model.
|
|
669
|
+
* Uses the relationship map to resolve rId → filename.
|
|
670
|
+
*/
|
|
671
|
+
const HEADER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml";
|
|
672
|
+
const FOOTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml";
|
|
673
|
+
/**
|
|
674
|
+
* A header/footer is "unmaterialized" when it lives in the package map but its
|
|
675
|
+
* rId has no resolvable relationship in `document.xml.rels` — i.e. it was
|
|
676
|
+
* created in memory (header editor, watermark coverage) and still lacks a part,
|
|
677
|
+
* relationship, and `[Content_Types]` entry. The selective fast-path can't
|
|
678
|
+
* register those, so it must bail to a full repack when this returns true.
|
|
679
|
+
*/
|
|
680
|
+
function hasUnmaterializedHeaderFooter(doc) {
|
|
681
|
+
const rels = doc.package.relationships;
|
|
682
|
+
const hasNew = (map, type) => {
|
|
683
|
+
if (!map) return false;
|
|
684
|
+
for (const rId of map.keys()) {
|
|
685
|
+
const rel = rels?.get(rId);
|
|
686
|
+
if (!rel || rel.type !== type || !rel.target) return true;
|
|
687
|
+
}
|
|
688
|
+
return false;
|
|
689
|
+
};
|
|
690
|
+
return hasNew(doc.package.headers, RELATIONSHIP_TYPES.header) || hasNew(doc.package.footers, RELATIONSHIP_TYPES.footer);
|
|
691
|
+
}
|
|
692
|
+
function findMaxHeaderFooterNum(zip, prefix) {
|
|
693
|
+
let max = 0;
|
|
694
|
+
const pattern = new RegExp(`^word/${prefix}(\\d+)\\.xml$`, "u");
|
|
695
|
+
zip.forEach((relativePath) => {
|
|
696
|
+
const m = pattern.exec(relativePath);
|
|
697
|
+
if (m) {
|
|
698
|
+
const num = Number.parseInt(m[1], 10);
|
|
699
|
+
if (num > max) max = num;
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
return max;
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Materialize header/footer parts created in memory (rId present in the package
|
|
706
|
+
* map, absent from `document.xml.rels`). For each: mint a `word/<prefix>N.xml`
|
|
707
|
+
* target, add a document relationship under the *existing* rId (a valid NCName,
|
|
708
|
+
* so the section's `<w:headerReference r:id>` keeps resolving without rewriting
|
|
709
|
+
* document.xml), and a `[Content_Types].xml` Override. The part body is written
|
|
710
|
+
* afterwards by `serializeHeadersFootersToZip`, which can now resolve the new
|
|
711
|
+
* relationship.
|
|
712
|
+
*/
|
|
713
|
+
async function materializeNewHeaderFooterParts(doc, zip, compressionLevel) {
|
|
714
|
+
const rels = doc.package.relationships;
|
|
715
|
+
if (!rels) return;
|
|
716
|
+
if (!hasUnmaterializedHeaderFooter(doc)) return;
|
|
717
|
+
const relEntries = [];
|
|
718
|
+
const overrides = [];
|
|
719
|
+
let maxHeaderNum = findMaxHeaderFooterNum(zip, "header");
|
|
720
|
+
let maxFooterNum = findMaxHeaderFooterNum(zip, "footer");
|
|
721
|
+
let maxRId = 0;
|
|
722
|
+
const considerNumericRId = (id) => {
|
|
723
|
+
const match = /^rId(?<num>\d+)$/u.exec(id);
|
|
724
|
+
if (match) {
|
|
725
|
+
const n = Number.parseInt(match.groups["num"], 10);
|
|
726
|
+
if (n > maxRId) maxRId = n;
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
for (const id of rels.keys()) considerNumericRId(id);
|
|
730
|
+
for (const id of doc.package.headers?.keys() ?? []) considerNumericRId(id);
|
|
731
|
+
for (const id of doc.package.footers?.keys() ?? []) considerNumericRId(id);
|
|
732
|
+
const remapRefs = (refs, oldRId, newRId) => {
|
|
733
|
+
for (const ref of refs ?? []) if (ref.rId === oldRId) ref.rId = newRId;
|
|
734
|
+
};
|
|
735
|
+
const materialize = (map, relType, prefix, contentType, isHeader) => {
|
|
736
|
+
if (!map) return;
|
|
737
|
+
for (const rId of [...map.keys()]) {
|
|
738
|
+
const existing = rels.get(rId);
|
|
739
|
+
if (existing && existing.type === relType && existing.target) continue;
|
|
740
|
+
let effectiveRId = rId;
|
|
741
|
+
if (existing) {
|
|
742
|
+
effectiveRId = `rId${++maxRId}`;
|
|
743
|
+
const headerFooter = map.get(rId);
|
|
744
|
+
if (headerFooter) {
|
|
745
|
+
map.delete(rId);
|
|
746
|
+
map.set(effectiveRId, headerFooter);
|
|
747
|
+
}
|
|
748
|
+
for (const block of doc.package.document.content) if (block.type === "paragraph") remapRefs(isHeader ? block.sectionProperties?.headerReferences : block.sectionProperties?.footerReferences, rId, effectiveRId);
|
|
749
|
+
const finalProps = doc.package.document.finalSectionProperties;
|
|
750
|
+
remapRefs(isHeader ? finalProps?.headerReferences : finalProps?.footerReferences, rId, effectiveRId);
|
|
751
|
+
}
|
|
752
|
+
const filename = `${prefix}${prefix === "header" ? ++maxHeaderNum : ++maxFooterNum}.xml`;
|
|
753
|
+
rels.set(effectiveRId, {
|
|
754
|
+
id: effectiveRId,
|
|
755
|
+
type: relType,
|
|
756
|
+
target: filename
|
|
757
|
+
});
|
|
758
|
+
relEntries.push(`<Relationship Id="${escapeXml(effectiveRId)}" Type="${relType}" Target="${filename}"/>`);
|
|
759
|
+
overrides.push(`<Override PartName="/word/${filename}" ContentType="${contentType}"/>`);
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
materialize(doc.package.headers, RELATIONSHIP_TYPES.header, "header", HEADER_CONTENT_TYPE, true);
|
|
763
|
+
materialize(doc.package.footers, RELATIONSHIP_TYPES.footer, "footer", FOOTER_CONTENT_TYPE, false);
|
|
764
|
+
if (relEntries.length === 0) return;
|
|
765
|
+
const compressionOptions = { level: compressionLevel };
|
|
766
|
+
const relsPath = "word/_rels/document.xml.rels";
|
|
767
|
+
const relsXml = await readRelsOrStub(zip, relsPath);
|
|
768
|
+
zip.file(relsPath, relsXml.replace("</Relationships>", `${relEntries.join("")}</Relationships>`), {
|
|
769
|
+
compression: "DEFLATE",
|
|
770
|
+
compressionOptions
|
|
771
|
+
});
|
|
772
|
+
const ctFile = zip.file("[Content_Types].xml");
|
|
773
|
+
if (ctFile) {
|
|
774
|
+
let ctXml = await ctFile.async("text");
|
|
775
|
+
const missing = overrides.filter((override) => {
|
|
776
|
+
const partName = /PartName="(?<partName>[^"]+)"/u.exec(override)?.groups?.["partName"];
|
|
777
|
+
return partName ? !ctXml.includes(`PartName="${partName}"`) : true;
|
|
778
|
+
});
|
|
779
|
+
if (missing.length > 0) {
|
|
780
|
+
ctXml = ctXml.replace("</Types>", `${missing.join("")}</Types>`);
|
|
781
|
+
zip.file("[Content_Types].xml", ctXml, {
|
|
782
|
+
compression: "DEFLATE",
|
|
783
|
+
compressionOptions
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* A picture watermark is "model-driven" when its raw VML was cleared (so the
|
|
790
|
+
* serializer synthesizes `<v:imagedata r:id>` from `imageRId`). Its image
|
|
791
|
+
* relationship may need rebinding into the header's own rels — work only the
|
|
792
|
+
* full-repack path does — so the selective fast-path bails whenever any such
|
|
793
|
+
* watermark is present, regardless of header count (a single header's rId could
|
|
794
|
+
* have been set without yet resolving in that header's rels).
|
|
795
|
+
*/
|
|
796
|
+
function hasModelDrivenPictureWatermark(doc) {
|
|
797
|
+
const headers = doc.package.headers;
|
|
798
|
+
if (!headers) return false;
|
|
799
|
+
for (const hf of headers.values()) if (hf.watermark?.kind === "picture" && !hf.rawWatermarkXml) return true;
|
|
800
|
+
return false;
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Rebind each picture watermark's `imageRId` so it resolves in its own header
|
|
804
|
+
* part's rels. A watermark propagated across headers (or onto a header created
|
|
805
|
+
* by coverage) carries the source header's rId, which is meaningless in a
|
|
806
|
+
* sibling header's `word/_rels/header*.xml.rels`. Per header: keep the rId if
|
|
807
|
+
* it already resolves; otherwise reuse an existing relationship to the same
|
|
808
|
+
* media target, or mint a new one. The media bytes are shared (preserved from
|
|
809
|
+
* the source), so no new media part is written. Raw-replay watermarks are
|
|
810
|
+
* byte-exact and skipped.
|
|
811
|
+
*/
|
|
812
|
+
async function rebindWatermarkRelIds(doc, zip, compressionLevel) {
|
|
813
|
+
const rels = doc.package.relationships;
|
|
814
|
+
const headers = doc.package.headers;
|
|
815
|
+
if (!rels || !headers) return;
|
|
816
|
+
const pending = [];
|
|
817
|
+
for (const [rId, hf] of headers) {
|
|
818
|
+
const watermark = hf.watermark;
|
|
819
|
+
if (!watermark || watermark.kind !== "picture" || hf.rawWatermarkXml) continue;
|
|
820
|
+
const rel = rels.get(rId);
|
|
821
|
+
if (!rel?.target) continue;
|
|
822
|
+
pending.push({
|
|
823
|
+
watermark,
|
|
824
|
+
relsPath: headerFooterRelsPath(rel.target),
|
|
825
|
+
partPath: headerFooterFilename(rel.target)
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
if (pending.length === 0) return;
|
|
829
|
+
const relsXmlByPath = /* @__PURE__ */ new Map();
|
|
830
|
+
const headerRelsPaths = new Set(pending.map((p) => p.relsPath));
|
|
831
|
+
for (const rel of rels.values()) if (rel.type === RELATIONSHIP_TYPES.header && rel.target) headerRelsPaths.add(headerFooterRelsPath(rel.target));
|
|
832
|
+
for (const relsPath of headerRelsPaths) relsXmlByPath.set(relsPath, await readRelsOrStub(zip, relsPath));
|
|
833
|
+
const relImage = (rel, relsPath) => {
|
|
834
|
+
if (rel?.type !== RELATIONSHIP_TYPES.image || !rel.target) return;
|
|
835
|
+
return rel.targetMode === "External" ? {
|
|
836
|
+
mode: "external",
|
|
837
|
+
url: rel.target
|
|
838
|
+
} : {
|
|
839
|
+
mode: "internal",
|
|
840
|
+
absolute: resolveRelativePath(relsPath, rel.target)
|
|
841
|
+
};
|
|
842
|
+
};
|
|
843
|
+
const sameImage = (a, b) => a.mode === "internal" && b.mode === "internal" ? a.absolute === b.absolute : a.mode === "external" && b.mode === "external" && a.url === b.url;
|
|
844
|
+
const resolveCanonical = (imageRId) => {
|
|
845
|
+
for (const [relsPath, xml] of relsXmlByPath) {
|
|
846
|
+
const canonical = relImage(parseRelationships(xml).get(imageRId), relsPath);
|
|
847
|
+
if (canonical) return canonical;
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
const changedPaths = /* @__PURE__ */ new Set();
|
|
851
|
+
for (const { watermark, relsPath, partPath } of pending) {
|
|
852
|
+
let canonical;
|
|
853
|
+
if (watermark.imageTarget !== void 0) canonical = watermark.imageTargetExternal ? {
|
|
854
|
+
mode: "external",
|
|
855
|
+
url: watermark.imageTarget
|
|
856
|
+
} : {
|
|
857
|
+
mode: "internal",
|
|
858
|
+
absolute: watermark.imageTarget
|
|
859
|
+
};
|
|
860
|
+
else canonical = resolveCanonical(watermark.imageRId);
|
|
861
|
+
if (!canonical) continue;
|
|
862
|
+
const relsXml = relsXmlByPath.get(relsPath) ?? EMPTY_RELS_XML;
|
|
863
|
+
const localRels = parseRelationships(relsXml);
|
|
864
|
+
const local = relImage(localRels.get(watermark.imageRId), relsPath);
|
|
865
|
+
if (local && sameImage(local, canonical)) continue;
|
|
866
|
+
let resolvedRId;
|
|
867
|
+
for (const [id, rel] of localRels) {
|
|
868
|
+
const image = relImage(rel, relsPath);
|
|
869
|
+
if (image && sameImage(image, canonical)) {
|
|
870
|
+
resolvedRId = id;
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
if (!resolvedRId) {
|
|
875
|
+
resolvedRId = `rId${findMaxRId(relsXml) + 1}`;
|
|
876
|
+
const relXml = canonical.mode === "external" ? `<Relationship Id="${resolvedRId}" Type="${RELATIONSHIP_TYPES.image}" Target="${escapeXml(canonical.url)}" TargetMode="External"/>` : `<Relationship Id="${resolvedRId}" Type="${RELATIONSHIP_TYPES.image}" Target="${escapeXml(relativeTargetForPart(partPath, canonical.absolute))}"/>`;
|
|
877
|
+
relsXmlByPath.set(relsPath, relsXml.replace("</Relationships>", `${relXml}</Relationships>`));
|
|
878
|
+
changedPaths.add(relsPath);
|
|
879
|
+
}
|
|
880
|
+
watermark.imageRId = resolvedRId;
|
|
881
|
+
}
|
|
882
|
+
const compressionOptions = { level: compressionLevel };
|
|
883
|
+
for (const path of changedPaths) {
|
|
884
|
+
const xml = relsXmlByPath.get(path);
|
|
885
|
+
if (xml) zip.file(path, xml, {
|
|
886
|
+
compression: "DEFLATE",
|
|
887
|
+
compressionOptions
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
function collectHeaderFooterUpdates(doc) {
|
|
892
|
+
const updates = /* @__PURE__ */ new Map();
|
|
893
|
+
const rels = doc.package.relationships;
|
|
894
|
+
if (!rels) return updates;
|
|
895
|
+
const documentRelsPath = "word/_rels/document.xml.rels";
|
|
896
|
+
const parts = [{
|
|
897
|
+
map: doc.package.headers,
|
|
898
|
+
type: RELATIONSHIP_TYPES.header
|
|
899
|
+
}, {
|
|
900
|
+
map: doc.package.footers,
|
|
901
|
+
type: RELATIONSHIP_TYPES.footer
|
|
902
|
+
}];
|
|
903
|
+
for (const { map, type } of parts) {
|
|
904
|
+
if (!map) continue;
|
|
905
|
+
for (const [rId, headerFooter] of map.entries()) {
|
|
906
|
+
const rel = rels.get(rId);
|
|
907
|
+
if (rel && rel.type === type && rel.target) {
|
|
908
|
+
const filename = resolveRelativePath(documentRelsPath, rel.target);
|
|
909
|
+
updates.set(filename, serializeHeaderFooter(headerFooter));
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
return updates;
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Serialize modified headers and footers into the ZIP
|
|
917
|
+
*/
|
|
918
|
+
function serializeHeadersFootersToZip(doc, zip, compressionLevel) {
|
|
919
|
+
const compressionOptions = { level: compressionLevel };
|
|
920
|
+
for (const [filename, xml] of collectHeaderFooterUpdates(doc)) zip.file(filename, xml, {
|
|
921
|
+
compression: "DEFLATE",
|
|
922
|
+
compressionOptions
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Write edited footnote/endnote bodies into the repacked ZIP.
|
|
927
|
+
*
|
|
928
|
+
* The full repack rebuilds document.xml from the model, but note parts are
|
|
929
|
+
* preserved from the original ZIP: the model only retains the normal notes, so
|
|
930
|
+
* re-emitting the whole part would drop the separator / continuationSeparator
|
|
931
|
+
* notes Word requires. Instead each edited note paragraph is spliced by `paraId`
|
|
932
|
+
* into the ORIGINAL part, so an edited note gets the model content while
|
|
933
|
+
* separators and every unedited note stay byte-exact.
|
|
934
|
+
*
|
|
935
|
+
* Full repack has no change-tracking signal, so "edited" is detected by
|
|
936
|
+
* comparing the current model's note serialization against a BASELINE that
|
|
937
|
+
* re-parses and re-serializes the original part. Both go through the same
|
|
938
|
+
* (lossy) parse+serialize — e.g. the in-note `w:footnoteRef` auto-number mark
|
|
939
|
+
* the model does not represent is dropped on both sides — so an unedited note
|
|
940
|
+
* matches its baseline and is left verbatim (mark intact); only a genuine body
|
|
941
|
+
* edit differs and is spliced.
|
|
942
|
+
*/
|
|
943
|
+
async function serializeNotesToZip(doc, originalZip, newZip, compressionLevel) {
|
|
944
|
+
const footnotes = doc.package.footnotes ?? [];
|
|
945
|
+
if (footnotes.length > 0) await patchNotePartIntoZip("word/footnotes.xml", serializeFootnotes(footnotes), (xml) => serializeFootnotes(parseFootnotes(xml).getNormalFootnotes()), originalZip, newZip, compressionLevel);
|
|
946
|
+
const endnotes = doc.package.endnotes ?? [];
|
|
947
|
+
if (endnotes.length > 0) await patchNotePartIntoZip("word/endnotes.xml", serializeEndnotes(endnotes), (xml) => serializeEndnotes(parseEndnotes(xml).getNormalEndnotes()), originalZip, newZip, compressionLevel);
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Write edited numbering definitions into word/numbering.xml.
|
|
951
|
+
*
|
|
952
|
+
* Like the note parts, numbering.xml is preserved verbatim by the copy loop:
|
|
953
|
+
* the model does not faithfully retain it (abstractNums drop `w:nsid`/`w:tmpl`,
|
|
954
|
+
* custom number formats collapse, level `w:pPr`/`w:rPr` keep only a subset), so
|
|
955
|
+
* re-emitting the whole part would lose those pieces. Instead each edited
|
|
956
|
+
* `w:abstractNum` / `w:num` is spliced by id into the ORIGINAL part.
|
|
957
|
+
*
|
|
958
|
+
* Full repack has no change-tracking signal, so "edited" is detected by
|
|
959
|
+
* comparing the model's numbering serialization against a BASELINE that
|
|
960
|
+
* re-parses and re-serializes the original part. Both go through the same
|
|
961
|
+
* (lossy) parse+serialize, so an unedited definition matches its baseline and
|
|
962
|
+
* is left byte-exact; only a genuine definition edit differs and is spliced.
|
|
963
|
+
*/
|
|
964
|
+
async function serializeNumberingIntoZip(doc, originalZip, newZip, compressionLevel) {
|
|
965
|
+
const numbering = doc.package.numbering;
|
|
966
|
+
if (!numbering || numbering.abstractNums.length === 0 && numbering.nums.length === 0) return;
|
|
967
|
+
const file = findNotePartEntry(originalZip, "word/numbering.xml");
|
|
968
|
+
if (!file) return;
|
|
969
|
+
const originalXml = await file.async("text");
|
|
970
|
+
const baselineXml = serializeNumberingXml(parseNumbering(originalXml).definitions);
|
|
971
|
+
const currentXml = serializeNumberingXml(numbering);
|
|
972
|
+
const changed = collectChangedNumberingDefs(baselineXml, currentXml);
|
|
973
|
+
if (changed.abstractNums.size === 0 && changed.nums.size === 0) return;
|
|
974
|
+
const patched = buildPatchedNumberingXml(originalXml, currentXml, changed);
|
|
975
|
+
if (patched === null) return;
|
|
976
|
+
newZip.file(file.name, patched, {
|
|
977
|
+
compression: "DEFLATE",
|
|
978
|
+
compressionOptions: { level: compressionLevel }
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
async function patchNotePartIntoZip(conventionalLowerPath, currentXml, baselineFrom, originalZip, newZip, compressionLevel) {
|
|
982
|
+
const file = findNotePartEntry(originalZip, conventionalLowerPath);
|
|
983
|
+
if (!file) return;
|
|
984
|
+
const originalXml = await file.async("text");
|
|
985
|
+
const changedIds = collectChangedNoteParaIds(baselineFrom(originalXml), currentXml);
|
|
986
|
+
if (changedIds.size === 0) return;
|
|
987
|
+
const patched = buildPatchedNoteXml(originalXml, currentXml, changedIds);
|
|
988
|
+
if (patched === null) return;
|
|
989
|
+
newZip.file(file.name, patched, {
|
|
990
|
+
compression: "DEFLATE",
|
|
991
|
+
compressionOptions: { level: compressionLevel }
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* The note paragraphs whose current serialization differs from the baseline
|
|
996
|
+
* (re-parsed original) serialization — i.e. the ones actually edited. A
|
|
997
|
+
* paragraph is only considered when its `paraId` resolves uniquely in both,
|
|
998
|
+
* so it can be spliced safely.
|
|
999
|
+
*/
|
|
1000
|
+
function collectChangedNoteParaIds(baselineXml, currentXml) {
|
|
1001
|
+
const changed = /* @__PURE__ */ new Set();
|
|
1002
|
+
const baselineIds = collectParaIds(baselineXml);
|
|
1003
|
+
for (const [id, count] of collectParaIds(currentXml)) {
|
|
1004
|
+
if (count !== 1 || baselineIds.get(id) !== 1) continue;
|
|
1005
|
+
const before = extractParagraphXml(baselineXml, id);
|
|
1006
|
+
const after = extractParagraphXml(currentXml, id);
|
|
1007
|
+
if (before !== null && after !== null && before !== after) changed.add(id);
|
|
1008
|
+
}
|
|
1009
|
+
return changed;
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Locate a note part in the ZIP, matching case-insensitively so a producer that
|
|
1013
|
+
* cased the entry differently still resolves to the existing part.
|
|
1014
|
+
*/
|
|
1015
|
+
function findNotePartEntry(zip, conventionalLowerPath) {
|
|
1016
|
+
const direct = zip.file(conventionalLowerPath);
|
|
1017
|
+
if (direct) return direct;
|
|
1018
|
+
for (const [path, file] of Object.entries(zip.files)) if (!file.dir && path.toLowerCase() === conventionalLowerPath) return file;
|
|
1019
|
+
return null;
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Update core properties XML with new modification date
|
|
1023
|
+
*/
|
|
1024
|
+
function updateCoreProperties(corePropsXml, options) {
|
|
1025
|
+
let result = corePropsXml;
|
|
1026
|
+
if (options.updateModifiedDate) {
|
|
1027
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1028
|
+
if (result.includes("<dcterms:modified")) result = result.replace(/<dcterms:modified[^<>]*>[^<]*<\/dcterms:modified>/u, `<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified>`);
|
|
1029
|
+
else result = result.replace("</cp:coreProperties>", `<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified></cp:coreProperties>`);
|
|
1030
|
+
}
|
|
1031
|
+
if (options.modifiedBy) if (result.includes("<cp:lastModifiedBy")) result = result.replace(/<cp:lastModifiedBy>[^<]*<\/cp:lastModifiedBy>/u, `<cp:lastModifiedBy>${escapeXml(options.modifiedBy)}</cp:lastModifiedBy>`);
|
|
1032
|
+
else result = result.replace("</cp:coreProperties>", `<cp:lastModifiedBy>${escapeXml(options.modifiedBy)}</cp:lastModifiedBy></cp:coreProperties>`);
|
|
1033
|
+
return result;
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Get content type for a file extension
|
|
1037
|
+
*/
|
|
1038
|
+
function getContentTypeForExtension(extension, mimeType) {
|
|
1039
|
+
if (mimeType) return mimeType;
|
|
1040
|
+
return {
|
|
1041
|
+
png: "image/png",
|
|
1042
|
+
jpg: "image/jpeg",
|
|
1043
|
+
jpeg: "image/jpeg",
|
|
1044
|
+
gif: "image/gif",
|
|
1045
|
+
bmp: "image/bmp",
|
|
1046
|
+
tif: "image/tiff",
|
|
1047
|
+
tiff: "image/tiff",
|
|
1048
|
+
svg: "image/svg+xml",
|
|
1049
|
+
webp: "image/webp",
|
|
1050
|
+
wmf: "image/x-wmf",
|
|
1051
|
+
emf: "image/x-emf"
|
|
1052
|
+
}[extension] || "application/octet-stream";
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Validate that a buffer is a valid DOCX file
|
|
1056
|
+
*
|
|
1057
|
+
* @param buffer - Buffer to validate
|
|
1058
|
+
* @returns Promise resolving to validation result
|
|
1059
|
+
*/
|
|
1060
|
+
async function validateDocx(buffer) {
|
|
1061
|
+
const errors = [];
|
|
1062
|
+
const warnings = [];
|
|
1063
|
+
try {
|
|
1064
|
+
const zip = await JSZip.loadAsync(buffer);
|
|
1065
|
+
for (const file of ["[Content_Types].xml", "word/document.xml"]) if (!zip.file(file)) errors.push(`Missing required file: ${file}`);
|
|
1066
|
+
for (const file of [
|
|
1067
|
+
"_rels/.rels",
|
|
1068
|
+
"word/_rels/document.xml.rels",
|
|
1069
|
+
"word/styles.xml"
|
|
1070
|
+
]) if (!zip.file(file)) warnings.push(`Missing recommended file: ${file}`);
|
|
1071
|
+
const docFile = zip.file("word/document.xml");
|
|
1072
|
+
if (docFile) {
|
|
1073
|
+
const docXml = await docFile.async("text");
|
|
1074
|
+
if (!docXml.includes("<?xml")) warnings.push("document.xml missing XML declaration");
|
|
1075
|
+
if (!docXml.includes("<w:document")) errors.push("document.xml missing w:document element");
|
|
1076
|
+
if (!docXml.includes("<w:body>")) errors.push("document.xml missing w:body element");
|
|
1077
|
+
}
|
|
1078
|
+
const ctFile = zip.file("[Content_Types].xml");
|
|
1079
|
+
if (ctFile) {
|
|
1080
|
+
const ctXml = await ctFile.async("text");
|
|
1081
|
+
if (!ctXml.includes("word/document.xml") && !ctXml.includes("application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")) warnings.push("Content_Types.xml may be missing document.xml type declaration");
|
|
1082
|
+
}
|
|
1083
|
+
} catch (error) {
|
|
1084
|
+
errors.push(`Failed to read as ZIP: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1085
|
+
}
|
|
1086
|
+
return {
|
|
1087
|
+
valid: errors.length === 0,
|
|
1088
|
+
errors,
|
|
1089
|
+
warnings
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Check if buffer looks like a DOCX file (quick check)
|
|
1094
|
+
*
|
|
1095
|
+
* @param buffer - Buffer to check
|
|
1096
|
+
* @returns true if buffer starts with ZIP signature
|
|
1097
|
+
*/
|
|
1098
|
+
function isDocxBuffer(buffer) {
|
|
1099
|
+
if (buffer.byteLength < 4) return false;
|
|
1100
|
+
const view = new Uint8Array(buffer);
|
|
1101
|
+
return view[0] === 80 && view[1] === 75;
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Create a new empty DOCX file
|
|
1105
|
+
*
|
|
1106
|
+
* @returns Promise resolving to minimal DOCX as ArrayBuffer
|
|
1107
|
+
*/
|
|
1108
|
+
function createEmptyDocx() {
|
|
1109
|
+
const zip = new JSZip();
|
|
1110
|
+
zip.file("[Content_Types].xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1111
|
+
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
1112
|
+
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
1113
|
+
<Default Extension="xml" ContentType="application/xml"/>
|
|
1114
|
+
<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
|
|
1115
|
+
<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
|
|
1116
|
+
<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
|
|
1117
|
+
<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
|
|
1118
|
+
</Types>`);
|
|
1119
|
+
zip.file("_rels/.rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1120
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
1121
|
+
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
|
1122
|
+
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
|
|
1123
|
+
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
|
|
1124
|
+
</Relationships>`);
|
|
1125
|
+
zip.file("word/_rels/document.xml.rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1126
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
1127
|
+
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
|
|
1128
|
+
</Relationships>`);
|
|
1129
|
+
zip.file("word/document.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1130
|
+
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
1131
|
+
<w:body>
|
|
1132
|
+
<w:p>
|
|
1133
|
+
<w:r>
|
|
1134
|
+
<w:t></w:t>
|
|
1135
|
+
</w:r>
|
|
1136
|
+
</w:p>
|
|
1137
|
+
<w:sectPr>
|
|
1138
|
+
<w:pgSz w:w="12240" w:h="15840"/>
|
|
1139
|
+
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/>
|
|
1140
|
+
</w:sectPr>
|
|
1141
|
+
</w:body>
|
|
1142
|
+
</w:document>`);
|
|
1143
|
+
zip.file("word/styles.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1144
|
+
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
|
1145
|
+
<w:docDefaults>
|
|
1146
|
+
<w:rPrDefault>
|
|
1147
|
+
<w:rPr>
|
|
1148
|
+
<w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/>
|
|
1149
|
+
<w:sz w:val="22"/>
|
|
1150
|
+
</w:rPr>
|
|
1151
|
+
</w:rPrDefault>
|
|
1152
|
+
<w:pPrDefault>
|
|
1153
|
+
<w:pPr>
|
|
1154
|
+
<w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
|
|
1155
|
+
</w:pPr>
|
|
1156
|
+
</w:pPrDefault>
|
|
1157
|
+
</w:docDefaults>
|
|
1158
|
+
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
|
|
1159
|
+
<w:name w:val="Normal"/>
|
|
1160
|
+
</w:style>
|
|
1161
|
+
</w:styles>`);
|
|
1162
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1163
|
+
zip.file("docProps/core.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1164
|
+
<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">
|
|
1165
|
+
<dc:creator>EigenPal DOCX Editor</dc:creator>
|
|
1166
|
+
<dcterms:created xsi:type="dcterms:W3CDTF">${now}</dcterms:created>
|
|
1167
|
+
<dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified>
|
|
1168
|
+
</cp:coreProperties>`);
|
|
1169
|
+
zip.file("docProps/app.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1170
|
+
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">
|
|
1171
|
+
<Application>EigenPal DOCX Editor</Application>
|
|
1172
|
+
<AppVersion>1.0.0</AppVersion>
|
|
1173
|
+
</Properties>`);
|
|
1174
|
+
return zip.generateAsync({
|
|
1175
|
+
type: "arraybuffer",
|
|
1176
|
+
compression: "DEFLATE",
|
|
1177
|
+
compressionOptions: { level: 6 }
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Create a new DOCX from a Document (without requiring original buffer)
|
|
1182
|
+
*
|
|
1183
|
+
* @param doc - Document to serialize
|
|
1184
|
+
* @returns Promise resolving to DOCX as ArrayBuffer
|
|
1185
|
+
*/
|
|
1186
|
+
async function createDocx(doc) {
|
|
1187
|
+
const emptyBuffer = await createEmptyDocx();
|
|
1188
|
+
return repackDocx({
|
|
1189
|
+
...doc,
|
|
1190
|
+
originalBuffer: emptyBuffer
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
//#endregion
|
|
1194
|
+
export { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_CONTENT_TYPE, COMMENTS_EXTENDED_PART, COMMENTS_EXTENDED_PART_LOWER, DocxPackageFidelityError, addCommentsExtendedOverride, addCommentsExtendedRelationship, addMedia, addRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, createDocx, createEmptyDocx, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, isDocxBuffer, removeCommentsExtendedOverride, removeCommentsExtendedRelationship, repackDocx, repackDocxFromRaw, updateCoreProperties, updateDocumentXml, updateMultipleFiles, updateXmlFile, validateDocx };
|