@stll/folio-core 0.52.0 → 0.53.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 +1519 -105
- package/dist/ai-edits/batch-claims.d.ts +130 -0
- package/dist/ai-edits/batch-claims.js +244 -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 +71 -7
- package/dist/ai-edits/headless.js +381 -41
- 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 +1 -1
- package/dist/ai-edits/read.js +56 -43
- package/dist/ai-edits/result-validation.d.ts +29 -0
- package/dist/ai-edits/result-validation.js +164 -0
- package/dist/ai-edits/snapshot.d.ts +36 -3
- package/dist/ai-edits/snapshot.js +177 -23
- package/dist/ai-edits/table-cell-mutations.d.ts +1 -1
- package/dist/ai-edits/table-cell-mutations.js +4 -1
- package/dist/ai-edits/table-geometry.d.ts +1 -1
- package/dist/ai-edits/table-row-column-mutations.d.ts +38 -16
- package/dist/ai-edits/table-row-column-mutations.js +61 -26
- 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.js +13 -2
- 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/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 +62 -9
- 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/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/normalizeBaseDirection.js +2 -1
- 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 +91 -24
- package/dist/docx/paragraphPropertySource.d.ts +4 -2
- package/dist/docx/paragraphPropertySource.js +7 -1
- package/dist/docx/paragraphTraversal.js +1 -0
- package/dist/docx/parseWarningMessage.js +4 -1
- package/dist/docx/parser.js +173 -20
- package/dist/docx/rezip.js +27 -5
- 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.js +106 -37
- 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/createBilingualDocument.js +3 -3
- 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 +2 -1
- package/dist/docx/unzip.js +1 -1
- package/dist/docx/wordprocessingPrefixes.d.ts +78 -0
- package/dist/docx/wordprocessingPrefixes.js +286 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +136 -0
- package/dist/i18n/messages/catalogs.gen.js +153 -17
- package/dist/i18n/messages/messages.gen.d.ts +8 -0
- 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 +530 -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/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/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/fromMarkdown.js +2 -1
- package/dist/markdown/internals.d.ts +11 -1
- package/dist/markdown/internals.js +24 -3
- package/dist/markdown/renderBlock.js +39 -9
- package/dist/markdown/renderParagraph.d.ts +13 -1
- package/dist/markdown/renderParagraph.js +85 -38
- package/dist/markdown/renderRuns.js +3 -10
- 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/commands/comments.d.ts +7 -8
- package/dist/prosemirror/commands/comments.js +241 -207
- package/dist/prosemirror/commands/contentControls.d.ts +1 -1
- package/dist/prosemirror/commands/formatPainter.d.ts +1 -1
- package/dist/prosemirror/commands/formatting.d.ts +1 -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/resolveAllTableChanges.d.ts +40 -0
- package/dist/prosemirror/commands/resolveAllTableChanges.js +615 -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 +59 -0
- package/dist/prosemirror/commands/sectionBreak.js +2 -1
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +8 -2
- package/dist/prosemirror/commands/tableCellMergeResolution.js +1 -1
- package/dist/prosemirror/contentControlRevisions.d.ts +1 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +181 -31
- package/dist/prosemirror/conversion/toProseDoc.js +39 -4
- 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 +3 -1
- package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -0
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +3 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +161 -123
- 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/pastedHtmlLists.d.ts +12 -0
- package/dist/prosemirror/extensions/features/pastedHtmlLists.js +126 -0
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +21 -5
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +21 -18
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +37 -17
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +7 -2
- package/dist/prosemirror/extensions/marks/markUtils.js +8 -2
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +10 -0
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +35 -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/FieldExtension.d.ts +3 -3
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +50 -15
- 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 +19 -18
- package/dist/prosemirror/extensions/types.d.ts +4 -1
- package/dist/prosemirror/findReplaceSelection.js +1 -1
- package/dist/prosemirror/index.d.ts +3 -2
- package/dist/prosemirror/index.js +3 -2
- 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 +110 -0
- package/dist/prosemirror/listNumbering.js +345 -0
- package/dist/prosemirror/listRenderingAttrs.d.ts +11 -2
- package/dist/prosemirror/listRenderingAttrs.js +8 -1
- package/dist/prosemirror/markupViewProjection.d.ts +95 -0
- package/dist/prosemirror/markupViewProjection.js +83 -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 +29 -7
- package/dist/prosemirror/paragraphMarkJoin.d.ts +19 -0
- package/dist/prosemirror/paragraphMarkJoin.js +24 -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/documentStyles.d.ts +10 -1
- package/dist/prosemirror/plugins/documentStyles.js +14 -1
- package/dist/prosemirror/plugins/suggestionMode.d.ts +16 -2
- package/dist/prosemirror/plugins/suggestionMode.js +116 -52
- 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 +1 -1
- 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/runFormattingInlineCarriers.d.ts +1 -1
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/index.js +3 -0
- package/dist/prosemirror/schema/nodes.d.ts +42 -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/tableGridMutation.d.ts +48 -2
- package/dist/prosemirror/tableGridMutation.js +106 -1
- 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/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 +3 -2
- package/dist/internal/headlessRevisionResolution.d.ts +0 -23
|
@@ -3,6 +3,7 @@ import { matchInlineProvenance } from "../compare/inline-provenance.js";
|
|
|
3
3
|
import { stageSectionBoundaryProperties } from "../compare/section-boundary-properties.js";
|
|
4
4
|
import { importReferencedStyleDefinitions } from "../compare/style-resources.js";
|
|
5
5
|
import { applyFolioDocumentOperations } from "../document-operations.js";
|
|
6
|
+
import { applyReplyThreadMarkers } from "../docx/commentReplyMarkers.js";
|
|
6
7
|
import { rebindDrawingImageRelationship } from "../docx/drawingRelationships.js";
|
|
7
8
|
import { getEndnoteText, getFootnoteText, isSeparatorEndnote, isSeparatorFootnote } from "../docx/footnoteParser.js";
|
|
8
9
|
import { getHeaderFooterText } from "../docx/headerFooterParser.js";
|
|
@@ -17,21 +18,26 @@ import { pluginsForHeadlessRevisionResolution } from "../internal/headlessRevisi
|
|
|
17
18
|
import { withTrackedSectionEndpointRemoval } from "../internal/sectionEndpointResolution.js";
|
|
18
19
|
import { captureSectionReferenceInventory, resolvedSectionReferenceLosses, withSectionReferenceResolution } from "../internal/sectionReferenceResolution.js";
|
|
19
20
|
import { expectCharacterStyleMarkAttrs } from "../prosemirror/attrs/index.js";
|
|
20
|
-
import { acceptAIEditRevision, rejectAIEditRevision, resolveAllChangesInHeadlessState } from "../prosemirror/commands/comments.js";
|
|
21
|
+
import { acceptAIEditRevision, acceptSuggestion, getSuggestions, rejectAIEditRevision, rejectAllSuggestions, rejectSuggestion, resolveAllChangesInHeadlessState, suggestionIdOfRevision } from "../prosemirror/commands/comments.js";
|
|
21
22
|
import { sectionRejectProperties } from "../prosemirror/commands/propertyChangeScope.js";
|
|
22
23
|
import { proseDocToBlocks, updateDocumentContent } from "../prosemirror/conversion/fromProseDoc.js";
|
|
23
24
|
import { footnoteToProseDoc, headerFooterToProseDoc, toProseDoc } from "../prosemirror/conversion/toProseDoc.js";
|
|
24
25
|
import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
|
|
25
26
|
import { getChangedParagraphIds, getTrackedSectionEndpointRemoval, hasStructuralChanges, hasUntrackedChanges } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
|
|
27
|
+
import { completeNumberingForDoc } from "../prosemirror/listInstanceReferences.js";
|
|
26
28
|
import "../prosemirror/listMarker.js";
|
|
27
29
|
import { createDocumentNumberingPlugin, withDocumentNumbering } from "../prosemirror/plugins/documentNumbering.js";
|
|
28
30
|
import { createDocumentStylesPlugin, getDocumentStyleResolver, withDocumentStyles } from "../prosemirror/plugins/documentStyles.js";
|
|
29
31
|
import { schema, singletonManager } from "../prosemirror/schema/index.js";
|
|
32
|
+
import { sectionPropertiesOf } from "../prosemirror/sectionCarrier.js";
|
|
33
|
+
import { storyListNumbering } from "../prosemirror/storyListNumbering.js";
|
|
30
34
|
import { canonicalJson } from "../utils/canonicalJson.js";
|
|
31
35
|
import { deterministicHexId } from "../utils/hexId.js";
|
|
32
|
-
import {
|
|
36
|
+
import { buildAnnotatedBlockTextWithNoteReferences } from "./clean-text.js";
|
|
37
|
+
import { anchoredCommentIdsInBlocks, anchoredCommentIdsInProseDoc, withoutLostCommentThreads } from "./comment-lifecycle.js";
|
|
38
|
+
import { FolioPendingSuggestionRegistry, createPendingSuggestionSourceSnapshot, withoutPendingSuggestionCommentMarks } from "./pending-suggestions.js";
|
|
33
39
|
import { getCommentAnchorsFromDoc, getTrackedChangeStatsFromDoc, getTrackedChangesFromDoc, getTrackedChangesFromSnapshot } from "./read.js";
|
|
34
|
-
import { createFolioAIEditSnapshotWithStyleResolver, detachFolioAIEditSnapshotExternalHyperlinks, folioStoryTables, isFolioAIContentBlock, normalizeFolioAIBlockText, sourceDocumentOf } from "./snapshot.js";
|
|
40
|
+
import { collectNoteReferenceLabels, createFolioAIEditSnapshotWithStyleResolver, detachFolioAIEditSnapshotExternalHyperlinks, folioStoryTables, isFolioAIContentBlock, normalizeFolioAIBlockText, sourceDocumentOf } from "./snapshot.js";
|
|
35
41
|
import { matchTableGeometry } from "./table-geometry.js";
|
|
36
42
|
import { tableTemplateCanCrossPackageLosslessly } from "./table-template.js";
|
|
37
43
|
import { TaggedError, panic } from "better-result";
|
|
@@ -248,6 +254,15 @@ const comparisonAccessByReviewer = /* @__PURE__ */ new WeakMap();
|
|
|
248
254
|
const MAIN_STORY = Object.freeze({ type: "main" });
|
|
249
255
|
const headerFooterStoryKey = ({ type, relationshipId }) => `${type}:${relationshipId}`;
|
|
250
256
|
const noteStoryKey = ({ type, noteId }) => `${type}:${noteId}`;
|
|
257
|
+
/**
|
|
258
|
+
* A part's roles as a reader label: `first`, or, in a document with several
|
|
259
|
+
* sections, `first (sections 1, 3), default (section 2)`.
|
|
260
|
+
*/
|
|
261
|
+
const describePlacements = (placements, sectionCount) => {
|
|
262
|
+
const sectionsByRole = /* @__PURE__ */ new Map();
|
|
263
|
+
for (const { type, section } of placements) sectionsByRole.set(type, [...sectionsByRole.get(type) ?? [], section]);
|
|
264
|
+
return [...sectionsByRole].map(([type, sections]) => sectionCount > 1 ? `${type} (${sections.length > 1 ? "sections" : "section"} ${sections.join(", ")})` : type).join(", ");
|
|
265
|
+
};
|
|
251
266
|
const secondaryStoryKey = (story) => story.type === "header" || story.type === "footer" ? headerFooterStoryKey(story) : noteStoryKey(story);
|
|
252
267
|
const editableStoryKey = (story) => story.type === "main" ? "main" : secondaryStoryKey(story);
|
|
253
268
|
const isFolioReviewedView = (value) => FOLIO_REVIEWED_VIEWS.some((view) => view === value);
|
|
@@ -256,6 +271,18 @@ const resolveReviewedState = (state, view) => {
|
|
|
256
271
|
if (view === "current-markup") return state;
|
|
257
272
|
return resolveAllChangesInHeadlessState(state, view === "original" ? "reject" : "accept");
|
|
258
273
|
};
|
|
274
|
+
/**
|
|
275
|
+
* Reject suggestions before resolving all ordinary revisions. A suggested
|
|
276
|
+
* whole-paragraph or table insert is flagged on the node; its flag must stay
|
|
277
|
+
* intact until that suggestion is explicitly accepted or rejected.
|
|
278
|
+
*/
|
|
279
|
+
const rejectSuggestions = (state) => {
|
|
280
|
+
let settled = state;
|
|
281
|
+
rejectAllSuggestions()(state, (transaction) => {
|
|
282
|
+
settled = state.apply(transaction);
|
|
283
|
+
});
|
|
284
|
+
return settled;
|
|
285
|
+
};
|
|
259
286
|
const createHeadlessPlugins = (styles, numbering) => [
|
|
260
287
|
...pluginsForHeadlessRevisionResolution(singletonManager.getPlugins()),
|
|
261
288
|
createDocumentStylesPlugin(styles),
|
|
@@ -266,7 +293,9 @@ const formatStorySnapshotForLLM = (snapshot, annotated) => {
|
|
|
266
293
|
const blocks = snapshot.blocks.filter(isFolioAIContentBlock);
|
|
267
294
|
if (!annotated) return blocks.map(formatBlockForLLM).join("\n");
|
|
268
295
|
const nodeByStart = /* @__PURE__ */ new Map();
|
|
269
|
-
sourceDocumentOf(snapshot)
|
|
296
|
+
const sourceDocument = sourceDocumentOf(snapshot);
|
|
297
|
+
const noteReferences = collectNoteReferenceLabels(sourceDocument);
|
|
298
|
+
sourceDocument.descendants((node, pos) => {
|
|
270
299
|
if (!node.isTextblock) return true;
|
|
271
300
|
nodeByStart.set(pos, node);
|
|
272
301
|
return false;
|
|
@@ -276,18 +305,22 @@ const formatStorySnapshotForLLM = (snapshot, annotated) => {
|
|
|
276
305
|
return blocks.map((block) => {
|
|
277
306
|
const from = startById.get(block.id);
|
|
278
307
|
const node = from === void 0 ? void 0 : nodeByStart.get(from);
|
|
279
|
-
const text = node ?
|
|
308
|
+
const text = node ? buildAnnotatedBlockTextWithNoteReferences(node, noteReferences) : block.text;
|
|
280
309
|
return formatBlockLine(block, text);
|
|
281
310
|
}).join("\n");
|
|
282
311
|
};
|
|
283
312
|
/**
|
|
284
313
|
* One LLM-ready line for a block: `[<blockId>] text`, with an `(h<level>)` tag
|
|
285
|
-
* for headings
|
|
286
|
-
* block id straight back into an
|
|
314
|
+
* for headings, then the number a numbered heading shows, and the list marker
|
|
315
|
+
* for list items, so a model can copy the block id straight back into an
|
|
316
|
+
* operation and match the numbers the document shows.
|
|
287
317
|
*/
|
|
288
318
|
const formatBlockLine = (block, text) => {
|
|
289
319
|
const label = `[${block.id}]`;
|
|
290
|
-
if (block.kind === "heading")
|
|
320
|
+
if (block.kind === "heading") {
|
|
321
|
+
const number = block.displayLabel !== void 0 && block.displayLabel !== block.styleId ? `${block.displayLabel} ` : "";
|
|
322
|
+
return `${label} (h${headingLevel(block)}) ${number}${text}`;
|
|
323
|
+
}
|
|
291
324
|
if (block.kind === "listItem") return `${label} ${block.displayLabel ?? "•"} ${text}`;
|
|
292
325
|
return `${label} ${text}`;
|
|
293
326
|
};
|
|
@@ -340,7 +373,10 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
340
373
|
resolvedStoryExpectations = /* @__PURE__ */ new Map();
|
|
341
374
|
createdComments = [];
|
|
342
375
|
usedCommentIds;
|
|
376
|
+
/** Comments the body anchored when it was loaded, read as the editor projects it. */
|
|
377
|
+
loadedMainCommentIds;
|
|
343
378
|
documentOperationUndoEntries = [];
|
|
379
|
+
pendingSuggestions = new FolioPendingSuggestionRegistry();
|
|
344
380
|
/**
|
|
345
381
|
* Resolved-state overrides recorded by {@link resolveComment}, keyed by
|
|
346
382
|
* comment id. Applied on read ({@link getComments}) and on write
|
|
@@ -356,6 +392,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
356
392
|
this.state = args.state;
|
|
357
393
|
this.author = args.author;
|
|
358
394
|
this.usedCommentIds = new Set((args.baseDocument.package.document.comments ?? []).map(({ id }) => id));
|
|
395
|
+
this.loadedMainCommentIds = anchoredCommentIdsInProseDoc(args.state.doc);
|
|
359
396
|
comparisonAccessByReviewer.set(this, Object.freeze({
|
|
360
397
|
stageTerminalTableReviewCarrier: (target) => this.stageTerminalTableReviewCarrier(target),
|
|
361
398
|
stageTargetStyles: (source, snapshots, importedHeaderFooterSnapshots) => this.stageTargetStyles(source, snapshots, importedHeaderFooterSnapshots),
|
|
@@ -609,6 +646,51 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
609
646
|
snapshot() {
|
|
610
647
|
return createStateSnapshot(this.state);
|
|
611
648
|
}
|
|
649
|
+
/** Export staged AI operations for storage by the host, outside the DOCX. */
|
|
650
|
+
exportPendingSuggestions() {
|
|
651
|
+
const active = new Set(getSuggestions(this.state).map(({ suggestionId }) => suggestionId));
|
|
652
|
+
for (const entry of this.secondaryStoryStates.values()) for (const { suggestionId } of getSuggestions(entry.state)) active.add(suggestionId);
|
|
653
|
+
return this.pendingSuggestions.exportPendingSuggestions({
|
|
654
|
+
activeSuggestionIds: active,
|
|
655
|
+
snapshotForStory: (story, commentIds) => {
|
|
656
|
+
const state = this.getEditableStoryState(story);
|
|
657
|
+
return state ? createPendingSuggestionSourceSnapshot(state, commentIds) : null;
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
/** Validate saved proposals against this document before restaging them. */
|
|
662
|
+
loadPendingSuggestions(records) {
|
|
663
|
+
return this.pendingSuggestions.loadPendingSuggestions({
|
|
664
|
+
records,
|
|
665
|
+
snapshotForStory: (story) => this.snapshotStory(story),
|
|
666
|
+
sourceSnapshotForStory: (story, commentIds) => {
|
|
667
|
+
const state = this.getEditableStoryState(story);
|
|
668
|
+
return state ? createPendingSuggestionSourceSnapshot(state, commentIds) : null;
|
|
669
|
+
},
|
|
670
|
+
apply: (record, snapshot) => {
|
|
671
|
+
const result = this.applyDocumentOperationsInternal({
|
|
672
|
+
story: record.story,
|
|
673
|
+
batch: {
|
|
674
|
+
version: 1,
|
|
675
|
+
operations: [record.operation],
|
|
676
|
+
mode: "suggested"
|
|
677
|
+
},
|
|
678
|
+
snapshot,
|
|
679
|
+
author: record.author,
|
|
680
|
+
createUndoEntry: false
|
|
681
|
+
});
|
|
682
|
+
return {
|
|
683
|
+
applied: result.applied,
|
|
684
|
+
skipped: result.skipped
|
|
685
|
+
};
|
|
686
|
+
},
|
|
687
|
+
activeSuggestionIds: () => {
|
|
688
|
+
const active = new Set(getSuggestions(this.state).map(({ suggestionId }) => suggestionId));
|
|
689
|
+
for (const entry of this.secondaryStoryStates.values()) for (const { suggestionId } of getSuggestions(entry.state)) active.add(suggestionId);
|
|
690
|
+
return active;
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
}
|
|
612
694
|
/**
|
|
613
695
|
* The package's numbering, flattened to what a reader sees: one entry per
|
|
614
696
|
* numbering instance and level, with the format and level text that produce
|
|
@@ -621,7 +703,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
621
703
|
* packages can be compared entry by entry.
|
|
622
704
|
*/
|
|
623
705
|
readNumberingDefinitions() {
|
|
624
|
-
return numberingLevelsOf(this.baseDocument.package.numbering).toSorted((left, right) => left.numId - right.numId || left.level - right.level);
|
|
706
|
+
return numberingLevelsOf(completeNumberingForDoc(this.baseDocument.package.numbering, this.state.doc)).toSorted((left, right) => left.numId - right.numId || left.level - right.level);
|
|
625
707
|
}
|
|
626
708
|
/** Return parsed package metadata without exposing the mutable document model. */
|
|
627
709
|
getDocumentProperties() {
|
|
@@ -810,7 +892,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
810
892
|
});
|
|
811
893
|
}
|
|
812
894
|
/** Apply a versioned operation batch to one editable document story. */
|
|
813
|
-
applyDocumentOperationsToStory({ story, batch, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground }) {
|
|
895
|
+
applyDocumentOperationsToStory({ story, batch, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedStyles }) {
|
|
814
896
|
return this.applyDocumentOperationsInternal({
|
|
815
897
|
story,
|
|
816
898
|
batch,
|
|
@@ -819,11 +901,14 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
819
901
|
...wordDiff !== void 0 && { wordDiff },
|
|
820
902
|
...tableTemplates !== void 0 && { tableTemplates },
|
|
821
903
|
...replacementBackground !== void 0 && { replacementBackground },
|
|
904
|
+
...undefinedStyles !== void 0 && { undefinedStyles },
|
|
822
905
|
createUndoEntry: true
|
|
823
906
|
});
|
|
824
907
|
}
|
|
825
|
-
applyDocumentOperationsInternal({ story, batch, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, createUndoEntry }) {
|
|
908
|
+
applyDocumentOperationsInternal({ story, batch, author, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedStyles, createUndoEntry }) {
|
|
826
909
|
const beforeState = this.requireEditableStoryState(story);
|
|
910
|
+
const operationAuthor = author ?? this.author;
|
|
911
|
+
const sourceSnapshot = snapshot ?? createStateSnapshot(beforeState);
|
|
827
912
|
const createdCommentsLengthBefore = this.createdComments.length;
|
|
828
913
|
const view = {
|
|
829
914
|
state: beforeState,
|
|
@@ -833,19 +918,20 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
833
918
|
};
|
|
834
919
|
const result = applyFolioDocumentOperations({
|
|
835
920
|
view,
|
|
836
|
-
snapshot:
|
|
921
|
+
snapshot: sourceSnapshot,
|
|
837
922
|
batch,
|
|
838
923
|
story: story.type === "main" ? "main" : story,
|
|
839
|
-
author:
|
|
924
|
+
author: operationAuthor,
|
|
840
925
|
...revisionStamp !== void 0 && { revisionStamp },
|
|
841
926
|
...wordDiff !== void 0 && { wordDiff },
|
|
842
927
|
...tableTemplates !== void 0 && { tableTemplates },
|
|
843
928
|
...replacementBackground !== void 0 && { replacementBackground },
|
|
929
|
+
...undefinedStyles !== void 0 && { undefinedStyles },
|
|
844
930
|
createCommentId: (text) => {
|
|
845
931
|
const comment = createReviewerComment({
|
|
846
932
|
id: this.nextCommentId(),
|
|
847
933
|
text,
|
|
848
|
-
author:
|
|
934
|
+
author: operationAuthor,
|
|
849
935
|
date: revisionStamp?.date
|
|
850
936
|
});
|
|
851
937
|
this.createdComments.push(comment);
|
|
@@ -856,7 +942,23 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
856
942
|
id: `headless-${String(undoHandleCursor++)}`
|
|
857
943
|
}) }
|
|
858
944
|
});
|
|
945
|
+
const appliedCommentIds = new Set(result.applied.flatMap(({ commentId }) => commentId === void 0 ? [] : [commentId]));
|
|
946
|
+
const createdByBatch = this.createdComments.splice(createdCommentsLengthBefore);
|
|
947
|
+
this.createdComments.push(...createdByBatch.filter((comment) => appliedCommentIds.has(comment.id)));
|
|
859
948
|
this.setEditableStoryState(story, view.state);
|
|
949
|
+
if (batch.mode === "suggested") {
|
|
950
|
+
const activeSuggestionIds = new Set(getSuggestions(beforeState).map(({ suggestionId }) => suggestionId));
|
|
951
|
+
for (const { suggestionId } of getSuggestions(this.state)) activeSuggestionIds.add(suggestionId);
|
|
952
|
+
for (const entry of this.secondaryStoryStates.values()) for (const { suggestionId } of getSuggestions(entry.state)) activeSuggestionIds.add(suggestionId);
|
|
953
|
+
this.pendingSuggestions.recordApplied({
|
|
954
|
+
snapshot: sourceSnapshot,
|
|
955
|
+
story,
|
|
956
|
+
operations: batch.operations,
|
|
957
|
+
applied: result.applied,
|
|
958
|
+
author: operationAuthor,
|
|
959
|
+
activeSuggestionIds
|
|
960
|
+
});
|
|
961
|
+
}
|
|
860
962
|
if (result.undoHandle !== null) this.documentOperationUndoEntries.push({
|
|
861
963
|
undoHandle: result.undoHandle,
|
|
862
964
|
story,
|
|
@@ -926,10 +1028,15 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
926
1028
|
* one per non-empty part: `[header default] …`, `[footer default] …`,
|
|
927
1029
|
* `[footnote #N] …`, `[endnote #N] …`. Lines reflect in-memory edits. Empty
|
|
928
1030
|
* parts and separator notes are omitted.
|
|
1031
|
+
*
|
|
1032
|
+
* A header or footer is labelled with the role its section references give
|
|
1033
|
+
* it (`default`, `first`, `even`); in a document with several sections, also
|
|
1034
|
+
* with the sections that show it: `[header first (sections 1, 3)] …`.
|
|
929
1035
|
*/
|
|
930
1036
|
getNotesAsText() {
|
|
931
1037
|
const pkg = this.baseDocument.package;
|
|
932
1038
|
const lines = [];
|
|
1039
|
+
const placements = this.headerFooterPlacements();
|
|
933
1040
|
const pushHeaderFooter = (map, label) => {
|
|
934
1041
|
if (!map) return;
|
|
935
1042
|
for (const [relationshipId, hf] of map) {
|
|
@@ -938,7 +1045,10 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
938
1045
|
relationshipId
|
|
939
1046
|
};
|
|
940
1047
|
const text = this.getHeaderFooterStoryText(handle, hf);
|
|
941
|
-
if (text.length > 0)
|
|
1048
|
+
if (text.length > 0) {
|
|
1049
|
+
const roles = placements.byPart.get(`${label}:${relationshipId}`);
|
|
1050
|
+
lines.push(`[${label} ${roles ? describePlacements(roles, placements.sectionCount) : hf.hdrFtrType}] ${text}`);
|
|
1051
|
+
}
|
|
942
1052
|
}
|
|
943
1053
|
};
|
|
944
1054
|
pushHeaderFooter(pkg.headers, "header");
|
|
@@ -1031,7 +1141,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1031
1141
|
* (nested tracked changes, hyperlinks) is out of scope.
|
|
1032
1142
|
*/
|
|
1033
1143
|
getComments(filter) {
|
|
1034
|
-
const definitions = this.withResolvedOverrides([...this.baseDocument.package.document.comments ?? [], ...this.createdComments]);
|
|
1144
|
+
const definitions = this.withResolvedOverrides(this.keptCommentThreads([...this.baseDocument.package.document.comments ?? [], ...this.createdComments], this.state, this.secondaryStoryStates.values()));
|
|
1035
1145
|
if (definitions.length === 0) return [];
|
|
1036
1146
|
const anchors = this.commentAnchors();
|
|
1037
1147
|
const repliesByParent = /* @__PURE__ */ new Map();
|
|
@@ -1054,6 +1164,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1054
1164
|
text: commentPlainText(comment),
|
|
1055
1165
|
anchoredText: anchor?.text ?? "",
|
|
1056
1166
|
blockId: anchor?.blockId ?? null,
|
|
1167
|
+
story: anchor?.story ?? null,
|
|
1057
1168
|
replies: (repliesByParent.get(comment.id) ?? []).map((reply) => ({
|
|
1058
1169
|
id: reply.id,
|
|
1059
1170
|
author: reply.author,
|
|
@@ -1071,7 +1182,8 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1071
1182
|
* {@link getComments} or its id; the reply threads under that comment's root
|
|
1072
1183
|
* (Word threads are flat). On {@link toBuffer} the reply is written as a real
|
|
1073
1184
|
* Word reply — linked via `commentsExtended.xml` and given its own
|
|
1074
|
-
* `commentRange` markers + reference anchored on the parent's range.
|
|
1185
|
+
* `commentRange` markers + reference anchored on the parent's range. The
|
|
1186
|
+
* live document carries the same anchor. Returns
|
|
1075
1187
|
* the created reply, or `null` when the target comment is absent.
|
|
1076
1188
|
*/
|
|
1077
1189
|
replyTo(target, input) {
|
|
@@ -1085,6 +1197,10 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1085
1197
|
if (!reply) return null;
|
|
1086
1198
|
this.createdComments.push(reply);
|
|
1087
1199
|
this.usedCommentIds.add(reply.id);
|
|
1200
|
+
this.anchorReplyInEditor({
|
|
1201
|
+
parentId: reply.parentId ?? parentId,
|
|
1202
|
+
replyId: reply.id
|
|
1203
|
+
});
|
|
1088
1204
|
return {
|
|
1089
1205
|
id: reply.id,
|
|
1090
1206
|
author: reply.author,
|
|
@@ -1092,6 +1208,31 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1092
1208
|
text: input.text
|
|
1093
1209
|
};
|
|
1094
1210
|
}
|
|
1211
|
+
anchorReplyInEditor({ parentId, replyId }) {
|
|
1212
|
+
for (const story of this.listStoryHandlesInternal()) {
|
|
1213
|
+
const state = this.getEditableStoryState(story);
|
|
1214
|
+
if (!state) continue;
|
|
1215
|
+
const commentMark = state.schema.marks["comment"];
|
|
1216
|
+
const referenceNode = state.schema.nodes["commentReference"];
|
|
1217
|
+
if (!commentMark || !referenceNode) continue;
|
|
1218
|
+
let from = null;
|
|
1219
|
+
let to = 0;
|
|
1220
|
+
let referenceAt = null;
|
|
1221
|
+
state.doc.descendants((node, pos) => {
|
|
1222
|
+
if (node.type === referenceNode && node.attrs["commentId"] === parentId) referenceAt ??= pos + node.nodeSize;
|
|
1223
|
+
if (node.isInline && node.marks.some((mark) => mark.type === commentMark && mark.attrs["commentId"] === parentId)) {
|
|
1224
|
+
from ??= pos;
|
|
1225
|
+
to = pos + node.nodeSize;
|
|
1226
|
+
}
|
|
1227
|
+
});
|
|
1228
|
+
if (referenceAt === null || from === null || from >= to) continue;
|
|
1229
|
+
let transaction = state.tr;
|
|
1230
|
+
transaction = transaction.addMark(from, to, commentMark.create({ commentId: replyId }));
|
|
1231
|
+
transaction = transaction.insert(referenceAt, referenceNode.create({ commentId: replyId }));
|
|
1232
|
+
this.setEditableStoryState(story, state.apply(transaction));
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1095
1236
|
/**
|
|
1096
1237
|
* Mark a comment thread resolved, or reopen a previously resolved one. Pass
|
|
1097
1238
|
* the id from {@link getComments} / {@link FolioReviewComment.id}. Applies
|
|
@@ -1111,6 +1252,39 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1111
1252
|
this.resolvedOverrides.set(target.id, resolved);
|
|
1112
1253
|
return true;
|
|
1113
1254
|
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Where each header and footer part is shown, as the live section
|
|
1257
|
+
* references state it: its role (`w:type`) and the 1-based section, in
|
|
1258
|
+
* section order. A part's own `hdrFtrType` holds one role, and one part can
|
|
1259
|
+
* serve several sections, in different roles.
|
|
1260
|
+
*/
|
|
1261
|
+
headerFooterPlacements() {
|
|
1262
|
+
const records = [];
|
|
1263
|
+
this.state.doc.descendants((node) => {
|
|
1264
|
+
if (node.type.name !== "paragraph") return true;
|
|
1265
|
+
const record = sectionPropertiesOf(node);
|
|
1266
|
+
if (record && !records.includes(record)) records.push(record);
|
|
1267
|
+
return false;
|
|
1268
|
+
});
|
|
1269
|
+
const final = this.currentFinalSectionProperties();
|
|
1270
|
+
if (final) records.push(final);
|
|
1271
|
+
const byPart = /* @__PURE__ */ new Map();
|
|
1272
|
+
for (const [index, record] of records.entries()) {
|
|
1273
|
+
const place = (part, type, rId) => {
|
|
1274
|
+
const key = `${part}:${rId}`;
|
|
1275
|
+
byPart.set(key, [...byPart.get(key) ?? [], {
|
|
1276
|
+
type,
|
|
1277
|
+
section: index + 1
|
|
1278
|
+
}]);
|
|
1279
|
+
};
|
|
1280
|
+
for (const { type, rId } of record.headerReferences ?? []) place("header", type, rId);
|
|
1281
|
+
for (const { type, rId } of record.footerReferences ?? []) place("footer", type, rId);
|
|
1282
|
+
}
|
|
1283
|
+
return {
|
|
1284
|
+
byPart,
|
|
1285
|
+
sectionCount: records.length
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1114
1288
|
currentFinalSectionProperties() {
|
|
1115
1289
|
return this.finalSectionPropertiesOverride ?? this.baseDocument.package.document.finalSectionProperties;
|
|
1116
1290
|
}
|
|
@@ -1203,6 +1377,8 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1203
1377
|
}
|
|
1204
1378
|
acceptChangeInternal(target) {
|
|
1205
1379
|
const id = revisionIdOf(target);
|
|
1380
|
+
const suggestionId = suggestionIdOfRevision(this.state, id);
|
|
1381
|
+
if (suggestionId !== null) this.runCommand(acceptSuggestion(suggestionId, { author: this.author }));
|
|
1206
1382
|
const bodyChanged = this.runCommand(acceptAIEditRevision(id));
|
|
1207
1383
|
const sectionChanged = this.resolveFinalSectionProperties("accept", id) > 0;
|
|
1208
1384
|
return bodyChanged || sectionChanged;
|
|
@@ -1216,13 +1392,40 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1216
1392
|
}
|
|
1217
1393
|
rejectChangeInternal(target) {
|
|
1218
1394
|
const id = revisionIdOf(target);
|
|
1395
|
+
const suggestionId = suggestionIdOfRevision(this.state, id);
|
|
1396
|
+
if (suggestionId !== null && this.runCommand(rejectSuggestion(suggestionId))) return true;
|
|
1219
1397
|
const bodyChanged = this.runCommand(rejectAIEditRevision(id));
|
|
1220
1398
|
const sectionChanged = this.resolveFinalSectionProperties("reject", id) > 0;
|
|
1221
1399
|
return bodyChanged || sectionChanged;
|
|
1222
1400
|
}
|
|
1401
|
+
/** Convert one pending suggestion into an ordinary tracked change. */
|
|
1402
|
+
acceptSuggestion(suggestionId, options) {
|
|
1403
|
+
return this.resolveWithSectionReferenceHistory(() => {
|
|
1404
|
+
let accepted = false;
|
|
1405
|
+
for (const handle of this.listStoryHandlesInternal()) {
|
|
1406
|
+
const state = this.getEditableStoryState(handle);
|
|
1407
|
+
if (!state || !getSuggestions(state).some((entry) => entry.suggestionId === suggestionId)) continue;
|
|
1408
|
+
accepted = this.runStoryCommand(acceptSuggestion(suggestionId, { author: options?.author ?? this.author }), handle) || accepted;
|
|
1409
|
+
}
|
|
1410
|
+
return accepted;
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
/** Remove one pending suggestion without applying it. */
|
|
1414
|
+
rejectSuggestion(suggestionId) {
|
|
1415
|
+
return this.resolveWithSectionReferenceHistory(() => {
|
|
1416
|
+
let rejected = false;
|
|
1417
|
+
for (const handle of this.listStoryHandlesInternal()) {
|
|
1418
|
+
const state = this.getEditableStoryState(handle);
|
|
1419
|
+
if (!state || !getSuggestions(state).some((entry) => entry.suggestionId === suggestionId)) continue;
|
|
1420
|
+
rejected = this.runStoryCommand(rejectSuggestion(suggestionId), handle) || rejected;
|
|
1421
|
+
}
|
|
1422
|
+
return rejected;
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1223
1425
|
/**
|
|
1224
|
-
* Accept every tracked change in the package.
|
|
1225
|
-
*
|
|
1426
|
+
* Accept every ordinary tracked change in the package. Pending suggestions
|
|
1427
|
+
* remain staged until {@link acceptSuggestion} is called. Returns the number
|
|
1428
|
+
* of ordinary changes present before the sweep.
|
|
1226
1429
|
*
|
|
1227
1430
|
* Every story, not just the body: a revision in a header or a footnote is
|
|
1228
1431
|
* one a reviewer meant to resolve, and leaving it behind means an accepted
|
|
@@ -1271,17 +1474,89 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1271
1474
|
}
|
|
1272
1475
|
resolveEveryStory(mode) {
|
|
1273
1476
|
let count = 0;
|
|
1274
|
-
|
|
1477
|
+
const resolvedStories = [];
|
|
1478
|
+
const refreshes = [];
|
|
1479
|
+
for (const handle of this.listStoryHandlesInternal()) {
|
|
1275
1480
|
const state = this.getEditableStoryState(handle);
|
|
1276
1481
|
if (!state) continue;
|
|
1277
|
-
|
|
1278
|
-
|
|
1482
|
+
const ordinaryCount = getTrackedChangesFromDoc(state.doc).filter(({ id }) => mode === "reject" || suggestionIdOfRevision(state, id) === null).length;
|
|
1483
|
+
count += ordinaryCount;
|
|
1484
|
+
const withSuggestions = mode === "accept" && ordinaryCount > 0 && getSuggestions(state).length > 0 ? this.acceptOrdinaryChangesWithSuggestions(state, handle) : null;
|
|
1485
|
+
if (withSuggestions) refreshes.push(withSuggestions.refresh);
|
|
1486
|
+
let resolvedState = state;
|
|
1487
|
+
if (mode === "reject") resolvedState = resolveAllChangesInHeadlessState(rejectSuggestions(state), mode);
|
|
1488
|
+
else if (ordinaryCount > 0) resolvedState = withSuggestions?.state ?? resolveAllChangesInHeadlessState(state, mode);
|
|
1489
|
+
resolvedStories.push({
|
|
1490
|
+
handle,
|
|
1491
|
+
state: resolvedState
|
|
1492
|
+
});
|
|
1493
|
+
}
|
|
1494
|
+
for (const { handle, state } of resolvedStories) this.setEditableStoryState(handle, state);
|
|
1495
|
+
if (refreshes.length > 0) {
|
|
1496
|
+
const activeSuggestionIds = new Set(getSuggestions(this.state).map(({ suggestionId }) => suggestionId));
|
|
1497
|
+
for (const entry of this.secondaryStoryStates.values()) for (const { suggestionId } of getSuggestions(entry.state)) activeSuggestionIds.add(suggestionId);
|
|
1498
|
+
for (const refresh of refreshes) refresh(activeSuggestionIds);
|
|
1279
1499
|
}
|
|
1280
1500
|
return count;
|
|
1281
1501
|
}
|
|
1502
|
+
acceptOrdinaryChangesWithSuggestions(state, story) {
|
|
1503
|
+
const originalSuggestions = getSuggestions(state);
|
|
1504
|
+
const records = this.exportPendingSuggestions().filter((record) => editableStoryKey(record.story) === editableStoryKey(story));
|
|
1505
|
+
const recordedIds = new Set(records.map(({ suggestionId }) => suggestionId));
|
|
1506
|
+
if (originalSuggestions.some(({ suggestionId }) => !recordedIds.has(suggestionId))) panic("A pending suggestion has no operation to restage after bulk acceptance");
|
|
1507
|
+
let clean = rejectSuggestions(state);
|
|
1508
|
+
const restagedCommentIds = new Set(records.flatMap(({ commentId }) => commentId === void 0 ? [] : [commentId]));
|
|
1509
|
+
clean = withoutPendingSuggestionCommentMarks(clean, restagedCommentIds);
|
|
1510
|
+
let resolved = resolveAllChangesInHeadlessState(clean, "accept");
|
|
1511
|
+
const restaged = [];
|
|
1512
|
+
for (const record of records) {
|
|
1513
|
+
const snapshot = createStateSnapshot(resolved);
|
|
1514
|
+
const view = {
|
|
1515
|
+
state: resolved,
|
|
1516
|
+
dispatch: (transaction) => {
|
|
1517
|
+
view.state = view.state.apply(transaction);
|
|
1518
|
+
}
|
|
1519
|
+
};
|
|
1520
|
+
const applied = applyFolioDocumentOperations({
|
|
1521
|
+
view,
|
|
1522
|
+
snapshot,
|
|
1523
|
+
batch: {
|
|
1524
|
+
version: 1,
|
|
1525
|
+
mode: "suggested",
|
|
1526
|
+
operations: [record.operation]
|
|
1527
|
+
},
|
|
1528
|
+
story: story.type === "main" ? "main" : story,
|
|
1529
|
+
author: record.author,
|
|
1530
|
+
createCommentId: () => {
|
|
1531
|
+
if (record.commentId === void 0) panic("A staged comment suggestion has no comment id", { suggestionId: record.suggestionId });
|
|
1532
|
+
return record.commentId;
|
|
1533
|
+
}
|
|
1534
|
+
}).applied.find(({ id }) => id === record.operation.id);
|
|
1535
|
+
if (!applied) continue;
|
|
1536
|
+
restaged.push({
|
|
1537
|
+
snapshot,
|
|
1538
|
+
operation: record.operation,
|
|
1539
|
+
applied,
|
|
1540
|
+
author: record.author
|
|
1541
|
+
});
|
|
1542
|
+
resolved = view.state;
|
|
1543
|
+
}
|
|
1544
|
+
const restagedIds = new Set(getSuggestions(resolved).map(({ suggestionId }) => suggestionId));
|
|
1545
|
+
if (restaged.some(({ applied }) => !restagedIds.has(applied.suggestionId ?? applied.id))) panic("Bulk acceptance lost a pending suggestion");
|
|
1546
|
+
return {
|
|
1547
|
+
state: resolved,
|
|
1548
|
+
refresh: (activeSuggestionIds) => this.pendingSuggestions.replaceRestagedStory({
|
|
1549
|
+
story,
|
|
1550
|
+
restaged,
|
|
1551
|
+
activeSuggestionIds
|
|
1552
|
+
})
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1282
1555
|
/** The current document model with edits merged back in. */
|
|
1283
1556
|
toDocument() {
|
|
1284
|
-
|
|
1557
|
+
const document = this.documentFromStateSnapshot(this.captureReviewerState());
|
|
1558
|
+
applyReplyThreadMarkers(document);
|
|
1559
|
+
return document;
|
|
1285
1560
|
}
|
|
1286
1561
|
captureReviewerState() {
|
|
1287
1562
|
const secondaryStoryStates = [];
|
|
@@ -1326,11 +1601,14 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1326
1601
|
document.package.footers.delete(handle.relationshipId);
|
|
1327
1602
|
}
|
|
1328
1603
|
this.mergeEditedSecondaryStories(document, snapshot.secondaryStoryStates);
|
|
1329
|
-
|
|
1604
|
+
const definitions = [...document.package.document.comments ?? [], ...snapshot.createdComments];
|
|
1605
|
+
const kept = this.keptCommentThreads(definitions, snapshot.mainState, snapshot.secondaryStoryStates);
|
|
1606
|
+
if (kept.length !== definitions.length || snapshot.createdComments.length > 0 || snapshot.resolvedOverrides.size > 0) document.package.document.comments = this.withResolvedOverrides(kept, snapshot.resolvedOverrides);
|
|
1330
1607
|
return document;
|
|
1331
1608
|
}
|
|
1332
1609
|
captureSaveSnapshot() {
|
|
1333
1610
|
const snapshot = this.captureReviewerState();
|
|
1611
|
+
const pendingCommentIds = new Set(this.exportPendingSuggestions().flatMap(({ commentId }) => commentId === void 0 ? [] : [commentId]));
|
|
1334
1612
|
const changedParaIds = new Set(getChangedParagraphIds(snapshot.mainState));
|
|
1335
1613
|
let structuralChange = hasStructuralChanges(snapshot.mainState) || snapshot.finalSectionPropertiesOverride !== void 0 || snapshot.importedStyles !== void 0 || snapshot.importedHeaders.size > 0 || snapshot.importedFooters.size > 0;
|
|
1336
1614
|
let untrackedChanges = hasUntrackedChanges(snapshot.mainState);
|
|
@@ -1357,7 +1635,15 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1357
1635
|
reason: "untrackedChange"
|
|
1358
1636
|
};
|
|
1359
1637
|
return {
|
|
1360
|
-
document: this.documentFromStateSnapshot(
|
|
1638
|
+
document: this.documentFromStateSnapshot({
|
|
1639
|
+
...snapshot,
|
|
1640
|
+
mainState: withoutPendingSuggestionCommentMarks(rejectSuggestions(snapshot.mainState), pendingCommentIds),
|
|
1641
|
+
secondaryStoryStates: snapshot.secondaryStoryStates.map((entry) => ({
|
|
1642
|
+
...entry,
|
|
1643
|
+
state: withoutPendingSuggestionCommentMarks(rejectSuggestions(entry.state), pendingCommentIds)
|
|
1644
|
+
})),
|
|
1645
|
+
createdComments: snapshot.createdComments.filter(({ id }) => !pendingCommentIds.has(id))
|
|
1646
|
+
}),
|
|
1361
1647
|
path,
|
|
1362
1648
|
changedNoteParaIds,
|
|
1363
1649
|
sectionReferenceRemovals: snapshot.sectionReferenceRemovals,
|
|
@@ -1469,16 +1755,11 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1469
1755
|
const key = secondaryStoryKey(story);
|
|
1470
1756
|
const existing = this.secondaryStoryStates.get(key);
|
|
1471
1757
|
if (existing) return existing.state;
|
|
1472
|
-
const
|
|
1473
|
-
if (!
|
|
1474
|
-
const conversionOptions = {
|
|
1475
|
-
...this.baseDocument.package.styles !== void 0 && { styles: this.baseDocument.package.styles },
|
|
1476
|
-
...this.baseDocument.package.theme !== void 0 && { theme: this.baseDocument.package.theme }
|
|
1477
|
-
};
|
|
1478
|
-
const storyDoc = story.type === "header" || story.type === "footer" ? headerFooterToProseDoc(source.content, conversionOptions) : footnoteToProseDoc(source.content, conversionOptions);
|
|
1758
|
+
const doc = this.secondaryStoryDoc(story);
|
|
1759
|
+
if (!doc) return null;
|
|
1479
1760
|
const state = ensureBaseDirectionInState(EditorState.create({
|
|
1480
1761
|
schema,
|
|
1481
|
-
doc
|
|
1762
|
+
doc,
|
|
1482
1763
|
plugins: createHeadlessPlugins(this.baseDocument.package.styles, this.baseDocument.package.numbering)
|
|
1483
1764
|
}));
|
|
1484
1765
|
this.secondaryStoryStates.set(key, {
|
|
@@ -1488,6 +1769,25 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1488
1769
|
});
|
|
1489
1770
|
return state;
|
|
1490
1771
|
}
|
|
1772
|
+
/**
|
|
1773
|
+
* A secondary story as its editable state holds it: the loaded state's
|
|
1774
|
+
* document once an operation has loaded it, otherwise the conversion loading
|
|
1775
|
+
* performs — with the same deterministic block ids — without retaining a
|
|
1776
|
+
* state for a story nothing edits.
|
|
1777
|
+
*/
|
|
1778
|
+
readSecondaryStoryDoc(story) {
|
|
1779
|
+
return this.secondaryStoryStates.get(secondaryStoryKey(story))?.state.doc ?? this.secondaryStoryDoc(story);
|
|
1780
|
+
}
|
|
1781
|
+
secondaryStoryDoc(story) {
|
|
1782
|
+
const source = story.type === "header" || story.type === "footer" ? this.getHeaderFooterStory(story) : this.getNoteStory(story);
|
|
1783
|
+
if (!source) return null;
|
|
1784
|
+
const conversionOptions = {
|
|
1785
|
+
...this.baseDocument.package.styles !== void 0 && { styles: this.baseDocument.package.styles },
|
|
1786
|
+
...this.baseDocument.package.theme !== void 0 && { theme: this.baseDocument.package.theme }
|
|
1787
|
+
};
|
|
1788
|
+
const storyDoc = story.type === "header" || story.type === "footer" ? headerFooterToProseDoc(source.content, conversionOptions) : footnoteToProseDoc(source.content, conversionOptions);
|
|
1789
|
+
return ensureDeterministicParaIdsInDoc(storyDoc);
|
|
1790
|
+
}
|
|
1491
1791
|
requireEditableStoryState(story) {
|
|
1492
1792
|
const state = this.getEditableStoryState(story);
|
|
1493
1793
|
if (state) return state;
|
|
@@ -1650,12 +1950,14 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1650
1950
|
let endnotes;
|
|
1651
1951
|
for (const entry of secondaryStoryStates) {
|
|
1652
1952
|
if (entry.state === entry.initialState) continue;
|
|
1953
|
+
const lists = storyListNumbering(entry.state, document.package.numbering);
|
|
1954
|
+
if (lists.numbering) document.package.numbering = lists.numbering;
|
|
1653
1955
|
if (entry.handle.type === "header" || entry.handle.type === "footer") {
|
|
1654
1956
|
const source = entry.handle.type === "header" ? document.package.headers?.get(entry.handle.relationshipId) : document.package.footers?.get(entry.handle.relationshipId);
|
|
1655
1957
|
if (!source) continue;
|
|
1656
1958
|
const edited = {
|
|
1657
1959
|
...source,
|
|
1658
|
-
content: proseDocToBlocks(
|
|
1960
|
+
content: proseDocToBlocks(lists.doc, source.content, document.package.styles)
|
|
1659
1961
|
};
|
|
1660
1962
|
if (entry.handle.type === "header") {
|
|
1661
1963
|
headers ??= new Map(document.package.headers);
|
|
@@ -1672,7 +1974,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1672
1974
|
if (!source) continue;
|
|
1673
1975
|
const edited = {
|
|
1674
1976
|
...source,
|
|
1675
|
-
content: proseDocToBlocks(
|
|
1977
|
+
content: proseDocToBlocks(lists.doc, source.content, document.package.styles)
|
|
1676
1978
|
};
|
|
1677
1979
|
footnotes ??= [...document.package.footnotes ?? []];
|
|
1678
1980
|
const index = footnotes.findIndex((note) => note.id === noteId);
|
|
@@ -1684,7 +1986,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1684
1986
|
if (!source) continue;
|
|
1685
1987
|
const edited = {
|
|
1686
1988
|
...source,
|
|
1687
|
-
content: proseDocToBlocks(
|
|
1989
|
+
content: proseDocToBlocks(lists.doc, source.content, document.package.styles)
|
|
1688
1990
|
};
|
|
1689
1991
|
endnotes ??= [...document.package.endnotes ?? []];
|
|
1690
1992
|
const index = endnotes.findIndex((note) => note.id === noteId);
|
|
@@ -1706,13 +2008,51 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1706
2008
|
};
|
|
1707
2009
|
});
|
|
1708
2010
|
}
|
|
1709
|
-
/**
|
|
2011
|
+
/**
|
|
2012
|
+
* `comments` without the threads an edit left anchored nowhere: anchored in
|
|
2013
|
+
* a story when it was loaded (or created anchored by this reviewer), and
|
|
2014
|
+
* anchored in no story now. See `comment-lifecycle.ts`.
|
|
2015
|
+
*/
|
|
2016
|
+
keptCommentThreads(comments, mainState, secondaryStoryStates) {
|
|
2017
|
+
const anchoredBefore = new Set(this.loadedMainCommentIds);
|
|
2018
|
+
for (const { id } of this.createdComments) anchoredBefore.add(id);
|
|
2019
|
+
const anchoredNow = anchoredCommentIdsInProseDoc(mainState.doc);
|
|
2020
|
+
const loaded = /* @__PURE__ */ new Map();
|
|
2021
|
+
for (const entry of secondaryStoryStates) loaded.set(secondaryStoryKey(entry.handle), entry);
|
|
2022
|
+
const addAll = (target, ids) => {
|
|
2023
|
+
for (const id of ids) target.add(id);
|
|
2024
|
+
};
|
|
2025
|
+
for (const handle of this.listStoryHandlesInternal()) {
|
|
2026
|
+
if (handle.type === "main") continue;
|
|
2027
|
+
const entry = loaded.get(secondaryStoryKey(handle));
|
|
2028
|
+
if (entry) {
|
|
2029
|
+
addAll(anchoredBefore, anchoredCommentIdsInProseDoc(entry.initialState.doc));
|
|
2030
|
+
addAll(anchoredNow, anchoredCommentIdsInProseDoc(entry.state.doc));
|
|
2031
|
+
continue;
|
|
2032
|
+
}
|
|
2033
|
+
addAll(anchoredNow, anchoredCommentIdsInBlocks((handle.type === "header" || handle.type === "footer" ? this.getHeaderFooterStory(handle) : this.getNoteStory(handle))?.content ?? []));
|
|
2034
|
+
}
|
|
2035
|
+
return withoutLostCommentThreads(comments, {
|
|
2036
|
+
anchoredBefore,
|
|
2037
|
+
anchoredNow
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
/**
|
|
2041
|
+
* Map each anchored comment id to its anchored text, its containing block id
|
|
2042
|
+
* and the story holding it. A comment can be anchored in any story, so every
|
|
2043
|
+
* story is read, not only the body.
|
|
2044
|
+
*/
|
|
1710
2045
|
commentAnchors() {
|
|
1711
2046
|
const anchors = /* @__PURE__ */ new Map();
|
|
1712
|
-
for (const
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
2047
|
+
for (const story of this.listStoryHandlesInternal()) {
|
|
2048
|
+
const doc = story.type === "main" ? this.state.doc : this.readSecondaryStoryDoc(story);
|
|
2049
|
+
if (!doc) continue;
|
|
2050
|
+
for (const anchor of getCommentAnchorsFromDoc(doc)) if (!anchors.has(anchor.commentId)) anchors.set(anchor.commentId, {
|
|
2051
|
+
text: anchor.quote,
|
|
2052
|
+
blockId: anchor.blockId,
|
|
2053
|
+
story
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
1716
2056
|
return anchors;
|
|
1717
2057
|
}
|
|
1718
2058
|
/** Allocate outside every parsed or newly-created comment and reply id. */
|