@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
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { FolioAIEditAppliedOperation, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditSnapshot } from "./types.js";
|
|
2
|
+
import { FolioDocumentStoryHandle } from "./headless.js";
|
|
3
|
+
import { EditorState } from "prosemirror-state";
|
|
4
|
+
//#region src/ai-edits/pending-suggestions.d.ts
|
|
5
|
+
declare const FOLIO_PENDING_SUGGESTION_VERSION: 1;
|
|
6
|
+
/** A host-owned, JSON-serializable proposal. It is never written into the DOCX. */
|
|
7
|
+
type FolioPendingSuggestionRecord = {
|
|
8
|
+
version: typeof FOLIO_PENDING_SUGGESTION_VERSION;
|
|
9
|
+
suggestionId: string;
|
|
10
|
+
operation: FolioAIEditOperation;
|
|
11
|
+
story: FolioDocumentStoryHandle;
|
|
12
|
+
anchor: {
|
|
13
|
+
blockId: string;
|
|
14
|
+
paraId: string | null;
|
|
15
|
+
originalTextHash: string;
|
|
16
|
+
selectedTextHash?: string;
|
|
17
|
+
startOffset?: number;
|
|
18
|
+
endOffset?: number;
|
|
19
|
+
};
|
|
20
|
+
author: string;
|
|
21
|
+
provenance: "suggested";
|
|
22
|
+
sourceDocumentFingerprint: string;
|
|
23
|
+
commentId?: number;
|
|
24
|
+
};
|
|
25
|
+
type FolioPendingSuggestionStaleReason = "missingAnchor" | "ambiguousAnchor" | "textChanged" | "unsupportedVersion" | "documentChanged" | "invalidRecord" | "applyFailed";
|
|
26
|
+
type FolioPendingSuggestionLoadResult = {
|
|
27
|
+
status: "restaged";
|
|
28
|
+
suggestionId: string;
|
|
29
|
+
} | {
|
|
30
|
+
status: "stale";
|
|
31
|
+
suggestionId: string | null;
|
|
32
|
+
reason: FolioPendingSuggestionStaleReason;
|
|
33
|
+
};
|
|
34
|
+
type RecordAppliedOptions = {
|
|
35
|
+
snapshot: FolioAIEditSnapshot;
|
|
36
|
+
story: FolioDocumentStoryHandle;
|
|
37
|
+
operations: readonly FolioAIEditOperation[];
|
|
38
|
+
applied: readonly FolioAIEditAppliedOperation[];
|
|
39
|
+
author: string;
|
|
40
|
+
activeSuggestionIds: ReadonlySet<string>;
|
|
41
|
+
};
|
|
42
|
+
type ReplaceRestagedStoryOptions = {
|
|
43
|
+
story: FolioDocumentStoryHandle;
|
|
44
|
+
restaged: readonly {
|
|
45
|
+
snapshot: FolioAIEditSnapshot;
|
|
46
|
+
operation: FolioAIEditOperation;
|
|
47
|
+
applied: FolioAIEditAppliedOperation;
|
|
48
|
+
author: string;
|
|
49
|
+
}[];
|
|
50
|
+
activeSuggestionIds: ReadonlySet<string>;
|
|
51
|
+
};
|
|
52
|
+
type LoadPendingSuggestionsOptions = {
|
|
53
|
+
records: readonly unknown[];
|
|
54
|
+
snapshotForStory: (story: FolioDocumentStoryHandle) => FolioAIEditSnapshot | null;
|
|
55
|
+
sourceSnapshotForStory: (story: FolioDocumentStoryHandle, commentIds: ReadonlySet<number>) => FolioAIEditSnapshot | null;
|
|
56
|
+
apply: (record: FolioPendingSuggestionRecord, snapshot: FolioAIEditSnapshot) => FolioAIEditApplyResult;
|
|
57
|
+
activeSuggestionIds: () => ReadonlySet<string>;
|
|
58
|
+
};
|
|
59
|
+
type ExportPendingSuggestionsOptions = {
|
|
60
|
+
activeSuggestionIds: ReadonlySet<string>;
|
|
61
|
+
snapshotForStory: (story: FolioDocumentStoryHandle, commentIds: ReadonlySet<number>) => FolioAIEditSnapshot | null;
|
|
62
|
+
};
|
|
63
|
+
/** Drop only comments attached to proposals that have not been accepted. */
|
|
64
|
+
declare const withoutPendingSuggestionCommentMarks: (state: EditorState, commentIds: ReadonlySet<number>) => EditorState;
|
|
65
|
+
/** The saved package's story, with all pending proposals removed. */
|
|
66
|
+
declare const createPendingSuggestionSourceSnapshot: (state: EditorState, commentIds: ReadonlySet<number>) => FolioAIEditSnapshot;
|
|
67
|
+
/** Tracks only operations that successfully staged in `suggested` mode. */
|
|
68
|
+
declare class FolioPendingSuggestionRegistry {
|
|
69
|
+
private readonly records;
|
|
70
|
+
private readonly sourceFingerprints;
|
|
71
|
+
clear(): void;
|
|
72
|
+
recordApplied({ snapshot, story, operations, applied, author, activeSuggestionIds }: RecordAppliedOptions): void;
|
|
73
|
+
/** Rebase records after ordinary revisions change their source story. */
|
|
74
|
+
replaceRestagedStory({ story, restaged, activeSuggestionIds }: ReplaceRestagedStoryOptions): void;
|
|
75
|
+
exportPendingSuggestions({ activeSuggestionIds, snapshotForStory }: ExportPendingSuggestionsOptions): FolioPendingSuggestionRecord[];
|
|
76
|
+
loadPendingSuggestions({ records, snapshotForStory, sourceSnapshotForStory, apply, activeSuggestionIds }: LoadPendingSuggestionsOptions): FolioPendingSuggestionLoadResult[];
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { FOLIO_PENDING_SUGGESTION_VERSION, FolioPendingSuggestionLoadResult, FolioPendingSuggestionRecord, FolioPendingSuggestionRegistry, FolioPendingSuggestionStaleReason, createPendingSuggestionSourceSnapshot, withoutPendingSuggestionCommentMarks };
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { parseFolioDocumentOperationBatch } from "../document-operations.js";
|
|
2
|
+
import { rejectAllSuggestions } from "../prosemirror/commands/comments.js";
|
|
3
|
+
import { getDocumentStyleResolver } from "../prosemirror/plugins/documentStyleState.js";
|
|
4
|
+
import { getFolioParaIdFromBlockId } from "../types/block-id.js";
|
|
5
|
+
import { canonicalJson } from "../utils/canonicalJson.js";
|
|
6
|
+
import { createFolioAIEditSnapshotWithStyleResolver, hashFolioAIBlockText, sourceDocumentOf } from "./snapshot.js";
|
|
7
|
+
//#region src/ai-edits/pending-suggestions.ts
|
|
8
|
+
const FOLIO_PENDING_SUGGESTION_VERSION = 1;
|
|
9
|
+
/** Drop only comments attached to proposals that have not been accepted. */
|
|
10
|
+
const withoutPendingSuggestionCommentMarks = (state, commentIds) => {
|
|
11
|
+
if (commentIds.size === 0) return state;
|
|
12
|
+
let transaction = state.tr;
|
|
13
|
+
state.doc.descendants((node, position) => {
|
|
14
|
+
for (const mark of node.marks) if (mark.type.name === "comment" && commentIds.has(mark.attrs["commentId"])) transaction = transaction.removeMark(position, position + node.nodeSize, mark);
|
|
15
|
+
});
|
|
16
|
+
return transaction.docChanged ? state.apply(transaction) : state;
|
|
17
|
+
};
|
|
18
|
+
/** The saved package's story, with all pending proposals removed. */
|
|
19
|
+
const createPendingSuggestionSourceSnapshot = (state, commentIds) => {
|
|
20
|
+
let source = state;
|
|
21
|
+
rejectAllSuggestions()(state, (transaction) => {
|
|
22
|
+
source = state.apply(transaction);
|
|
23
|
+
});
|
|
24
|
+
source = withoutPendingSuggestionCommentMarks(source, commentIds);
|
|
25
|
+
return createFolioAIEditSnapshotWithStyleResolver(source.doc, getDocumentStyleResolver(source));
|
|
26
|
+
};
|
|
27
|
+
const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28
|
+
const operationBlockId = (operation) => {
|
|
29
|
+
switch (operation.type) {
|
|
30
|
+
case "replaceRange":
|
|
31
|
+
case "commentOnRange":
|
|
32
|
+
case "formatRange": return operation.range.blockId;
|
|
33
|
+
default: return operation.blockId;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const storyFromUnknown = (value) => {
|
|
37
|
+
if (!isObject(value)) return null;
|
|
38
|
+
switch (value["type"]) {
|
|
39
|
+
case "main": return { type: "main" };
|
|
40
|
+
case "header":
|
|
41
|
+
case "footer": return typeof value["relationshipId"] === "string" ? {
|
|
42
|
+
type: value["type"],
|
|
43
|
+
relationshipId: value["relationshipId"]
|
|
44
|
+
} : null;
|
|
45
|
+
case "footnote":
|
|
46
|
+
case "endnote": return typeof value["noteId"] === "number" && Number.isSafeInteger(value["noteId"]) ? {
|
|
47
|
+
type: value["type"],
|
|
48
|
+
noteId: value["noteId"]
|
|
49
|
+
} : null;
|
|
50
|
+
default: return null;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const fingerprintOf = (snapshot, story) => hashFolioAIBlockText(canonicalJson([story, snapshot.blocks.map((block) => [block, snapshot.anchors[block.id]?.structuralBoundaryHash])]));
|
|
54
|
+
const paraIdCountsOf = (snapshot) => {
|
|
55
|
+
const counts = /* @__PURE__ */ new Map();
|
|
56
|
+
sourceDocumentOf(snapshot).descendants((node) => {
|
|
57
|
+
const paraId = node.attrs["paraId"];
|
|
58
|
+
if (node.type.name === "paragraph" && typeof paraId === "string") counts.set(paraId, (counts.get(paraId) ?? 0) + 1);
|
|
59
|
+
});
|
|
60
|
+
return counts;
|
|
61
|
+
};
|
|
62
|
+
const recordKey = (record) => canonicalJson([
|
|
63
|
+
record.story,
|
|
64
|
+
record.suggestionId,
|
|
65
|
+
record.operation.id
|
|
66
|
+
]);
|
|
67
|
+
const parseRecord = (value) => {
|
|
68
|
+
if (!isObject(value) || !isObject(value["anchor"])) return null;
|
|
69
|
+
const story = storyFromUnknown(value["story"]);
|
|
70
|
+
const anchor = value["anchor"];
|
|
71
|
+
if (story === null || typeof value["suggestionId"] !== "string" || typeof value["author"] !== "string" || value["provenance"] !== "suggested" || typeof value["sourceDocumentFingerprint"] !== "string" || value["commentId"] !== void 0 && (typeof value["commentId"] !== "number" || !Number.isSafeInteger(value["commentId"])) || typeof anchor["blockId"] !== "string" || anchor["paraId"] !== null && typeof anchor["paraId"] !== "string" || typeof anchor["originalTextHash"] !== "string") return null;
|
|
72
|
+
let operation;
|
|
73
|
+
try {
|
|
74
|
+
const parsed = parseFolioDocumentOperationBatch({
|
|
75
|
+
version: 1,
|
|
76
|
+
operations: [value["operation"]],
|
|
77
|
+
mode: "suggested"
|
|
78
|
+
}).operations.at(0);
|
|
79
|
+
if (!parsed) return null;
|
|
80
|
+
operation = parsed;
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
if (operationBlockId(operation) !== anchor["blockId"] || (operation.suggestionId ?? operation.id) !== value["suggestionId"] || getFolioParaIdFromBlockId(anchor["blockId"]) !== anchor["paraId"]) return null;
|
|
85
|
+
if (operation.type === "replaceRange" || operation.type === "formatRange") {
|
|
86
|
+
if (anchor["selectedTextHash"] !== operation.range.selectedTextHash || anchor["startOffset"] !== operation.range.startOffset || anchor["endOffset"] !== operation.range.endOffset) return null;
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
version: 1,
|
|
90
|
+
suggestionId: value["suggestionId"],
|
|
91
|
+
operation,
|
|
92
|
+
story,
|
|
93
|
+
anchor: {
|
|
94
|
+
blockId: anchor["blockId"],
|
|
95
|
+
paraId: anchor["paraId"],
|
|
96
|
+
originalTextHash: anchor["originalTextHash"],
|
|
97
|
+
...typeof anchor["selectedTextHash"] === "string" && { selectedTextHash: anchor["selectedTextHash"] },
|
|
98
|
+
...typeof anchor["startOffset"] === "number" && { startOffset: anchor["startOffset"] },
|
|
99
|
+
...typeof anchor["endOffset"] === "number" && { endOffset: anchor["endOffset"] }
|
|
100
|
+
},
|
|
101
|
+
author: value["author"],
|
|
102
|
+
provenance: "suggested",
|
|
103
|
+
sourceDocumentFingerprint: value["sourceDocumentFingerprint"],
|
|
104
|
+
...typeof value["commentId"] === "number" && Number.isSafeInteger(value["commentId"]) && { commentId: value["commentId"] }
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
/** Tracks only operations that successfully staged in `suggested` mode. */
|
|
108
|
+
var FolioPendingSuggestionRegistry = class {
|
|
109
|
+
records = /* @__PURE__ */ new Map();
|
|
110
|
+
sourceFingerprints = /* @__PURE__ */ new Map();
|
|
111
|
+
clear() {
|
|
112
|
+
this.records.clear();
|
|
113
|
+
this.sourceFingerprints.clear();
|
|
114
|
+
}
|
|
115
|
+
recordApplied({ snapshot, story, operations, applied, author, activeSuggestionIds }) {
|
|
116
|
+
if (applied.length === 0) return;
|
|
117
|
+
const storyKey = canonicalJson(story);
|
|
118
|
+
for (const [key, record] of this.records) if (!activeSuggestionIds.has(record.suggestionId)) this.records.delete(key);
|
|
119
|
+
if (![...this.records.values()].some((record) => canonicalJson(record.story) === storyKey)) this.sourceFingerprints.delete(storyKey);
|
|
120
|
+
const fingerprint = this.sourceFingerprints.get(storyKey) ?? fingerprintOf(snapshot, story);
|
|
121
|
+
this.sourceFingerprints.set(storyKey, fingerprint);
|
|
122
|
+
const appliedById = new Map(applied.map((entry) => [entry.id, entry]));
|
|
123
|
+
for (const operation of operations) {
|
|
124
|
+
const outcome = appliedById.get(operation.id);
|
|
125
|
+
if (!outcome?.suggestionId) continue;
|
|
126
|
+
const blockId = operationBlockId(operation);
|
|
127
|
+
const anchor = snapshot.anchors[blockId];
|
|
128
|
+
if (!anchor) continue;
|
|
129
|
+
const range = operation.type === "replaceRange" || operation.type === "formatRange" ? operation.range : null;
|
|
130
|
+
const record = {
|
|
131
|
+
version: 1,
|
|
132
|
+
suggestionId: outcome.suggestionId,
|
|
133
|
+
operation: structuredClone(operation),
|
|
134
|
+
story: structuredClone(story),
|
|
135
|
+
anchor: {
|
|
136
|
+
blockId,
|
|
137
|
+
paraId: getFolioParaIdFromBlockId(blockId),
|
|
138
|
+
originalTextHash: anchor.textHash,
|
|
139
|
+
...range !== null && {
|
|
140
|
+
selectedTextHash: range.selectedTextHash,
|
|
141
|
+
startOffset: range.startOffset,
|
|
142
|
+
endOffset: range.endOffset
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
author,
|
|
146
|
+
provenance: "suggested",
|
|
147
|
+
sourceDocumentFingerprint: fingerprint,
|
|
148
|
+
...outcome.commentId !== void 0 && { commentId: outcome.commentId }
|
|
149
|
+
};
|
|
150
|
+
this.records.set(recordKey(record), record);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/** Rebase records after ordinary revisions change their source story. */
|
|
154
|
+
replaceRestagedStory({ story, restaged, activeSuggestionIds }) {
|
|
155
|
+
if (restaged.length === 0) return;
|
|
156
|
+
const storyKey = canonicalJson(story);
|
|
157
|
+
for (const [key, record] of this.records) if (canonicalJson(record.story) === storyKey) this.records.delete(key);
|
|
158
|
+
const first = restaged.at(0);
|
|
159
|
+
if (!first) return;
|
|
160
|
+
this.sourceFingerprints.set(storyKey, fingerprintOf(first.snapshot, story));
|
|
161
|
+
for (const { snapshot, operation, applied, author } of restaged) this.recordApplied({
|
|
162
|
+
snapshot,
|
|
163
|
+
story,
|
|
164
|
+
operations: [operation],
|
|
165
|
+
applied: [applied],
|
|
166
|
+
author,
|
|
167
|
+
activeSuggestionIds
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
exportPendingSuggestions({ activeSuggestionIds, snapshotForStory }) {
|
|
171
|
+
const pending = [];
|
|
172
|
+
const fingerprints = /* @__PURE__ */ new Map();
|
|
173
|
+
const commentIdsByStory = /* @__PURE__ */ new Map();
|
|
174
|
+
for (const record of this.records.values()) {
|
|
175
|
+
if (!activeSuggestionIds.has(record.suggestionId) || record.commentId === void 0) continue;
|
|
176
|
+
const storyKey = canonicalJson(record.story);
|
|
177
|
+
const commentIds = commentIdsByStory.get(storyKey) ?? /* @__PURE__ */ new Set();
|
|
178
|
+
commentIds.add(record.commentId);
|
|
179
|
+
commentIdsByStory.set(storyKey, commentIds);
|
|
180
|
+
}
|
|
181
|
+
for (const [key, record] of this.records) if (activeSuggestionIds.has(record.suggestionId)) {
|
|
182
|
+
const storyKey = canonicalJson(record.story);
|
|
183
|
+
let fingerprint = fingerprints.get(storyKey);
|
|
184
|
+
if (fingerprint === void 0) {
|
|
185
|
+
const snapshot = snapshotForStory(record.story, commentIdsByStory.get(storyKey) ?? /* @__PURE__ */ new Set());
|
|
186
|
+
if (!snapshot) continue;
|
|
187
|
+
fingerprint = fingerprintOf(snapshot, record.story);
|
|
188
|
+
fingerprints.set(storyKey, fingerprint);
|
|
189
|
+
}
|
|
190
|
+
const current = {
|
|
191
|
+
...record,
|
|
192
|
+
sourceDocumentFingerprint: fingerprint
|
|
193
|
+
};
|
|
194
|
+
this.records.set(key, current);
|
|
195
|
+
pending.push(structuredClone(current));
|
|
196
|
+
} else this.records.delete(key);
|
|
197
|
+
for (const [storyKey, fingerprint] of fingerprints) this.sourceFingerprints.set(storyKey, fingerprint);
|
|
198
|
+
if (pending.length === 0) this.sourceFingerprints.clear();
|
|
199
|
+
return pending;
|
|
200
|
+
}
|
|
201
|
+
loadPendingSuggestions({ records, snapshotForStory, sourceSnapshotForStory, apply, activeSuggestionIds }) {
|
|
202
|
+
const baselines = /* @__PURE__ */ new Map();
|
|
203
|
+
const changedStories = /* @__PURE__ */ new Set();
|
|
204
|
+
return records.map((value) => {
|
|
205
|
+
const suggestionId = isObject(value) && typeof value["suggestionId"] === "string" ? value["suggestionId"] : null;
|
|
206
|
+
if (!isObject(value) || value["version"] !== 1) return {
|
|
207
|
+
status: "stale",
|
|
208
|
+
suggestionId,
|
|
209
|
+
reason: "unsupportedVersion"
|
|
210
|
+
};
|
|
211
|
+
const record = parseRecord(value);
|
|
212
|
+
if (!record) return {
|
|
213
|
+
status: "stale",
|
|
214
|
+
suggestionId,
|
|
215
|
+
reason: "invalidRecord"
|
|
216
|
+
};
|
|
217
|
+
const key = recordKey(record);
|
|
218
|
+
const existing = this.records.get(key);
|
|
219
|
+
if (existing && activeSuggestionIds().has(record.suggestionId)) {
|
|
220
|
+
const { commentId: _existingCommentId, ...existingProposal } = existing;
|
|
221
|
+
const { commentId: _loadedCommentId, ...loadedProposal } = record;
|
|
222
|
+
return canonicalJson(existingProposal) === canonicalJson(loadedProposal) ? {
|
|
223
|
+
status: "restaged",
|
|
224
|
+
suggestionId: record.suggestionId
|
|
225
|
+
} : {
|
|
226
|
+
status: "stale",
|
|
227
|
+
suggestionId,
|
|
228
|
+
reason: "invalidRecord"
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const storyKey = canonicalJson(record.story);
|
|
232
|
+
if (!baselines.has(storyKey)) {
|
|
233
|
+
const snapshot = snapshotForStory(record.story);
|
|
234
|
+
const active = activeSuggestionIds();
|
|
235
|
+
const commentIds = /* @__PURE__ */ new Set();
|
|
236
|
+
for (const existingRecord of this.records.values()) if (canonicalJson(existingRecord.story) === storyKey && active.has(existingRecord.suggestionId) && existingRecord.commentId !== void 0) commentIds.add(existingRecord.commentId);
|
|
237
|
+
const source = sourceSnapshotForStory(record.story, commentIds);
|
|
238
|
+
baselines.set(storyKey, snapshot && source ? {
|
|
239
|
+
snapshot,
|
|
240
|
+
fingerprint: fingerprintOf(source, record.story)
|
|
241
|
+
} : null);
|
|
242
|
+
}
|
|
243
|
+
const baseline = baselines.get(storyKey);
|
|
244
|
+
if (!baseline || record.anchor.paraId === null) return {
|
|
245
|
+
status: "stale",
|
|
246
|
+
suggestionId,
|
|
247
|
+
reason: "missingAnchor"
|
|
248
|
+
};
|
|
249
|
+
const snapshot = changedStories.has(storyKey) ? snapshotForStory(record.story) : baseline.snapshot;
|
|
250
|
+
if (!snapshot) return {
|
|
251
|
+
status: "stale",
|
|
252
|
+
suggestionId,
|
|
253
|
+
reason: "missingAnchor"
|
|
254
|
+
};
|
|
255
|
+
const multiplicity = paraIdCountsOf(snapshot).get(record.anchor.paraId) ?? 0;
|
|
256
|
+
if (multiplicity === 0 || !snapshot.anchors[record.anchor.paraId]) return {
|
|
257
|
+
status: "stale",
|
|
258
|
+
suggestionId,
|
|
259
|
+
reason: "missingAnchor"
|
|
260
|
+
};
|
|
261
|
+
if (multiplicity > 1) return {
|
|
262
|
+
status: "stale",
|
|
263
|
+
suggestionId,
|
|
264
|
+
reason: "ambiguousAnchor"
|
|
265
|
+
};
|
|
266
|
+
const anchor = snapshot.anchors[record.anchor.paraId];
|
|
267
|
+
if (!anchor || anchor.textHash !== record.anchor.originalTextHash) return {
|
|
268
|
+
status: "stale",
|
|
269
|
+
suggestionId,
|
|
270
|
+
reason: "textChanged"
|
|
271
|
+
};
|
|
272
|
+
const { startOffset, endOffset, selectedTextHash } = record.anchor;
|
|
273
|
+
if (startOffset !== void 0 && endOffset !== void 0 && selectedTextHash !== void 0 && hashFolioAIBlockText(anchor.text.slice(startOffset, endOffset)) !== selectedTextHash) return {
|
|
274
|
+
status: "stale",
|
|
275
|
+
suggestionId,
|
|
276
|
+
reason: "textChanged"
|
|
277
|
+
};
|
|
278
|
+
if (baseline.fingerprint !== record.sourceDocumentFingerprint) return {
|
|
279
|
+
status: "stale",
|
|
280
|
+
suggestionId,
|
|
281
|
+
reason: "documentChanged"
|
|
282
|
+
};
|
|
283
|
+
const applied = apply(record, snapshot).applied.find((entry) => entry.id === record.operation.id);
|
|
284
|
+
if (!applied) return {
|
|
285
|
+
status: "stale",
|
|
286
|
+
suggestionId,
|
|
287
|
+
reason: "applyFailed"
|
|
288
|
+
};
|
|
289
|
+
this.sourceFingerprints.set(storyKey, record.sourceDocumentFingerprint);
|
|
290
|
+
if (!this.records.has(key)) {
|
|
291
|
+
const { commentId: _oldCommentId, ...rest } = record;
|
|
292
|
+
this.records.set(key, structuredClone({
|
|
293
|
+
...rest,
|
|
294
|
+
...applied.commentId !== void 0 && { commentId: applied.commentId }
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
297
|
+
changedStories.add(storyKey);
|
|
298
|
+
return {
|
|
299
|
+
status: "restaged",
|
|
300
|
+
suggestionId: record.suggestionId
|
|
301
|
+
};
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
//#endregion
|
|
306
|
+
export { FOLIO_PENDING_SUGGESTION_VERSION, FolioPendingSuggestionRegistry, createPendingSuggestionSourceSnapshot, withoutPendingSuggestionCommentMarks };
|
package/dist/ai-edits/read.d.ts
CHANGED
|
@@ -62,14 +62,16 @@ type FolioCommentAnchor = {
|
|
|
62
62
|
declare const getTrackedChangesFromSnapshot: (snapshot: FolioAIEditSnapshot) => FolioReviewChange[];
|
|
63
63
|
/**
|
|
64
64
|
* The tracked changes present in the body, read from inline marks and
|
|
65
|
-
* structural node attributes.
|
|
66
|
-
* into
|
|
65
|
+
* structural node attributes. Adjacent runs sharing a revision wrapper path
|
|
66
|
+
* fold into one entry; interrupted or differently nested wrappers stay separate.
|
|
67
67
|
*
|
|
68
68
|
* A tracked row insertion or deletion marks the row AND every run in its
|
|
69
69
|
* cells, the way Word writes it. Both halves are one change, so the run marks
|
|
70
70
|
* fold into the row's entry rather than reporting a second time.
|
|
71
71
|
*/
|
|
72
72
|
declare const getTrackedChangesFromDoc: (doc: Node) => FolioReviewChange[];
|
|
73
|
+
/** Physical revision ids behind an inline change split by markup. */
|
|
74
|
+
declare const getTrackedChangeGroupIdsFromDoc: (doc: Node, id: number) => number[];
|
|
73
75
|
/** @internal Read revision statistics without paying for an unrelated block projection. */
|
|
74
76
|
declare const getTrackedChangeStatsFromDoc: (doc: Node) => {
|
|
75
77
|
highestId: number;
|
|
@@ -78,8 +80,8 @@ declare const getTrackedChangeStatsFromDoc: (doc: Node) => {
|
|
|
78
80
|
/**
|
|
79
81
|
* The comment anchors present in the body, read from the `comment` mark the
|
|
80
82
|
* editor renders. Each entry carries the anchored text and containing block id;
|
|
81
|
-
*
|
|
83
|
+
* ranges for one comment id within the body fold into a single anchor.
|
|
82
84
|
*/
|
|
83
85
|
declare const getCommentAnchorsFromDoc: (doc: Node) => FolioCommentAnchor[];
|
|
84
86
|
//#endregion
|
|
85
|
-
export { FOLIO_REVIEW_CHANGE_KINDS, FolioCommentAnchor, FolioReviewChange, FolioReviewChangeKind, getCommentAnchorsFromDoc, getTrackedChangeStatsFromDoc, getTrackedChangesFromDoc, getTrackedChangesFromSnapshot };
|
|
87
|
+
export { FOLIO_REVIEW_CHANGE_KINDS, FolioCommentAnchor, FolioReviewChange, FolioReviewChangeKind, getCommentAnchorsFromDoc, getTrackedChangeGroupIdsFromDoc, getTrackedChangeStatsFromDoc, getTrackedChangesFromDoc, getTrackedChangesFromSnapshot };
|
package/dist/ai-edits/read.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { expectRunPropertyChangeMarkAttrs } from "../prosemirror/attrs/index.js";
|
|
1
|
+
import { expectRunPropertyChangeMarkAttrs, expectTrackedChangeMarkAttrs } from "../prosemirror/attrs/index.js";
|
|
2
2
|
import { getFolioNodeRevisionCarriers } from "../prosemirror/revisionCarriers.js";
|
|
3
3
|
import { expandRunFormattingCarrier, runFormattingCarrierReviewText, runFormattingInlineAtomDisposition } from "../prosemirror/runFormattingInlineCarriers.js";
|
|
4
4
|
import { getTableCellMergeChange } from "../prosemirror/tableCellMergeRevision.js";
|
|
5
|
-
import {
|
|
5
|
+
import { enclosingInsertionAncestors, trackedRevisionLayerOf } from "../prosemirror/trackedRevisionPath.js";
|
|
6
|
+
import { readerTextOf } from "./note-references.js";
|
|
7
|
+
import { collectNoteReferenceLabels, createFolioAIEditSnapshot, sourceDocumentOf } from "./snapshot.js";
|
|
6
8
|
//#region src/ai-edits/read.ts
|
|
7
9
|
/**
|
|
8
10
|
* Runtime census of every tracked-change discriminator the reviewer exposes.
|
|
@@ -50,23 +52,31 @@ const firstBlockIdWithin = ({ node, nodePos, blockStarts }) => {
|
|
|
50
52
|
});
|
|
51
53
|
return blockId;
|
|
52
54
|
};
|
|
53
|
-
/**
|
|
54
|
-
* Whether a run's revision inside a marked row is that row's own. Folio writes
|
|
55
|
-
* both halves under one revision id; Word mints a fresh `w:id` per element, so
|
|
56
|
-
* an author + timestamp match counts too. A third party's edit inside the row
|
|
57
|
-
* matches neither and keeps its own entry.
|
|
58
|
-
*/
|
|
59
55
|
const belongsToRowRevision = (scope, revision) => revision.id === scope.change.id || revision.author === scope.change.author && revision.date === scope.change.date;
|
|
60
56
|
/** Shared revision interpreter; a null block map omits unrelated block-id projection. */
|
|
61
|
-
const
|
|
57
|
+
const getTrackedChangeGroupsFromProjectedDoc = (doc, blockStarts) => {
|
|
62
58
|
const insertionType = doc.type.schema.marks["insertion"];
|
|
63
59
|
const deletionType = doc.type.schema.marks["deletion"];
|
|
64
60
|
const grouped = /* @__PURE__ */ new Map();
|
|
61
|
+
const inlineRanges = /* @__PURE__ */ new Map();
|
|
62
|
+
const lastInlineGroupByPath = /* @__PURE__ */ new Map();
|
|
63
|
+
const transparentInlineEnds = /* @__PURE__ */ new Map();
|
|
64
|
+
const transparentGap = (start, end) => {
|
|
65
|
+
let pos = start;
|
|
66
|
+
while (pos < end) {
|
|
67
|
+
const next = transparentInlineEnds.get(pos);
|
|
68
|
+
if (next === void 0) return false;
|
|
69
|
+
pos = next;
|
|
70
|
+
}
|
|
71
|
+
return pos === end;
|
|
72
|
+
};
|
|
65
73
|
const structuralChangeCellPositions = /* @__PURE__ */ new Map();
|
|
66
74
|
const rowRevisionScopes = [];
|
|
67
75
|
const derivedFormattingRepresentationPositions = /* @__PURE__ */ new Set();
|
|
76
|
+
const noteReferences = collectNoteReferenceLabels(doc);
|
|
68
77
|
let currentBlockId = null;
|
|
69
78
|
doc.descendants((node, pos) => {
|
|
79
|
+
if (node.type.name === "commentReference") transparentInlineEnds.set(pos, pos + node.nodeSize);
|
|
70
80
|
while (pos >= (rowRevisionScopes.at(-1)?.end ?? Number.POSITIVE_INFINITY)) rowRevisionScopes.pop();
|
|
71
81
|
const nodeRevisionCarriers = getFolioNodeRevisionCarriers(node, pos);
|
|
72
82
|
if (nodeRevisionCarriers.length > 0) {
|
|
@@ -207,25 +217,50 @@ const getTrackedChangesFromProjectedDoc = (doc, blockStarts) => {
|
|
|
207
217
|
}
|
|
208
218
|
}
|
|
209
219
|
}
|
|
210
|
-
const text = node
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
220
|
+
const text = readerTextOf(node, noteReferences);
|
|
221
|
+
const insertionMark = node.marks.find((mark) => mark.type === insertionType);
|
|
222
|
+
const deletionMark = node.marks.find((mark) => mark.type === deletionType);
|
|
223
|
+
const mark = deletionMark ?? insertionMark;
|
|
224
|
+
if (!mark || typeof mark.attrs["revisionId"] !== "number") return;
|
|
225
|
+
const attrs = expectTrackedChangeMarkAttrs(mark);
|
|
226
|
+
const pathLayers = [...enclosingInsertionAncestors({
|
|
227
|
+
insertionMark: deletionMark ? insertionMark : void 0,
|
|
228
|
+
ancestors: attrs._docxRevisionAncestors ?? [],
|
|
229
|
+
node
|
|
230
|
+
}), trackedRevisionLayerOf(mark, node)];
|
|
231
|
+
const layers = pathLayers.map((layer) => ({
|
|
232
|
+
kind: layer.type === "insertion" || layer.type === "moveTo" ? "insertion" : "deletion",
|
|
233
|
+
revision: {
|
|
234
|
+
id: layer.revisionId,
|
|
235
|
+
author: layer.author,
|
|
236
|
+
date: layer.date ?? null
|
|
237
|
+
}
|
|
238
|
+
}));
|
|
239
|
+
for (const [layerIndex, { kind: layerKind, revision }] of layers.entries()) {
|
|
226
240
|
const rowScope = rowRevisionScopes.at(-1);
|
|
227
|
-
if (rowScope?.kind ===
|
|
228
|
-
const
|
|
241
|
+
if (rowScope?.kind === layerKind && belongsToRowRevision(rowScope, revision)) continue;
|
|
242
|
+
const path = `${currentBlockId ?? ""}:${JSON.stringify(pathLayers.slice(0, layerIndex + 1))}`;
|
|
243
|
+
const previousKey = lastInlineGroupByPath.get(path);
|
|
244
|
+
const previousRange = previousKey === void 0 ? void 0 : inlineRanges.get(previousKey);
|
|
245
|
+
const key = previousKey !== void 0 && previousRange && transparentGap(previousRange.end, pos) ? previousKey : `${path}:${pos}`;
|
|
246
|
+
lastInlineGroupByPath.set(path, key);
|
|
247
|
+
const hyperlink = node.marks.find((candidate) => candidate.type.name === "hyperlink");
|
|
248
|
+
const commentId = node.marks.find((candidate) => candidate.type.name === "comment")?.attrs["commentId"];
|
|
249
|
+
const boundary = {
|
|
250
|
+
hyperlink: hyperlink ? String(hyperlink.attrs["href"] ?? "") : null,
|
|
251
|
+
comment: typeof commentId === "number" ? commentId : null,
|
|
252
|
+
revisionParents: JSON.stringify(pathLayers.slice(0, layerIndex))
|
|
253
|
+
};
|
|
254
|
+
const range = inlineRanges.get(key);
|
|
255
|
+
if (range) {
|
|
256
|
+
range.end = pos + node.nodeSize;
|
|
257
|
+
range.lastBoundary = boundary;
|
|
258
|
+
} else inlineRanges.set(key, {
|
|
259
|
+
start: pos,
|
|
260
|
+
end: pos + node.nodeSize,
|
|
261
|
+
firstBoundary: boundary,
|
|
262
|
+
lastBoundary: boundary
|
|
263
|
+
});
|
|
229
264
|
const existing = grouped.get(key);
|
|
230
265
|
if (existing) {
|
|
231
266
|
existing.text += text;
|
|
@@ -233,71 +268,99 @@ const getTrackedChangesFromProjectedDoc = (doc, blockStarts) => {
|
|
|
233
268
|
}
|
|
234
269
|
grouped.set(key, {
|
|
235
270
|
...revision,
|
|
236
|
-
type:
|
|
271
|
+
type: layerKind,
|
|
237
272
|
text,
|
|
238
273
|
blockId: currentBlockId
|
|
239
274
|
});
|
|
240
275
|
}
|
|
241
276
|
});
|
|
242
|
-
|
|
277
|
+
const groups = [];
|
|
278
|
+
let previousKey = null;
|
|
279
|
+
for (const [key, change] of grouped) {
|
|
280
|
+
const range = inlineRanges.get(key);
|
|
281
|
+
const previous = groups.at(-1);
|
|
282
|
+
const previousRange = previousKey === null ? void 0 : inlineRanges.get(previousKey);
|
|
283
|
+
if (previous && range && previousRange && previousRange.end <= range.start && transparentGap(previousRange.end, range.start) && previousRange.lastBoundary.revisionParents === range.firstBoundary.revisionParents && (previousRange.lastBoundary.hyperlink !== range.firstBoundary.hyperlink || previousRange.lastBoundary.comment !== range.firstBoundary.comment || previousRange.end !== range.start) && (change.type === "insertion" || change.type === "deletion") && previous.change.type === change.type && previous.change.author === change.author && previous.change.date === change.date && previous.change.blockId === change.blockId) {
|
|
284
|
+
previous.change.text += change.text;
|
|
285
|
+
previous.ids.push(change.id);
|
|
286
|
+
previousRange.end = range.end;
|
|
287
|
+
previousRange.lastBoundary = range.lastBoundary;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
groups.push({
|
|
291
|
+
change: { ...change },
|
|
292
|
+
ids: [change.id]
|
|
293
|
+
});
|
|
294
|
+
previousKey = key;
|
|
295
|
+
}
|
|
296
|
+
return groups;
|
|
243
297
|
};
|
|
298
|
+
const getTrackedChangesFromProjectedDoc = (doc, blockStarts) => getTrackedChangeGroupsFromProjectedDoc(doc, blockStarts).map(({ change }) => change);
|
|
244
299
|
/** Read revisions from the exact immutable document that produced a snapshot. */
|
|
245
300
|
const getTrackedChangesFromSnapshot = (snapshot) => getTrackedChangesFromProjectedDoc(sourceDocumentOf(snapshot), blockStartIdsFromSnapshot(snapshot));
|
|
246
301
|
/**
|
|
247
302
|
* The tracked changes present in the body, read from inline marks and
|
|
248
|
-
* structural node attributes.
|
|
249
|
-
* into
|
|
303
|
+
* structural node attributes. Adjacent runs sharing a revision wrapper path
|
|
304
|
+
* fold into one entry; interrupted or differently nested wrappers stay separate.
|
|
250
305
|
*
|
|
251
306
|
* A tracked row insertion or deletion marks the row AND every run in its
|
|
252
307
|
* cells, the way Word writes it. Both halves are one change, so the run marks
|
|
253
308
|
* fold into the row's entry rather than reporting a second time.
|
|
254
309
|
*/
|
|
255
310
|
const getTrackedChangesFromDoc = (doc) => getTrackedChangesFromProjectedDoc(doc, blockStartIdsFromDoc(doc));
|
|
311
|
+
/** Physical revision ids behind an inline change split by markup. */
|
|
312
|
+
const getTrackedChangeGroupIdsFromDoc = (doc, id) => getTrackedChangeGroupsFromProjectedDoc(doc, blockStartIdsFromDoc(doc)).find(({ ids }) => ids.includes(id))?.ids ?? [id];
|
|
256
313
|
/** @internal Read revision statistics without paying for an unrelated block projection. */
|
|
257
314
|
const getTrackedChangeStatsFromDoc = (doc) => {
|
|
258
315
|
let highestId = 0;
|
|
259
|
-
const
|
|
260
|
-
for (const
|
|
316
|
+
const groups = getTrackedChangeGroupsFromProjectedDoc(doc, null);
|
|
317
|
+
for (const { ids } of groups) for (const id of ids) highestId = Math.max(highestId, id);
|
|
261
318
|
return {
|
|
262
319
|
highestId,
|
|
263
|
-
present:
|
|
320
|
+
present: groups.length > 0
|
|
264
321
|
};
|
|
265
322
|
};
|
|
266
323
|
/**
|
|
267
324
|
* The comment anchors present in the body, read from the `comment` mark the
|
|
268
325
|
* editor renders. Each entry carries the anchored text and containing block id;
|
|
269
|
-
*
|
|
326
|
+
* ranges for one comment id within the body fold into a single anchor.
|
|
270
327
|
*/
|
|
271
328
|
const getCommentAnchorsFromDoc = (doc) => {
|
|
272
329
|
const commentType = doc.type.schema.marks["comment"];
|
|
273
330
|
if (!commentType) return [];
|
|
274
331
|
const blockStarts = blockStartIdsFromDoc(doc);
|
|
275
|
-
const
|
|
332
|
+
const ranges = /* @__PURE__ */ new Map();
|
|
333
|
+
const noteReferences = collectNoteReferenceLabels(doc);
|
|
276
334
|
let currentBlockId = null;
|
|
335
|
+
let bodyText = "";
|
|
277
336
|
doc.descendants((node, pos) => {
|
|
278
337
|
if (node.isTextblock) {
|
|
279
338
|
currentBlockId = blockStarts.get(pos) ?? null;
|
|
280
339
|
return true;
|
|
281
340
|
}
|
|
282
341
|
if (!node.isInline || node.text === void 0) return;
|
|
283
|
-
const text = node
|
|
342
|
+
const text = readerTextOf(node, noteReferences);
|
|
343
|
+
const end = bodyText.length + text.length;
|
|
284
344
|
for (const mark of node.marks) {
|
|
285
345
|
if (mark.type !== commentType || typeof mark.attrs["commentId"] !== "number") continue;
|
|
286
346
|
const commentId = mark.attrs["commentId"];
|
|
287
|
-
const
|
|
288
|
-
if (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
existing.quote += text;
|
|
297
|
-
existing.blockId ??= currentBlockId;
|
|
347
|
+
const range = ranges.get(commentId);
|
|
348
|
+
if (range) {
|
|
349
|
+
range.end = end;
|
|
350
|
+
range.blockId ??= currentBlockId;
|
|
351
|
+
} else ranges.set(commentId, {
|
|
352
|
+
blockId: currentBlockId,
|
|
353
|
+
start: bodyText.length,
|
|
354
|
+
end
|
|
355
|
+
});
|
|
298
356
|
}
|
|
357
|
+
bodyText += text;
|
|
299
358
|
});
|
|
300
|
-
return [...
|
|
359
|
+
return [...ranges].map(([commentId, { blockId, start, end }]) => ({
|
|
360
|
+
commentId,
|
|
361
|
+
blockId,
|
|
362
|
+
quote: bodyText.slice(start, end)
|
|
363
|
+
}));
|
|
301
364
|
};
|
|
302
365
|
//#endregion
|
|
303
|
-
export { FOLIO_REVIEW_CHANGE_KINDS, getCommentAnchorsFromDoc, getTrackedChangeStatsFromDoc, getTrackedChangesFromDoc, getTrackedChangesFromSnapshot };
|
|
366
|
+
export { FOLIO_REVIEW_CHANGE_KINDS, getCommentAnchorsFromDoc, getTrackedChangeGroupIdsFromDoc, getTrackedChangeStatsFromDoc, getTrackedChangesFromDoc, getTrackedChangesFromSnapshot };
|