@stll/folio-core 0.52.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/dist/ai-edits/apply.d.ts +26 -1
- package/dist/ai-edits/apply.js +1779 -141
- package/dist/ai-edits/batch-claims.d.ts +145 -0
- package/dist/ai-edits/batch-claims.js +275 -0
- package/dist/ai-edits/blockRange.js +9 -3
- package/dist/ai-edits/character-boundaries.d.ts +43 -0
- package/dist/ai-edits/character-boundaries.js +95 -0
- package/dist/ai-edits/clean-text.d.ts +33 -3
- package/dist/ai-edits/clean-text.js +52 -6
- package/dist/ai-edits/comment-lifecycle.d.ts +18 -0
- package/dist/ai-edits/comment-lifecycle.js +52 -0
- package/dist/ai-edits/headless.d.ts +91 -7
- package/dist/ai-edits/headless.js +520 -51
- package/dist/ai-edits/index.d.ts +2 -1
- package/dist/ai-edits/index.js +2 -1
- package/dist/ai-edits/minimal-replacement.d.ts +21 -6
- package/dist/ai-edits/minimal-replacement.js +134 -15
- package/dist/ai-edits/newListNumbering.d.ts +23 -0
- package/dist/ai-edits/newListNumbering.js +94 -0
- package/dist/ai-edits/note-references.d.ts +96 -0
- package/dist/ai-edits/note-references.js +139 -0
- package/dist/ai-edits/pending-suggestions.d.ts +79 -0
- package/dist/ai-edits/pending-suggestions.js +306 -0
- package/dist/ai-edits/read.d.ts +6 -4
- package/dist/ai-edits/read.js +113 -50
- package/dist/ai-edits/result-validation.d.ts +29 -0
- package/dist/ai-edits/result-validation.js +164 -0
- package/dist/ai-edits/revisionStretches.d.ts +17 -0
- package/dist/ai-edits/revisionStretches.js +80 -0
- package/dist/ai-edits/snapshot.d.ts +36 -3
- package/dist/ai-edits/snapshot.js +180 -25
- package/dist/ai-edits/table-cell-mutations.d.ts +4 -2
- package/dist/ai-edits/table-cell-mutations.js +6 -2
- package/dist/ai-edits/table-geometry.d.ts +1 -1
- package/dist/ai-edits/table-row-column-mutations.d.ts +44 -17
- package/dist/ai-edits/table-row-column-mutations.js +86 -34
- package/dist/ai-edits/types.d.ts +155 -16
- package/dist/compare/compare.d.ts +1 -1
- package/dist/compare/compare.js +65 -16
- package/dist/compare/content-alignment.d.ts +5 -1
- package/dist/compare/content-alignment.js +52 -34
- package/dist/compare/content-types.d.ts +7 -0
- package/dist/compare/content.d.ts +4 -1
- package/dist/compare/content.js +6 -1
- package/dist/compare/formatting.js +2 -1
- package/dist/compare/inline-atoms.d.ts +21 -4
- package/dist/compare/inline-atoms.js +138 -16
- package/dist/compare/inline-provenance.js +1 -1
- package/dist/compare/plan.js +10 -5
- package/dist/compare/scenario.js +14 -3
- package/dist/compare/section-boundary-properties.js +1 -1
- package/dist/compare/types.d.ts +4 -2
- package/dist/compare/types.js +2 -1
- package/dist/compare/verification.d.ts +1 -1
- package/dist/compare/verification.js +15 -3
- package/dist/controller/committedLayoutDiff.d.ts +25 -0
- package/dist/controller/committedLayoutDiff.js +71 -0
- package/dist/controller/contentControlWidgetController.d.ts +1 -1
- package/dist/controller/folioEditor.d.ts +1 -1
- package/dist/controller/fontReadiness.d.ts +70 -3
- package/dist/controller/fontReadiness.js +100 -10
- package/dist/controller/headerFooterEditorManager.js +6 -1
- package/dist/controller/layoutPipeline.d.ts +12 -10
- package/dist/controller/layoutPipeline.js +65 -11
- package/dist/controller/layoutRunOptions.d.ts +24 -0
- package/dist/controller/layoutRunOptions.js +17 -0
- package/dist/controller/layoutScheduler.d.ts +19 -14
- package/dist/controller/layoutScheduler.js +15 -12
- package/dist/controller/layoutSession.d.ts +26 -2
- package/dist/controller/layoutSession.js +1 -1
- package/dist/controller/noteEditorManager.js +8 -3
- package/dist/document-operations.d.ts +11 -2
- package/dist/document-operations.js +230 -21
- package/dist/docx/altChunk.d.ts +8 -0
- package/dist/docx/altChunk.js +17 -0
- package/dist/docx/archiveInflation.d.ts +127 -0
- package/dist/docx/archiveInflation.js +181 -0
- package/dist/docx/attributeRemainder.d.ts +1 -1
- package/dist/docx/blockContentParser.d.ts +64 -1
- package/dist/docx/blockContentParser.js +17 -4
- package/dist/docx/blockCustomXmlShell.d.ts +7 -0
- package/dist/docx/blockCustomXmlShell.js +14 -0
- package/dist/docx/blockPlainText.js +7 -0
- package/dist/docx/commentAnchorIndex.js +1 -1
- package/dist/docx/commentRangeIntegrity.js +8 -3
- package/dist/docx/commentReferenceNormalization.js +1 -1
- package/dist/docx/commentReplyMarkers.js +20 -1
- package/dist/docx/compatibility.d.ts +1 -1
- package/dist/docx/compatibility.js +34 -13
- package/dist/docx/containerChildren.gen.d.ts +1 -1
- package/dist/docx/containerChildren.gen.js +1 -0
- package/dist/docx/documentParser.js +12 -12
- package/dist/docx/drawingIdNormalization.d.ts +3 -1
- package/dist/docx/drawingIdNormalization.js +6 -1
- package/dist/docx/ensureParaIds.js +119 -97
- package/dist/docx/footnoteParser.js +8 -4
- package/dist/docx/headerFooterParser.js +3 -3
- package/dist/docx/headerFooterReferenceNormalization.d.ts +20 -1
- package/dist/docx/headerFooterReferenceNormalization.js +52 -27
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/index.d.ts +1 -1
- package/dist/docx/listNumberingInstances.d.ts +59 -0
- package/dist/docx/listNumberingInstances.js +249 -0
- package/dist/docx/metadataPrivacy.js +24 -1
- package/dist/docx/normalizeBaseDirection.js +2 -1
- package/dist/docx/noteReferenceMark.d.ts +15 -0
- package/dist/docx/noteReferenceMark.js +48 -0
- package/dist/docx/opaqueCarrier.d.ts +7 -0
- package/dist/docx/opaqueCarrier.js +38 -0
- package/dist/docx/packageParts.js +4 -1
- package/dist/docx/paragraphParser.js +96 -27
- package/dist/docx/paragraphPropertySource.d.ts +4 -2
- package/dist/docx/paragraphPropertySource.js +10 -2
- package/dist/docx/paragraphTraversal.js +1 -0
- package/dist/docx/parseWarningMessage.js +4 -1
- package/dist/docx/parser.js +175 -22
- package/dist/docx/rezip.js +31 -7
- package/dist/docx/sdtProperties.js +1 -1
- package/dist/docx/sdtPropertiesPatch.js +3 -0
- package/dist/docx/selectiveSave.js +16 -9
- package/dist/docx/selectiveXmlPatch.d.ts +3 -1
- package/dist/docx/selectiveXmlPatch.js +186 -39
- package/dist/docx/serializer/blockCustomXmlSerializer.d.ts +5 -0
- package/dist/docx/serializer/blockCustomXmlSerializer.js +4 -0
- package/dist/docx/serializer/documentSerializer.js +2 -0
- package/dist/docx/serializer/headerFooterSerializer.js +2 -0
- package/dist/docx/serializer/noteSerializer.js +3 -1
- package/dist/docx/serializer/paragraphSerializer.js +33 -9
- package/dist/docx/serializer/tableSerializer.js +25 -38
- package/dist/docx/server/boundedArchive.d.ts +8 -13
- package/dist/docx/server/boundedArchive.js +70 -59
- package/dist/docx/server/createBilingualDocument.js +3 -3
- package/dist/docx/server/extractDocxText.d.ts +8 -2
- package/dist/docx/server/extractDocxText.js +2 -2
- package/dist/docx/server/validateDocxConformance.d.ts +1 -1
- package/dist/docx/server/validateDocxConformance.js +1 -0
- package/dist/docx/tableParser.d.ts +157 -1
- package/dist/docx/tableParser.js +89 -10
- package/dist/docx/textBoxParser.js +1 -1
- package/dist/docx/unzip.d.ts +20 -2
- package/dist/docx/unzip.js +136 -25
- package/dist/docx/wordprocessingPrefixes.d.ts +78 -0
- package/dist/docx/wordprocessingPrefixes.js +286 -0
- package/dist/fonts/embeddedFonts.js +1 -1
- package/dist/i18n/messages/catalogs.gen.d.ts +170 -34
- package/dist/i18n/messages/catalogs.gen.js +187 -51
- package/dist/i18n/messages/messages.gen.d.ts +10 -2
- package/dist/internal/compare/inline-presentation.d.ts +2 -1
- package/dist/internal/compare/inline-presentation.js +11 -10
- package/dist/internal/headlessRevisionResolutionGuard.d.ts +2 -8
- package/dist/internal/headlessRevisionResolutionGuard.js +2 -11
- package/dist/internal/indexedPositionMap.d.ts +11 -0
- package/dist/internal/indexedPositionMap.js +42 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
- package/dist/internal/revisionResolutionEdits.d.ts +13 -0
- package/dist/internal/revisionResolutionEdits.js +19 -0
- package/dist/internal/revisionResolutionInline.d.ts +24 -0
- package/dist/internal/{headlessRevisionResolution.js → revisionResolutionInline.js} +61 -43
- package/dist/internal/revisionResolutionStep.d.ts +34 -0
- package/dist/internal/revisionResolutionStep.js +282 -0
- package/dist/internal/revisionResolutionTracking.d.ts +11 -0
- package/dist/internal/revisionResolutionTracking.js +124 -0
- package/dist/internal/wholeStoryRevisionResolution.d.ts +56 -0
- package/dist/internal/wholeStoryRevisionResolution.js +600 -0
- package/dist/layout-bridge/convert/markupViewFlow.d.ts +20 -0
- package/dist/layout-bridge/convert/markupViewFlow.js +123 -0
- package/dist/layout-bridge/convert/tableConversion.js +1 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +10 -1
- package/dist/layout-engine/layoutInstrumentation.d.ts +9 -1
- package/dist/layout-engine/layoutInstrumentation.js +4 -1
- package/dist/layout-engine/measure/cache.d.ts +18 -1
- package/dist/layout-engine/measure/cache.js +31 -1
- package/dist/layout-engine/measure/font-metrics.worker.js +3 -7
- package/dist/layout-engine/measure/measureContainer.js +7 -47
- package/dist/layout-engine/measure/measureHelpers.d.ts +6 -1
- package/dist/layout-engine/measure/measureHelpers.js +22 -2
- package/dist/layout-engine/measure/measureParagraph.js +2 -2
- package/dist/layout-engine/measure/measureWorker.js +2 -3
- package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +6 -7
- package/dist/layout-engine/measure/measureWorkerProtocol.js +1 -2
- package/dist/layout-engine/measure/paragraphMeasureShared.d.ts +12 -1
- package/dist/layout-engine/measure/paragraphMeasureShared.js +14 -1
- package/dist/layout-engine/types.d.ts +6 -0
- package/dist/layout-painter/renderPage.js +1 -0
- package/dist/layout-painter/renderParagraph.js +1 -1
- package/dist/managers/ContextMenuManager.js +5 -2
- package/dist/managers/types.d.ts +3 -0
- package/dist/markdown/escape.d.ts +2 -2
- package/dist/markdown/escape.js +4 -5
- package/dist/markdown/fromMarkdown.js +2 -1
- package/dist/markdown/internals.d.ts +11 -1
- package/dist/markdown/internals.js +24 -3
- package/dist/markdown/renderBlock.js +121 -25
- package/dist/markdown/renderParagraph.d.ts +13 -1
- package/dist/markdown/renderParagraph.js +85 -38
- package/dist/markdown/renderRuns.d.ts +10 -1
- package/dist/markdown/renderRuns.js +323 -69
- package/dist/markdown/renderTable.js +24 -12
- package/dist/markdown/trailers.js +2 -2
- package/dist/markdown/types.d.ts +29 -7
- package/dist/paged-layout/incrementalMeasure.d.ts +1 -2
- package/dist/paged-layout/incrementalMeasure.js +1 -9
- package/dist/paged-layout/transactionDirtyRange.d.ts +1 -3
- package/dist/paged-layout/transactionDirtyRange.js +29 -41
- package/dist/panel-layout.d.ts +83 -0
- package/dist/panel-layout.js +96 -0
- package/dist/prosemirror/anchoredTextBoxes.d.ts +37 -0
- package/dist/prosemirror/anchoredTextBoxes.js +156 -0
- package/dist/prosemirror/attrs/index.d.ts +6 -2
- package/dist/prosemirror/attrs/index.js +172 -1
- package/dist/prosemirror/clearRunColor.d.ts +6 -0
- package/dist/prosemirror/clearRunColor.js +46 -0
- package/dist/prosemirror/commands/comments.d.ts +7 -8
- package/dist/prosemirror/commands/comments.js +281 -212
- package/dist/prosemirror/commands/contentControls.d.ts +1 -1
- package/dist/prosemirror/commands/formatPainter.d.ts +1 -1
- package/dist/prosemirror/commands/formatPainter.js +1 -1
- package/dist/prosemirror/commands/formatting.d.ts +1 -1
- package/dist/prosemirror/commands/hyperlink.js +2 -1
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/paragraph.d.ts +7 -1
- package/dist/prosemirror/commands/paragraph.js +9 -1
- package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +13 -0
- package/dist/prosemirror/commands/paragraphBookmarkJoin.js +22 -0
- package/dist/prosemirror/commands/pastePlainText.d.ts +1 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +3 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +24 -3
- package/dist/prosemirror/commands/resolveAllTableChanges.d.ts +40 -0
- package/dist/prosemirror/commands/resolveAllTableChanges.js +620 -0
- package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.d.ts +15 -0
- package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.js +46 -0
- package/dist/prosemirror/commands/resolveParagraphProperties.d.ts +16 -0
- package/dist/prosemirror/commands/resolveParagraphProperties.js +73 -0
- package/dist/prosemirror/commands/sectionBreak.js +2 -1
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +15 -2
- package/dist/prosemirror/commands/tableCellMergeResolution.js +23 -7
- package/dist/prosemirror/containerFinalParagraph.d.ts +11 -5
- package/dist/prosemirror/containerFinalParagraph.js +7 -6
- package/dist/prosemirror/contentControlRevisions.d.ts +1 -1
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
- package/dist/prosemirror/conversion/fromProseDoc.js +177 -605
- package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -11
- package/dist/prosemirror/conversion/toProseDoc.js +70 -154
- package/dist/prosemirror/documentSchema.d.ts +8 -0
- package/dist/prosemirror/documentSchema.js +18 -0
- package/dist/prosemirror/emptyFieldResultRuns.d.ts +18 -0
- package/dist/prosemirror/emptyFieldResultRuns.js +33 -0
- package/dist/prosemirror/extensions/ExtensionManager.d.ts +1 -1
- package/dist/prosemirror/extensions/ExtensionManager.js +3 -1
- package/dist/prosemirror/extensions/StarterKit.js +5 -1
- package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +116 -63
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +4 -1
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +24 -3
- package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.d.ts +20 -0
- package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +43 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +167 -128
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +19 -2
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +33 -20
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +31 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +270 -99
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +3 -2
- package/dist/prosemirror/extensions/features/pasteCleanup.js +2 -1
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +1 -1
- package/dist/prosemirror/extensions/features/pastedHtmlLists.d.ts +12 -0
- package/dist/prosemirror/extensions/features/pastedHtmlLists.js +124 -0
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +33 -11
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +8 -4
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +21 -18
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +37 -17
- package/dist/prosemirror/extensions/marks/StrikeExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/SubscriptExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/SuperscriptExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +15 -8
- package/dist/prosemirror/extensions/marks/markUtils.js +25 -10
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +12 -0
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +46 -0
- package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.js +52 -0
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +2 -2
- package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +3 -3
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +50 -15
- package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +5 -3
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +4 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +121 -226
- package/dist/prosemirror/extensions/types.d.ts +11 -1
- package/dist/prosemirror/findReplaceSelection.js +1 -1
- package/dist/prosemirror/hyperlinkRemoval.d.ts +9 -0
- package/dist/prosemirror/hyperlinkRemoval.js +129 -0
- package/dist/prosemirror/index.d.ts +5 -3
- package/dist/prosemirror/index.js +5 -3
- package/dist/prosemirror/indexedNodeLookup.d.ts +17 -0
- package/dist/prosemirror/indexedNodeLookup.js +103 -0
- package/dist/prosemirror/listAutoformatMarkers.d.ts +19 -0
- package/dist/prosemirror/listAutoformatMarkers.js +98 -0
- package/dist/prosemirror/listInstanceReferences.d.ts +12 -0
- package/dist/prosemirror/listInstanceReferences.js +72 -0
- package/dist/prosemirror/listLabels.d.ts +24 -0
- package/dist/prosemirror/listLabels.js +111 -0
- package/dist/prosemirror/listNumbering.d.ts +92 -0
- package/dist/prosemirror/listNumbering.js +330 -0
- package/dist/prosemirror/listRendering.d.ts +27 -0
- package/dist/prosemirror/listRendering.js +27 -0
- package/dist/prosemirror/listRenderingAttrs.d.ts +11 -2
- package/dist/prosemirror/listRenderingAttrs.js +8 -1
- package/dist/prosemirror/markupViewNotes.d.ts +8 -0
- package/dist/prosemirror/markupViewNotes.js +49 -0
- package/dist/prosemirror/markupViewProjection.d.ts +97 -0
- package/dist/prosemirror/markupViewProjection.js +88 -0
- package/dist/prosemirror/noteReferenceReview.d.ts +77 -0
- package/dist/prosemirror/noteReferenceReview.js +332 -0
- package/dist/prosemirror/numberingAttr.d.ts +9 -1
- package/dist/prosemirror/numberingAttr.js +9 -1
- package/dist/prosemirror/outlineLevelAttr.js +1 -1
- package/dist/prosemirror/paragraphIndentation.d.ts +10 -1
- package/dist/prosemirror/paragraphIndentation.js +32 -7
- package/dist/prosemirror/paragraphMarkJoin.d.ts +21 -0
- package/dist/prosemirror/paragraphMarkJoin.js +26 -0
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +64 -0
- package/dist/prosemirror/paragraphPropertyCarry.js +158 -0
- package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +1 -1
- package/dist/prosemirror/plugins/documentNumbering.d.ts +27 -1
- package/dist/prosemirror/plugins/documentNumbering.js +97 -11
- package/dist/prosemirror/plugins/documentStyleState.d.ts +26 -0
- package/dist/prosemirror/plugins/documentStyleState.js +32 -0
- package/dist/prosemirror/plugins/documentStyles.d.ts +3 -13
- package/dist/prosemirror/plugins/documentStyles.js +67 -17
- package/dist/prosemirror/plugins/index.d.ts +2 -1
- package/dist/prosemirror/plugins/index.js +2 -1
- package/dist/prosemirror/plugins/paragraphStyleResolution.d.ts +15 -0
- package/dist/prosemirror/plugins/paragraphStyleResolution.js +230 -0
- package/dist/prosemirror/plugins/suggestionMode.d.ts +27 -3
- package/dist/prosemirror/plugins/suggestionMode.js +490 -63
- package/dist/prosemirror/plugins/templateDirectives.d.ts +1 -1
- package/dist/prosemirror/plugins/transactionInvariants.d.ts +32 -0
- package/dist/prosemirror/plugins/transactionInvariants.js +86 -0
- package/dist/prosemirror/positionSweep.d.ts +24 -0
- package/dist/prosemirror/positionSweep.js +222 -0
- package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +23 -3
- package/dist/prosemirror/rebaseParagraphRunFormatting.js +39 -13
- package/dist/prosemirror/rebaseParagraphRuns.d.ts +36 -0
- package/dist/prosemirror/rebaseParagraphRuns.js +99 -0
- package/dist/prosemirror/rejoinRunCarriers.d.ts +1 -1
- package/dist/prosemirror/replacedAnnotations.d.ts +33 -1
- package/dist/prosemirror/replacedAnnotations.js +170 -1
- package/dist/prosemirror/runFormattingFromMarks.d.ts +18 -0
- package/dist/prosemirror/runFormattingFromMarks.js +567 -0
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +1 -1
- package/dist/prosemirror/runFormattingReconciliation.js +10 -9
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/index.js +3 -0
- package/dist/prosemirror/schema/nodes.d.ts +44 -11
- package/dist/prosemirror/sectionMarkEdits.d.ts +20 -0
- package/dist/prosemirror/sectionMarkEdits.js +59 -0
- package/dist/prosemirror/storyListNumbering.d.ts +17 -0
- package/dist/prosemirror/storyListNumbering.js +102 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.d.ts +59 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.js +145 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +21 -2
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +38 -1
- package/dist/prosemirror/styles/tableStyleRegions.d.ts +31 -0
- package/dist/prosemirror/styles/tableStyleRegions.js +55 -0
- package/dist/prosemirror/tableCellPaste.d.ts +74 -0
- package/dist/prosemirror/tableCellPaste.js +525 -0
- package/dist/prosemirror/tableGridMutation.d.ts +87 -2
- package/dist/prosemirror/tableGridMutation.js +255 -2
- package/dist/prosemirror/tableRunIn.d.ts +51 -0
- package/dist/prosemirror/tableRunIn.js +165 -0
- package/dist/prosemirror/textInput.js +11 -2
- package/dist/prosemirror/trackedRevisionPath.d.ts +17 -0
- package/dist/prosemirror/trackedRevisionPath.js +32 -0
- package/dist/prosemirror/validation.js +5 -1
- package/dist/redline.js +93 -9
- package/dist/render-dom/BodySelectionOverlay.d.ts +4 -1
- package/dist/render-dom/BodySelectionOverlay.js +3 -2
- package/dist/server.d.ts +2 -2
- package/dist/utils/findReplace.js +2 -2
- package/dist/utils/mergeDocumentContent.js +1 -1
- package/dist/utils/noteReferenceLabels.d.ts +36 -0
- package/dist/utils/noteReferenceLabels.js +32 -0
- package/dist/utils/replaceText.js +1 -1
- package/dist/version-comparison.d.ts +1 -0
- package/dist/version-comparison.js +1 -0
- package/package.json +6 -5
- package/dist/internal/headlessRevisionResolution.d.ts +0 -23
package/dist/docx/rezip.js
CHANGED
|
@@ -26,10 +26,11 @@ import { serializeFontTableXml } from "./serializer/fontTableSerializer.js";
|
|
|
26
26
|
import { serializeHeaderFooter } from "./serializer/headerFooterSerializer.js";
|
|
27
27
|
import { serializeEndnotes, serializeFootnotes, serializeNewEndnotesPart, serializeNewFootnotesPart } from "./serializer/noteSerializer.js";
|
|
28
28
|
import { serializeNumberingXml } from "./serializer/numberingSerializer.js";
|
|
29
|
-
import { readRootNamespaceBindings } from "./serializer/partNamespaces.js";
|
|
29
|
+
import { readRootNamespaceBindings, serializePartElement } from "./serializer/partNamespaces.js";
|
|
30
30
|
import { serializeSettingsXml } from "./serializer/settingsSerializer.js";
|
|
31
31
|
import { serializeStyle, serializeStylesXml } from "./serializer/stylesSerializer.js";
|
|
32
32
|
import { serializeThemeXml } from "./serializer/themeSerializer.js";
|
|
33
|
+
import { hasCanonicalWordprocessingPrefixes } from "./wordprocessingPrefixes.js";
|
|
33
34
|
import { WORDPROCESSINGML_NAMESPACE_URIS, findChild, findChildByNamespaceUri, findChildrenByNamespaceUri, getAttribute, getAttributeByNamespaceUri, getChildElements, getLocalName, getNamespaceUri, matchesName, parseXml, parseXmlDocument } from "./xmlParser.js";
|
|
34
35
|
import { TaggedError, panic } from "better-result";
|
|
35
36
|
import { escapeXmlAttribute, escapeXmlText, validateDocxPackage } from "@stll/docx-core";
|
|
@@ -363,7 +364,7 @@ function collectNewImages(blocks) {
|
|
|
363
364
|
for (const sub of item.content) if (sub.type === "run") collectFromRun(sub);
|
|
364
365
|
}
|
|
365
366
|
} else if (block.type === "table") for (const row of block.rows) for (const cell of row.cells) images.push(...collectNewImages(cell.content));
|
|
366
|
-
else if (block.type === "blockSdt") images.push(...collectNewImages(block.content));
|
|
367
|
+
else if (block.type === "blockSdt" || block.type === "blockCustomXml") images.push(...collectNewImages(block.content));
|
|
367
368
|
return images;
|
|
368
369
|
}
|
|
369
370
|
/** Map MIME type to file extension (inverse of getContentTypeForExtension) */
|
|
@@ -484,7 +485,7 @@ function collectHyperlinksWithoutRId(blocks) {
|
|
|
484
485
|
};
|
|
485
486
|
for (const block of blocks) if (block.type === "paragraph") collectInlineHyperlinks(block.content);
|
|
486
487
|
else if (block.type === "table") for (const row of block.rows) for (const cell of row.cells) hyperlinks.push(...collectHyperlinksWithoutRId(cell.content));
|
|
487
|
-
else if (block.type === "blockSdt") hyperlinks.push(...collectHyperlinksWithoutRId(block.content));
|
|
488
|
+
else if (block.type === "blockSdt" || block.type === "blockCustomXml") hyperlinks.push(...collectHyperlinksWithoutRId(block.content));
|
|
488
489
|
return hyperlinks;
|
|
489
490
|
}
|
|
490
491
|
/** The selective save boundary must use the same resource census as full repack. */
|
|
@@ -1338,7 +1339,8 @@ async function serializeHeadersFootersToZip(doc, zip, compressionLevel) {
|
|
|
1338
1339
|
}
|
|
1339
1340
|
async function serializeNotesToZip({ doc, originalZip, newZip, compressionLevel, changedNoteParaIds }) {
|
|
1340
1341
|
const footnotes = doc.package.footnotes ?? [];
|
|
1341
|
-
|
|
1342
|
+
const originalFootnotes = doc.package.footnotes === void 0 ? null : findNotePartEntry(originalZip, "word/footnotes.xml");
|
|
1343
|
+
if (footnotes.length > 0 || originalFootnotes) if (originalFootnotes) await patchNotePartIntoZip({
|
|
1342
1344
|
conventionalLowerPath: "word/footnotes.xml",
|
|
1343
1345
|
currentXml: serializeFootnotes(footnotes),
|
|
1344
1346
|
replacementXml: serializeNewFootnotesPart(footnotes),
|
|
@@ -1358,7 +1360,8 @@ async function serializeNotesToZip({ doc, originalZip, newZip, compressionLevel,
|
|
|
1358
1360
|
compressionLevel
|
|
1359
1361
|
});
|
|
1360
1362
|
const endnotes = doc.package.endnotes ?? [];
|
|
1361
|
-
|
|
1363
|
+
const originalEndnotes = doc.package.endnotes === void 0 ? null : findNotePartEntry(originalZip, "word/endnotes.xml");
|
|
1364
|
+
if (endnotes.length > 0 || originalEndnotes) if (originalEndnotes) await patchNotePartIntoZip({
|
|
1362
1365
|
conventionalLowerPath: "word/endnotes.xml",
|
|
1363
1366
|
currentXml: serializeEndnotes(endnotes),
|
|
1364
1367
|
replacementXml: serializeNewEndnotesPart(endnotes),
|
|
@@ -1444,6 +1447,25 @@ async function serializeNumberingIntoZip(doc, originalZip, newZip, compressionLe
|
|
|
1444
1447
|
const STYLES_PART_PATH = "word/styles.xml";
|
|
1445
1448
|
const STYLES_CLOSE_ROOT = "</w:styles>";
|
|
1446
1449
|
/**
|
|
1450
|
+
* One serialized element with the namespace declarations its own prefixes
|
|
1451
|
+
* need, for splicing into a part whose root binds them differently (or not
|
|
1452
|
+
* at all). A prefix no table knows throws rather than being written unbound.
|
|
1453
|
+
*/
|
|
1454
|
+
const selfBoundFragment = (fragment, partPath) => {
|
|
1455
|
+
const openEnd = fragment.indexOf(">");
|
|
1456
|
+
const selfClosing = fragment[openEnd - 1] === "/";
|
|
1457
|
+
const rootName = /^<(?<name>[^\s/>]+)/u.exec(fragment)?.groups?.["name"];
|
|
1458
|
+
if (openEnd === -1 || rootName === void 0) throw new DocxPackageFidelityError(`Cannot splice a malformed element into ${partPath}`);
|
|
1459
|
+
return serializePartElement({
|
|
1460
|
+
partPath,
|
|
1461
|
+
rootName,
|
|
1462
|
+
rootAttributes: fragment.slice(rootName.length + 1, selfClosing ? openEnd - 1 : openEnd).trim(),
|
|
1463
|
+
baselinePrefixes: [],
|
|
1464
|
+
sourceBindings: void 0,
|
|
1465
|
+
body: selfClosing ? "" : fragment.slice(openEnd + 1, fragment.lastIndexOf("</"))
|
|
1466
|
+
});
|
|
1467
|
+
};
|
|
1468
|
+
/**
|
|
1447
1469
|
* The style table a package folio creates starts from: `docDefaults` and
|
|
1448
1470
|
* `Normal`, and nothing else. A document that carries its own style table
|
|
1449
1471
|
* replaces this part wholesale.
|
|
@@ -1532,7 +1554,8 @@ async function serializeAddedStylesIntoZip(doc, originalZip, newZip, compression
|
|
|
1532
1554
|
if (!styles || styles.styles.length === 0) return;
|
|
1533
1555
|
const file = findNotePartEntry(originalZip, STYLES_PART_PATH);
|
|
1534
1556
|
const originalXml = file ? await file.async("text") : null;
|
|
1535
|
-
const
|
|
1557
|
+
const rootName = originalXml === null ? void 0 : /<(?![?!])(?<name>[^\s/>]+)/u.exec(originalXml)?.groups?.["name"];
|
|
1558
|
+
const rootClose = originalXml !== null && rootName !== void 0 && getLocalName(rootName) === "styles" ? originalXml.lastIndexOf(`</${rootName}>`) : -1;
|
|
1536
1559
|
if (file === null || originalXml === null || rootClose < 0) {
|
|
1537
1560
|
await materializeNewNotePart({
|
|
1538
1561
|
contentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml",
|
|
@@ -1552,7 +1575,8 @@ async function serializeAddedStylesIntoZip(doc, originalZip, newZip, compression
|
|
|
1552
1575
|
added.push(style);
|
|
1553
1576
|
}
|
|
1554
1577
|
if (added.length === 0) return;
|
|
1555
|
-
const
|
|
1578
|
+
const canonical = hasCanonicalWordprocessingPrefixes(originalXml);
|
|
1579
|
+
const patched = originalXml.slice(0, rootClose) + added.map((style) => canonical ? serializeStyle(style) : selfBoundFragment(serializeStyle(style), file.name)).join("") + originalXml.slice(rootClose);
|
|
1556
1580
|
newZip.file(file.name, patched, {
|
|
1557
1581
|
compression: "DEFLATE",
|
|
1558
1582
|
compressionOptions: { level: compressionLevel }
|
|
@@ -6,7 +6,7 @@ import { WORDPROCESSINGML_NAMESPACE_URIS, findChild, findChildByLocalName, getAt
|
|
|
6
6
|
//#region src/docx/sdtProperties.ts
|
|
7
7
|
function parseListItems(el) {
|
|
8
8
|
const items = [];
|
|
9
|
-
for (const child of el.elements ?? []) if (child.type === "element" && (child.name
|
|
9
|
+
for (const child of el.elements ?? []) if (child.type === "element" && getLocalName(child.name ?? "") === "listItem") {
|
|
10
10
|
const displayText = getAttributeAnyPrefix(child, "displayText");
|
|
11
11
|
const value = getAttributeAnyPrefix(child, "value");
|
|
12
12
|
if (displayText === null && value === null) continue;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OOXML_NAMESPACE_SCOPE, findChild, getAttribute, parseXml } from "./xmlParser.js";
|
|
1
2
|
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
2
3
|
//#region src/docx/sdtPropertiesPatch.ts
|
|
3
4
|
/**
|
|
@@ -66,6 +67,8 @@ const withDateState = (xml, props) => {
|
|
|
66
67
|
const fullDate = props.dateValueISO;
|
|
67
68
|
const format = props.dateFormat;
|
|
68
69
|
if (fullDate === void 0 && format === void 0) return xml;
|
|
70
|
+
const capturedDate = parseXml(xml, OOXML_NAMESPACE_SCOPE).elements?.at(0);
|
|
71
|
+
if ((fullDate === void 0 || getAttribute(capturedDate, "w", "fullDate") === fullDate) && (format === void 0 || getAttribute(findChild(capturedDate, "w", "dateFormat"), "w", "val") === format)) return xml;
|
|
69
72
|
const attributes = (prefix, matched) => fullDate === void 0 ? matched : `${withoutAttr(matched, "fullDate")} ${prefix}:fullDate="${escapeXmlAttribute(fullDate)}"`;
|
|
70
73
|
const formatChild = (prefix) => format === void 0 ? "" : `<${prefix}:dateFormat ${prefix}:val="${escapeXmlAttribute(format)}"/>`;
|
|
71
74
|
const opened = /<(?<prefix>\w+):date\b(?<attrs>[^>]*)>(?<inner>[\s\S]*?)<\/\w+:date>/iu;
|
|
@@ -126,12 +126,15 @@ async function ensureCommentsExtendedPackaging(zip, updates) {
|
|
|
126
126
|
* (`w:nsid`/`w:tmpl`, custom formats, level sub-elements), so only the changed
|
|
127
127
|
* definitions are spliced by id; every other definition stays byte-exact.
|
|
128
128
|
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
129
|
+
* Unchanged numbering leaves the original part untouched. Numbering the
|
|
130
|
+
* splice cannot write (a package without a numbering part, or an edit it
|
|
131
|
+
* cannot split) answers `false`: the paragraphs may reference those
|
|
132
|
+
* definitions, so the caller falls back to a full repack rather than save a
|
|
133
|
+
* package whose `w:numPr` names an instance it does not define.
|
|
131
134
|
*/
|
|
132
135
|
async function patchNumberingPart(zip, doc, updates) {
|
|
133
136
|
const numbering = doc.package.numbering;
|
|
134
|
-
if (!numbering || numbering.abstractNums.length === 0 && numbering.nums.length === 0) return;
|
|
137
|
+
if (!numbering || numbering.abstractNums.length === 0 && numbering.nums.length === 0) return true;
|
|
135
138
|
const conventionalLowerPath = "word/numbering.xml";
|
|
136
139
|
let file = zip.file(conventionalLowerPath);
|
|
137
140
|
if (!file) {
|
|
@@ -140,15 +143,19 @@ async function patchNumberingPart(zip, doc, updates) {
|
|
|
140
143
|
break;
|
|
141
144
|
}
|
|
142
145
|
}
|
|
143
|
-
if (!file) return;
|
|
146
|
+
if (!file) return false;
|
|
144
147
|
const originalXml = await file.async("text");
|
|
148
|
+
const baselineXml = serializeNumberingXml(parseNumbering(originalXml).definitions);
|
|
149
|
+
const currentXml = serializeNumberingXml(numbering);
|
|
150
|
+
if (currentXml === baselineXml) return true;
|
|
145
151
|
const patched = patchNumberingDefinitions({
|
|
146
152
|
originalXml,
|
|
147
|
-
baselineXml
|
|
148
|
-
currentXml
|
|
153
|
+
baselineXml,
|
|
154
|
+
currentXml
|
|
149
155
|
});
|
|
150
|
-
if (patched === null
|
|
151
|
-
updates.set(file.name, patched);
|
|
156
|
+
if (patched === null) return false;
|
|
157
|
+
if (patched !== originalXml) updates.set(file.name, patched);
|
|
158
|
+
return true;
|
|
152
159
|
}
|
|
153
160
|
/**
|
|
154
161
|
* Attempt a selective save — patch only changed paragraphs in document.xml.
|
|
@@ -250,7 +257,7 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
250
257
|
}
|
|
251
258
|
}
|
|
252
259
|
if (!await patchCommentsExtended(zip, commentPlan, updates)) return null;
|
|
253
|
-
await patchNumberingPart(zip, doc, updates);
|
|
260
|
+
if (!await patchNumberingPart(zip, doc, updates)) return null;
|
|
254
261
|
for (const [path, xml] of await collectHeaderFooterUpdates(doc, zip)) updates.set(path, xml);
|
|
255
262
|
await queueSettingsUpdates(zip, updates);
|
|
256
263
|
const corePropsFile = zip.file("docProps/core.xml");
|
|
@@ -165,7 +165,9 @@ type XmlSplice = {
|
|
|
165
165
|
* the rest of the part byte-for-byte, so it can write half a comment range:
|
|
166
166
|
* invalid OOXML that anchors the comment to nothing. Answers null when it
|
|
167
167
|
* would, leaving the caller to rewrite a wider region — ultimately the whole
|
|
168
|
-
* part from the model, which is balanced with itself.
|
|
168
|
+
* part from the model, which is balanced with itself. Overlapping source
|
|
169
|
+
* regions are refused too: replacing an inner region moves the outer region's
|
|
170
|
+
* end, so its original offsets cannot be applied to the resulting string.
|
|
169
171
|
*/
|
|
170
172
|
declare const spliceXml: (xml: string, splices: readonly XmlSplice[]) => string | null;
|
|
171
173
|
type NoteElementName = "footnote" | "endnote";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { patchBreaksCommentRangeBalance } from "./commentRangeIntegrity.js";
|
|
2
2
|
import { resolveParagraphIdentities } from "./paraIdAttribute.js";
|
|
3
3
|
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
4
|
+
import { PARAGRAPH_SCAN_NAMES, hasCanonicalWordprocessingPrefixes, matchCloseTag, matchOpenTag, resolveSelectiveScanPrefixes, splicesAsCanonical } from "./wordprocessingPrefixes.js";
|
|
4
5
|
import { WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, findAttributeByNamespaceUri, getAttributeByNamespaceUri, getChildElements, getLocalName, getNamespacePrefix, getNamespaceUri, parseXmlDocument } from "./xmlParser.js";
|
|
5
6
|
//#region src/docx/selectiveXmlPatch.ts
|
|
6
7
|
/**
|
|
@@ -108,29 +109,6 @@ function buildParagraphOffsetIndex(xml) {
|
|
|
108
109
|
for (const [id, range] of ranges) if (seenCount.get(id) === 1) index.set(id, range);
|
|
109
110
|
return index;
|
|
110
111
|
}
|
|
111
|
-
/** The containers {@link scanParagraphs} tracks, by the literal tag the part writes. */
|
|
112
|
-
const TRACKED_CONTAINERS = [
|
|
113
|
-
{
|
|
114
|
-
name: "mc:Fallback",
|
|
115
|
-
key: "fallback"
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: "mc:AlternateContent",
|
|
119
|
-
key: "alternateContent"
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: "w:txbxContent",
|
|
123
|
-
key: "textBox"
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
name: "w:tc",
|
|
127
|
-
key: "tableCell"
|
|
128
|
-
}
|
|
129
|
-
].map(({ name, key }) => ({
|
|
130
|
-
key,
|
|
131
|
-
open: `<${name}`,
|
|
132
|
-
close: `</${name}>`
|
|
133
|
-
}));
|
|
134
112
|
/**
|
|
135
113
|
* Every `<w:p>` element of `xml`, in the document order of its opening tags,
|
|
136
114
|
* with the `w14:paraId` that tag carries and the containers around it.
|
|
@@ -145,6 +123,8 @@ const TRACKED_CONTAINERS = [
|
|
|
145
123
|
* no splice can be built from it.
|
|
146
124
|
*/
|
|
147
125
|
function scanParagraphs(xml) {
|
|
126
|
+
const resolution = resolveSelectiveScanPrefixes(xml);
|
|
127
|
+
const mcPrefixes = resolution.type === "resolved" ? resolution.prefixes.mc : ["mc"];
|
|
148
128
|
const paragraphs = [];
|
|
149
129
|
const open = [];
|
|
150
130
|
const depth = {
|
|
@@ -153,6 +133,28 @@ function scanParagraphs(xml) {
|
|
|
153
133
|
textBox: 0,
|
|
154
134
|
tableCell: 0
|
|
155
135
|
};
|
|
136
|
+
const containers = [
|
|
137
|
+
{
|
|
138
|
+
key: "fallback",
|
|
139
|
+
prefixes: mcPrefixes,
|
|
140
|
+
name: "Fallback"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
key: "alternateContent",
|
|
144
|
+
prefixes: mcPrefixes,
|
|
145
|
+
name: "AlternateContent"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
key: "textBox",
|
|
149
|
+
prefixes: ["w"],
|
|
150
|
+
name: "txbxContent"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
key: "tableCell",
|
|
154
|
+
prefixes: ["w"],
|
|
155
|
+
name: "tc"
|
|
156
|
+
}
|
|
157
|
+
];
|
|
156
158
|
let pos = 0;
|
|
157
159
|
scan: while (pos < xml.length) {
|
|
158
160
|
const tagStart = xml.indexOf("<", pos);
|
|
@@ -165,13 +167,14 @@ function scanParagraphs(xml) {
|
|
|
165
167
|
pos = end;
|
|
166
168
|
continue;
|
|
167
169
|
}
|
|
168
|
-
for (const { key,
|
|
169
|
-
|
|
170
|
+
for (const { key, prefixes, name } of containers) {
|
|
171
|
+
const closeLength = matchCloseTag(xml, tagStart, prefixes, name);
|
|
172
|
+
if (closeLength !== -1) {
|
|
170
173
|
depth[key] = Math.max(0, depth[key] - 1);
|
|
171
|
-
pos = tagStart +
|
|
174
|
+
pos = tagStart + closeLength;
|
|
172
175
|
continue scan;
|
|
173
176
|
}
|
|
174
|
-
if (xml
|
|
177
|
+
if (matchOpenTag(xml, tagStart, prefixes, name) !== -1) {
|
|
175
178
|
const tagEnd = xml.indexOf(">", tagStart);
|
|
176
179
|
if (tagEnd === -1) break scan;
|
|
177
180
|
if (xml[tagEnd - 1] !== "/") depth[key] += 1;
|
|
@@ -333,10 +336,9 @@ const nearestSharedParaId = (own, other, paragraph, step) => {
|
|
|
333
336
|
* - an id-less paragraph whose story's ordinals do not line up.
|
|
334
337
|
*/
|
|
335
338
|
const routeChangedParagraphs = (originalXml, serializedXml, changedIds) => {
|
|
336
|
-
|
|
337
|
-
if (rootName !== void 0 && !rootName.startsWith("w:")) return {
|
|
339
|
+
if (!splicesAsCanonical(originalXml, PARAGRAPH_SCAN_NAMES)) return {
|
|
338
340
|
type: "refused",
|
|
339
|
-
reason: `non-canonical-wordprocessingml-prefix: ${
|
|
341
|
+
reason: `non-canonical-wordprocessingml-prefix: ${rootElementName(originalXml) ?? "unknown"}`
|
|
340
342
|
};
|
|
341
343
|
const original = addressableParagraphs(originalXml);
|
|
342
344
|
const serialized = addressableParagraphs(serializedXml);
|
|
@@ -423,9 +425,18 @@ const routeChangedParagraphs = (originalXml, serializedXml, changedIds) => {
|
|
|
423
425
|
newXml: authored ? newXml : withoutMintedIds(newXml, sourceXml)
|
|
424
426
|
});
|
|
425
427
|
}
|
|
428
|
+
const candidate = spliceXml(originalXml, splices);
|
|
429
|
+
if (candidate === null) return {
|
|
430
|
+
type: "refused",
|
|
431
|
+
reason: "unsafe-paragraph-splices"
|
|
432
|
+
};
|
|
433
|
+
if (!splicesAsCanonical(candidate, PARAGRAPH_SCAN_NAMES)) return {
|
|
434
|
+
type: "refused",
|
|
435
|
+
reason: "replacement-namespace-conflict"
|
|
436
|
+
};
|
|
426
437
|
return {
|
|
427
438
|
type: "routed",
|
|
428
|
-
|
|
439
|
+
xml: candidate
|
|
429
440
|
};
|
|
430
441
|
};
|
|
431
442
|
/**
|
|
@@ -459,7 +470,7 @@ function validatePatchSafety(originalXml, serializedXml, changedIds) {
|
|
|
459
470
|
function buildPatchedDocumentXml(originalXml, serializedXml, changedIds) {
|
|
460
471
|
if (changedIds.size === 0) return originalXml;
|
|
461
472
|
const routing = routeChangedParagraphs(originalXml, serializedXml, changedIds);
|
|
462
|
-
return routing.type === "refused" ? null :
|
|
473
|
+
return routing.type === "refused" ? null : routing.xml;
|
|
463
474
|
}
|
|
464
475
|
/**
|
|
465
476
|
* Build a patched note part (word/footnotes.xml / word/endnotes.xml) by
|
|
@@ -489,11 +500,18 @@ function buildPatchedNoteXml(originalXml, serializedXml, changedIds) {
|
|
|
489
500
|
* the rest of the part byte-for-byte, so it can write half a comment range:
|
|
490
501
|
* invalid OOXML that anchors the comment to nothing. Answers null when it
|
|
491
502
|
* would, leaving the caller to rewrite a wider region — ultimately the whole
|
|
492
|
-
* part from the model, which is balanced with itself.
|
|
503
|
+
* part from the model, which is balanced with itself. Overlapping source
|
|
504
|
+
* regions are refused too: replacing an inner region moves the outer region's
|
|
505
|
+
* end, so its original offsets cannot be applied to the resulting string.
|
|
493
506
|
*/
|
|
494
507
|
const spliceXml = (xml, splices) => {
|
|
495
508
|
let result = xml;
|
|
496
|
-
|
|
509
|
+
let unpatchedEnd = xml.length;
|
|
510
|
+
for (const { start, end, newXml } of [...splices].toSorted((a, b) => b.start - a.start)) {
|
|
511
|
+
if (end > unpatchedEnd) return null;
|
|
512
|
+
result = result.slice(0, start) + newXml + result.slice(end);
|
|
513
|
+
unpatchedEnd = start;
|
|
514
|
+
}
|
|
497
515
|
return patchBreaksCommentRangeBalance(xml, result) ? null : result;
|
|
498
516
|
};
|
|
499
517
|
/**
|
|
@@ -647,6 +665,40 @@ const paragraphRanges = (xml, wordPrefix) => {
|
|
|
647
665
|
}
|
|
648
666
|
return ranges;
|
|
649
667
|
};
|
|
668
|
+
const OPENING_PARA_ID = /^<[^>]*?\sw14:paraId="(?<id>[^"]*)"/u;
|
|
669
|
+
const openingParaId = (paragraph) => OPENING_PARA_ID.exec(paragraph)?.groups?.["id"];
|
|
670
|
+
/** A note's XML outside its paragraphs, one entry per gap between them. */
|
|
671
|
+
const noteGaps = (note, ranges) => {
|
|
672
|
+
const gaps = [];
|
|
673
|
+
let cursor = 0;
|
|
674
|
+
for (const range of ranges) {
|
|
675
|
+
gaps.push(note.slice(cursor, range.start));
|
|
676
|
+
cursor = range.end;
|
|
677
|
+
}
|
|
678
|
+
gaps.push(note.slice(cursor));
|
|
679
|
+
return gaps;
|
|
680
|
+
};
|
|
681
|
+
/**
|
|
682
|
+
* Whether a note's block structure differs between two serializations of it:
|
|
683
|
+
* a paragraph added, removed or replaced by another, or anything written
|
|
684
|
+
* between paragraphs changed — a table, a row, a cell's properties, a
|
|
685
|
+
* row-level revision. Paragraph-by-paragraph splicing pairs paragraphs by
|
|
686
|
+
* ordinal, so it is only faithful when neither happened; a note whose shape
|
|
687
|
+
* changed is rewritten whole. A paragraph the baseline has no id for pairs
|
|
688
|
+
* with any id, because that id was minted after reading, not changed.
|
|
689
|
+
*/
|
|
690
|
+
const noteShapeChanged = (baseline, current) => {
|
|
691
|
+
const baselineRanges = paragraphRanges(baseline.note, baseline.prefix);
|
|
692
|
+
const currentRanges = paragraphRanges(current.note, current.prefix);
|
|
693
|
+
if (baselineRanges.length !== currentRanges.length) return true;
|
|
694
|
+
const currentGaps = noteGaps(current.note, currentRanges);
|
|
695
|
+
if (noteGaps(baseline.note, baselineRanges).some((gap, index) => gap !== currentGaps[index])) return true;
|
|
696
|
+
return baselineRanges.some((range, index) => {
|
|
697
|
+
const baselineId = openingParaId(baseline.note.slice(range.start, range.end));
|
|
698
|
+
const currentRange = currentRanges[index];
|
|
699
|
+
return baselineId !== void 0 && baselineId !== openingParaId(current.note.slice(currentRange.start, currentRange.end));
|
|
700
|
+
});
|
|
701
|
+
};
|
|
650
702
|
const collectChangedNoteParaIds = (baselineXml, currentXml) => {
|
|
651
703
|
const changed = /* @__PURE__ */ new Set();
|
|
652
704
|
const baselineIds = collectParaIds(baselineXml);
|
|
@@ -681,6 +733,7 @@ const collectChangedNoteParaIds = (baselineXml, currentXml) => {
|
|
|
681
733
|
*/
|
|
682
734
|
function buildPatchedNotePartXml({ originalXml, baselineXml, serializedXml, replacementXml, elementName, changedParaIds }) {
|
|
683
735
|
const currentElements = collectNoteElementSyntax(serializedXml, elementName);
|
|
736
|
+
const baselineElements = collectNoteElementSyntax(baselineXml, elementName);
|
|
684
737
|
const originalElements = collectNoteElementSyntax(originalXml, elementName);
|
|
685
738
|
const replacementElements = collectNoteElementSyntax(replacementXml, elementName);
|
|
686
739
|
const replacementXmlnsDeclarations = collectXmlnsFromOpeningTag(replacementXml);
|
|
@@ -690,9 +743,25 @@ function buildPatchedNotePartXml({ originalXml, baselineXml, serializedXml, repl
|
|
|
690
743
|
const serializedParaIds = collectParaIds(serializedXml);
|
|
691
744
|
const effectiveChangedParaIds = changedParaIds ?? collectChangedNoteParaIds(baselineXml, serializedXml);
|
|
692
745
|
const unroutedChangedParaIds = new Set([...effectiveChangedParaIds].filter((paraId) => serializedParaIds.has(paraId)));
|
|
746
|
+
/** Notes the model has and the part does not: new notes, appended to the part. */
|
|
747
|
+
const addedNotes = [];
|
|
693
748
|
for (const [id, currentSyntaxEntries] of currentElements) {
|
|
694
749
|
const originalSyntaxEntries = originalElements.get(id);
|
|
695
750
|
const replacementSyntaxEntries = replacementElements.get(id);
|
|
751
|
+
if (originalSyntaxEntries === void 0) {
|
|
752
|
+
const replacementSyntax = currentSyntaxEntries.length === 1 && replacementSyntaxEntries?.length === 1 ? replacementSyntaxEntries[0] : void 0;
|
|
753
|
+
const replacementNote = replacementSyntax ? extractNoteElement(replacementXml, replacementSyntax, id) : null;
|
|
754
|
+
if (!replacementSyntax || !replacementNote) return {
|
|
755
|
+
type: "refused",
|
|
756
|
+
reason: "unroutable-paragraph"
|
|
757
|
+
};
|
|
758
|
+
for (const paraId of collectParaIds(replacementNote).keys()) unroutedChangedParaIds.delete(paraId);
|
|
759
|
+
addedNotes.push({
|
|
760
|
+
note: replacementNote,
|
|
761
|
+
syntax: replacementSyntax
|
|
762
|
+
});
|
|
763
|
+
continue;
|
|
764
|
+
}
|
|
696
765
|
if (currentSyntaxEntries.length !== 1 || originalSyntaxEntries?.length !== 1 || replacementSyntaxEntries?.length !== 1) return {
|
|
697
766
|
type: "refused",
|
|
698
767
|
reason: "unroutable-paragraph"
|
|
@@ -716,7 +785,17 @@ function buildPatchedNotePartXml({ originalXml, baselineXml, serializedXml, repl
|
|
|
716
785
|
const originalParagraphs = paragraphRanges(originalNote, originalSyntax.elementPrefix);
|
|
717
786
|
const replacementParagraphs = paragraphRanges(replacementNote, replacementSyntax.elementPrefix);
|
|
718
787
|
const noteChangedParaIds = [...collectParaIds(currentNote).keys()].filter((paraId) => unroutedChangedParaIds.has(paraId));
|
|
719
|
-
|
|
788
|
+
const baselineSyntaxEntries = baselineElements.get(id);
|
|
789
|
+
const baselineSyntax = baselineSyntaxEntries?.length === 1 ? baselineSyntaxEntries[0] : void 0;
|
|
790
|
+
const baselineNote = baselineSyntax ? extractNoteElement(baselineXml, baselineSyntax, id) : null;
|
|
791
|
+
const reshaped = baselineSyntax !== void 0 && baselineNote !== null && baselineNote !== currentNote && noteShapeChanged({
|
|
792
|
+
note: baselineNote,
|
|
793
|
+
prefix: baselineSyntax.elementPrefix
|
|
794
|
+
}, {
|
|
795
|
+
note: currentNote,
|
|
796
|
+
prefix: currentSyntax.elementPrefix
|
|
797
|
+
});
|
|
798
|
+
if (noteChangedParaIds.length === 0 && !reshaped) continue;
|
|
720
799
|
const wholeNoteSplice = {
|
|
721
800
|
start: originalOffsets.start,
|
|
722
801
|
end: originalOffsets.end,
|
|
@@ -727,7 +806,7 @@ function buildPatchedNotePartXml({ originalXml, baselineXml, serializedXml, repl
|
|
|
727
806
|
})
|
|
728
807
|
};
|
|
729
808
|
noteSplices.push(wholeNoteSplice);
|
|
730
|
-
if (currentParagraphs.length !== originalParagraphs.length || currentParagraphs.length !== replacementParagraphs.length) {
|
|
809
|
+
if (reshaped || currentParagraphs.length !== originalParagraphs.length || currentParagraphs.length !== replacementParagraphs.length) {
|
|
731
810
|
for (const paraId of noteChangedParaIds) unroutedChangedParaIds.delete(paraId);
|
|
732
811
|
paragraphSplices.push(wholeNoteSplice);
|
|
733
812
|
continue;
|
|
@@ -754,10 +833,36 @@ function buildPatchedNotePartXml({ originalXml, baselineXml, serializedXml, repl
|
|
|
754
833
|
});
|
|
755
834
|
}
|
|
756
835
|
}
|
|
836
|
+
for (const [id, baselineSyntaxEntries] of baselineElements) {
|
|
837
|
+
if (currentElements.has(id) || baselineSyntaxEntries.length !== 1) continue;
|
|
838
|
+
const originalSyntaxEntries = originalElements.get(id);
|
|
839
|
+
const originalSyntax = originalSyntaxEntries?.length === 1 ? originalSyntaxEntries[0] : void 0;
|
|
840
|
+
const originalOffsets = originalSyntax && findNoteElement(originalXml, originalSyntax, id);
|
|
841
|
+
if (!originalOffsets) return {
|
|
842
|
+
type: "refused",
|
|
843
|
+
reason: "unroutable-paragraph"
|
|
844
|
+
};
|
|
845
|
+
const removal = {
|
|
846
|
+
start: originalOffsets.start,
|
|
847
|
+
end: originalOffsets.end,
|
|
848
|
+
newXml: ""
|
|
849
|
+
};
|
|
850
|
+
paragraphSplices.push(removal);
|
|
851
|
+
noteSplices.push(removal);
|
|
852
|
+
}
|
|
757
853
|
if (unroutedChangedParaIds.size > 0) return {
|
|
758
854
|
type: "refused",
|
|
759
855
|
reason: "unroutable-paragraph"
|
|
760
856
|
};
|
|
857
|
+
if (addedNotes.length > 0) {
|
|
858
|
+
const appended = appendNotesSplice(originalXml, originalElements, addedNotes, { sourceXmlnsDeclarations: replacementXmlnsDeclarations });
|
|
859
|
+
if (!appended) return {
|
|
860
|
+
type: "refused",
|
|
861
|
+
reason: "unroutable-paragraph"
|
|
862
|
+
};
|
|
863
|
+
paragraphSplices.push(appended);
|
|
864
|
+
noteSplices.push(appended);
|
|
865
|
+
}
|
|
761
866
|
const patched = spliceXml(originalXml, paragraphSplices);
|
|
762
867
|
if (patched !== null) return {
|
|
763
868
|
type: "patched",
|
|
@@ -773,6 +878,31 @@ function buildPatchedNotePartXml({ originalXml, baselineXml, serializedXml, repl
|
|
|
773
878
|
};
|
|
774
879
|
}
|
|
775
880
|
/**
|
|
881
|
+
* Insert new notes after the part's last note, spelled with that note's
|
|
882
|
+
* prefixes. Null when the part holds no note to follow.
|
|
883
|
+
*/
|
|
884
|
+
const appendNotesSplice = (originalXml, originalElements, addedNotes, { sourceXmlnsDeclarations }) => {
|
|
885
|
+
let last = null;
|
|
886
|
+
for (const [id, entries] of originalElements) for (const syntax of entries) {
|
|
887
|
+
const offsets = findNoteElement(originalXml, syntax, id);
|
|
888
|
+
if (offsets && (!last || offsets.end > last.end)) last = {
|
|
889
|
+
end: offsets.end,
|
|
890
|
+
syntax
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
if (!last) return null;
|
|
894
|
+
const target = last.syntax;
|
|
895
|
+
return {
|
|
896
|
+
start: last.end,
|
|
897
|
+
end: last.end,
|
|
898
|
+
newXml: addedNotes.map(({ note, syntax }) => rewriteWordprocessingPrefixes(note, {
|
|
899
|
+
source: syntax,
|
|
900
|
+
target,
|
|
901
|
+
sourceXmlnsDeclarations
|
|
902
|
+
})).join("")
|
|
903
|
+
};
|
|
904
|
+
};
|
|
905
|
+
/**
|
|
776
906
|
* The full range of the first `<openLiteral …>…</closeTag>` element, or null.
|
|
777
907
|
* Used to locate an unkeyed sub-element (a level's `mc:AlternateContent`).
|
|
778
908
|
*/
|
|
@@ -892,8 +1022,24 @@ function originalCustomNumFmtFormat(numFmtElement) {
|
|
|
892
1022
|
*/
|
|
893
1023
|
function collectXmlnsFromOpeningTag(elementXml) {
|
|
894
1024
|
const out = {};
|
|
895
|
-
|
|
896
|
-
|
|
1025
|
+
let tagStart = elementXml.indexOf("<");
|
|
1026
|
+
while (tagStart !== -1 && (elementXml.startsWith("<?", tagStart) || elementXml.startsWith("<!--", tagStart))) {
|
|
1027
|
+
const endMarker = elementXml.startsWith("<!--", tagStart) ? "-->" : "?>";
|
|
1028
|
+
const end = elementXml.indexOf(endMarker, tagStart);
|
|
1029
|
+
if (end === -1) return out;
|
|
1030
|
+
tagStart = elementXml.indexOf("<", end + endMarker.length);
|
|
1031
|
+
}
|
|
1032
|
+
if (tagStart === -1) return out;
|
|
1033
|
+
let tagEnd = tagStart + 1;
|
|
1034
|
+
let quote = null;
|
|
1035
|
+
while (tagEnd < elementXml.length) {
|
|
1036
|
+
const character = elementXml[tagEnd];
|
|
1037
|
+
if (character === quote) quote = null;
|
|
1038
|
+
else if (quote === null && (character === "\"" || character === "'")) quote = character;
|
|
1039
|
+
else if (quote === null && character === ">") break;
|
|
1040
|
+
tagEnd += 1;
|
|
1041
|
+
}
|
|
1042
|
+
const openTag = elementXml.slice(tagStart, tagEnd);
|
|
897
1043
|
const pattern = /\s(?<name>xmlns(?::[\w.-]+)?)="(?<uri>[^"]*)"/gu;
|
|
898
1044
|
let match;
|
|
899
1045
|
while ((match = pattern.exec(openTag)) !== null) out[match.groups["name"]] = match.groups["uri"];
|
|
@@ -1056,9 +1202,10 @@ const patchNumberingByNamespace = ({ original, currentXml, changed, added }) =>
|
|
|
1056
1202
|
const patchNumberingDefinitions = ({ originalXml, baselineXml, currentXml }) => {
|
|
1057
1203
|
const changed = collectChangedNumberingDefs(baselineXml, currentXml);
|
|
1058
1204
|
const added = collectAddedNumberingDefs(baselineXml, currentXml);
|
|
1205
|
+
if (changed.abstractNums.size === 0 && changed.nums.size === 0 && added.abstractNums.size === 0 && added.nums.size === 0) return originalXml;
|
|
1059
1206
|
const original = parseXmlDocument(originalXml);
|
|
1060
1207
|
if (!original || getLocalName(original.name) !== "numbering" || !WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(original) ?? "")) return null;
|
|
1061
|
-
if (getNamespacePrefix(original.name ?? "") !== "w") return patchNumberingByNamespace({
|
|
1208
|
+
if (getNamespacePrefix(original.name ?? "") !== "w" || !hasCanonicalWordprocessingPrefixes(originalXml)) return patchNumberingByNamespace({
|
|
1062
1209
|
original,
|
|
1063
1210
|
currentXml,
|
|
1064
1211
|
changed,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
//#region src/docx/serializer/blockCustomXmlSerializer.d.ts
|
|
3
|
+
declare const serializeBlockCustomXml: (block: document_d_exports.BlockCustomXml, serializeChild: (child: document_d_exports.BlockContent) => string) => string;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { serializeBlockCustomXml };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { serializeBlockCustomXml } from "./blockCustomXmlSerializer.js";
|
|
1
2
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
2
3
|
import { serializeBookmarkMarker } from "./markupRangeAttributes.js";
|
|
3
4
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
@@ -45,6 +46,7 @@ function serializeBlockContent(block) {
|
|
|
45
46
|
case "paragraph": return serializeParagraph(block);
|
|
46
47
|
case "table": return serializeTable(block, serializeParagraph);
|
|
47
48
|
case "blockSdt": return serializeBlockSdt(block, serializeBlockContent);
|
|
49
|
+
case "blockCustomXml": return serializeBlockCustomXml(block, serializeBlockContent);
|
|
48
50
|
case "preservedBlock": return block.xml;
|
|
49
51
|
case "bookmarkStart":
|
|
50
52
|
case "bookmarkEnd": return serializeBookmarkMarker(block);
|
|
@@ -2,6 +2,7 @@ import { canReplayHeaderFooterVerbatim, getHeaderFooterVerbatimXml } from "../he
|
|
|
2
2
|
import { isEmptyParagraph } from "../paragraphParser.js";
|
|
3
3
|
import { captureVerbatimXml } from "../verbatimCapture.js";
|
|
4
4
|
import { getLocalName, parseXmlDocument } from "../xmlParser.js";
|
|
5
|
+
import { serializeBlockCustomXml } from "./blockCustomXmlSerializer.js";
|
|
5
6
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
6
7
|
import { serializeBookmarkMarker } from "./markupRangeAttributes.js";
|
|
7
8
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
@@ -41,6 +42,7 @@ function serializeBlock(block) {
|
|
|
41
42
|
case "paragraph": return serializeParagraph(block);
|
|
42
43
|
case "table": return serializeTable(block, serializeParagraph);
|
|
43
44
|
case "blockSdt": return serializeBlockSdt(block, serializeBlock);
|
|
45
|
+
case "blockCustomXml": return serializeBlockCustomXml(block, serializeBlock);
|
|
44
46
|
case "preservedBlock": return block.xml;
|
|
45
47
|
case "bookmarkStart":
|
|
46
48
|
case "bookmarkEnd": return serializeBookmarkMarker(block);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { serializeBlockCustomXml } from "./blockCustomXmlSerializer.js";
|
|
1
2
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
2
3
|
import { serializeBookmarkMarker } from "./markupRangeAttributes.js";
|
|
3
4
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
@@ -43,6 +44,7 @@ function serializeBlock(block) {
|
|
|
43
44
|
case "paragraph": return serializeParagraph(block);
|
|
44
45
|
case "table": return serializeTable(block, serializeParagraph);
|
|
45
46
|
case "blockSdt": return serializeBlockSdt(block, serializeBlock);
|
|
47
|
+
case "blockCustomXml": return serializeBlockCustomXml(block, serializeBlock);
|
|
46
48
|
case "preservedBlock": return block.xml;
|
|
47
49
|
case "bookmarkStart":
|
|
48
50
|
case "bookmarkEnd": return serializeBookmarkMarker(block);
|
|
@@ -65,7 +67,7 @@ function serializeRequiredNoteSeparators(elementName) {
|
|
|
65
67
|
return `<w:${elementName} w:type="separator" w:id="-1">${NOTE_SEPARATOR_BODY}<w:r><w:separator/></w:r></w:p></w:${elementName}><w:${elementName} w:type="continuationSeparator" w:id="0">${NOTE_SEPARATOR_BODY}<w:r><w:continuationSeparator/></w:r></w:p></w:${elementName}>`;
|
|
66
68
|
}
|
|
67
69
|
function insertNoteReferenceMark(xml, elementName) {
|
|
68
|
-
if (
|
|
70
|
+
if (new RegExp(`<(?:[\\w.-]+:)?${elementName}Ref[\\s/>]`, "u").test(xml)) return xml;
|
|
69
71
|
const paragraphOpen = /<w:p(?=[\s>])[^>]*>/u.exec(xml);
|
|
70
72
|
if (!paragraphOpen) return `${`<w:p><w:r><w:rPr><w:rStyle w:val="${elementName === "footnote" ? "FootnoteReference" : "EndnoteReference"}"/></w:rPr><w:${elementName}Ref/></w:r></w:p>`}${xml}`;
|
|
71
73
|
const paragraphStart = paragraphOpen.index + paragraphOpen[0].length;
|