@beyondwork/docx-react-component 1.0.29 → 1.0.31
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/package.json +65 -96
- package/src/README.md +85 -0
- package/src/api/README.md +26 -0
- package/src/api/public-types.ts +1952 -0
- package/src/api/session-state.ts +62 -0
- package/src/compare/diff-engine.ts +623 -0
- package/src/compare/export-redlines.ts +280 -0
- package/src/compare/index.ts +25 -0
- package/src/compare/snapshot.ts +97 -0
- package/src/component-inventory.md +99 -0
- package/src/core/README.md +10 -0
- package/src/core/commands/README.md +3 -0
- package/{dist/chunk-TJBP2K4T.js → src/core/commands/formatting-commands.ts} +536 -196
- package/src/core/commands/image-commands.ts +373 -0
- package/src/core/commands/index.ts +1879 -0
- package/src/core/commands/list-commands.ts +565 -0
- package/src/core/commands/paragraph-layout-commands.ts +339 -0
- package/src/core/commands/review-commands.ts +108 -0
- package/{dist/core/commands/section-layout-commands.cjs → src/core/commands/section-layout-commands.ts} +340 -137
- package/src/core/commands/structural-helpers.ts +309 -0
- package/{dist/core/commands/style-commands.cjs → src/core/commands/style-commands.ts} +113 -65
- package/src/core/commands/table-structure-commands.ts +854 -0
- package/{dist/chunk-UZXBISGO.js → src/core/commands/text-commands.ts} +142 -86
- package/src/core/schema/README.md +3 -0
- package/src/core/schema/text-schema.ts +516 -0
- package/src/core/search/search-text.ts +357 -0
- package/src/core/selection/README.md +3 -0
- package/src/core/selection/mapping.ts +289 -0
- package/src/core/selection/review-anchors.ts +183 -0
- package/src/core/state/README.md +3 -0
- package/src/core/state/editor-state.ts +892 -0
- package/src/core/state/text-transaction.ts +869 -0
- package/src/formats/xlsx/io/parse-shared-strings.ts +41 -0
- package/src/formats/xlsx/io/parse-sheet.ts +459 -0
- package/src/formats/xlsx/io/parse-styles.ts +59 -0
- package/src/formats/xlsx/io/parse-workbook.ts +75 -0
- package/src/formats/xlsx/io/serialize-shared-strings.ts +72 -0
- package/src/formats/xlsx/io/serialize-sheet.ts +333 -0
- package/src/formats/xlsx/io/serialize-styles.ts +98 -0
- package/src/formats/xlsx/io/serialize-workbook.ts +429 -0
- package/src/formats/xlsx/io/xlsx-session.ts +314 -0
- package/src/formats/xlsx/model/cell.ts +189 -0
- package/src/formats/xlsx/model/sheet.ts +326 -0
- package/src/formats/xlsx/model/styles.ts +118 -0
- package/src/formats/xlsx/model/workbook.ts +453 -0
- package/src/formats/xlsx/runtime/cell-commands.ts +567 -0
- package/src/formats/xlsx/runtime/sheet-commands.ts +206 -0
- package/src/formats/xlsx/runtime/workbook-runtime.ts +177 -0
- package/src/formats/xlsx/runtime/workbook-transaction.ts +822 -0
- package/src/index.ts +142 -0
- package/src/io/README.md +10 -0
- package/src/io/docx-session.ts +3175 -0
- package/src/io/export/README.md +3 -0
- package/src/io/export/export-session.ts +220 -0
- package/src/io/export/minimal-docx.ts +115 -0
- package/src/io/export/reattach-preserved-parts.ts +54 -0
- package/src/io/export/serialize-comments.ts +947 -0
- package/src/io/export/serialize-footnotes.ts +394 -0
- package/src/io/export/serialize-headers-footers.ts +368 -0
- package/src/io/export/serialize-main-document.ts +1342 -0
- package/src/io/export/serialize-numbering.ts +218 -0
- package/src/io/export/serialize-revisions.ts +389 -0
- package/src/io/export/serialize-runtime-revisions.ts +463 -0
- package/src/io/export/serialize-tables.ts +174 -0
- package/src/io/export/split-review-boundaries.ts +356 -0
- package/src/io/export/split-story-blocks-for-runtime-revisions.ts +252 -0
- package/src/io/export/table-properties-xml.ts +318 -0
- package/src/io/normalize/README.md +3 -0
- package/src/io/normalize/normalize-text.ts +670 -0
- package/src/io/ooxml/README.md +3 -0
- package/src/io/ooxml/highlight-colors.ts +39 -0
- package/src/io/ooxml/numbering-sentinels.ts +44 -0
- package/src/io/ooxml/parse-comments.ts +852 -0
- package/src/io/ooxml/parse-complex-content.ts +287 -0
- package/src/io/ooxml/parse-fields.ts +834 -0
- package/src/io/ooxml/parse-footnotes.ts +952 -0
- package/src/io/ooxml/parse-headers-footers.ts +1212 -0
- package/src/io/ooxml/parse-inline-media.ts +461 -0
- package/src/io/ooxml/parse-main-document.ts +2947 -0
- package/src/io/ooxml/parse-numbering.ts +747 -0
- package/src/io/ooxml/parse-revisions.ts +1045 -0
- package/src/io/ooxml/parse-settings.ts +184 -0
- package/src/io/ooxml/parse-shapes.ts +296 -0
- package/src/io/ooxml/parse-styles.ts +639 -0
- package/src/io/ooxml/parse-tables.ts +627 -0
- package/src/io/ooxml/parse-theme.ts +346 -0
- package/src/io/ooxml/part-manifest.ts +136 -0
- package/src/io/ooxml/revision-boundaries.ts +475 -0
- package/src/io/ooxml/workflow-payload.ts +544 -0
- package/src/io/opc/README.md +3 -0
- package/src/io/opc/corrupt-package.ts +166 -0
- package/src/io/opc/docx-package.ts +74 -0
- package/src/io/opc/package-reader.ts +325 -0
- package/src/io/opc/package-writer.ts +273 -0
- package/src/io/source-package-provenance.ts +241 -0
- package/{dist/chunk-RMH72RZI.js → src/legal/bookmarks.ts} +130 -44
- package/src/legal/cross-references.ts +414 -0
- package/src/legal/defined-terms.ts +203 -0
- package/src/legal/index.ts +32 -0
- package/src/legal/signature-blocks.ts +259 -0
- package/src/model/README.md +3 -0
- package/src/model/canonical-document.ts +2722 -0
- package/src/model/cds-1.0.0.ts +212 -0
- package/src/model/snapshot.ts +760 -0
- package/src/preservation/README.md +3 -0
- package/src/preservation/markup-compatibility.ts +48 -0
- package/src/preservation/opaque-fragment-store.ts +89 -0
- package/src/preservation/opaque-region.ts +233 -0
- package/src/preservation/package-preservation.ts +113 -0
- package/src/preservation/preserved-part-manifest.ts +56 -0
- package/src/preservation/relationship-retention.ts +57 -0
- package/src/preservation/store.ts +255 -0
- package/src/review/README.md +16 -0
- package/src/review/store/README.md +3 -0
- package/src/review/store/comment-anchors.ts +70 -0
- package/src/review/store/comment-remapping.ts +154 -0
- package/src/review/store/comment-store.ts +349 -0
- package/src/review/store/comment-thread.ts +109 -0
- package/src/review/store/revision-actions.ts +423 -0
- package/src/review/store/revision-store.ts +323 -0
- package/src/review/store/revision-types.ts +182 -0
- package/src/review/store/runtime-comment-store.ts +43 -0
- package/src/runtime/README.md +3 -0
- package/src/runtime/ai-action-policy.ts +764 -0
- package/src/runtime/context-analytics.ts +824 -0
- package/src/runtime/document-layout.ts +332 -0
- package/src/runtime/document-locations.ts +521 -0
- package/src/runtime/document-navigation.ts +616 -0
- package/src/runtime/document-outline.ts +440 -0
- package/src/runtime/document-runtime.ts +4055 -0
- package/src/runtime/document-search.ts +145 -0
- package/src/runtime/event-refresh-hints.ts +137 -0
- package/src/runtime/numbering-prefix.ts +244 -0
- package/src/runtime/page-layout-estimation.ts +305 -0
- package/src/runtime/read-only-diagnostics-runtime.ts +241 -0
- package/src/runtime/resolved-numbering-geometry.ts +293 -0
- package/src/runtime/review-runtime.ts +44 -0
- package/src/runtime/revision-runtime.ts +107 -0
- package/src/runtime/session-capabilities.ts +192 -0
- package/src/runtime/story-context.ts +164 -0
- package/src/runtime/story-targeting.ts +162 -0
- package/src/runtime/suggestions-snapshot.ts +137 -0
- package/src/runtime/surface-projection.ts +1553 -0
- package/src/runtime/table-commands.ts +173 -0
- package/src/runtime/table-schema.ts +309 -0
- package/src/runtime/table-style-resolver.ts +409 -0
- package/src/runtime/view-state.ts +493 -0
- package/src/runtime/virtualized-rendering.ts +258 -0
- package/src/runtime/workflow-markup.ts +393 -0
- package/src/ui/README.md +30 -0
- package/src/ui/WordReviewEditor.tsx +5268 -0
- package/src/ui/browser-export.ts +52 -0
- package/src/ui/comments/README.md +3 -0
- package/src/ui/compatibility/README.md +3 -0
- package/src/ui/editor-command-bag.ts +127 -0
- package/src/ui/editor-runtime-boundary.ts +1558 -0
- package/src/ui/editor-shell-view.tsx +144 -0
- package/src/ui/editor-surface/README.md +3 -0
- package/src/ui/editor-surface-controller.tsx +66 -0
- package/src/ui/headless/comment-decoration-model.ts +124 -0
- package/src/ui/headless/preserve-editor-selection.ts +5 -0
- package/src/ui/headless/revision-decoration-model.ts +128 -0
- package/src/ui/headless/selection-helpers.ts +54 -0
- package/src/ui/headless/selection-tool-context.ts +19 -0
- package/src/ui/headless/selection-tool-resolver.ts +752 -0
- package/src/ui/headless/selection-tool-types.ts +129 -0
- package/src/ui/headless/selection-toolbar-model.ts +11 -0
- package/src/ui/headless/use-editor-keyboard.ts +103 -0
- package/src/ui/review/README.md +3 -0
- package/src/ui/runtime-shortcut-dispatch.ts +365 -0
- package/src/ui/runtime-snapshot-selectors.ts +197 -0
- package/src/ui/shared/revision-filters.ts +31 -0
- package/src/ui/status/README.md +3 -0
- package/src/ui/theme/README.md +3 -0
- package/src/ui/toolbar/README.md +3 -0
- package/src/ui/workflow-surface-blocked-rails.ts +94 -0
- package/src/ui-tailwind/chrome/chrome-preset-model.ts +107 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +15 -0
- package/src/ui-tailwind/chrome/responsive-chrome.ts +46 -0
- package/src/ui-tailwind/chrome/review-queue-bar.tsx +97 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +64 -0
- package/src/ui-tailwind/chrome/tw-context-analytics-summary.tsx +122 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +121 -0
- package/src/ui-tailwind/chrome/tw-layout-panel.tsx +114 -0
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +30 -0
- package/src/ui-tailwind/chrome/tw-page-ruler.tsx +365 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +23 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +35 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +37 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +303 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +116 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-suggestion.tsx +29 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +27 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +186 -0
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +139 -0
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +250 -0
- package/src/ui-tailwind/chrome/tw-unsaved-modal.tsx +58 -0
- package/src/ui-tailwind/chrome/use-before-unload.ts +20 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +179 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +189 -0
- package/src/ui-tailwind/editor-surface/pm-contextual-ui.ts +31 -0
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +411 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +123 -0
- package/src/ui-tailwind/editor-surface/pm-schema.ts +927 -0
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +567 -0
- package/src/ui-tailwind/editor-surface/search-plugin.ts +168 -0
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +63 -0
- package/src/ui-tailwind/editor-surface/tw-caret.tsx +12 -0
- package/src/ui-tailwind/editor-surface/tw-editor-surface.tsx +150 -0
- package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +129 -0
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +58 -0
- package/src/ui-tailwind/editor-surface/tw-paragraph-block.tsx +151 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +1047 -0
- package/src/ui-tailwind/editor-surface/tw-segment-view.tsx +111 -0
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +503 -0
- package/src/ui-tailwind/index.ts +62 -0
- package/src/ui-tailwind/page-chrome-model.ts +27 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +406 -0
- package/src/ui-tailwind/review/tw-health-panel.tsx +149 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +130 -0
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +164 -0
- package/src/ui-tailwind/status/tw-status-bar.tsx +65 -0
- package/{dist → src}/ui-tailwind/theme/editor-theme.css +58 -40
- package/src/ui-tailwind/toolbar/toolbar-layout.ts +47 -0
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +52 -0
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +1478 -0
- package/src/ui-tailwind/tw-review-workspace.tsx +1587 -0
- package/src/validation/README.md +3 -0
- package/src/validation/compatibility-engine.ts +878 -0
- package/src/validation/compatibility-report.ts +161 -0
- package/src/validation/diagnostics.ts +204 -0
- package/src/validation/docx-comment-proof.ts +720 -0
- package/src/validation/import-diagnostics.ts +128 -0
- package/src/validation/low-priority-word-surfaces.ts +373 -0
- package/dist/canonical-document-BLEbzL2J.d.cts +0 -844
- package/dist/canonical-document-BLEbzL2J.d.ts +0 -844
- package/dist/chunk-2FJS5GZM.js +0 -763
- package/dist/chunk-2FJS5GZM.js.map +0 -1
- package/dist/chunk-2OQBZS3F.js +0 -446
- package/dist/chunk-2OQBZS3F.js.map +0 -1
- package/dist/chunk-2S7W4KFO.js +0 -127
- package/dist/chunk-2S7W4KFO.js.map +0 -1
- package/dist/chunk-2TG72QSW.js +0 -3874
- package/dist/chunk-2TG72QSW.js.map +0 -1
- package/dist/chunk-36QNIZBO.js +0 -532
- package/dist/chunk-36QNIZBO.js.map +0 -1
- package/dist/chunk-4AQOYAW4.js +0 -3069
- package/dist/chunk-4AQOYAW4.js.map +0 -1
- package/dist/chunk-4D5EWJ3P.js +0 -77
- package/dist/chunk-4D5EWJ3P.js.map +0 -1
- package/dist/chunk-5FN54NDH.js +0 -2257
- package/dist/chunk-5FN54NDH.js.map +0 -1
- package/dist/chunk-BOYGQYRQ.js +0 -7306
- package/dist/chunk-BOYGQYRQ.js.map +0 -1
- package/dist/chunk-CN3XMECL.js +0 -212
- package/dist/chunk-CN3XMECL.js.map +0 -1
- package/dist/chunk-EBI3BX6U.js +0 -164
- package/dist/chunk-EBI3BX6U.js.map +0 -1
- package/dist/chunk-EILUG3VB.js +0 -1275
- package/dist/chunk-EILUG3VB.js.map +0 -1
- package/dist/chunk-FUDY333O.js +0 -70
- package/dist/chunk-FUDY333O.js.map +0 -1
- package/dist/chunk-GBVOWFIK.js +0 -1237
- package/dist/chunk-GBVOWFIK.js.map +0 -1
- package/dist/chunk-H4TQ3H3Y.js +0 -262
- package/dist/chunk-H4TQ3H3Y.js.map +0 -1
- package/dist/chunk-JGB3IXZO.js +0 -189
- package/dist/chunk-JGB3IXZO.js.map +0 -1
- package/dist/chunk-KD2QRQPY.js +0 -4342
- package/dist/chunk-KD2QRQPY.js.map +0 -1
- package/dist/chunk-KLMXQVYK.js +0 -369
- package/dist/chunk-KLMXQVYK.js.map +0 -1
- package/dist/chunk-KZUG5KFQ.js +0 -214
- package/dist/chunk-KZUG5KFQ.js.map +0 -1
- package/dist/chunk-QDAQ4CJU.js +0 -345
- package/dist/chunk-QDAQ4CJU.js.map +0 -1
- package/dist/chunk-RMH72RZI.js.map +0 -1
- package/dist/chunk-SWKWQZXM.js +0 -117
- package/dist/chunk-SWKWQZXM.js.map +0 -1
- package/dist/chunk-TJBP2K4T.js.map +0 -1
- package/dist/chunk-TLCEAQDQ.js +0 -542
- package/dist/chunk-TLCEAQDQ.js.map +0 -1
- package/dist/chunk-UZXBISGO.js.map +0 -1
- package/dist/chunk-WGBAKP3Q.js +0 -3220
- package/dist/chunk-WGBAKP3Q.js.map +0 -1
- package/dist/compare/index.cjs +0 -5475
- package/dist/compare/index.cjs.map +0 -1
- package/dist/compare/index.d.cts +0 -114
- package/dist/compare/index.d.ts +0 -114
- package/dist/compare/index.js +0 -731
- package/dist/compare/index.js.map +0 -1
- package/dist/core/commands/formatting-commands.cjs +0 -828
- package/dist/core/commands/formatting-commands.cjs.map +0 -1
- package/dist/core/commands/formatting-commands.d.cts +0 -63
- package/dist/core/commands/formatting-commands.d.ts +0 -63
- package/dist/core/commands/formatting-commands.js +0 -37
- package/dist/core/commands/formatting-commands.js.map +0 -1
- package/dist/core/commands/image-commands.cjs +0 -2023
- package/dist/core/commands/image-commands.cjs.map +0 -1
- package/dist/core/commands/image-commands.d.cts +0 -58
- package/dist/core/commands/image-commands.d.ts +0 -58
- package/dist/core/commands/image-commands.js +0 -18
- package/dist/core/commands/image-commands.js.map +0 -1
- package/dist/core/commands/section-layout-commands.cjs.map +0 -1
- package/dist/core/commands/section-layout-commands.d.cts +0 -62
- package/dist/core/commands/section-layout-commands.d.ts +0 -62
- package/dist/core/commands/section-layout-commands.js +0 -21
- package/dist/core/commands/section-layout-commands.js.map +0 -1
- package/dist/core/commands/style-commands.cjs.map +0 -1
- package/dist/core/commands/style-commands.d.cts +0 -13
- package/dist/core/commands/style-commands.d.ts +0 -13
- package/dist/core/commands/style-commands.js +0 -9
- package/dist/core/commands/style-commands.js.map +0 -1
- package/dist/core/commands/table-structure-commands.cjs +0 -1883
- package/dist/core/commands/table-structure-commands.cjs.map +0 -1
- package/dist/core/commands/table-structure-commands.d.cts +0 -59
- package/dist/core/commands/table-structure-commands.d.ts +0 -59
- package/dist/core/commands/table-structure-commands.js +0 -12
- package/dist/core/commands/table-structure-commands.js.map +0 -1
- package/dist/core/commands/text-commands.cjs +0 -2391
- package/dist/core/commands/text-commands.cjs.map +0 -1
- package/dist/core/commands/text-commands.d.cts +0 -24
- package/dist/core/commands/text-commands.d.ts +0 -24
- package/dist/core/commands/text-commands.js +0 -28
- package/dist/core/commands/text-commands.js.map +0 -1
- package/dist/core/selection/mapping.cjs +0 -200
- package/dist/core/selection/mapping.cjs.map +0 -1
- package/dist/core/selection/mapping.d.cts +0 -2
- package/dist/core/selection/mapping.d.ts +0 -2
- package/dist/core/selection/mapping.js +0 -31
- package/dist/core/selection/mapping.js.map +0 -1
- package/dist/core/state/editor-state.cjs +0 -2278
- package/dist/core/state/editor-state.cjs.map +0 -1
- package/dist/core/state/editor-state.d.cts +0 -2
- package/dist/core/state/editor-state.d.ts +0 -2
- package/dist/core/state/editor-state.js +0 -26
- package/dist/core/state/editor-state.js.map +0 -1
- package/dist/index.cjs +0 -38553
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -15
- package/dist/index.d.ts +0 -15
- package/dist/index.js +0 -7856
- package/dist/index.js.map +0 -1
- package/dist/io/docx-session.cjs +0 -16236
- package/dist/io/docx-session.cjs.map +0 -1
- package/dist/io/docx-session.d.cts +0 -21
- package/dist/io/docx-session.d.ts +0 -21
- package/dist/io/docx-session.js +0 -18
- package/dist/io/docx-session.js.map +0 -1
- package/dist/legal/index.cjs +0 -3900
- package/dist/legal/index.cjs.map +0 -1
- package/dist/legal/index.d.cts +0 -86
- package/dist/legal/index.d.ts +0 -86
- package/dist/legal/index.js +0 -616
- package/dist/legal/index.js.map +0 -1
- package/dist/public-types-7ZL_94cz.d.ts +0 -1573
- package/dist/public-types-CeMaDueh.d.cts +0 -1573
- package/dist/public-types.cjs +0 -19
- package/dist/public-types.cjs.map +0 -1
- package/dist/public-types.d.cts +0 -2
- package/dist/public-types.d.ts +0 -2
- package/dist/public-types.js +0 -1
- package/dist/public-types.js.map +0 -1
- package/dist/runtime/document-runtime.cjs +0 -11140
- package/dist/runtime/document-runtime.cjs.map +0 -1
- package/dist/runtime/document-runtime.d.cts +0 -231
- package/dist/runtime/document-runtime.d.ts +0 -231
- package/dist/runtime/document-runtime.js +0 -21
- package/dist/runtime/document-runtime.js.map +0 -1
- package/dist/structural-helpers-CilgOVhh.d.cts +0 -10
- package/dist/structural-helpers-q0Gd-eBN.d.ts +0 -10
- package/dist/ui-tailwind/editor-surface/search-plugin.cjs +0 -313
- package/dist/ui-tailwind/editor-surface/search-plugin.cjs.map +0 -1
- package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +0 -67
- package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +0 -67
- package/dist/ui-tailwind/editor-surface/search-plugin.js +0 -23
- package/dist/ui-tailwind/editor-surface/search-plugin.js.map +0 -1
- package/dist/ui-tailwind/index.cjs +0 -4833
- package/dist/ui-tailwind/index.cjs.map +0 -1
- package/dist/ui-tailwind/index.d.cts +0 -617
- package/dist/ui-tailwind/index.d.ts +0 -617
- package/dist/ui-tailwind/index.js +0 -575
- package/dist/ui-tailwind/index.js.map +0 -1
package/dist/chunk-KD2QRQPY.js
DELETED
|
@@ -1,4342 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
deleteSelectionOrBackward,
|
|
3
|
-
deleteSelectionOrForward,
|
|
4
|
-
insertHardBreak,
|
|
5
|
-
insertTab,
|
|
6
|
-
insertText,
|
|
7
|
-
splitParagraph
|
|
8
|
-
} from "./chunk-UZXBISGO.js";
|
|
9
|
-
import {
|
|
10
|
-
applyTextTransaction
|
|
11
|
-
} from "./chunk-QDAQ4CJU.js";
|
|
12
|
-
import {
|
|
13
|
-
searchSurfaceBlocks
|
|
14
|
-
} from "./chunk-CN3XMECL.js";
|
|
15
|
-
import {
|
|
16
|
-
buildPageLayoutSnapshot,
|
|
17
|
-
buildResolvedSections,
|
|
18
|
-
canCreateDocxCommentAnchor,
|
|
19
|
-
createDocumentNavigationSnapshot,
|
|
20
|
-
createEditorViewStateSnapshot,
|
|
21
|
-
createViewState,
|
|
22
|
-
detachReviewAnchor,
|
|
23
|
-
findPageForOffset,
|
|
24
|
-
getAnchorRange,
|
|
25
|
-
incrementInvalidationCounter,
|
|
26
|
-
mapReviewAnchor,
|
|
27
|
-
mappingTouchesAnchorContent,
|
|
28
|
-
rangeStaysWithinSingleParagraph,
|
|
29
|
-
recordPerfSample,
|
|
30
|
-
resolveActiveSection,
|
|
31
|
-
setDocumentMode,
|
|
32
|
-
setFocused,
|
|
33
|
-
setViewMode,
|
|
34
|
-
setWorkspaceMode,
|
|
35
|
-
setZoomLevel
|
|
36
|
-
} from "./chunk-GBVOWFIK.js";
|
|
37
|
-
import {
|
|
38
|
-
parseTextStory
|
|
39
|
-
} from "./chunk-KLMXQVYK.js";
|
|
40
|
-
import {
|
|
41
|
-
createEditorSurfaceSnapshot,
|
|
42
|
-
getStoryBlocks,
|
|
43
|
-
normalizeHeaderFooterTarget,
|
|
44
|
-
replaceStoryBlocks,
|
|
45
|
-
storyTargetKey
|
|
46
|
-
} from "./chunk-EILUG3VB.js";
|
|
47
|
-
import {
|
|
48
|
-
buildCompatibilityReport,
|
|
49
|
-
createDiagnostics,
|
|
50
|
-
createRevisionSidebarProjection,
|
|
51
|
-
diagnosticsBlockExport,
|
|
52
|
-
editorSessionStateFromPersistedSnapshot,
|
|
53
|
-
getRevisionActionability,
|
|
54
|
-
persistedSnapshotFromEditorSessionState,
|
|
55
|
-
remapRevisionStore,
|
|
56
|
-
setRevisionStatus
|
|
57
|
-
} from "./chunk-2FJS5GZM.js";
|
|
58
|
-
import {
|
|
59
|
-
createCommentSidebarProjection,
|
|
60
|
-
createCommentStoreFromRuntimeComments
|
|
61
|
-
} from "./chunk-2S7W4KFO.js";
|
|
62
|
-
import {
|
|
63
|
-
describeOpaqueFragment,
|
|
64
|
-
findOpaqueFragmentsIntersectingRange
|
|
65
|
-
} from "./chunk-SWKWQZXM.js";
|
|
66
|
-
import {
|
|
67
|
-
createEditorState,
|
|
68
|
-
createPersistedEditorSnapshot,
|
|
69
|
-
createSelectionSnapshot,
|
|
70
|
-
deriveDocumentStats,
|
|
71
|
-
normalizeCommentThreadRecord
|
|
72
|
-
} from "./chunk-5FN54NDH.js";
|
|
73
|
-
import {
|
|
74
|
-
DEFAULT_BOUNDARY_ASSOC,
|
|
75
|
-
MAIN_STORY_TARGET,
|
|
76
|
-
areAnchorsEqual,
|
|
77
|
-
createDetachedAnchor,
|
|
78
|
-
createEmptyMapping,
|
|
79
|
-
createNodeAnchor,
|
|
80
|
-
createRangeAnchor,
|
|
81
|
-
mapAnchor,
|
|
82
|
-
mapRange,
|
|
83
|
-
storyTargetsEqual
|
|
84
|
-
} from "./chunk-EBI3BX6U.js";
|
|
85
|
-
import {
|
|
86
|
-
buildBookmarkNameMap
|
|
87
|
-
} from "./chunk-RMH72RZI.js";
|
|
88
|
-
import {
|
|
89
|
-
buildFieldRegistry,
|
|
90
|
-
isSupportedFieldFamily,
|
|
91
|
-
parseTocLevelRange,
|
|
92
|
-
resolveRefFieldText
|
|
93
|
-
} from "./chunk-TLCEAQDQ.js";
|
|
94
|
-
|
|
95
|
-
// src/core/commands/review-commands.ts
|
|
96
|
-
function isSingleRevisionReviewCommand(command) {
|
|
97
|
-
return "revisionId" in command;
|
|
98
|
-
}
|
|
99
|
-
function getReviewCommandIntent(command) {
|
|
100
|
-
switch (command.type) {
|
|
101
|
-
case "review.accept-revision":
|
|
102
|
-
case "review.accept-all-revisions":
|
|
103
|
-
return "accept";
|
|
104
|
-
case "review.reject-revision":
|
|
105
|
-
case "review.reject-all-revisions":
|
|
106
|
-
return "reject";
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
function createAcceptRevisionCommand(revisionId, origin) {
|
|
110
|
-
return {
|
|
111
|
-
type: "review.accept-revision",
|
|
112
|
-
revisionId,
|
|
113
|
-
...origin ? { origin } : {}
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
function createRejectRevisionCommand(revisionId, origin) {
|
|
117
|
-
return {
|
|
118
|
-
type: "review.reject-revision",
|
|
119
|
-
revisionId,
|
|
120
|
-
...origin ? { origin } : {}
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// src/review/store/comment-remapping.ts
|
|
125
|
-
function remapCommentThreads(options) {
|
|
126
|
-
const comments = Object.fromEntries(
|
|
127
|
-
Object.entries(options.comments).map(([commentId, comment]) => [
|
|
128
|
-
commentId,
|
|
129
|
-
remapCommentThread(comment, options.mapping, options.nextContent)
|
|
130
|
-
])
|
|
131
|
-
);
|
|
132
|
-
const detachedCommentIds = Object.values(comments).filter((comment) => comment.anchor.kind === "detached").map((comment) => comment.commentId);
|
|
133
|
-
return {
|
|
134
|
-
comments,
|
|
135
|
-
warnings: mergeDetachedAnchorWarnings(comments, options.existingWarnings ?? []),
|
|
136
|
-
detachedCommentIds
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
function remapCommentThread(comment, mapping, nextContent) {
|
|
140
|
-
if (comment.anchor.kind === "detached") {
|
|
141
|
-
return comment;
|
|
142
|
-
}
|
|
143
|
-
const mappedAnchor = mapReviewAnchor(comment.anchor, mapping);
|
|
144
|
-
const anchor = normalizeCommentAnchor(comment.anchor, mappedAnchor, mapping, nextContent);
|
|
145
|
-
return {
|
|
146
|
-
...comment,
|
|
147
|
-
anchor
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
function normalizeCommentAnchor(previousAnchor, mappedAnchor, mapping, nextContent) {
|
|
151
|
-
if (mappedAnchor.kind === "detached") {
|
|
152
|
-
return mappedAnchor;
|
|
153
|
-
}
|
|
154
|
-
const previousRange = getAnchorRange(previousAnchor);
|
|
155
|
-
const mappedRange = getAnchorRange(mappedAnchor);
|
|
156
|
-
if (previousAnchor.kind === "range" && previousRange.from < previousRange.to && mappedAnchor.kind === "range" && mappedRange.from === mappedRange.to && mappingTouchesAnchorContent(previousAnchor, mapping)) {
|
|
157
|
-
return detachReviewAnchor(previousRange, detachReason(mapping));
|
|
158
|
-
}
|
|
159
|
-
if (mappedAnchor.kind === "range" && !rangeStaysWithinSingleParagraph(nextContent, mappedAnchor.range)) {
|
|
160
|
-
return detachReviewAnchor(previousRange, "invalidatedByStructureChange");
|
|
161
|
-
}
|
|
162
|
-
return mappedAnchor;
|
|
163
|
-
}
|
|
164
|
-
function detachReason(mapping) {
|
|
165
|
-
return mapping.metadata?.invalidatesStructures ? "invalidatedByStructureChange" : "deleted";
|
|
166
|
-
}
|
|
167
|
-
function mergeDetachedAnchorWarnings(comments, existingWarnings) {
|
|
168
|
-
const retainedWarnings = existingWarnings.filter(
|
|
169
|
-
(warning) => warning.code !== "comment_anchor_detached" || !warning.details || typeof warning.details.commentId !== "string" || comments[warning.details.commentId]?.anchor.kind === "detached"
|
|
170
|
-
);
|
|
171
|
-
const knownDetachedIds = new Set(
|
|
172
|
-
retainedWarnings.filter((warning) => warning.code === "comment_anchor_detached").map(
|
|
173
|
-
(warning) => typeof warning.details?.commentId === "string" ? warning.details.commentId : void 0
|
|
174
|
-
).filter((value) => Boolean(value))
|
|
175
|
-
);
|
|
176
|
-
const detachedWarnings = Object.values(comments).filter(
|
|
177
|
-
(comment) => comment.anchor.kind === "detached" && !knownDetachedIds.has(comment.commentId)
|
|
178
|
-
).map((comment) => createDetachedCommentWarning(comment));
|
|
179
|
-
return [...retainedWarnings, ...detachedWarnings];
|
|
180
|
-
}
|
|
181
|
-
function createDetachedCommentWarning(comment) {
|
|
182
|
-
const anchor = comment.anchor.kind === "detached" ? comment.anchor : void 0;
|
|
183
|
-
return {
|
|
184
|
-
warningId: `warning:comment-anchor-detached:${comment.commentId}`,
|
|
185
|
-
code: "comment_anchor_detached",
|
|
186
|
-
severity: "warning",
|
|
187
|
-
message: `Comment ${comment.commentId} detached after edit remapping.`,
|
|
188
|
-
source: "review",
|
|
189
|
-
affectedAnchor: anchor,
|
|
190
|
-
details: {
|
|
191
|
-
commentId: comment.commentId,
|
|
192
|
-
reason: anchor?.reason
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// src/review/store/revision-actions.ts
|
|
198
|
-
function applyRevisionAction(options) {
|
|
199
|
-
const revision = options.store.revisions[options.revisionId];
|
|
200
|
-
if (!revision) {
|
|
201
|
-
return skippedResult(options, "missing", "Revision record was not found.");
|
|
202
|
-
}
|
|
203
|
-
if (revision.status !== "active") {
|
|
204
|
-
return skippedResult(
|
|
205
|
-
options,
|
|
206
|
-
"already-resolved",
|
|
207
|
-
`Revision is already ${revision.status}.`
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
if (revision.anchor.kind === "detached") {
|
|
211
|
-
return skippedResult(
|
|
212
|
-
options,
|
|
213
|
-
"detached-anchor",
|
|
214
|
-
"Detached revisions remain visible but cannot be accepted or rejected."
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
if (getRevisionActionability(revision) !== "actionable") {
|
|
218
|
-
return skippedResult(
|
|
219
|
-
options,
|
|
220
|
-
"preserve-only",
|
|
221
|
-
revision.metadata.preserveOnlyReason ?? "This revision kind remains preserve-only in the current runtime."
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
if (revision.anchor.kind !== "range") {
|
|
225
|
-
return skippedResult(
|
|
226
|
-
options,
|
|
227
|
-
"structural-range",
|
|
228
|
-
"Non-range revisions remain preserve-only in the current runtime."
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
const story = parseTextStory(options.document.content);
|
|
232
|
-
const range = normalizeRange(
|
|
233
|
-
revision.anchor.range.from,
|
|
234
|
-
revision.anchor.range.to
|
|
235
|
-
);
|
|
236
|
-
if (range.to > story.size) {
|
|
237
|
-
return skippedResult(
|
|
238
|
-
options,
|
|
239
|
-
"invalid-range",
|
|
240
|
-
`Revision range ${range.from}-${range.to} exceeds story size ${story.size}.`
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
const paragraphMarkRange = resolveParagraphMarkDeletionRange(story, revision, options.intent);
|
|
244
|
-
if (paragraphMarkRange) {
|
|
245
|
-
const resultingStatus2 = toResultingStatus(options.intent);
|
|
246
|
-
const textResult2 = applyTextTransaction(
|
|
247
|
-
options.document,
|
|
248
|
-
createSelectionSnapshot(paragraphMarkRange.from, paragraphMarkRange.to),
|
|
249
|
-
{
|
|
250
|
-
type: "replace",
|
|
251
|
-
range: paragraphMarkRange,
|
|
252
|
-
insertion: []
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
timestamp: options.timestamp
|
|
256
|
-
}
|
|
257
|
-
);
|
|
258
|
-
const nextStore2 = remapRevisionStore(
|
|
259
|
-
setRevisionStatus(options.store, revision.revisionId, resultingStatus2),
|
|
260
|
-
textResult2.mapping
|
|
261
|
-
);
|
|
262
|
-
return {
|
|
263
|
-
document: textResult2.document,
|
|
264
|
-
store: nextStore2,
|
|
265
|
-
mapping: textResult2.mapping,
|
|
266
|
-
outcome: {
|
|
267
|
-
kind: "applied",
|
|
268
|
-
revisionId: revision.revisionId,
|
|
269
|
-
intent: options.intent,
|
|
270
|
-
resultingStatus: resultingStatus2,
|
|
271
|
-
contentChanged: true
|
|
272
|
-
},
|
|
273
|
-
detachedRevisionIds: findNewDetachedRevisionIds(options.store, nextStore2)
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
if (requiresParagraphBoundaryDeletion(revision, options.intent)) {
|
|
277
|
-
return skippedResult(
|
|
278
|
-
options,
|
|
279
|
-
"structural-range",
|
|
280
|
-
"Paragraph-boundary revisions need a stable paragraph break and remain blocked for this shape."
|
|
281
|
-
);
|
|
282
|
-
}
|
|
283
|
-
const slice = story.units.slice(range.from, range.to);
|
|
284
|
-
if (slice.some(
|
|
285
|
-
(unit) => unit.kind === "paragraph_break" || unit.kind === "opaque_block"
|
|
286
|
-
)) {
|
|
287
|
-
return skippedResult(
|
|
288
|
-
options,
|
|
289
|
-
"structural-range",
|
|
290
|
-
"Paragraph-boundary and structural revisions remain preserve-only."
|
|
291
|
-
);
|
|
292
|
-
}
|
|
293
|
-
if (slice.some(
|
|
294
|
-
(unit) => unit.kind === "image" || unit.kind === "opaque_inline"
|
|
295
|
-
)) {
|
|
296
|
-
return skippedResult(
|
|
297
|
-
options,
|
|
298
|
-
"protected-range",
|
|
299
|
-
"Revisions touching protected inline content remain preserve-only."
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
const resultingStatus = toResultingStatus(options.intent);
|
|
303
|
-
const contentChanged = requiresContentDeletion(revision, options.intent);
|
|
304
|
-
if (!contentChanged) {
|
|
305
|
-
return {
|
|
306
|
-
document: options.document,
|
|
307
|
-
store: setRevisionStatus(options.store, revision.revisionId, resultingStatus),
|
|
308
|
-
mapping: createEmptyMapping(),
|
|
309
|
-
outcome: {
|
|
310
|
-
kind: "applied",
|
|
311
|
-
revisionId: revision.revisionId,
|
|
312
|
-
intent: options.intent,
|
|
313
|
-
resultingStatus,
|
|
314
|
-
contentChanged: false
|
|
315
|
-
},
|
|
316
|
-
detachedRevisionIds: []
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
const textResult = applyTextTransaction(
|
|
320
|
-
options.document,
|
|
321
|
-
createSelectionSnapshot(range.from, range.to),
|
|
322
|
-
{
|
|
323
|
-
type: "replace",
|
|
324
|
-
range,
|
|
325
|
-
insertion: []
|
|
326
|
-
},
|
|
327
|
-
{
|
|
328
|
-
timestamp: options.timestamp
|
|
329
|
-
}
|
|
330
|
-
);
|
|
331
|
-
const nextStore = remapRevisionStore(
|
|
332
|
-
setRevisionStatus(options.store, revision.revisionId, resultingStatus),
|
|
333
|
-
textResult.mapping
|
|
334
|
-
);
|
|
335
|
-
return {
|
|
336
|
-
document: textResult.document,
|
|
337
|
-
store: nextStore,
|
|
338
|
-
mapping: textResult.mapping,
|
|
339
|
-
outcome: {
|
|
340
|
-
kind: "applied",
|
|
341
|
-
revisionId: revision.revisionId,
|
|
342
|
-
intent: options.intent,
|
|
343
|
-
resultingStatus,
|
|
344
|
-
contentChanged: true
|
|
345
|
-
},
|
|
346
|
-
detachedRevisionIds: findNewDetachedRevisionIds(options.store, nextStore)
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
function skippedResult(options, reason, detail) {
|
|
350
|
-
return {
|
|
351
|
-
document: options.document,
|
|
352
|
-
store: options.store,
|
|
353
|
-
mapping: createEmptyMapping(),
|
|
354
|
-
outcome: {
|
|
355
|
-
kind: "skipped",
|
|
356
|
-
revisionId: options.revisionId,
|
|
357
|
-
intent: options.intent,
|
|
358
|
-
reason,
|
|
359
|
-
detail
|
|
360
|
-
},
|
|
361
|
-
detachedRevisionIds: []
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
function toResultingStatus(intent) {
|
|
365
|
-
return intent === "accept" ? "accepted" : "rejected";
|
|
366
|
-
}
|
|
367
|
-
function requiresContentDeletion(revision, intent) {
|
|
368
|
-
return revision.kind === "insertion" && intent === "reject" || revision.kind === "deletion" && intent === "accept";
|
|
369
|
-
}
|
|
370
|
-
function requiresParagraphBoundaryDeletion(revision, intent) {
|
|
371
|
-
return revision.metadata.originalRevisionType === "paragraph-del" && intent === "accept" || revision.metadata.originalRevisionType === "paragraph-ins" && intent === "reject";
|
|
372
|
-
}
|
|
373
|
-
function resolveParagraphMarkDeletionRange(story, revision, intent) {
|
|
374
|
-
const originalRevisionType = revision.metadata.originalRevisionType;
|
|
375
|
-
if (revision.anchor.kind !== "range" || originalRevisionType !== "paragraph-del" && originalRevisionType !== "paragraph-ins") {
|
|
376
|
-
return void 0;
|
|
377
|
-
}
|
|
378
|
-
const shouldDeleteBoundary = originalRevisionType === "paragraph-del" && intent === "accept" || originalRevisionType === "paragraph-ins" && intent === "reject";
|
|
379
|
-
if (!shouldDeleteBoundary) {
|
|
380
|
-
return void 0;
|
|
381
|
-
}
|
|
382
|
-
const paragraphs = mapParagraphRanges(story);
|
|
383
|
-
const anchorPosition = normalizeRange(
|
|
384
|
-
revision.anchor.range.from,
|
|
385
|
-
revision.anchor.range.to
|
|
386
|
-
).from;
|
|
387
|
-
const paragraph = paragraphs.find(
|
|
388
|
-
(candidate) => candidate.end === anchorPosition || anchorPosition >= candidate.start && anchorPosition <= candidate.end
|
|
389
|
-
);
|
|
390
|
-
if (!paragraph) {
|
|
391
|
-
return void 0;
|
|
392
|
-
}
|
|
393
|
-
if (originalRevisionType === "paragraph-del") {
|
|
394
|
-
const boundaryIndex2 = paragraph.end;
|
|
395
|
-
if (story.units[boundaryIndex2]?.kind !== "paragraph_break") {
|
|
396
|
-
return void 0;
|
|
397
|
-
}
|
|
398
|
-
return {
|
|
399
|
-
from: boundaryIndex2,
|
|
400
|
-
to: boundaryIndex2 + 1
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
const boundaryIndex = paragraph.start - 1;
|
|
404
|
-
if (boundaryIndex < 0 || story.units[boundaryIndex]?.kind !== "paragraph_break") {
|
|
405
|
-
return void 0;
|
|
406
|
-
}
|
|
407
|
-
return {
|
|
408
|
-
from: boundaryIndex,
|
|
409
|
-
to: boundaryIndex + 1
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
function mapParagraphRanges(story) {
|
|
413
|
-
const paragraphs = [];
|
|
414
|
-
let start = 0;
|
|
415
|
-
let hasPendingParagraph = true;
|
|
416
|
-
for (let index = 0; index < story.units.length; index += 1) {
|
|
417
|
-
const unit = story.units[index];
|
|
418
|
-
if (unit.kind === "paragraph_break") {
|
|
419
|
-
paragraphs.push({ start, end: index });
|
|
420
|
-
start = index + 1;
|
|
421
|
-
hasPendingParagraph = true;
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
|
-
if (unit.kind === "opaque_block") {
|
|
425
|
-
if (hasPendingParagraph) {
|
|
426
|
-
paragraphs.push({ start, end: index });
|
|
427
|
-
}
|
|
428
|
-
start = index + 1;
|
|
429
|
-
hasPendingParagraph = Boolean(unit.nextParagraph);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
if (hasPendingParagraph) {
|
|
433
|
-
paragraphs.push({ start, end: story.units.length });
|
|
434
|
-
}
|
|
435
|
-
return paragraphs;
|
|
436
|
-
}
|
|
437
|
-
function normalizeRange(from, to) {
|
|
438
|
-
return {
|
|
439
|
-
from: Math.min(from, to),
|
|
440
|
-
to: Math.max(from, to)
|
|
441
|
-
};
|
|
442
|
-
}
|
|
443
|
-
function findNewDetachedRevisionIds(previousStore, nextStore) {
|
|
444
|
-
const detachedRevisionIds = [];
|
|
445
|
-
for (const [revisionId, revision] of Object.entries(nextStore.revisions)) {
|
|
446
|
-
if (revision.status === "detached" && previousStore.revisions[revisionId]?.status !== "detached") {
|
|
447
|
-
detachedRevisionIds.push(revisionId);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
return detachedRevisionIds;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// src/runtime/revision-runtime.ts
|
|
454
|
-
function applyRevisionRuntimeCommand(options) {
|
|
455
|
-
const revisionIds = isSingleRevisionReviewCommand(options.command) ? [options.command.revisionId] : listBatchRevisionIds(options.state.store);
|
|
456
|
-
const outcomes = [];
|
|
457
|
-
const mappings = [];
|
|
458
|
-
const appliedRevisionIds = [];
|
|
459
|
-
const detachedRevisionIds = /* @__PURE__ */ new Set();
|
|
460
|
-
let state = options.state;
|
|
461
|
-
for (const revisionId of revisionIds) {
|
|
462
|
-
const result = applyRevisionAction({
|
|
463
|
-
document: state.document,
|
|
464
|
-
store: state.store,
|
|
465
|
-
revisionId,
|
|
466
|
-
intent: getReviewCommandIntent(options.command),
|
|
467
|
-
timestamp: options.timestamp
|
|
468
|
-
});
|
|
469
|
-
state = {
|
|
470
|
-
document: result.document,
|
|
471
|
-
store: result.store
|
|
472
|
-
};
|
|
473
|
-
outcomes.push(result.outcome);
|
|
474
|
-
mappings.push({
|
|
475
|
-
revisionId,
|
|
476
|
-
mapping: result.mapping,
|
|
477
|
-
steps: result.mapping.steps.length
|
|
478
|
-
});
|
|
479
|
-
if (result.outcome.kind === "applied") {
|
|
480
|
-
appliedRevisionIds.push(revisionId);
|
|
481
|
-
}
|
|
482
|
-
for (const detachedRevisionId of result.detachedRevisionIds) {
|
|
483
|
-
detachedRevisionIds.add(detachedRevisionId);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
return {
|
|
487
|
-
...state,
|
|
488
|
-
outcomes,
|
|
489
|
-
mappings,
|
|
490
|
-
effects: {
|
|
491
|
-
appliedRevisionIds,
|
|
492
|
-
skippedRevisions: outcomes.filter(
|
|
493
|
-
(outcome) => outcome.kind === "skipped"
|
|
494
|
-
),
|
|
495
|
-
detachedRevisionIds: [...detachedRevisionIds]
|
|
496
|
-
}
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
function listBatchRevisionIds(store) {
|
|
500
|
-
return Object.values(store.revisions).filter((revision) => revision.status === "active").sort((left, right) => {
|
|
501
|
-
const createdAtDelta = left.createdAt.localeCompare(right.createdAt);
|
|
502
|
-
if (createdAtDelta !== 0) {
|
|
503
|
-
return createdAtDelta;
|
|
504
|
-
}
|
|
505
|
-
return left.revisionId.localeCompare(right.revisionId);
|
|
506
|
-
}).map((revision) => revision.revisionId);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
// src/core/commands/index.ts
|
|
510
|
-
function executeEditorCommand(state, command, context) {
|
|
511
|
-
switch (command.type) {
|
|
512
|
-
case "selection.set":
|
|
513
|
-
return createTransaction(
|
|
514
|
-
{
|
|
515
|
-
...state,
|
|
516
|
-
selection: normalizeSelection(command.selection)
|
|
517
|
-
},
|
|
518
|
-
{
|
|
519
|
-
historyBoundary: "skip",
|
|
520
|
-
markDirty: false
|
|
521
|
-
}
|
|
522
|
-
);
|
|
523
|
-
case "document.replace": {
|
|
524
|
-
const mapping = command.mapping ?? createEmptyMapping();
|
|
525
|
-
const selection = command.selection ?? remapSelection(state.selection, mapping);
|
|
526
|
-
const reviewState = remapReviewStateAfterContentChange(
|
|
527
|
-
state,
|
|
528
|
-
command.document,
|
|
529
|
-
mapping
|
|
530
|
-
);
|
|
531
|
-
return createTransaction(
|
|
532
|
-
{
|
|
533
|
-
...state,
|
|
534
|
-
document: reviewState.document,
|
|
535
|
-
selection,
|
|
536
|
-
warnings: reviewState.warnings,
|
|
537
|
-
runtime: {
|
|
538
|
-
...state.runtime,
|
|
539
|
-
activeCommentId: reviewState.activeCommentId
|
|
540
|
-
},
|
|
541
|
-
compatibility: {
|
|
542
|
-
...state.compatibility,
|
|
543
|
-
generatedAt: context.timestamp,
|
|
544
|
-
warnings: reviewState.warnings,
|
|
545
|
-
featureEntries: state.compatibility.featureEntries.map(
|
|
546
|
-
(entry) => entry.affectedAnchor ? {
|
|
547
|
-
...entry,
|
|
548
|
-
affectedAnchor: mapAnchor(entry.affectedAnchor, mapping)
|
|
549
|
-
} : entry
|
|
550
|
-
)
|
|
551
|
-
}
|
|
552
|
-
},
|
|
553
|
-
{
|
|
554
|
-
historyBoundary: "push",
|
|
555
|
-
markDirty: true,
|
|
556
|
-
mapping,
|
|
557
|
-
effects: reviewState.effects
|
|
558
|
-
}
|
|
559
|
-
);
|
|
560
|
-
}
|
|
561
|
-
case "text.insert": {
|
|
562
|
-
const suggestingResult = context.documentMode === "suggesting" ? applySuggestingInsert(state, command.text, context) : void 0;
|
|
563
|
-
if (suggestingResult) return suggestingResult;
|
|
564
|
-
return applyTextCommand(
|
|
565
|
-
state,
|
|
566
|
-
context.timestamp,
|
|
567
|
-
(document, selection) => insertText(document, selection, command.text, context)
|
|
568
|
-
);
|
|
569
|
-
}
|
|
570
|
-
case "text.delete-backward": {
|
|
571
|
-
const suggestingResult = context.documentMode === "suggesting" ? applySuggestingDelete(state, "backward", context) : void 0;
|
|
572
|
-
if (suggestingResult) return suggestingResult;
|
|
573
|
-
return applyTextCommand(
|
|
574
|
-
state,
|
|
575
|
-
context.timestamp,
|
|
576
|
-
(document, selection) => deleteSelectionOrBackward(document, selection, context)
|
|
577
|
-
);
|
|
578
|
-
}
|
|
579
|
-
case "text.delete-forward": {
|
|
580
|
-
const suggestingResult = context.documentMode === "suggesting" ? applySuggestingDelete(state, "forward", context) : void 0;
|
|
581
|
-
if (suggestingResult) return suggestingResult;
|
|
582
|
-
return applyTextCommand(
|
|
583
|
-
state,
|
|
584
|
-
context.timestamp,
|
|
585
|
-
(document, selection) => deleteSelectionOrForward(document, selection, context)
|
|
586
|
-
);
|
|
587
|
-
}
|
|
588
|
-
case "text.insert-tab": {
|
|
589
|
-
const suggestingResult = context.documentMode === "suggesting" ? applySuggestingInsertUnit(state, "tab", context) : void 0;
|
|
590
|
-
if (suggestingResult) return suggestingResult;
|
|
591
|
-
return applyTextCommand(
|
|
592
|
-
state,
|
|
593
|
-
context.timestamp,
|
|
594
|
-
(document, selection) => insertTab(document, selection, context)
|
|
595
|
-
);
|
|
596
|
-
}
|
|
597
|
-
case "text.insert-hard-break": {
|
|
598
|
-
const suggestingResult = context.documentMode === "suggesting" ? applySuggestingInsertUnit(state, "hard_break", context) : void 0;
|
|
599
|
-
if (suggestingResult) return suggestingResult;
|
|
600
|
-
return applyTextCommand(
|
|
601
|
-
state,
|
|
602
|
-
context.timestamp,
|
|
603
|
-
(document, selection) => insertHardBreak(document, selection, context)
|
|
604
|
-
);
|
|
605
|
-
}
|
|
606
|
-
case "paragraph.split":
|
|
607
|
-
if (context.documentMode === "suggesting") {
|
|
608
|
-
return createTransaction(state, {
|
|
609
|
-
historyBoundary: "skip",
|
|
610
|
-
markDirty: false,
|
|
611
|
-
effects: {
|
|
612
|
-
commandBlocked: {
|
|
613
|
-
code: "suggesting_unsupported",
|
|
614
|
-
message: "Paragraph splits are not supported in suggesting mode."
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
return applyTextCommand(
|
|
620
|
-
state,
|
|
621
|
-
context.timestamp,
|
|
622
|
-
(document, selection) => splitParagraph(document, selection, context)
|
|
623
|
-
);
|
|
624
|
-
case "runtime.set-read-only":
|
|
625
|
-
return createTransaction(
|
|
626
|
-
{
|
|
627
|
-
...state,
|
|
628
|
-
readOnly: command.readOnly
|
|
629
|
-
},
|
|
630
|
-
{
|
|
631
|
-
historyBoundary: "skip",
|
|
632
|
-
markDirty: false
|
|
633
|
-
}
|
|
634
|
-
);
|
|
635
|
-
case "runtime.focus":
|
|
636
|
-
return createTransaction(
|
|
637
|
-
{
|
|
638
|
-
...state,
|
|
639
|
-
runtime: {
|
|
640
|
-
...state.runtime,
|
|
641
|
-
hasFocus: command.focused
|
|
642
|
-
}
|
|
643
|
-
},
|
|
644
|
-
{
|
|
645
|
-
historyBoundary: "skip",
|
|
646
|
-
markDirty: false
|
|
647
|
-
}
|
|
648
|
-
);
|
|
649
|
-
case "warning.add": {
|
|
650
|
-
if (state.warnings.some((warning) => warning.warningId === command.warning.warningId)) {
|
|
651
|
-
return createTransaction(state, {
|
|
652
|
-
historyBoundary: "skip",
|
|
653
|
-
markDirty: false
|
|
654
|
-
});
|
|
655
|
-
}
|
|
656
|
-
const warnings = [...state.warnings, command.warning];
|
|
657
|
-
return createTransaction(
|
|
658
|
-
{
|
|
659
|
-
...state,
|
|
660
|
-
warnings,
|
|
661
|
-
compatibility: {
|
|
662
|
-
...state.compatibility,
|
|
663
|
-
generatedAt: context.timestamp,
|
|
664
|
-
warnings
|
|
665
|
-
}
|
|
666
|
-
},
|
|
667
|
-
{
|
|
668
|
-
historyBoundary: "skip",
|
|
669
|
-
markDirty: false,
|
|
670
|
-
effects: {
|
|
671
|
-
warningsAdded: [command.warning]
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
);
|
|
675
|
-
}
|
|
676
|
-
case "warning.clear": {
|
|
677
|
-
const existing = state.warnings.find((warning) => warning.warningId === command.warningId);
|
|
678
|
-
if (!existing) {
|
|
679
|
-
return createTransaction(state, {
|
|
680
|
-
historyBoundary: "skip",
|
|
681
|
-
markDirty: false
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
const warnings = state.warnings.filter((warning) => warning.warningId !== command.warningId);
|
|
685
|
-
return createTransaction(
|
|
686
|
-
{
|
|
687
|
-
...state,
|
|
688
|
-
warnings,
|
|
689
|
-
compatibility: {
|
|
690
|
-
...state.compatibility,
|
|
691
|
-
generatedAt: context.timestamp,
|
|
692
|
-
warnings
|
|
693
|
-
}
|
|
694
|
-
},
|
|
695
|
-
{
|
|
696
|
-
historyBoundary: "skip",
|
|
697
|
-
markDirty: false,
|
|
698
|
-
effects: {
|
|
699
|
-
warningsCleared: [
|
|
700
|
-
{
|
|
701
|
-
warningId: existing.warningId,
|
|
702
|
-
code: existing.code
|
|
703
|
-
}
|
|
704
|
-
]
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
);
|
|
708
|
-
}
|
|
709
|
-
case "comment.add": {
|
|
710
|
-
const comments = {
|
|
711
|
-
...state.document.review.comments,
|
|
712
|
-
[command.comment.commentId]: normalizeCommentThreadRecord(command.comment)
|
|
713
|
-
};
|
|
714
|
-
return createTransaction(
|
|
715
|
-
{
|
|
716
|
-
...state,
|
|
717
|
-
document: {
|
|
718
|
-
...state.document,
|
|
719
|
-
updatedAt: context.timestamp,
|
|
720
|
-
review: {
|
|
721
|
-
...state.document.review,
|
|
722
|
-
comments
|
|
723
|
-
}
|
|
724
|
-
},
|
|
725
|
-
runtime: {
|
|
726
|
-
...state.runtime,
|
|
727
|
-
activeCommentId: command.comment.commentId
|
|
728
|
-
}
|
|
729
|
-
},
|
|
730
|
-
{
|
|
731
|
-
historyBoundary: "push",
|
|
732
|
-
markDirty: true,
|
|
733
|
-
effects: {
|
|
734
|
-
commentAdded: {
|
|
735
|
-
commentId: command.comment.commentId,
|
|
736
|
-
anchor: command.comment.anchor
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
);
|
|
741
|
-
}
|
|
742
|
-
case "comment.open":
|
|
743
|
-
return createTransaction(
|
|
744
|
-
{
|
|
745
|
-
...state,
|
|
746
|
-
runtime: {
|
|
747
|
-
...state.runtime,
|
|
748
|
-
activeCommentId: command.commentId
|
|
749
|
-
}
|
|
750
|
-
},
|
|
751
|
-
{
|
|
752
|
-
historyBoundary: "skip",
|
|
753
|
-
markDirty: false
|
|
754
|
-
}
|
|
755
|
-
);
|
|
756
|
-
case "comment.resolve": {
|
|
757
|
-
const existing = state.document.review.comments[command.commentId];
|
|
758
|
-
if (!existing) {
|
|
759
|
-
return createTransaction(state, {
|
|
760
|
-
historyBoundary: "skip",
|
|
761
|
-
markDirty: false
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
const comments = {
|
|
765
|
-
...state.document.review.comments,
|
|
766
|
-
[command.commentId]: {
|
|
767
|
-
...existing,
|
|
768
|
-
status: existing.anchor.kind === "detached" ? "detached" : "resolved",
|
|
769
|
-
resolution: {
|
|
770
|
-
resolvedAt: context.timestamp,
|
|
771
|
-
resolvedBy: command.resolvedBy ?? existing.createdBy ?? existing.authorId ?? existing.entries?.[0]?.authorId ?? "unknown"
|
|
772
|
-
},
|
|
773
|
-
isResolved: true,
|
|
774
|
-
resolvedAt: context.timestamp
|
|
775
|
-
}
|
|
776
|
-
};
|
|
777
|
-
return createTransaction(
|
|
778
|
-
{
|
|
779
|
-
...state,
|
|
780
|
-
document: {
|
|
781
|
-
...state.document,
|
|
782
|
-
updatedAt: context.timestamp,
|
|
783
|
-
review: {
|
|
784
|
-
...state.document.review,
|
|
785
|
-
comments
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
},
|
|
789
|
-
{
|
|
790
|
-
historyBoundary: "push",
|
|
791
|
-
markDirty: true,
|
|
792
|
-
effects: {
|
|
793
|
-
commentResolved: {
|
|
794
|
-
commentId: command.commentId
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
);
|
|
799
|
-
}
|
|
800
|
-
case "comment.reopen": {
|
|
801
|
-
const existingThread = state.document.review.comments[command.commentId];
|
|
802
|
-
if (!existingThread || existingThread.status === "detached") {
|
|
803
|
-
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
804
|
-
}
|
|
805
|
-
const reopenedComments = {
|
|
806
|
-
...state.document.review.comments,
|
|
807
|
-
[command.commentId]: {
|
|
808
|
-
...existingThread,
|
|
809
|
-
status: "open",
|
|
810
|
-
isResolved: false,
|
|
811
|
-
resolvedAt: void 0,
|
|
812
|
-
resolution: void 0
|
|
813
|
-
}
|
|
814
|
-
};
|
|
815
|
-
return createTransaction(
|
|
816
|
-
{
|
|
817
|
-
...state,
|
|
818
|
-
document: {
|
|
819
|
-
...state.document,
|
|
820
|
-
updatedAt: context.timestamp,
|
|
821
|
-
review: { ...state.document.review, comments: reopenedComments }
|
|
822
|
-
},
|
|
823
|
-
runtime: { ...state.runtime, activeCommentId: command.commentId }
|
|
824
|
-
},
|
|
825
|
-
{
|
|
826
|
-
historyBoundary: "push",
|
|
827
|
-
markDirty: true,
|
|
828
|
-
effects: { commentReopened: { commentId: command.commentId } }
|
|
829
|
-
}
|
|
830
|
-
);
|
|
831
|
-
}
|
|
832
|
-
case "comment.add-reply": {
|
|
833
|
-
const threadForReply = state.document.review.comments[command.commentId];
|
|
834
|
-
if (!threadForReply) {
|
|
835
|
-
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
836
|
-
}
|
|
837
|
-
if (threadForReply.status === "resolved" || threadForReply.status === "detached") {
|
|
838
|
-
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
839
|
-
}
|
|
840
|
-
const entryId = `${command.commentId}-entry-${(threadForReply.entries?.length ?? 0) + 1}`;
|
|
841
|
-
const newEntry = {
|
|
842
|
-
entryId,
|
|
843
|
-
authorId: command.authorId ?? threadForReply.createdBy ?? "unknown",
|
|
844
|
-
body: command.body,
|
|
845
|
-
createdAt: context.timestamp
|
|
846
|
-
};
|
|
847
|
-
const updatedThread = {
|
|
848
|
-
...threadForReply,
|
|
849
|
-
entries: [...threadForReply.entries ?? [], newEntry]
|
|
850
|
-
};
|
|
851
|
-
const replyComments = {
|
|
852
|
-
...state.document.review.comments,
|
|
853
|
-
[command.commentId]: updatedThread
|
|
854
|
-
};
|
|
855
|
-
return createTransaction(
|
|
856
|
-
{
|
|
857
|
-
...state,
|
|
858
|
-
document: {
|
|
859
|
-
...state.document,
|
|
860
|
-
updatedAt: context.timestamp,
|
|
861
|
-
review: { ...state.document.review, comments: replyComments }
|
|
862
|
-
}
|
|
863
|
-
},
|
|
864
|
-
{
|
|
865
|
-
historyBoundary: "push",
|
|
866
|
-
markDirty: true,
|
|
867
|
-
effects: { commentReplyAdded: { commentId: command.commentId } }
|
|
868
|
-
}
|
|
869
|
-
);
|
|
870
|
-
}
|
|
871
|
-
case "comment.edit-body": {
|
|
872
|
-
const threadToEdit = state.document.review.comments[command.commentId];
|
|
873
|
-
if (!threadToEdit || !threadToEdit.entries?.length) {
|
|
874
|
-
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
875
|
-
}
|
|
876
|
-
const editedEntries = [...threadToEdit.entries];
|
|
877
|
-
editedEntries[0] = { ...editedEntries[0], body: command.body };
|
|
878
|
-
const editedThread = {
|
|
879
|
-
...threadToEdit,
|
|
880
|
-
body: command.body,
|
|
881
|
-
entries: editedEntries
|
|
882
|
-
};
|
|
883
|
-
const editedComments = {
|
|
884
|
-
...state.document.review.comments,
|
|
885
|
-
[command.commentId]: editedThread
|
|
886
|
-
};
|
|
887
|
-
return createTransaction(
|
|
888
|
-
{
|
|
889
|
-
...state,
|
|
890
|
-
document: {
|
|
891
|
-
...state.document,
|
|
892
|
-
updatedAt: context.timestamp,
|
|
893
|
-
review: { ...state.document.review, comments: editedComments }
|
|
894
|
-
}
|
|
895
|
-
},
|
|
896
|
-
{
|
|
897
|
-
historyBoundary: "push",
|
|
898
|
-
markDirty: true,
|
|
899
|
-
effects: { commentBodyEdited: { commentId: command.commentId } }
|
|
900
|
-
}
|
|
901
|
-
);
|
|
902
|
-
}
|
|
903
|
-
case "change.accept":
|
|
904
|
-
return applyReviewCommand(
|
|
905
|
-
state,
|
|
906
|
-
createAcceptRevisionCommand(command.changeId, command.origin),
|
|
907
|
-
context.timestamp
|
|
908
|
-
);
|
|
909
|
-
case "change.reject":
|
|
910
|
-
return applyReviewCommand(
|
|
911
|
-
state,
|
|
912
|
-
createRejectRevisionCommand(command.changeId, command.origin),
|
|
913
|
-
context.timestamp
|
|
914
|
-
);
|
|
915
|
-
case "change.accept-all":
|
|
916
|
-
return applyReviewCommand(
|
|
917
|
-
state,
|
|
918
|
-
{
|
|
919
|
-
type: "review.accept-all-revisions",
|
|
920
|
-
...command.origin ? { origin: command.origin } : {}
|
|
921
|
-
},
|
|
922
|
-
context.timestamp
|
|
923
|
-
);
|
|
924
|
-
case "change.reject-all":
|
|
925
|
-
return applyReviewCommand(
|
|
926
|
-
state,
|
|
927
|
-
{
|
|
928
|
-
type: "review.reject-all-revisions",
|
|
929
|
-
...command.origin ? { origin: command.origin } : {}
|
|
930
|
-
},
|
|
931
|
-
context.timestamp
|
|
932
|
-
);
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
function remapSelection(selection, mapping) {
|
|
936
|
-
const activeRange = mapAnchor(selection.activeRange, mapping);
|
|
937
|
-
if (activeRange.kind === "range") {
|
|
938
|
-
return {
|
|
939
|
-
anchor: activeRange.range.from,
|
|
940
|
-
head: activeRange.range.to,
|
|
941
|
-
isCollapsed: activeRange.range.from === activeRange.range.to,
|
|
942
|
-
activeRange
|
|
943
|
-
};
|
|
944
|
-
}
|
|
945
|
-
if (activeRange.kind === "node") {
|
|
946
|
-
return {
|
|
947
|
-
anchor: activeRange.at,
|
|
948
|
-
head: activeRange.at,
|
|
949
|
-
isCollapsed: true,
|
|
950
|
-
activeRange
|
|
951
|
-
};
|
|
952
|
-
}
|
|
953
|
-
return {
|
|
954
|
-
anchor: selection.anchor,
|
|
955
|
-
head: selection.head,
|
|
956
|
-
isCollapsed: selection.anchor === selection.head,
|
|
957
|
-
activeRange
|
|
958
|
-
};
|
|
959
|
-
}
|
|
960
|
-
function selectionChanged(left, right) {
|
|
961
|
-
return left.anchor !== right.anchor || left.head !== right.head || left.isCollapsed !== right.isCollapsed || !areAnchorsEqual(left.activeRange, right.activeRange);
|
|
962
|
-
}
|
|
963
|
-
function createTransaction(nextState, options) {
|
|
964
|
-
return {
|
|
965
|
-
nextState,
|
|
966
|
-
mapping: options.mapping ?? createEmptyMapping(),
|
|
967
|
-
historyBoundary: options.historyBoundary,
|
|
968
|
-
markDirty: options.markDirty,
|
|
969
|
-
effects: {
|
|
970
|
-
warningsAdded: options.effects?.warningsAdded ?? [],
|
|
971
|
-
warningsCleared: options.effects?.warningsCleared ?? [],
|
|
972
|
-
commentAdded: options.effects?.commentAdded,
|
|
973
|
-
commentResolved: options.effects?.commentResolved,
|
|
974
|
-
changeAccepted: options.effects?.changeAccepted,
|
|
975
|
-
changeRejected: options.effects?.changeRejected,
|
|
976
|
-
revisionAuthored: options.effects?.revisionAuthored,
|
|
977
|
-
commandBlocked: options.effects?.commandBlocked
|
|
978
|
-
}
|
|
979
|
-
};
|
|
980
|
-
}
|
|
981
|
-
function normalizeSelection(selection) {
|
|
982
|
-
const activeRange = normalizeSelectionAnchor(
|
|
983
|
-
selection.activeRange,
|
|
984
|
-
selection.anchor,
|
|
985
|
-
selection.head
|
|
986
|
-
);
|
|
987
|
-
if (activeRange.kind === "range") {
|
|
988
|
-
return {
|
|
989
|
-
anchor: activeRange.range.from,
|
|
990
|
-
head: activeRange.range.to,
|
|
991
|
-
isCollapsed: activeRange.range.from === activeRange.range.to,
|
|
992
|
-
activeRange
|
|
993
|
-
};
|
|
994
|
-
}
|
|
995
|
-
if (activeRange.kind === "node") {
|
|
996
|
-
return {
|
|
997
|
-
anchor: activeRange.at,
|
|
998
|
-
head: activeRange.at,
|
|
999
|
-
isCollapsed: true,
|
|
1000
|
-
activeRange
|
|
1001
|
-
};
|
|
1002
|
-
}
|
|
1003
|
-
return {
|
|
1004
|
-
anchor: activeRange.lastKnownRange.from,
|
|
1005
|
-
head: activeRange.lastKnownRange.to,
|
|
1006
|
-
isCollapsed: activeRange.lastKnownRange.from === activeRange.lastKnownRange.to,
|
|
1007
|
-
activeRange
|
|
1008
|
-
};
|
|
1009
|
-
}
|
|
1010
|
-
function normalizeSelectionAnchor(value, anchor, head) {
|
|
1011
|
-
if (!value || typeof value !== "object") {
|
|
1012
|
-
return createRangeAnchor(anchor, head, DEFAULT_BOUNDARY_ASSOC);
|
|
1013
|
-
}
|
|
1014
|
-
const record = value;
|
|
1015
|
-
switch (record.kind) {
|
|
1016
|
-
case "range": {
|
|
1017
|
-
const assoc = normalizeBoundaryAssoc(record.assoc);
|
|
1018
|
-
const internalRange = record.range;
|
|
1019
|
-
if (internalRange && typeof internalRange === "object" && typeof internalRange.from === "number" && typeof internalRange.to === "number") {
|
|
1020
|
-
return createRangeAnchor(
|
|
1021
|
-
internalRange.from,
|
|
1022
|
-
internalRange.to,
|
|
1023
|
-
assoc
|
|
1024
|
-
);
|
|
1025
|
-
}
|
|
1026
|
-
if (typeof record.from === "number" && typeof record.to === "number") {
|
|
1027
|
-
return createRangeAnchor(record.from, record.to, assoc);
|
|
1028
|
-
}
|
|
1029
|
-
return createRangeAnchor(anchor, head, assoc);
|
|
1030
|
-
}
|
|
1031
|
-
case "node":
|
|
1032
|
-
return createNodeAnchor(
|
|
1033
|
-
typeof record.at === "number" ? record.at : anchor,
|
|
1034
|
-
normalizeAssoc(record.assoc)
|
|
1035
|
-
);
|
|
1036
|
-
case "detached": {
|
|
1037
|
-
const lastKnownRange = record.lastKnownRange;
|
|
1038
|
-
if (lastKnownRange && typeof lastKnownRange === "object" && typeof lastKnownRange.from === "number" && typeof lastKnownRange.to === "number") {
|
|
1039
|
-
return createDetachedAnchor(
|
|
1040
|
-
{
|
|
1041
|
-
from: lastKnownRange.from,
|
|
1042
|
-
to: lastKnownRange.to
|
|
1043
|
-
},
|
|
1044
|
-
normalizeDetachedReason(record.reason)
|
|
1045
|
-
);
|
|
1046
|
-
}
|
|
1047
|
-
return createDetachedAnchor({ from: anchor, to: head }, normalizeDetachedReason(record.reason));
|
|
1048
|
-
}
|
|
1049
|
-
default:
|
|
1050
|
-
return createRangeAnchor(anchor, head, DEFAULT_BOUNDARY_ASSOC);
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
function normalizeBoundaryAssoc(value) {
|
|
1054
|
-
if (value && typeof value === "object") {
|
|
1055
|
-
const record = value;
|
|
1056
|
-
return {
|
|
1057
|
-
start: normalizeAssoc(record.start),
|
|
1058
|
-
end: normalizeAssoc(record.end)
|
|
1059
|
-
};
|
|
1060
|
-
}
|
|
1061
|
-
return DEFAULT_BOUNDARY_ASSOC;
|
|
1062
|
-
}
|
|
1063
|
-
function normalizeAssoc(value) {
|
|
1064
|
-
return value === -1 ? -1 : 1;
|
|
1065
|
-
}
|
|
1066
|
-
function normalizeDetachedReason(value) {
|
|
1067
|
-
if (value === "deleted" || value === "invalidatedByStructureChange" || value === "importAmbiguity") {
|
|
1068
|
-
return value;
|
|
1069
|
-
}
|
|
1070
|
-
return "importAmbiguity";
|
|
1071
|
-
}
|
|
1072
|
-
function applyTextCommand(state, timestamp, apply) {
|
|
1073
|
-
if (state.readOnly) {
|
|
1074
|
-
return createTransaction(state, {
|
|
1075
|
-
historyBoundary: "skip",
|
|
1076
|
-
markDirty: false
|
|
1077
|
-
});
|
|
1078
|
-
}
|
|
1079
|
-
const result = apply(state.document, state.selection);
|
|
1080
|
-
const reviewState = remapReviewStateAfterContentChange(
|
|
1081
|
-
state,
|
|
1082
|
-
result.document,
|
|
1083
|
-
result.mapping
|
|
1084
|
-
);
|
|
1085
|
-
return createTransaction(
|
|
1086
|
-
{
|
|
1087
|
-
...state,
|
|
1088
|
-
document: reviewState.document,
|
|
1089
|
-
selection: result.selection,
|
|
1090
|
-
warnings: reviewState.warnings,
|
|
1091
|
-
runtime: {
|
|
1092
|
-
...state.runtime,
|
|
1093
|
-
activeCommentId: reviewState.activeCommentId
|
|
1094
|
-
}
|
|
1095
|
-
},
|
|
1096
|
-
{
|
|
1097
|
-
historyBoundary: "push",
|
|
1098
|
-
markDirty: true,
|
|
1099
|
-
mapping: result.mapping,
|
|
1100
|
-
effects: reviewState.effects
|
|
1101
|
-
}
|
|
1102
|
-
);
|
|
1103
|
-
}
|
|
1104
|
-
function applyReviewCommand(state, command, timestamp) {
|
|
1105
|
-
if (state.readOnly) {
|
|
1106
|
-
return createTransaction(state, {
|
|
1107
|
-
historyBoundary: "skip",
|
|
1108
|
-
markDirty: false
|
|
1109
|
-
});
|
|
1110
|
-
}
|
|
1111
|
-
const result = applyRevisionRuntimeCommand({
|
|
1112
|
-
state: {
|
|
1113
|
-
document: state.document,
|
|
1114
|
-
store: createRevisionStoreFromState(state)
|
|
1115
|
-
},
|
|
1116
|
-
command,
|
|
1117
|
-
timestamp
|
|
1118
|
-
});
|
|
1119
|
-
const hasAppliedOutcome = result.outcomes.some((outcome) => outcome.kind === "applied");
|
|
1120
|
-
if (!hasAppliedOutcome) {
|
|
1121
|
-
return createTransaction(state, {
|
|
1122
|
-
historyBoundary: "skip",
|
|
1123
|
-
markDirty: false
|
|
1124
|
-
});
|
|
1125
|
-
}
|
|
1126
|
-
let selection = state.selection;
|
|
1127
|
-
let comments = result.document.review.comments;
|
|
1128
|
-
let warnings = state.warnings;
|
|
1129
|
-
let activeCommentId = state.runtime.activeCommentId;
|
|
1130
|
-
const mappingSteps = [];
|
|
1131
|
-
for (const entry of result.mappings) {
|
|
1132
|
-
if (entry.steps === 0) {
|
|
1133
|
-
continue;
|
|
1134
|
-
}
|
|
1135
|
-
selection = remapSelection(selection, entry.mapping);
|
|
1136
|
-
mappingSteps.push(...entry.mapping.steps);
|
|
1137
|
-
const remappedComments = remapCommentThreads({
|
|
1138
|
-
comments,
|
|
1139
|
-
mapping: entry.mapping,
|
|
1140
|
-
nextContent: result.document.content,
|
|
1141
|
-
existingWarnings: mapWarningsThroughMapping(warnings, entry.mapping)
|
|
1142
|
-
});
|
|
1143
|
-
comments = remappedComments.comments;
|
|
1144
|
-
warnings = remappedComments.warnings;
|
|
1145
|
-
activeCommentId = activeCommentId && comments[activeCommentId] ? activeCommentId : void 0;
|
|
1146
|
-
}
|
|
1147
|
-
warnings = mergeDetachedRevisionWarnings(result.store, warnings);
|
|
1148
|
-
const nextDocument = {
|
|
1149
|
-
...result.document,
|
|
1150
|
-
review: {
|
|
1151
|
-
...result.document.review,
|
|
1152
|
-
comments,
|
|
1153
|
-
revisions: toEditorRevisionRecords(result.store)
|
|
1154
|
-
}
|
|
1155
|
-
};
|
|
1156
|
-
const appliedRevisionIds = result.effects.appliedRevisionIds;
|
|
1157
|
-
return createTransaction(
|
|
1158
|
-
{
|
|
1159
|
-
...state,
|
|
1160
|
-
document: nextDocument,
|
|
1161
|
-
selection,
|
|
1162
|
-
warnings,
|
|
1163
|
-
runtime: {
|
|
1164
|
-
...state.runtime,
|
|
1165
|
-
activeCommentId
|
|
1166
|
-
}
|
|
1167
|
-
},
|
|
1168
|
-
{
|
|
1169
|
-
historyBoundary: "push",
|
|
1170
|
-
markDirty: true,
|
|
1171
|
-
mapping: combineMappingSteps(mappingSteps),
|
|
1172
|
-
effects: {
|
|
1173
|
-
...buildWarningEffects(state.warnings, warnings),
|
|
1174
|
-
changeAccepted: command.type === "review.accept-revision" && appliedRevisionIds[0] ? {
|
|
1175
|
-
changeId: appliedRevisionIds[0]
|
|
1176
|
-
} : void 0,
|
|
1177
|
-
changeRejected: command.type === "review.reject-revision" && appliedRevisionIds[0] ? {
|
|
1178
|
-
changeId: appliedRevisionIds[0]
|
|
1179
|
-
} : void 0
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
);
|
|
1183
|
-
}
|
|
1184
|
-
function remapReviewStateAfterContentChange(state, nextDocument, mapping) {
|
|
1185
|
-
const mappedWarnings = mapWarningsThroughMapping(state.warnings, mapping);
|
|
1186
|
-
const remappedComments = remapCommentThreads({
|
|
1187
|
-
comments: nextDocument.review.comments,
|
|
1188
|
-
mapping,
|
|
1189
|
-
nextContent: nextDocument.content,
|
|
1190
|
-
existingWarnings: mappedWarnings
|
|
1191
|
-
});
|
|
1192
|
-
const revisions = Object.fromEntries(
|
|
1193
|
-
Object.entries(nextDocument.review.revisions).map(([changeId, revision]) => [
|
|
1194
|
-
changeId,
|
|
1195
|
-
{
|
|
1196
|
-
...revision,
|
|
1197
|
-
anchor: mapAnchor(revision.anchor, mapping)
|
|
1198
|
-
}
|
|
1199
|
-
])
|
|
1200
|
-
);
|
|
1201
|
-
const activeCommentId = state.runtime.activeCommentId && remappedComments.comments[state.runtime.activeCommentId] ? state.runtime.activeCommentId : void 0;
|
|
1202
|
-
const warnings = remappedComments.warnings;
|
|
1203
|
-
return {
|
|
1204
|
-
document: {
|
|
1205
|
-
...nextDocument,
|
|
1206
|
-
review: {
|
|
1207
|
-
...nextDocument.review,
|
|
1208
|
-
comments: remappedComments.comments,
|
|
1209
|
-
revisions
|
|
1210
|
-
}
|
|
1211
|
-
},
|
|
1212
|
-
warnings,
|
|
1213
|
-
activeCommentId,
|
|
1214
|
-
effects: buildWarningEffects(state.warnings, warnings)
|
|
1215
|
-
};
|
|
1216
|
-
}
|
|
1217
|
-
function createRevisionStoreFromState(state) {
|
|
1218
|
-
return {
|
|
1219
|
-
version: "revision-store/1",
|
|
1220
|
-
revisions: Object.fromEntries(
|
|
1221
|
-
Object.values(state.document.review.revisions).map((revision) => [
|
|
1222
|
-
revision.changeId,
|
|
1223
|
-
{
|
|
1224
|
-
revisionId: revision.changeId,
|
|
1225
|
-
kind: revision.kind,
|
|
1226
|
-
anchor: revision.anchor,
|
|
1227
|
-
authorId: revision.authorId ?? "unknown",
|
|
1228
|
-
createdAt: revision.createdAt,
|
|
1229
|
-
status: revision.status === "open" ? "active" : revision.status,
|
|
1230
|
-
warningIds: [...revision.warningIds ?? []],
|
|
1231
|
-
metadata: {
|
|
1232
|
-
source: revision.metadata?.source ?? "runtime",
|
|
1233
|
-
storyTarget: revision.metadata?.storyTarget,
|
|
1234
|
-
preserveOnlyReason: revision.metadata?.preserveOnlyReason,
|
|
1235
|
-
importedRevisionForm: revision.metadata?.importedRevisionForm,
|
|
1236
|
-
originalRevisionType: revision.metadata?.originalRevisionType,
|
|
1237
|
-
ooxmlRevisionId: revision.metadata?.ooxmlRevisionId
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
])
|
|
1241
|
-
)
|
|
1242
|
-
};
|
|
1243
|
-
}
|
|
1244
|
-
function toEditorRevisionRecords(store) {
|
|
1245
|
-
return Object.fromEntries(
|
|
1246
|
-
Object.values(store.revisions).map((revision) => [
|
|
1247
|
-
revision.revisionId,
|
|
1248
|
-
{
|
|
1249
|
-
changeId: revision.revisionId,
|
|
1250
|
-
kind: revision.kind,
|
|
1251
|
-
anchor: revision.anchor,
|
|
1252
|
-
authorId: revision.authorId,
|
|
1253
|
-
createdAt: revision.createdAt,
|
|
1254
|
-
warningIds: [...revision.warningIds],
|
|
1255
|
-
metadata: {
|
|
1256
|
-
source: revision.metadata.source,
|
|
1257
|
-
storyTarget: revision.metadata.storyTarget,
|
|
1258
|
-
preserveOnlyReason: revision.metadata.preserveOnlyReason,
|
|
1259
|
-
importedRevisionForm: revision.metadata.importedRevisionForm,
|
|
1260
|
-
originalRevisionType: revision.metadata.originalRevisionType,
|
|
1261
|
-
ooxmlRevisionId: revision.metadata.ooxmlRevisionId
|
|
1262
|
-
},
|
|
1263
|
-
status: revision.status === "active" ? "open" : revision.status
|
|
1264
|
-
}
|
|
1265
|
-
])
|
|
1266
|
-
);
|
|
1267
|
-
}
|
|
1268
|
-
function mapWarningsThroughMapping(warnings, mapping) {
|
|
1269
|
-
return warnings.map(
|
|
1270
|
-
(warning) => warning.affectedAnchor ? {
|
|
1271
|
-
...warning,
|
|
1272
|
-
affectedAnchor: mapAnchor(warning.affectedAnchor, mapping)
|
|
1273
|
-
} : warning
|
|
1274
|
-
);
|
|
1275
|
-
}
|
|
1276
|
-
function buildWarningEffects(previousWarnings, nextWarnings) {
|
|
1277
|
-
const previousById = new Set(previousWarnings.map((warning) => warning.warningId));
|
|
1278
|
-
const nextById = new Set(nextWarnings.map((warning) => warning.warningId));
|
|
1279
|
-
return {
|
|
1280
|
-
warningsAdded: nextWarnings.filter((warning) => !previousById.has(warning.warningId)),
|
|
1281
|
-
warningsCleared: previousWarnings.filter((warning) => !nextById.has(warning.warningId)).map((warning) => ({
|
|
1282
|
-
warningId: warning.warningId,
|
|
1283
|
-
code: warning.code
|
|
1284
|
-
}))
|
|
1285
|
-
};
|
|
1286
|
-
}
|
|
1287
|
-
function mergeDetachedRevisionWarnings(store, existingWarnings) {
|
|
1288
|
-
const retainedWarnings = existingWarnings.filter(
|
|
1289
|
-
(warning) => warning.code !== "revision_anchor_detached" || !warning.details || typeof warning.details.changeId !== "string" || store.revisions[warning.details.changeId]?.status === "detached"
|
|
1290
|
-
);
|
|
1291
|
-
const knownDetachedIds = new Set(
|
|
1292
|
-
retainedWarnings.filter((warning) => warning.code === "revision_anchor_detached").map(
|
|
1293
|
-
(warning) => typeof warning.details?.changeId === "string" ? warning.details.changeId : void 0
|
|
1294
|
-
).filter((value) => Boolean(value))
|
|
1295
|
-
);
|
|
1296
|
-
const detachedWarnings = Object.values(store.revisions).filter(
|
|
1297
|
-
(revision) => revision.status === "detached" && !knownDetachedIds.has(revision.revisionId)
|
|
1298
|
-
).map((revision) => ({
|
|
1299
|
-
warningId: `warning:revision-anchor-detached:${revision.revisionId}`,
|
|
1300
|
-
code: "revision_anchor_detached",
|
|
1301
|
-
severity: "warning",
|
|
1302
|
-
message: `Revision ${revision.revisionId} detached after review remapping.`,
|
|
1303
|
-
source: "review",
|
|
1304
|
-
affectedAnchor: revision.anchor.kind === "detached" ? revision.anchor : void 0,
|
|
1305
|
-
details: {
|
|
1306
|
-
changeId: revision.revisionId,
|
|
1307
|
-
reason: revision.anchor.kind === "detached" ? revision.anchor.reason : void 0
|
|
1308
|
-
}
|
|
1309
|
-
}));
|
|
1310
|
-
return [...retainedWarnings, ...detachedWarnings];
|
|
1311
|
-
}
|
|
1312
|
-
function combineMappingSteps(steps) {
|
|
1313
|
-
return steps.length > 0 ? {
|
|
1314
|
-
steps
|
|
1315
|
-
} : createEmptyMapping();
|
|
1316
|
-
}
|
|
1317
|
-
var suggestingRevisionCounter = 0;
|
|
1318
|
-
function createSuggestingRevisionId(existing, timestamp) {
|
|
1319
|
-
suggestingRevisionCounter += 1;
|
|
1320
|
-
const ts = timestamp.replace(/[^0-9]/gu, "");
|
|
1321
|
-
let id = `change-${ts}-s${suggestingRevisionCounter}`;
|
|
1322
|
-
while (existing[id]) {
|
|
1323
|
-
suggestingRevisionCounter += 1;
|
|
1324
|
-
id = `change-${ts}-s${suggestingRevisionCounter}`;
|
|
1325
|
-
}
|
|
1326
|
-
return id;
|
|
1327
|
-
}
|
|
1328
|
-
function createAuthoredRevision(existing, kind, from, to, authorId, timestamp) {
|
|
1329
|
-
const changeId = createSuggestingRevisionId(existing, timestamp);
|
|
1330
|
-
return {
|
|
1331
|
-
changeId,
|
|
1332
|
-
kind,
|
|
1333
|
-
anchor: {
|
|
1334
|
-
kind: "range",
|
|
1335
|
-
range: { from, to },
|
|
1336
|
-
assoc: { start: 1, end: -1 }
|
|
1337
|
-
},
|
|
1338
|
-
authorId,
|
|
1339
|
-
createdAt: timestamp,
|
|
1340
|
-
warningIds: [],
|
|
1341
|
-
metadata: {
|
|
1342
|
-
source: "runtime"
|
|
1343
|
-
},
|
|
1344
|
-
status: "open"
|
|
1345
|
-
};
|
|
1346
|
-
}
|
|
1347
|
-
function createSuggestingUnsupportedTransaction(state, message) {
|
|
1348
|
-
return createTransaction(state, {
|
|
1349
|
-
historyBoundary: "skip",
|
|
1350
|
-
markDirty: false,
|
|
1351
|
-
effects: {
|
|
1352
|
-
commandBlocked: {
|
|
1353
|
-
code: "suggesting_unsupported",
|
|
1354
|
-
message
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
});
|
|
1358
|
-
}
|
|
1359
|
-
function isSingleParagraphSuggestingRange(document, from, to) {
|
|
1360
|
-
const ranges = [];
|
|
1361
|
-
let cursor = 0;
|
|
1362
|
-
let previousWasParagraph = false;
|
|
1363
|
-
for (const block of document.content.children) {
|
|
1364
|
-
if (block.type === "paragraph") {
|
|
1365
|
-
if (previousWasParagraph) {
|
|
1366
|
-
cursor += 1;
|
|
1367
|
-
}
|
|
1368
|
-
const start = cursor;
|
|
1369
|
-
cursor += block.children.reduce((size, child) => {
|
|
1370
|
-
if (child.type === "text") {
|
|
1371
|
-
return size + child.text.length;
|
|
1372
|
-
}
|
|
1373
|
-
if (child.type === "hyperlink") {
|
|
1374
|
-
return size + child.children.reduce((childSize, entry) => {
|
|
1375
|
-
if (entry.type === "text") {
|
|
1376
|
-
return childSize + entry.text.length;
|
|
1377
|
-
}
|
|
1378
|
-
return childSize + 1;
|
|
1379
|
-
}, 0);
|
|
1380
|
-
}
|
|
1381
|
-
return size + 1;
|
|
1382
|
-
}, 0);
|
|
1383
|
-
ranges.push({ start, end: cursor });
|
|
1384
|
-
previousWasParagraph = true;
|
|
1385
|
-
continue;
|
|
1386
|
-
}
|
|
1387
|
-
cursor += 1;
|
|
1388
|
-
previousWasParagraph = false;
|
|
1389
|
-
}
|
|
1390
|
-
return ranges.some((range) => from >= range.start && to <= range.end);
|
|
1391
|
-
}
|
|
1392
|
-
function applySuggestingInsert(state, text, context) {
|
|
1393
|
-
if (state.readOnly) {
|
|
1394
|
-
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
1395
|
-
}
|
|
1396
|
-
const authorId = context.defaultAuthorId ?? "unknown";
|
|
1397
|
-
const selection = state.selection;
|
|
1398
|
-
const from = Math.min(selection.anchor, selection.head);
|
|
1399
|
-
const to = Math.max(selection.anchor, selection.head);
|
|
1400
|
-
const isCollapsed = from === to;
|
|
1401
|
-
if (!isCollapsed && !isSingleParagraphSuggestingRange(state.document, from, to)) {
|
|
1402
|
-
return createSuggestingUnsupportedTransaction(
|
|
1403
|
-
state,
|
|
1404
|
-
"Suggesting mode does not yet support multi-paragraph replacement ranges."
|
|
1405
|
-
);
|
|
1406
|
-
}
|
|
1407
|
-
if (isCollapsed) {
|
|
1408
|
-
const result2 = insertText(state.document, selection, text, { timestamp: context.timestamp });
|
|
1409
|
-
const insertedFrom2 = from;
|
|
1410
|
-
const insertedTo2 = from + Array.from(text).length;
|
|
1411
|
-
const reviewState2 = remapReviewStateAfterContentChange(
|
|
1412
|
-
state,
|
|
1413
|
-
result2.document,
|
|
1414
|
-
result2.mapping
|
|
1415
|
-
);
|
|
1416
|
-
const adjacentInsertion = findAdjacentAuthoredInsertion(
|
|
1417
|
-
reviewState2.document.review.revisions,
|
|
1418
|
-
insertedFrom2
|
|
1419
|
-
);
|
|
1420
|
-
let finalRevisionId;
|
|
1421
|
-
let finalRevisions;
|
|
1422
|
-
if (adjacentInsertion && adjacentInsertion.anchor.kind === "range") {
|
|
1423
|
-
const extended = {
|
|
1424
|
-
...adjacentInsertion,
|
|
1425
|
-
anchor: {
|
|
1426
|
-
kind: "range",
|
|
1427
|
-
range: { from: adjacentInsertion.anchor.range.from, to: insertedTo2 },
|
|
1428
|
-
assoc: { start: 1, end: -1 }
|
|
1429
|
-
}
|
|
1430
|
-
};
|
|
1431
|
-
finalRevisionId = extended.changeId;
|
|
1432
|
-
finalRevisions = {
|
|
1433
|
-
...reviewState2.document.review.revisions,
|
|
1434
|
-
[extended.changeId]: extended
|
|
1435
|
-
};
|
|
1436
|
-
} else {
|
|
1437
|
-
const revision = createAuthoredRevision(
|
|
1438
|
-
reviewState2.document.review.revisions,
|
|
1439
|
-
"insertion",
|
|
1440
|
-
insertedFrom2,
|
|
1441
|
-
insertedTo2,
|
|
1442
|
-
authorId,
|
|
1443
|
-
context.timestamp
|
|
1444
|
-
);
|
|
1445
|
-
finalRevisionId = revision.changeId;
|
|
1446
|
-
finalRevisions = {
|
|
1447
|
-
...reviewState2.document.review.revisions,
|
|
1448
|
-
[revision.changeId]: revision
|
|
1449
|
-
};
|
|
1450
|
-
}
|
|
1451
|
-
const finalDocument2 = {
|
|
1452
|
-
...reviewState2.document,
|
|
1453
|
-
review: {
|
|
1454
|
-
...reviewState2.document.review,
|
|
1455
|
-
revisions: finalRevisions
|
|
1456
|
-
}
|
|
1457
|
-
};
|
|
1458
|
-
return createTransaction(
|
|
1459
|
-
{
|
|
1460
|
-
...state,
|
|
1461
|
-
document: finalDocument2,
|
|
1462
|
-
selection: result2.selection,
|
|
1463
|
-
warnings: reviewState2.warnings,
|
|
1464
|
-
runtime: {
|
|
1465
|
-
...state.runtime,
|
|
1466
|
-
activeCommentId: reviewState2.activeCommentId
|
|
1467
|
-
}
|
|
1468
|
-
},
|
|
1469
|
-
{
|
|
1470
|
-
historyBoundary: "push",
|
|
1471
|
-
markDirty: true,
|
|
1472
|
-
mapping: result2.mapping,
|
|
1473
|
-
effects: {
|
|
1474
|
-
...reviewState2.effects,
|
|
1475
|
-
revisionAuthored: { changeId: finalRevisionId, kind: "insertion" }
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
);
|
|
1479
|
-
}
|
|
1480
|
-
const insertSelection = createSelectionSnapshot(to, to);
|
|
1481
|
-
const result = insertText(state.document, insertSelection, text, { timestamp: context.timestamp });
|
|
1482
|
-
const insertedFrom = to;
|
|
1483
|
-
const insertedTo = to + Array.from(text).length;
|
|
1484
|
-
const reviewState = remapReviewStateAfterContentChange(
|
|
1485
|
-
state,
|
|
1486
|
-
result.document,
|
|
1487
|
-
result.mapping
|
|
1488
|
-
);
|
|
1489
|
-
const deletionRevision = createAuthoredRevision(
|
|
1490
|
-
reviewState.document.review.revisions,
|
|
1491
|
-
"deletion",
|
|
1492
|
-
from,
|
|
1493
|
-
to,
|
|
1494
|
-
authorId,
|
|
1495
|
-
context.timestamp
|
|
1496
|
-
);
|
|
1497
|
-
const insertionRevision = createAuthoredRevision(
|
|
1498
|
-
{
|
|
1499
|
-
...reviewState.document.review.revisions,
|
|
1500
|
-
[deletionRevision.changeId]: deletionRevision
|
|
1501
|
-
},
|
|
1502
|
-
"insertion",
|
|
1503
|
-
insertedFrom,
|
|
1504
|
-
insertedTo,
|
|
1505
|
-
authorId,
|
|
1506
|
-
context.timestamp
|
|
1507
|
-
);
|
|
1508
|
-
const finalDocument = {
|
|
1509
|
-
...reviewState.document,
|
|
1510
|
-
review: {
|
|
1511
|
-
...reviewState.document.review,
|
|
1512
|
-
revisions: {
|
|
1513
|
-
...reviewState.document.review.revisions,
|
|
1514
|
-
[deletionRevision.changeId]: deletionRevision,
|
|
1515
|
-
[insertionRevision.changeId]: insertionRevision
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
};
|
|
1519
|
-
const caretPos = insertedTo;
|
|
1520
|
-
return createTransaction(
|
|
1521
|
-
{
|
|
1522
|
-
...state,
|
|
1523
|
-
document: finalDocument,
|
|
1524
|
-
selection: createSelectionSnapshot(caretPos, caretPos),
|
|
1525
|
-
warnings: reviewState.warnings,
|
|
1526
|
-
runtime: {
|
|
1527
|
-
...state.runtime,
|
|
1528
|
-
activeCommentId: reviewState.activeCommentId
|
|
1529
|
-
}
|
|
1530
|
-
},
|
|
1531
|
-
{
|
|
1532
|
-
historyBoundary: "push",
|
|
1533
|
-
markDirty: true,
|
|
1534
|
-
mapping: result.mapping,
|
|
1535
|
-
effects: {
|
|
1536
|
-
...reviewState.effects,
|
|
1537
|
-
revisionAuthored: { changeId: insertionRevision.changeId, kind: "insertion" }
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
);
|
|
1541
|
-
}
|
|
1542
|
-
function applySuggestingDelete(state, direction, context) {
|
|
1543
|
-
if (state.readOnly) {
|
|
1544
|
-
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
1545
|
-
}
|
|
1546
|
-
const authorId = context.defaultAuthorId ?? "unknown";
|
|
1547
|
-
const selection = state.selection;
|
|
1548
|
-
const from = Math.min(selection.anchor, selection.head);
|
|
1549
|
-
const to = Math.max(selection.anchor, selection.head);
|
|
1550
|
-
const isCollapsed = from === to;
|
|
1551
|
-
if (!isCollapsed && !isSingleParagraphSuggestingRange(state.document, from, to)) {
|
|
1552
|
-
return createSuggestingUnsupportedTransaction(
|
|
1553
|
-
state,
|
|
1554
|
-
"Suggesting mode does not yet support multi-paragraph deletion ranges."
|
|
1555
|
-
);
|
|
1556
|
-
}
|
|
1557
|
-
let deleteFrom;
|
|
1558
|
-
let deleteTo;
|
|
1559
|
-
if (isCollapsed) {
|
|
1560
|
-
if (direction === "backward") {
|
|
1561
|
-
deleteFrom = Math.max(0, from - 1);
|
|
1562
|
-
deleteTo = from;
|
|
1563
|
-
} else {
|
|
1564
|
-
deleteFrom = from;
|
|
1565
|
-
deleteTo = from + 1;
|
|
1566
|
-
}
|
|
1567
|
-
} else {
|
|
1568
|
-
deleteFrom = from;
|
|
1569
|
-
deleteTo = to;
|
|
1570
|
-
}
|
|
1571
|
-
if (deleteFrom === deleteTo) {
|
|
1572
|
-
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
1573
|
-
}
|
|
1574
|
-
const existingDeletion = findOverlappingAuthoredDeletion(
|
|
1575
|
-
state.document.review.revisions,
|
|
1576
|
-
deleteFrom,
|
|
1577
|
-
deleteTo
|
|
1578
|
-
);
|
|
1579
|
-
if (existingDeletion) {
|
|
1580
|
-
const extendedFrom = Math.min(
|
|
1581
|
-
existingDeletion.anchor.kind === "range" ? existingDeletion.anchor.range.from : deleteFrom,
|
|
1582
|
-
deleteFrom
|
|
1583
|
-
);
|
|
1584
|
-
const extendedTo = Math.max(
|
|
1585
|
-
existingDeletion.anchor.kind === "range" ? existingDeletion.anchor.range.to : deleteTo,
|
|
1586
|
-
deleteTo
|
|
1587
|
-
);
|
|
1588
|
-
const updatedRevision = {
|
|
1589
|
-
...existingDeletion,
|
|
1590
|
-
anchor: {
|
|
1591
|
-
kind: "range",
|
|
1592
|
-
range: { from: extendedFrom, to: extendedTo },
|
|
1593
|
-
assoc: { start: 1, end: -1 }
|
|
1594
|
-
}
|
|
1595
|
-
};
|
|
1596
|
-
const nextDocument2 = {
|
|
1597
|
-
...state.document,
|
|
1598
|
-
updatedAt: context.timestamp,
|
|
1599
|
-
review: {
|
|
1600
|
-
...state.document.review,
|
|
1601
|
-
revisions: {
|
|
1602
|
-
...state.document.review.revisions,
|
|
1603
|
-
[updatedRevision.changeId]: updatedRevision
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
};
|
|
1607
|
-
const caretPos2 = direction === "backward" ? deleteFrom : deleteTo;
|
|
1608
|
-
return createTransaction(
|
|
1609
|
-
{
|
|
1610
|
-
...state,
|
|
1611
|
-
document: nextDocument2,
|
|
1612
|
-
selection: createSelectionSnapshot(caretPos2, caretPos2)
|
|
1613
|
-
},
|
|
1614
|
-
{
|
|
1615
|
-
historyBoundary: "push",
|
|
1616
|
-
markDirty: true,
|
|
1617
|
-
effects: {
|
|
1618
|
-
revisionAuthored: { changeId: updatedRevision.changeId, kind: "deletion" }
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
);
|
|
1622
|
-
}
|
|
1623
|
-
const revision = createAuthoredRevision(
|
|
1624
|
-
state.document.review.revisions,
|
|
1625
|
-
"deletion",
|
|
1626
|
-
deleteFrom,
|
|
1627
|
-
deleteTo,
|
|
1628
|
-
authorId,
|
|
1629
|
-
context.timestamp
|
|
1630
|
-
);
|
|
1631
|
-
const nextDocument = {
|
|
1632
|
-
...state.document,
|
|
1633
|
-
updatedAt: context.timestamp,
|
|
1634
|
-
review: {
|
|
1635
|
-
...state.document.review,
|
|
1636
|
-
revisions: {
|
|
1637
|
-
...state.document.review.revisions,
|
|
1638
|
-
[revision.changeId]: revision
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
};
|
|
1642
|
-
const caretPos = direction === "backward" ? deleteFrom : deleteTo;
|
|
1643
|
-
return createTransaction(
|
|
1644
|
-
{
|
|
1645
|
-
...state,
|
|
1646
|
-
document: nextDocument,
|
|
1647
|
-
selection: createSelectionSnapshot(caretPos, caretPos)
|
|
1648
|
-
},
|
|
1649
|
-
{
|
|
1650
|
-
historyBoundary: "push",
|
|
1651
|
-
markDirty: true,
|
|
1652
|
-
effects: {
|
|
1653
|
-
revisionAuthored: { changeId: revision.changeId, kind: "deletion" }
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
);
|
|
1657
|
-
}
|
|
1658
|
-
function applySuggestingInsertUnit(state, unitType, context) {
|
|
1659
|
-
if (state.readOnly) {
|
|
1660
|
-
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
1661
|
-
}
|
|
1662
|
-
const authorId = context.defaultAuthorId ?? "unknown";
|
|
1663
|
-
const selection = state.selection;
|
|
1664
|
-
const from = Math.min(selection.anchor, selection.head);
|
|
1665
|
-
const to = Math.max(selection.anchor, selection.head);
|
|
1666
|
-
if (from !== to && !isSingleParagraphSuggestingRange(state.document, from, to)) {
|
|
1667
|
-
return createSuggestingUnsupportedTransaction(
|
|
1668
|
-
state,
|
|
1669
|
-
"Suggesting mode does not yet support multi-paragraph replacement ranges."
|
|
1670
|
-
);
|
|
1671
|
-
}
|
|
1672
|
-
const insertPos = to;
|
|
1673
|
-
const insertSelection = createSelectionSnapshot(insertPos, insertPos);
|
|
1674
|
-
const applyFn = unitType === "tab" ? insertTab : insertHardBreak;
|
|
1675
|
-
const result = applyFn(state.document, insertSelection, { timestamp: context.timestamp });
|
|
1676
|
-
const reviewState = remapReviewStateAfterContentChange(
|
|
1677
|
-
state,
|
|
1678
|
-
result.document,
|
|
1679
|
-
result.mapping
|
|
1680
|
-
);
|
|
1681
|
-
const deletionRevision = from !== to ? createAuthoredRevision(
|
|
1682
|
-
reviewState.document.review.revisions,
|
|
1683
|
-
"deletion",
|
|
1684
|
-
from,
|
|
1685
|
-
to,
|
|
1686
|
-
authorId,
|
|
1687
|
-
context.timestamp
|
|
1688
|
-
) : void 0;
|
|
1689
|
-
const insertionRevision = createAuthoredRevision(
|
|
1690
|
-
{
|
|
1691
|
-
...reviewState.document.review.revisions,
|
|
1692
|
-
...deletionRevision ? { [deletionRevision.changeId]: deletionRevision } : {}
|
|
1693
|
-
},
|
|
1694
|
-
"insertion",
|
|
1695
|
-
insertPos,
|
|
1696
|
-
insertPos + 1,
|
|
1697
|
-
authorId,
|
|
1698
|
-
context.timestamp
|
|
1699
|
-
);
|
|
1700
|
-
const finalDocument = {
|
|
1701
|
-
...reviewState.document,
|
|
1702
|
-
review: {
|
|
1703
|
-
...reviewState.document.review,
|
|
1704
|
-
revisions: {
|
|
1705
|
-
...reviewState.document.review.revisions,
|
|
1706
|
-
...deletionRevision ? { [deletionRevision.changeId]: deletionRevision } : {},
|
|
1707
|
-
[insertionRevision.changeId]: insertionRevision
|
|
1708
|
-
}
|
|
1709
|
-
}
|
|
1710
|
-
};
|
|
1711
|
-
return createTransaction(
|
|
1712
|
-
{
|
|
1713
|
-
...state,
|
|
1714
|
-
document: finalDocument,
|
|
1715
|
-
selection: result.selection,
|
|
1716
|
-
warnings: reviewState.warnings,
|
|
1717
|
-
runtime: {
|
|
1718
|
-
...state.runtime,
|
|
1719
|
-
activeCommentId: reviewState.activeCommentId
|
|
1720
|
-
}
|
|
1721
|
-
},
|
|
1722
|
-
{
|
|
1723
|
-
historyBoundary: "push",
|
|
1724
|
-
markDirty: true,
|
|
1725
|
-
mapping: result.mapping,
|
|
1726
|
-
effects: {
|
|
1727
|
-
...reviewState.effects,
|
|
1728
|
-
revisionAuthored: { changeId: insertionRevision.changeId, kind: "insertion" }
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
);
|
|
1732
|
-
}
|
|
1733
|
-
function findOverlappingAuthoredDeletion(revisions, from, to) {
|
|
1734
|
-
for (const revision of Object.values(revisions)) {
|
|
1735
|
-
if (revision.kind === "deletion" && revision.status === "open" && revision.metadata?.source === "runtime" && revision.anchor.kind === "range") {
|
|
1736
|
-
const revFrom = revision.anchor.range.from;
|
|
1737
|
-
const revTo = revision.anchor.range.to;
|
|
1738
|
-
if (from >= revFrom && from <= revTo || to >= revFrom && to <= revTo || from === revTo || to === revFrom) {
|
|
1739
|
-
return revision;
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
return void 0;
|
|
1744
|
-
}
|
|
1745
|
-
function findAdjacentAuthoredInsertion(revisions, cursorAt) {
|
|
1746
|
-
for (const revision of Object.values(revisions)) {
|
|
1747
|
-
if (revision.kind === "insertion" && revision.status === "open" && revision.metadata?.source === "runtime" && revision.anchor.kind === "range" && revision.anchor.range.to === cursorAt) {
|
|
1748
|
-
return revision;
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
return void 0;
|
|
1752
|
-
}
|
|
1753
|
-
|
|
1754
|
-
// src/validation/compatibility-report.ts
|
|
1755
|
-
var COMPATIBILITY_REPORT_VERSION = "compatibility-report/1";
|
|
1756
|
-
function createCompatibilityReport(input) {
|
|
1757
|
-
const diagnostics = createDiagnostics(input);
|
|
1758
|
-
return Object.freeze({
|
|
1759
|
-
reportVersion: COMPATIBILITY_REPORT_VERSION,
|
|
1760
|
-
generatedAt: input.generatedAt,
|
|
1761
|
-
blockExport: diagnosticsBlockExport(diagnostics, input.blockExport),
|
|
1762
|
-
featureEntries: diagnostics.featureEntries,
|
|
1763
|
-
warnings: diagnostics.warnings,
|
|
1764
|
-
errors: diagnostics.errors
|
|
1765
|
-
});
|
|
1766
|
-
}
|
|
1767
|
-
function mergeCompatibilityReports(reports, options) {
|
|
1768
|
-
return createCompatibilityReport({
|
|
1769
|
-
generatedAt: options.generatedAt,
|
|
1770
|
-
blockExport: options.blockExport ?? reports.some((report) => report.blockExport),
|
|
1771
|
-
featureEntries: flattenUnique(reports.flatMap((report) => report.featureEntries)),
|
|
1772
|
-
warnings: flattenUnique(reports.flatMap((report) => report.warnings)),
|
|
1773
|
-
errors: flattenUnique(reports.flatMap((report) => report.errors))
|
|
1774
|
-
});
|
|
1775
|
-
}
|
|
1776
|
-
function flattenUnique(items) {
|
|
1777
|
-
const deduped = /* @__PURE__ */ new Map();
|
|
1778
|
-
for (const item of items) {
|
|
1779
|
-
deduped.set(JSON.stringify(item), item);
|
|
1780
|
-
}
|
|
1781
|
-
return Object.freeze([...deduped.values()]);
|
|
1782
|
-
}
|
|
1783
|
-
|
|
1784
|
-
// src/runtime/workflow-markup.ts
|
|
1785
|
-
var BLOCKED_IMPORT_FEATURE_KEYS = /* @__PURE__ */ new Set(["alt-chunk", "alternate-content", "custom-xml"]);
|
|
1786
|
-
function collectWorkflowMarkupSnapshot(input) {
|
|
1787
|
-
const highlights = [];
|
|
1788
|
-
const fields = [];
|
|
1789
|
-
const opaqueFragments = [];
|
|
1790
|
-
const surface = input.renderSnapshot.surface;
|
|
1791
|
-
if (surface) {
|
|
1792
|
-
collectSurfaceMarkup(
|
|
1793
|
-
surface.blocks,
|
|
1794
|
-
MAIN_STORY_TARGET,
|
|
1795
|
-
input.preservation,
|
|
1796
|
-
highlights,
|
|
1797
|
-
opaqueFragments
|
|
1798
|
-
);
|
|
1799
|
-
for (const story of surface.secondaryStories) {
|
|
1800
|
-
collectSurfaceMarkup(
|
|
1801
|
-
story.blocks,
|
|
1802
|
-
story.target,
|
|
1803
|
-
input.preservation,
|
|
1804
|
-
highlights,
|
|
1805
|
-
opaqueFragments
|
|
1806
|
-
);
|
|
1807
|
-
}
|
|
1808
|
-
fields.push(...collectFieldMarkup(surface, input.fieldSnapshot));
|
|
1809
|
-
}
|
|
1810
|
-
opaqueFragments.push(...collectOpaqueFragmentMarkup(input.preservation, opaqueFragments));
|
|
1811
|
-
const comments = input.renderSnapshot.comments.threads.map((thread) => ({
|
|
1812
|
-
markupId: `comment:${thread.commentId}`,
|
|
1813
|
-
kind: "comment",
|
|
1814
|
-
commentId: thread.commentId,
|
|
1815
|
-
anchor: thread.anchor,
|
|
1816
|
-
label: thread.anchorLabel,
|
|
1817
|
-
excerpt: thread.excerpt,
|
|
1818
|
-
status: thread.status,
|
|
1819
|
-
warningCount: thread.warningCount,
|
|
1820
|
-
entryCount: thread.entryCount,
|
|
1821
|
-
createdAt: thread.createdAt,
|
|
1822
|
-
createdBy: thread.createdBy
|
|
1823
|
-
}));
|
|
1824
|
-
const revisions = input.renderSnapshot.trackedChanges.revisions.map(
|
|
1825
|
-
(revision) => ({
|
|
1826
|
-
markupId: `revision:${revision.revisionId}`,
|
|
1827
|
-
kind: "revision",
|
|
1828
|
-
revisionId: revision.revisionId,
|
|
1829
|
-
revisionKind: revision.kind,
|
|
1830
|
-
anchor: revision.anchor,
|
|
1831
|
-
label: revision.label,
|
|
1832
|
-
excerpt: revision.excerpt,
|
|
1833
|
-
status: revision.status,
|
|
1834
|
-
actionability: revision.actionability,
|
|
1835
|
-
authorId: revision.authorId,
|
|
1836
|
-
createdAt: revision.createdAt,
|
|
1837
|
-
preserveOnlyReason: revision.preserveOnlyReason
|
|
1838
|
-
})
|
|
1839
|
-
);
|
|
1840
|
-
const protectedRanges = input.protectionSnapshot.ranges.filter(
|
|
1841
|
-
(range) => typeof range.start === "number" && typeof range.end === "number"
|
|
1842
|
-
).map(
|
|
1843
|
-
(range) => ({
|
|
1844
|
-
markupId: `protected-range:${range.rangeId}`,
|
|
1845
|
-
kind: "protected_range",
|
|
1846
|
-
rangeId: range.rangeId,
|
|
1847
|
-
anchor: createRangeAnchor2(range.start, range.end),
|
|
1848
|
-
storyTarget: MAIN_STORY_TARGET,
|
|
1849
|
-
label: `Protected range ${range.rangeId}`,
|
|
1850
|
-
excerpt: range.enforcementReason,
|
|
1851
|
-
enforced: range.enforced,
|
|
1852
|
-
enforcementReason: range.enforcementReason,
|
|
1853
|
-
editorGroup: range.editorGroup,
|
|
1854
|
-
editor: range.editor
|
|
1855
|
-
})
|
|
1856
|
-
);
|
|
1857
|
-
const items = [
|
|
1858
|
-
...highlights,
|
|
1859
|
-
...comments,
|
|
1860
|
-
...revisions,
|
|
1861
|
-
...fields,
|
|
1862
|
-
...protectedRanges,
|
|
1863
|
-
...opaqueFragments
|
|
1864
|
-
];
|
|
1865
|
-
return {
|
|
1866
|
-
totalCount: items.length,
|
|
1867
|
-
items,
|
|
1868
|
-
highlights,
|
|
1869
|
-
comments,
|
|
1870
|
-
revisions,
|
|
1871
|
-
fields,
|
|
1872
|
-
protectedRanges,
|
|
1873
|
-
opaqueFragments
|
|
1874
|
-
};
|
|
1875
|
-
}
|
|
1876
|
-
function deriveWorkflowCandidateRangesFromMarkup(snapshot, options = {}) {
|
|
1877
|
-
const allowedKinds = options.kinds ? new Set(options.kinds) : null;
|
|
1878
|
-
const includeDetached = options.includeDetached === true;
|
|
1879
|
-
return snapshot.items.filter((item) => allowedKinds ? allowedKinds.has(item.kind) : true).filter((item) => includeDetached || item.anchor.kind !== "detached").map(
|
|
1880
|
-
(item) => ({
|
|
1881
|
-
candidateId: item.markupId,
|
|
1882
|
-
storyTarget: item.storyTarget,
|
|
1883
|
-
anchor: item.anchor,
|
|
1884
|
-
label: item.label,
|
|
1885
|
-
source: options.source ?? "host"
|
|
1886
|
-
})
|
|
1887
|
-
);
|
|
1888
|
-
}
|
|
1889
|
-
function collectSurfaceMarkup(blocks, storyTarget, preservation, highlights, opaqueFragments) {
|
|
1890
|
-
for (const block of blocks) {
|
|
1891
|
-
if (block.kind === "paragraph") {
|
|
1892
|
-
for (const segment of block.segments) {
|
|
1893
|
-
collectSegmentMarkup(segment, storyTarget, preservation, highlights, opaqueFragments);
|
|
1894
|
-
}
|
|
1895
|
-
continue;
|
|
1896
|
-
}
|
|
1897
|
-
if (block.kind === "table") {
|
|
1898
|
-
for (const row of block.rows) {
|
|
1899
|
-
for (const cell of row.cells) {
|
|
1900
|
-
collectSurfaceMarkup(cell.content, storyTarget, preservation, highlights, opaqueFragments);
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
1903
|
-
continue;
|
|
1904
|
-
}
|
|
1905
|
-
if (block.kind === "sdt_block") {
|
|
1906
|
-
collectSurfaceMarkup(block.children, storyTarget, preservation, highlights, opaqueFragments);
|
|
1907
|
-
continue;
|
|
1908
|
-
}
|
|
1909
|
-
const fragment = preservation.opaqueFragments[block.fragmentId];
|
|
1910
|
-
const descriptor = fragment ? describeOpaqueFragment(fragment) : null;
|
|
1911
|
-
const blockedReasonCode = fragment && BLOCKED_IMPORT_FEATURE_KEYS.has(descriptor?.featureKey ?? "") ? "workflow_blocked_import" : "workflow_preserve_only";
|
|
1912
|
-
opaqueFragments.push({
|
|
1913
|
-
markupId: `opaque:${block.fragmentId}`,
|
|
1914
|
-
kind: "opaque_fragment",
|
|
1915
|
-
fragmentId: block.fragmentId,
|
|
1916
|
-
warningId: block.warningId,
|
|
1917
|
-
anchor: createRangeAnchor2(block.from, block.to),
|
|
1918
|
-
storyTarget,
|
|
1919
|
-
label: block.label,
|
|
1920
|
-
excerpt: block.detail,
|
|
1921
|
-
detail: block.detail,
|
|
1922
|
-
blockedReasonCode
|
|
1923
|
-
});
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
function collectSegmentMarkup(segment, storyTarget, preservation, highlights, opaqueFragments) {
|
|
1927
|
-
if (segment.kind === "text" && segment.markAttrs?.backgroundColor) {
|
|
1928
|
-
highlights.push({
|
|
1929
|
-
markupId: `highlight:${storyTargetKey2(storyTarget)}:${segment.from}:${segment.to}:${segment.markAttrs.backgroundColor}`,
|
|
1930
|
-
kind: "highlight",
|
|
1931
|
-
anchor: createRangeAnchor2(segment.from, segment.to),
|
|
1932
|
-
storyTarget,
|
|
1933
|
-
label: `Highlight ${segment.markAttrs.backgroundColor}`,
|
|
1934
|
-
excerpt: segment.text,
|
|
1935
|
-
color: segment.markAttrs.backgroundColor,
|
|
1936
|
-
text: segment.text
|
|
1937
|
-
});
|
|
1938
|
-
return;
|
|
1939
|
-
}
|
|
1940
|
-
if (segment.kind === "opaque_inline") {
|
|
1941
|
-
const fragment = preservation.opaqueFragments[segment.fragmentId];
|
|
1942
|
-
const descriptor = fragment ? describeOpaqueFragment(fragment) : null;
|
|
1943
|
-
const blockedReasonCode = fragment && BLOCKED_IMPORT_FEATURE_KEYS.has(descriptor?.featureKey ?? "") ? "workflow_blocked_import" : "workflow_preserve_only";
|
|
1944
|
-
opaqueFragments.push({
|
|
1945
|
-
markupId: `opaque:${segment.fragmentId}`,
|
|
1946
|
-
kind: "opaque_fragment",
|
|
1947
|
-
fragmentId: segment.fragmentId,
|
|
1948
|
-
warningId: segment.warningId,
|
|
1949
|
-
anchor: createRangeAnchor2(segment.from, segment.to),
|
|
1950
|
-
storyTarget,
|
|
1951
|
-
label: segment.label,
|
|
1952
|
-
excerpt: segment.detail,
|
|
1953
|
-
detail: segment.detail,
|
|
1954
|
-
blockedReasonCode
|
|
1955
|
-
});
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
function collectFieldMarkup(surface, fieldSnapshot) {
|
|
1959
|
-
if (!surface) {
|
|
1960
|
-
return [];
|
|
1961
|
-
}
|
|
1962
|
-
const stories = [
|
|
1963
|
-
{ blocks: surface.blocks, storyTarget: MAIN_STORY_TARGET },
|
|
1964
|
-
...surface.secondaryStories.map((story) => ({
|
|
1965
|
-
blocks: story.blocks,
|
|
1966
|
-
storyTarget: story.target
|
|
1967
|
-
}))
|
|
1968
|
-
];
|
|
1969
|
-
return fieldSnapshot.fields.flatMap((field) => {
|
|
1970
|
-
const displayText = field.displayText.trim();
|
|
1971
|
-
if (!displayText) {
|
|
1972
|
-
return [];
|
|
1973
|
-
}
|
|
1974
|
-
for (const story of stories) {
|
|
1975
|
-
const matches = searchSurfaceBlocks(story.blocks, displayText, { limit: 2 });
|
|
1976
|
-
if (matches.length === 1) {
|
|
1977
|
-
const match = matches[0];
|
|
1978
|
-
return [
|
|
1979
|
-
{
|
|
1980
|
-
markupId: `field:${field.index}`,
|
|
1981
|
-
kind: "field",
|
|
1982
|
-
anchor: createRangeAnchor2(match.from, match.to),
|
|
1983
|
-
storyTarget: story.storyTarget,
|
|
1984
|
-
label: displayText,
|
|
1985
|
-
excerpt: field.instruction,
|
|
1986
|
-
fieldIndex: field.index,
|
|
1987
|
-
fieldFamily: field.fieldFamily,
|
|
1988
|
-
fieldTarget: field.fieldTarget,
|
|
1989
|
-
refreshStatus: field.refreshStatus,
|
|
1990
|
-
displayText: field.displayText
|
|
1991
|
-
}
|
|
1992
|
-
];
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
return [];
|
|
1996
|
-
});
|
|
1997
|
-
}
|
|
1998
|
-
function collectOpaqueFragmentMarkup(preservation, existing) {
|
|
1999
|
-
const seen = new Set(existing.map((item) => item.fragmentId));
|
|
2000
|
-
return Object.values(preservation.opaqueFragments).filter(
|
|
2001
|
-
(fragment) => !seen.has(fragment.fragmentId) && fragment.packagePartName === "/word/document.xml"
|
|
2002
|
-
).map((fragment) => {
|
|
2003
|
-
const descriptor = describeOpaqueFragment(fragment);
|
|
2004
|
-
const blockedReasonCode = BLOCKED_IMPORT_FEATURE_KEYS.has(descriptor.featureKey) ? "workflow_blocked_import" : "workflow_preserve_only";
|
|
2005
|
-
return {
|
|
2006
|
-
markupId: `opaque:${fragment.fragmentId}`,
|
|
2007
|
-
kind: "opaque_fragment",
|
|
2008
|
-
fragmentId: fragment.fragmentId,
|
|
2009
|
-
warningId: fragment.warningId,
|
|
2010
|
-
anchor: createRangeAnchor2(fragment.lastKnownRange.from, fragment.lastKnownRange.to),
|
|
2011
|
-
storyTarget: MAIN_STORY_TARGET,
|
|
2012
|
-
label: descriptor.label,
|
|
2013
|
-
excerpt: descriptor.detail,
|
|
2014
|
-
detail: descriptor.detail,
|
|
2015
|
-
blockedReasonCode
|
|
2016
|
-
};
|
|
2017
|
-
});
|
|
2018
|
-
}
|
|
2019
|
-
function createRangeAnchor2(from, to) {
|
|
2020
|
-
return {
|
|
2021
|
-
kind: "range",
|
|
2022
|
-
from,
|
|
2023
|
-
to,
|
|
2024
|
-
assoc: {
|
|
2025
|
-
start: -1,
|
|
2026
|
-
end: 1
|
|
2027
|
-
}
|
|
2028
|
-
};
|
|
2029
|
-
}
|
|
2030
|
-
function storyTargetKey2(storyTarget) {
|
|
2031
|
-
switch (storyTarget.kind) {
|
|
2032
|
-
case "main":
|
|
2033
|
-
return "main";
|
|
2034
|
-
case "header":
|
|
2035
|
-
case "footer":
|
|
2036
|
-
return `${storyTarget.kind}:${storyTarget.relationshipId}:${storyTarget.variant}:${storyTarget.sectionIndex ?? "none"}`;
|
|
2037
|
-
case "footnote":
|
|
2038
|
-
case "endnote":
|
|
2039
|
-
return `${storyTarget.kind}:${storyTarget.noteId}`;
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
|
|
2043
|
-
// src/runtime/document-runtime.ts
|
|
2044
|
-
function createDocumentRuntime(options) {
|
|
2045
|
-
const clock = options.clock ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
2046
|
-
const editorBuild = options.editorBuild ?? "dev";
|
|
2047
|
-
let defaultAuthorId = options.defaultAuthorId;
|
|
2048
|
-
const sessionId = createSessionId(options.documentId, clock());
|
|
2049
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
2050
|
-
const eventListeners = /* @__PURE__ */ new Set();
|
|
2051
|
-
const history = {
|
|
2052
|
-
past: [],
|
|
2053
|
-
future: []
|
|
2054
|
-
};
|
|
2055
|
-
let activeStory = MAIN_STORY_TARGET;
|
|
2056
|
-
const storySelections = /* @__PURE__ */ new Map();
|
|
2057
|
-
let viewState = createViewState(options.initialViewState);
|
|
2058
|
-
let protectionSnapshot = options.protectionSnapshot ?? options.initialSessionState?.protectionSnapshot ?? options.initialSnapshot?.protectionSnapshot ?? {
|
|
2059
|
-
hasDocumentProtection: false,
|
|
2060
|
-
enforcementActive: false,
|
|
2061
|
-
ranges: [],
|
|
2062
|
-
enforcedRangeCount: 0,
|
|
2063
|
-
preservedRangeCount: 0
|
|
2064
|
-
};
|
|
2065
|
-
let workflowOverlay = null;
|
|
2066
|
-
let hostAnnotationOverlay = null;
|
|
2067
|
-
const initialPersistedSnapshot = options.initialSessionState ? persistedSnapshotFromEditorSessionState(options.initialSessionState, {
|
|
2068
|
-
savedAt: options.initialSessionState.updatedAt
|
|
2069
|
-
}) : options.initialSnapshot;
|
|
2070
|
-
let state = createEditorState({
|
|
2071
|
-
documentId: options.documentId,
|
|
2072
|
-
sessionId,
|
|
2073
|
-
sourceLabel: options.sourceLabel,
|
|
2074
|
-
readOnly: options.readOnly,
|
|
2075
|
-
persistedSnapshot: initialPersistedSnapshot,
|
|
2076
|
-
canonicalDocument: options.initialCanonicalDocument,
|
|
2077
|
-
fatalError: options.fatalError
|
|
2078
|
-
});
|
|
2079
|
-
storySelections.set(storyTargetKey(MAIN_STORY_TARGET), state.selection);
|
|
2080
|
-
let cachedSurface;
|
|
2081
|
-
let cachedCompatibility;
|
|
2082
|
-
let cachedComments;
|
|
2083
|
-
let cachedTrackedChanges;
|
|
2084
|
-
let cachedPageLayout;
|
|
2085
|
-
let cachedNavigation;
|
|
2086
|
-
let cachedViewStateSnapshot;
|
|
2087
|
-
let cachedInteractionGuardSnapshot;
|
|
2088
|
-
let cachedWorkflowScopeSnapshot;
|
|
2089
|
-
let cachedWorkflowMarkupSnapshot;
|
|
2090
|
-
function getCachedSurface(document, nextActiveStory) {
|
|
2091
|
-
const activeStoryKey = storyTargetKey(nextActiveStory);
|
|
2092
|
-
if (cachedSurface && cachedSurface.revisionToken === state.revisionToken && cachedSurface.activeStoryKey === activeStoryKey) {
|
|
2093
|
-
return cachedSurface.snapshot;
|
|
2094
|
-
}
|
|
2095
|
-
const snapshot = createEditorSurfaceSnapshot(document, state.selection, nextActiveStory);
|
|
2096
|
-
recordPerfSample("snapshot.surface");
|
|
2097
|
-
incrementInvalidationCounter("runtime.snapshot.surfaceMisses");
|
|
2098
|
-
cachedSurface = {
|
|
2099
|
-
revisionToken: state.revisionToken,
|
|
2100
|
-
activeStoryKey,
|
|
2101
|
-
snapshot
|
|
2102
|
-
};
|
|
2103
|
-
return snapshot;
|
|
2104
|
-
}
|
|
2105
|
-
function getCachedCompatibilityReport(nextState) {
|
|
2106
|
-
if (cachedCompatibility && cachedCompatibility.revisionToken === nextState.revisionToken && cachedCompatibility.warnings === nextState.warnings && cachedCompatibility.fatalError === nextState.fatalError) {
|
|
2107
|
-
return cachedCompatibility.report;
|
|
2108
|
-
}
|
|
2109
|
-
const derived = createDerivedCompatibility(nextState);
|
|
2110
|
-
recordPerfSample("snapshot.compatibility");
|
|
2111
|
-
incrementInvalidationCounter("runtime.snapshot.compatibilityMisses");
|
|
2112
|
-
const report = {
|
|
2113
|
-
blockExport: derived.blockExport,
|
|
2114
|
-
blockExportReasons: listBlockExportReasons(derived),
|
|
2115
|
-
warningCount: derived.warnings.length,
|
|
2116
|
-
errorCount: derived.errors.length,
|
|
2117
|
-
featureEntries: derived.featureEntries.map(
|
|
2118
|
-
(entry) => toPublicCompatibilityFeatureEntry(entry)
|
|
2119
|
-
)
|
|
2120
|
-
};
|
|
2121
|
-
cachedCompatibility = {
|
|
2122
|
-
revisionToken: nextState.revisionToken,
|
|
2123
|
-
warnings: nextState.warnings,
|
|
2124
|
-
fatalError: nextState.fatalError,
|
|
2125
|
-
report
|
|
2126
|
-
};
|
|
2127
|
-
return report;
|
|
2128
|
-
}
|
|
2129
|
-
function getCachedCommentSidebarSnapshot(nextState) {
|
|
2130
|
-
if (cachedComments && cachedComments.comments === nextState.document.review.comments && cachedComments.activeCommentId === nextState.runtime.activeCommentId) {
|
|
2131
|
-
return cachedComments.snapshot;
|
|
2132
|
-
}
|
|
2133
|
-
const snapshot = toPublicCommentSidebarSnapshot(nextState);
|
|
2134
|
-
cachedComments = {
|
|
2135
|
-
comments: nextState.document.review.comments,
|
|
2136
|
-
activeCommentId: nextState.runtime.activeCommentId,
|
|
2137
|
-
snapshot
|
|
2138
|
-
};
|
|
2139
|
-
return snapshot;
|
|
2140
|
-
}
|
|
2141
|
-
function getCachedTrackedChangesSnapshot(nextState, _surface) {
|
|
2142
|
-
if (cachedTrackedChanges && cachedTrackedChanges.revisions === nextState.document.review.revisions && cachedTrackedChanges.revisionToken === nextState.revisionToken) {
|
|
2143
|
-
return cachedTrackedChanges.snapshot;
|
|
2144
|
-
}
|
|
2145
|
-
const snapshot = toPublicTrackedChangesSnapshot(nextState);
|
|
2146
|
-
cachedTrackedChanges = {
|
|
2147
|
-
revisions: nextState.document.review.revisions,
|
|
2148
|
-
revisionToken: nextState.revisionToken,
|
|
2149
|
-
snapshot
|
|
2150
|
-
};
|
|
2151
|
-
return snapshot;
|
|
2152
|
-
}
|
|
2153
|
-
function getCachedDocumentNavigationSnapshot(nextState, nextActiveStory) {
|
|
2154
|
-
const activeStoryKey = storyTargetKey(nextActiveStory);
|
|
2155
|
-
if (cachedNavigation && cachedNavigation.revisionToken === nextState.revisionToken && cachedNavigation.activeStoryKey === activeStoryKey) {
|
|
2156
|
-
if (cachedNavigation.selectionHead === nextState.selection.head) {
|
|
2157
|
-
return cachedNavigation.snapshot;
|
|
2158
|
-
}
|
|
2159
|
-
const snapshot2 = createDocumentNavigationSnapshot(
|
|
2160
|
-
nextState.document,
|
|
2161
|
-
nextState.selection.head,
|
|
2162
|
-
nextActiveStory
|
|
2163
|
-
);
|
|
2164
|
-
if (snapshot2.activePageIndex === cachedNavigation.snapshot.activePageIndex && snapshot2.activeSectionIndex === cachedNavigation.snapshot.activeSectionIndex) {
|
|
2165
|
-
cachedNavigation = {
|
|
2166
|
-
revisionToken: nextState.revisionToken,
|
|
2167
|
-
activeStoryKey,
|
|
2168
|
-
selectionHead: nextState.selection.head,
|
|
2169
|
-
snapshot: cachedNavigation.snapshot
|
|
2170
|
-
};
|
|
2171
|
-
return cachedNavigation.snapshot;
|
|
2172
|
-
}
|
|
2173
|
-
cachedNavigation = {
|
|
2174
|
-
revisionToken: nextState.revisionToken,
|
|
2175
|
-
activeStoryKey,
|
|
2176
|
-
selectionHead: nextState.selection.head,
|
|
2177
|
-
snapshot: snapshot2
|
|
2178
|
-
};
|
|
2179
|
-
return snapshot2;
|
|
2180
|
-
}
|
|
2181
|
-
const snapshot = createDocumentNavigationSnapshot(
|
|
2182
|
-
nextState.document,
|
|
2183
|
-
nextState.selection.head,
|
|
2184
|
-
nextActiveStory
|
|
2185
|
-
);
|
|
2186
|
-
recordPerfSample("snapshot.navigation");
|
|
2187
|
-
incrementInvalidationCounter("runtime.snapshot.navigationMisses");
|
|
2188
|
-
cachedNavigation = {
|
|
2189
|
-
revisionToken: nextState.revisionToken,
|
|
2190
|
-
activeStoryKey,
|
|
2191
|
-
selectionHead: nextState.selection.head,
|
|
2192
|
-
snapshot
|
|
2193
|
-
};
|
|
2194
|
-
return snapshot;
|
|
2195
|
-
}
|
|
2196
|
-
function resolvePageLayoutActiveSectionIndex(nextState, nextActiveStory) {
|
|
2197
|
-
if (nextActiveStory.kind === "main") {
|
|
2198
|
-
return getCachedDocumentNavigationSnapshot(nextState, nextActiveStory).activeSectionIndex;
|
|
2199
|
-
}
|
|
2200
|
-
if ("sectionIndex" in nextActiveStory && typeof nextActiveStory.sectionIndex === "number") {
|
|
2201
|
-
return nextActiveStory.sectionIndex;
|
|
2202
|
-
}
|
|
2203
|
-
return storyTargetKey(nextActiveStory);
|
|
2204
|
-
}
|
|
2205
|
-
function getCachedPageLayoutSnapshot(nextState, nextActiveStory) {
|
|
2206
|
-
const activeStoryKey = storyTargetKey(nextActiveStory);
|
|
2207
|
-
const activeSectionIndex = resolvePageLayoutActiveSectionIndex(
|
|
2208
|
-
nextState,
|
|
2209
|
-
nextActiveStory
|
|
2210
|
-
);
|
|
2211
|
-
if (cachedPageLayout && cachedPageLayout.revisionToken === nextState.revisionToken && cachedPageLayout.activeStoryKey === activeStoryKey && cachedPageLayout.activeSectionIndex === activeSectionIndex) {
|
|
2212
|
-
return cachedPageLayout.snapshot;
|
|
2213
|
-
}
|
|
2214
|
-
const snapshot = derivePageLayoutSnapshot(nextState, nextActiveStory, storySelections);
|
|
2215
|
-
cachedPageLayout = {
|
|
2216
|
-
revisionToken: nextState.revisionToken,
|
|
2217
|
-
activeStoryKey,
|
|
2218
|
-
activeSectionIndex,
|
|
2219
|
-
snapshot
|
|
2220
|
-
};
|
|
2221
|
-
return snapshot;
|
|
2222
|
-
}
|
|
2223
|
-
function evaluateWorkflowBlockedReasons(selection, commandType) {
|
|
2224
|
-
const reasons = [];
|
|
2225
|
-
const selectionBounds = {
|
|
2226
|
-
from: Math.min(selection.anchor, selection.head),
|
|
2227
|
-
to: Math.max(selection.anchor, selection.head)
|
|
2228
|
-
};
|
|
2229
|
-
const selectionRange = expandSelectionRange(selectionBounds);
|
|
2230
|
-
const opaqueReason = deriveOpaqueWorkflowBlockedReason(selectionRange);
|
|
2231
|
-
if (opaqueReason) {
|
|
2232
|
-
reasons.push(opaqueReason);
|
|
2233
|
-
}
|
|
2234
|
-
if (state.readOnly) {
|
|
2235
|
-
reasons.push({
|
|
2236
|
-
code: "document_read_only",
|
|
2237
|
-
message: "Document is in read-only mode."
|
|
2238
|
-
});
|
|
2239
|
-
}
|
|
2240
|
-
if (viewState.documentMode === "viewing") {
|
|
2241
|
-
reasons.push({
|
|
2242
|
-
code: "document_viewing_mode",
|
|
2243
|
-
message: "Document is in viewing mode."
|
|
2244
|
-
});
|
|
2245
|
-
}
|
|
2246
|
-
if (isBlockedByProtection(protectionSnapshot, selection)) {
|
|
2247
|
-
reasons.push({
|
|
2248
|
-
code: "protected_range",
|
|
2249
|
-
message: "Selection falls within a protected range."
|
|
2250
|
-
});
|
|
2251
|
-
}
|
|
2252
|
-
const effectiveDocumentMode = getEffectiveDocumentMode(selection);
|
|
2253
|
-
if (effectiveDocumentMode === "suggesting" && commandType) {
|
|
2254
|
-
if (activeStory.kind !== "main" && SUGGESTING_SECONDARY_STORY_UNSUPPORTED_COMMANDS.has(commandType)) {
|
|
2255
|
-
reasons.push({
|
|
2256
|
-
code: "suggesting_unsupported",
|
|
2257
|
-
message: "Suggesting mode is not yet export-safe in this story."
|
|
2258
|
-
});
|
|
2259
|
-
}
|
|
2260
|
-
if (SUGGESTING_UNSUPPORTED_COMMANDS.has(commandType)) {
|
|
2261
|
-
reasons.push({
|
|
2262
|
-
code: "suggesting_unsupported",
|
|
2263
|
-
message: `"${commandType}" is not supported in suggesting mode.`
|
|
2264
|
-
});
|
|
2265
|
-
}
|
|
2266
|
-
}
|
|
2267
|
-
if (workflowOverlay) {
|
|
2268
|
-
const matchingScope = getMatchingWorkflowScope(selection);
|
|
2269
|
-
if (!matchingScope && workflowOverlay.scopes.length > 0) {
|
|
2270
|
-
reasons.push({
|
|
2271
|
-
code: "outside_workflow_scope",
|
|
2272
|
-
message: "Selection is outside any active workflow scope."
|
|
2273
|
-
});
|
|
2274
|
-
} else if (matchingScope) {
|
|
2275
|
-
if (matchingScope.mode === "comment") {
|
|
2276
|
-
const isCommentCommand = commandType?.startsWith("comment.") ?? false;
|
|
2277
|
-
if (!isCommentCommand) {
|
|
2278
|
-
reasons.push({
|
|
2279
|
-
code: "workflow_comment_only",
|
|
2280
|
-
message: `Scope "${matchingScope.label ?? matchingScope.scopeId}" allows comments only.`,
|
|
2281
|
-
scopeId: matchingScope.scopeId,
|
|
2282
|
-
workItemId: matchingScope.workItemId
|
|
2283
|
-
});
|
|
2284
|
-
}
|
|
2285
|
-
} else if (matchingScope.mode === "view") {
|
|
2286
|
-
reasons.push({
|
|
2287
|
-
code: "workflow_view_only",
|
|
2288
|
-
message: `Scope "${matchingScope.label ?? matchingScope.scopeId}" is view-only.`,
|
|
2289
|
-
scopeId: matchingScope.scopeId,
|
|
2290
|
-
workItemId: matchingScope.workItemId
|
|
2291
|
-
});
|
|
2292
|
-
}
|
|
2293
|
-
}
|
|
2294
|
-
}
|
|
2295
|
-
return reasons;
|
|
2296
|
-
}
|
|
2297
|
-
function getMatchingWorkflowScope(selection) {
|
|
2298
|
-
if (!workflowOverlay) {
|
|
2299
|
-
return null;
|
|
2300
|
-
}
|
|
2301
|
-
const selectionBounds = {
|
|
2302
|
-
from: Math.min(selection.anchor, selection.head),
|
|
2303
|
-
to: Math.max(selection.anchor, selection.head)
|
|
2304
|
-
};
|
|
2305
|
-
const activeScopes = getEffectiveWorkflowScopes(workflowOverlay);
|
|
2306
|
-
return activeScopes.find((scope) => {
|
|
2307
|
-
if (scope.anchor.kind === "detached") return false;
|
|
2308
|
-
const scopeFrom = scope.anchor.kind === "range" ? scope.anchor.from : scope.anchor.at;
|
|
2309
|
-
const scopeTo = scope.anchor.kind === "range" ? scope.anchor.to : scope.anchor.at;
|
|
2310
|
-
return selectionBounds.from >= scopeFrom && selectionBounds.to <= scopeTo;
|
|
2311
|
-
}) ?? null;
|
|
2312
|
-
}
|
|
2313
|
-
function getEffectiveDocumentMode(selection) {
|
|
2314
|
-
if (viewState.documentMode === "viewing") {
|
|
2315
|
-
return "viewing";
|
|
2316
|
-
}
|
|
2317
|
-
const matchingScope = getMatchingWorkflowScope(selection);
|
|
2318
|
-
if (matchingScope?.mode === "suggest") {
|
|
2319
|
-
return "suggesting";
|
|
2320
|
-
}
|
|
2321
|
-
return viewState.documentMode;
|
|
2322
|
-
}
|
|
2323
|
-
function expandSelectionRange(range) {
|
|
2324
|
-
return {
|
|
2325
|
-
from: range.from,
|
|
2326
|
-
to: range.to > range.from ? range.to : range.from + 1
|
|
2327
|
-
};
|
|
2328
|
-
}
|
|
2329
|
-
function deriveOpaqueWorkflowBlockedReason(range) {
|
|
2330
|
-
const targetPartPath = getStoryTargetOpaquePartPath(activeStory);
|
|
2331
|
-
if (!targetPartPath) {
|
|
2332
|
-
return null;
|
|
2333
|
-
}
|
|
2334
|
-
const fragments = findOpaqueFragmentsIntersectingRange(
|
|
2335
|
-
state.document.preservation,
|
|
2336
|
-
range
|
|
2337
|
-
).filter((fragment2) => fragment2.packagePartName === targetPartPath);
|
|
2338
|
-
if (fragments.length === 0) {
|
|
2339
|
-
return null;
|
|
2340
|
-
}
|
|
2341
|
-
const blockedImportFeatureKeys = /* @__PURE__ */ new Set([
|
|
2342
|
-
"alt-chunk",
|
|
2343
|
-
"alternate-content",
|
|
2344
|
-
"custom-xml"
|
|
2345
|
-
]);
|
|
2346
|
-
const blockedImportFragment = fragments.find(
|
|
2347
|
-
(fragment2) => blockedImportFeatureKeys.has(describeOpaqueFragment(fragment2).featureKey)
|
|
2348
|
-
) ?? null;
|
|
2349
|
-
const fragment = blockedImportFragment ?? fragments[0];
|
|
2350
|
-
const descriptor = describeOpaqueFragment(fragment);
|
|
2351
|
-
const isBlockedImport = blockedImportFragment !== null;
|
|
2352
|
-
return {
|
|
2353
|
-
code: isBlockedImport ? "workflow_blocked_import" : "workflow_preserve_only",
|
|
2354
|
-
message: isBlockedImport ? `${descriptor.label} remains a blocked import and cannot be edited.` : `${descriptor.label} remains preserve-only and cannot be edited.`,
|
|
2355
|
-
anchor: toPublicAnchorProjection(
|
|
2356
|
-
createRangeAnchor(fragment.lastKnownRange.from, fragment.lastKnownRange.to, {
|
|
2357
|
-
start: -1,
|
|
2358
|
-
end: 1
|
|
2359
|
-
})
|
|
2360
|
-
),
|
|
2361
|
-
storyTarget: activeStory
|
|
2362
|
-
};
|
|
2363
|
-
}
|
|
2364
|
-
function getStoryTargetOpaquePartPath(storyTarget) {
|
|
2365
|
-
if (storyTarget.kind === "main") {
|
|
2366
|
-
return "/word/document.xml";
|
|
2367
|
-
}
|
|
2368
|
-
if (storyTarget.kind === "header") {
|
|
2369
|
-
return state.document.subParts?.headers.find(
|
|
2370
|
-
(header) => header.relationshipId === storyTarget.relationshipId && header.variant === storyTarget.variant && header.sectionIndex === storyTarget.sectionIndex
|
|
2371
|
-
)?.partPath ?? null;
|
|
2372
|
-
}
|
|
2373
|
-
if (storyTarget.kind === "footer") {
|
|
2374
|
-
return state.document.subParts?.footers.find(
|
|
2375
|
-
(footer) => footer.relationshipId === storyTarget.relationshipId && footer.variant === storyTarget.variant && footer.sectionIndex === storyTarget.sectionIndex
|
|
2376
|
-
)?.partPath ?? null;
|
|
2377
|
-
}
|
|
2378
|
-
if (storyTarget.kind === "footnote") {
|
|
2379
|
-
return "/word/footnotes.xml";
|
|
2380
|
-
}
|
|
2381
|
-
if (storyTarget.kind === "endnote") {
|
|
2382
|
-
return "/word/endnotes.xml";
|
|
2383
|
-
}
|
|
2384
|
-
return null;
|
|
2385
|
-
}
|
|
2386
|
-
function deriveWorkflowScopeSnapshot() {
|
|
2387
|
-
if (!workflowOverlay) return null;
|
|
2388
|
-
const blockedReasons = getCachedInteractionGuardSnapshot().blockedReasons;
|
|
2389
|
-
const activeItem = workflowOverlay.activeWorkItemId ? workflowOverlay.workItems?.find(
|
|
2390
|
-
(item) => item.workItemId === workflowOverlay.activeWorkItemId
|
|
2391
|
-
) : void 0;
|
|
2392
|
-
return {
|
|
2393
|
-
overlayPresent: true,
|
|
2394
|
-
activeWorkItemId: workflowOverlay.activeWorkItemId ?? null,
|
|
2395
|
-
activeWorkItem: activeItem,
|
|
2396
|
-
scopes: workflowOverlay.scopes,
|
|
2397
|
-
candidates: workflowOverlay.candidates ?? [],
|
|
2398
|
-
blockedReasons
|
|
2399
|
-
};
|
|
2400
|
-
}
|
|
2401
|
-
function deriveHostAnnotationSnapshot() {
|
|
2402
|
-
return {
|
|
2403
|
-
totalCount: hostAnnotationOverlay?.annotations.length ?? 0,
|
|
2404
|
-
annotations: structuredClone(hostAnnotationOverlay?.annotations ?? [])
|
|
2405
|
-
};
|
|
2406
|
-
}
|
|
2407
|
-
function getEffectiveWorkflowScopes(overlay) {
|
|
2408
|
-
const activeWorkItemId = overlay.activeWorkItemId ?? null;
|
|
2409
|
-
const activeWorkItemScopeIds = activeWorkItemId === null ? null : new Set(
|
|
2410
|
-
overlay.workItems?.find((item) => item.workItemId === activeWorkItemId)?.scopeIds ?? []
|
|
2411
|
-
);
|
|
2412
|
-
return overlay.scopes.filter((scope) => {
|
|
2413
|
-
const scopeStoryTarget = scope.storyTarget ?? MAIN_STORY_TARGET;
|
|
2414
|
-
if (!storyTargetsEqual(scopeStoryTarget, activeStory)) {
|
|
2415
|
-
return false;
|
|
2416
|
-
}
|
|
2417
|
-
if (activeWorkItemId === null) {
|
|
2418
|
-
return true;
|
|
2419
|
-
}
|
|
2420
|
-
return scope.workItemId === activeWorkItemId || activeWorkItemScopeIds?.has(scope.scopeId) === true;
|
|
2421
|
-
});
|
|
2422
|
-
}
|
|
2423
|
-
function getCachedInteractionGuardSnapshot() {
|
|
2424
|
-
const activeStoryKey = storyTargetKey(activeStory);
|
|
2425
|
-
if (cachedInteractionGuardSnapshot && cachedInteractionGuardSnapshot.revisionToken === state.revisionToken && cachedInteractionGuardSnapshot.activeStoryKey === activeStoryKey && cachedInteractionGuardSnapshot.selection === state.selection && cachedInteractionGuardSnapshot.readOnly === state.readOnly && cachedInteractionGuardSnapshot.documentMode === viewState.documentMode && cachedInteractionGuardSnapshot.protectionSnapshot === protectionSnapshot && cachedInteractionGuardSnapshot.workflowOverlay === workflowOverlay) {
|
|
2426
|
-
return cachedInteractionGuardSnapshot.snapshot;
|
|
2427
|
-
}
|
|
2428
|
-
const blockedReasons = evaluateWorkflowBlockedReasons(state.selection);
|
|
2429
|
-
const matchingScope = getMatchingWorkflowScope(state.selection);
|
|
2430
|
-
const primaryBlockedReason = blockedReasons[0];
|
|
2431
|
-
const snapshot = {
|
|
2432
|
-
effectiveMode: primaryBlockedReason ? primaryBlockedReason.code === "workflow_comment_only" ? "comment" : primaryBlockedReason.code === "workflow_view_only" ? "view" : "blocked" : getEffectiveDocumentMode(state.selection) === "suggesting" ? "suggest" : matchingScope?.mode ?? "edit",
|
|
2433
|
-
...matchingScope?.scopeId ? { matchedScopeId: matchingScope.scopeId } : {},
|
|
2434
|
-
...matchingScope?.mode ? { matchedScopeMode: matchingScope.mode } : {},
|
|
2435
|
-
...primaryBlockedReason ? { disabledReason: primaryBlockedReason.message } : {},
|
|
2436
|
-
blockedReasons
|
|
2437
|
-
};
|
|
2438
|
-
cachedInteractionGuardSnapshot = {
|
|
2439
|
-
revisionToken: state.revisionToken,
|
|
2440
|
-
activeStoryKey,
|
|
2441
|
-
selection: state.selection,
|
|
2442
|
-
readOnly: state.readOnly,
|
|
2443
|
-
documentMode: viewState.documentMode,
|
|
2444
|
-
protectionSnapshot,
|
|
2445
|
-
workflowOverlay,
|
|
2446
|
-
snapshot
|
|
2447
|
-
};
|
|
2448
|
-
return snapshot;
|
|
2449
|
-
}
|
|
2450
|
-
function getCachedWorkflowScopeSnapshot() {
|
|
2451
|
-
if (!workflowOverlay) {
|
|
2452
|
-
return null;
|
|
2453
|
-
}
|
|
2454
|
-
const interactionGuardSnapshot = getCachedInteractionGuardSnapshot();
|
|
2455
|
-
if (cachedWorkflowScopeSnapshot && cachedWorkflowScopeSnapshot.workflowOverlay === workflowOverlay && cachedWorkflowScopeSnapshot.interactionGuardSnapshot === interactionGuardSnapshot) {
|
|
2456
|
-
return cachedWorkflowScopeSnapshot.snapshot;
|
|
2457
|
-
}
|
|
2458
|
-
const snapshot = deriveWorkflowScopeSnapshot();
|
|
2459
|
-
cachedWorkflowScopeSnapshot = {
|
|
2460
|
-
workflowOverlay,
|
|
2461
|
-
interactionGuardSnapshot,
|
|
2462
|
-
snapshot
|
|
2463
|
-
};
|
|
2464
|
-
return snapshot;
|
|
2465
|
-
}
|
|
2466
|
-
function getCachedWorkflowMarkupSnapshot() {
|
|
2467
|
-
const activeStoryKey = storyTargetKey(activeStory);
|
|
2468
|
-
if (cachedWorkflowMarkupSnapshot && cachedWorkflowMarkupSnapshot.revisionToken === state.revisionToken && cachedWorkflowMarkupSnapshot.activeStoryKey === activeStoryKey && cachedWorkflowMarkupSnapshot.protectionSnapshot === protectionSnapshot && cachedWorkflowMarkupSnapshot.preservation === state.document.preservation) {
|
|
2469
|
-
return cachedWorkflowMarkupSnapshot.snapshot;
|
|
2470
|
-
}
|
|
2471
|
-
const snapshot = collectWorkflowMarkupSnapshot({
|
|
2472
|
-
renderSnapshot: cachedRenderSnapshot,
|
|
2473
|
-
fieldSnapshot: buildFieldSnapshot(state.document),
|
|
2474
|
-
protectionSnapshot,
|
|
2475
|
-
preservation: state.document.preservation
|
|
2476
|
-
});
|
|
2477
|
-
cachedWorkflowMarkupSnapshot = {
|
|
2478
|
-
revisionToken: state.revisionToken,
|
|
2479
|
-
activeStoryKey,
|
|
2480
|
-
protectionSnapshot,
|
|
2481
|
-
preservation: state.document.preservation,
|
|
2482
|
-
snapshot
|
|
2483
|
-
};
|
|
2484
|
-
return snapshot;
|
|
2485
|
-
}
|
|
2486
|
-
function refreshRenderSnapshot() {
|
|
2487
|
-
const surface = getCachedSurface(state.document, activeStory);
|
|
2488
|
-
return {
|
|
2489
|
-
documentId: state.documentId,
|
|
2490
|
-
sessionId: state.sessionId,
|
|
2491
|
-
sourceLabel: state.sourceLabel,
|
|
2492
|
-
revisionToken: state.revisionToken,
|
|
2493
|
-
isReady: state.phase === "ready",
|
|
2494
|
-
isDirty: state.isDirty,
|
|
2495
|
-
readOnly: state.readOnly,
|
|
2496
|
-
documentMode: viewState.documentMode,
|
|
2497
|
-
selection: toPublicSelectionSnapshot(state.selection, activeStory),
|
|
2498
|
-
activeStory,
|
|
2499
|
-
pageLayout: getCachedPageLayoutSnapshot(state, activeStory) ?? void 0,
|
|
2500
|
-
documentStats: toPublicDocumentStats(state),
|
|
2501
|
-
comments: getCachedCommentSidebarSnapshot(state),
|
|
2502
|
-
trackedChanges: getCachedTrackedChangesSnapshot(state, surface),
|
|
2503
|
-
compatibility: getCachedCompatibilityReport(state),
|
|
2504
|
-
warnings: state.warnings.map((warning) => toPublicWarning(warning)),
|
|
2505
|
-
fatalError: state.fatalError ? toPublicError(state.fatalError) : void 0,
|
|
2506
|
-
commandState: {
|
|
2507
|
-
canUndo: history.past.length > 0,
|
|
2508
|
-
canRedo: history.future.length > 0,
|
|
2509
|
-
readOnly: state.readOnly
|
|
2510
|
-
},
|
|
2511
|
-
surface,
|
|
2512
|
-
protectionSnapshot
|
|
2513
|
-
};
|
|
2514
|
-
}
|
|
2515
|
-
function getCachedViewStateSnapshot() {
|
|
2516
|
-
const activeStoryKey = storyTargetKey(activeStory);
|
|
2517
|
-
const pageLayout = cachedRenderSnapshot.pageLayout;
|
|
2518
|
-
if (cachedViewStateSnapshot && cachedViewStateSnapshot.revisionToken === state.revisionToken && cachedViewStateSnapshot.activeStoryKey === activeStoryKey && cachedViewStateSnapshot.selection === state.selection && cachedViewStateSnapshot.viewStateRef === viewState && cachedViewStateSnapshot.pageLayout === pageLayout) {
|
|
2519
|
-
return cachedViewStateSnapshot.snapshot;
|
|
2520
|
-
}
|
|
2521
|
-
const surface = cachedRenderSnapshot.surface;
|
|
2522
|
-
const mainSurface = activeStory.kind === "main" ? surface : getCachedSurface(state.document, MAIN_STORY_TARGET);
|
|
2523
|
-
const snapshot = createEditorViewStateSnapshot(
|
|
2524
|
-
viewState,
|
|
2525
|
-
activeStory,
|
|
2526
|
-
toPublicSelectionSnapshot(state.selection, activeStory),
|
|
2527
|
-
surface,
|
|
2528
|
-
mainSurface,
|
|
2529
|
-
pageLayout,
|
|
2530
|
-
state.document.numbering
|
|
2531
|
-
);
|
|
2532
|
-
cachedViewStateSnapshot = {
|
|
2533
|
-
revisionToken: state.revisionToken,
|
|
2534
|
-
activeStoryKey,
|
|
2535
|
-
selection: state.selection,
|
|
2536
|
-
viewStateRef: viewState,
|
|
2537
|
-
pageLayout,
|
|
2538
|
-
snapshot
|
|
2539
|
-
};
|
|
2540
|
-
return snapshot;
|
|
2541
|
-
}
|
|
2542
|
-
let cachedRenderSnapshot = refreshRenderSnapshot();
|
|
2543
|
-
emit({
|
|
2544
|
-
type: "ready",
|
|
2545
|
-
documentId: state.documentId,
|
|
2546
|
-
sessionId: state.sessionId,
|
|
2547
|
-
source: options.sourceKind ?? (options.initialSessionState ? "session" : options.initialSnapshot ? "snapshot" : "canonical"),
|
|
2548
|
-
stats: toPublicDocumentStats(state),
|
|
2549
|
-
compatibility: toPublicCompatibilityReport(createDerivedCompatibility(state)),
|
|
2550
|
-
comments: cachedRenderSnapshot.comments,
|
|
2551
|
-
trackedChanges: cachedRenderSnapshot.trackedChanges
|
|
2552
|
-
});
|
|
2553
|
-
if (options.fatalError) {
|
|
2554
|
-
emit({
|
|
2555
|
-
type: "error",
|
|
2556
|
-
documentId: state.documentId,
|
|
2557
|
-
error: options.fatalError
|
|
2558
|
-
});
|
|
2559
|
-
}
|
|
2560
|
-
return {
|
|
2561
|
-
subscribe(listener) {
|
|
2562
|
-
listeners.add(listener);
|
|
2563
|
-
return () => {
|
|
2564
|
-
listeners.delete(listener);
|
|
2565
|
-
};
|
|
2566
|
-
},
|
|
2567
|
-
subscribeToEvents(listener) {
|
|
2568
|
-
eventListeners.add(listener);
|
|
2569
|
-
return () => {
|
|
2570
|
-
eventListeners.delete(listener);
|
|
2571
|
-
};
|
|
2572
|
-
},
|
|
2573
|
-
getRenderSnapshot() {
|
|
2574
|
-
return cachedRenderSnapshot;
|
|
2575
|
-
},
|
|
2576
|
-
getCanonicalDocument() {
|
|
2577
|
-
return state.document;
|
|
2578
|
-
},
|
|
2579
|
-
getSourcePackage() {
|
|
2580
|
-
return state.sourcePackage;
|
|
2581
|
-
},
|
|
2582
|
-
emitBlockedCommand(command, reasons) {
|
|
2583
|
-
emit({
|
|
2584
|
-
type: "command_blocked",
|
|
2585
|
-
documentId: state.documentId,
|
|
2586
|
-
command,
|
|
2587
|
-
reasons
|
|
2588
|
-
});
|
|
2589
|
-
},
|
|
2590
|
-
dispatch(command) {
|
|
2591
|
-
const commandSelection = getCommandSelection(command, state.selection);
|
|
2592
|
-
if (isMutationCommand(command)) {
|
|
2593
|
-
const blockedReasons = evaluateWorkflowBlockedReasons(
|
|
2594
|
-
commandSelection,
|
|
2595
|
-
command.type
|
|
2596
|
-
);
|
|
2597
|
-
if (blockedReasons.length > 0) {
|
|
2598
|
-
emit({
|
|
2599
|
-
type: "command_blocked",
|
|
2600
|
-
documentId: state.documentId,
|
|
2601
|
-
command: command.type,
|
|
2602
|
-
reasons: blockedReasons
|
|
2603
|
-
});
|
|
2604
|
-
return;
|
|
2605
|
-
}
|
|
2606
|
-
}
|
|
2607
|
-
if (command.type === "history.undo") {
|
|
2608
|
-
if (viewState.documentMode === "viewing") return;
|
|
2609
|
-
applyHistory("undo");
|
|
2610
|
-
return;
|
|
2611
|
-
}
|
|
2612
|
-
if (command.type === "history.redo") {
|
|
2613
|
-
if (viewState.documentMode === "viewing") return;
|
|
2614
|
-
applyHistory("redo");
|
|
2615
|
-
return;
|
|
2616
|
-
}
|
|
2617
|
-
try {
|
|
2618
|
-
const transaction = executeEditorCommand(state, command, {
|
|
2619
|
-
timestamp: command.origin?.timestamp ?? clock(),
|
|
2620
|
-
documentMode: getEffectiveDocumentMode(commandSelection),
|
|
2621
|
-
defaultAuthorId: defaultAuthorId ?? void 0
|
|
2622
|
-
});
|
|
2623
|
-
commit(transaction);
|
|
2624
|
-
} catch (error) {
|
|
2625
|
-
emitError(toRuntimeError(error));
|
|
2626
|
-
}
|
|
2627
|
-
},
|
|
2628
|
-
undo() {
|
|
2629
|
-
this.dispatch({
|
|
2630
|
-
type: "history.undo",
|
|
2631
|
-
origin: createOrigin("runtime", clock())
|
|
2632
|
-
});
|
|
2633
|
-
},
|
|
2634
|
-
redo() {
|
|
2635
|
-
this.dispatch({
|
|
2636
|
-
type: "history.redo",
|
|
2637
|
-
origin: createOrigin("runtime", clock())
|
|
2638
|
-
});
|
|
2639
|
-
},
|
|
2640
|
-
focus() {
|
|
2641
|
-
viewState = setFocused(viewState, true);
|
|
2642
|
-
this.dispatch({
|
|
2643
|
-
type: "runtime.focus",
|
|
2644
|
-
focused: true,
|
|
2645
|
-
origin: createOrigin("api", clock())
|
|
2646
|
-
});
|
|
2647
|
-
},
|
|
2648
|
-
blur() {
|
|
2649
|
-
viewState = setFocused(viewState, false);
|
|
2650
|
-
this.dispatch({
|
|
2651
|
-
type: "runtime.focus",
|
|
2652
|
-
focused: false,
|
|
2653
|
-
origin: createOrigin("api", clock())
|
|
2654
|
-
});
|
|
2655
|
-
},
|
|
2656
|
-
setDefaultAuthorId(authorId) {
|
|
2657
|
-
defaultAuthorId = authorId;
|
|
2658
|
-
},
|
|
2659
|
-
replaceText(text, target) {
|
|
2660
|
-
try {
|
|
2661
|
-
const timestamp = clock();
|
|
2662
|
-
applyTextCommandInActiveStory(
|
|
2663
|
-
{
|
|
2664
|
-
type: "text.insert",
|
|
2665
|
-
text,
|
|
2666
|
-
origin: createOrigin("api", timestamp)
|
|
2667
|
-
},
|
|
2668
|
-
{
|
|
2669
|
-
selection: target ? createSelectionFromPublicAnchor(target) : state.selection,
|
|
2670
|
-
blockedCommandName: "replaceText"
|
|
2671
|
-
}
|
|
2672
|
-
);
|
|
2673
|
-
} catch (error) {
|
|
2674
|
-
emitError(toRuntimeError(error));
|
|
2675
|
-
}
|
|
2676
|
-
},
|
|
2677
|
-
applyActiveStoryTextCommand(command) {
|
|
2678
|
-
try {
|
|
2679
|
-
applyTextCommandInActiveStory(command);
|
|
2680
|
-
} catch (error) {
|
|
2681
|
-
emitError(toRuntimeError(error));
|
|
2682
|
-
}
|
|
2683
|
-
},
|
|
2684
|
-
addComment(params) {
|
|
2685
|
-
if (viewState.documentMode === "viewing") {
|
|
2686
|
-
throw new Error("Cannot add comments in viewing mode.");
|
|
2687
|
-
}
|
|
2688
|
-
const commentId = createEntityId("comment", state.document.review.comments, clock());
|
|
2689
|
-
const anchor = params.anchor ? toInternalAnchorProjection(params.anchor) : state.selection.activeRange;
|
|
2690
|
-
const selection = params.anchor ? createSelectionFromPublicAnchor(params.anchor) : state.selection;
|
|
2691
|
-
if (!canCreateDocxCommentAnchor(state.document.content, anchor)) {
|
|
2692
|
-
const message = "DOCX comments must use a non-empty range that stays within a single paragraph.";
|
|
2693
|
-
emitError({
|
|
2694
|
-
errorId: createSessionId("comment-anchor", clock()),
|
|
2695
|
-
code: "validation_failed",
|
|
2696
|
-
isFatal: false,
|
|
2697
|
-
message,
|
|
2698
|
-
source: "runtime"
|
|
2699
|
-
});
|
|
2700
|
-
throw new Error(message);
|
|
2701
|
-
}
|
|
2702
|
-
const authorId = params.authorId ?? defaultAuthorId ?? "unknown";
|
|
2703
|
-
const createdAt = clock();
|
|
2704
|
-
const entries = [
|
|
2705
|
-
{
|
|
2706
|
-
entryId: `${commentId}-entry-1`,
|
|
2707
|
-
authorId,
|
|
2708
|
-
body: params.body ?? "",
|
|
2709
|
-
createdAt
|
|
2710
|
-
}
|
|
2711
|
-
];
|
|
2712
|
-
const comment = {
|
|
2713
|
-
commentId,
|
|
2714
|
-
anchor,
|
|
2715
|
-
createdAt,
|
|
2716
|
-
createdBy: authorId,
|
|
2717
|
-
authorId,
|
|
2718
|
-
body: params.body ?? "",
|
|
2719
|
-
entries,
|
|
2720
|
-
status: anchor.kind === "detached" ? "detached" : "open",
|
|
2721
|
-
warningIds: [],
|
|
2722
|
-
isResolved: false,
|
|
2723
|
-
metadata: {
|
|
2724
|
-
source: "runtime"
|
|
2725
|
-
}
|
|
2726
|
-
};
|
|
2727
|
-
this.dispatch({
|
|
2728
|
-
type: "comment.add",
|
|
2729
|
-
comment,
|
|
2730
|
-
selection,
|
|
2731
|
-
origin: createOrigin("api", clock())
|
|
2732
|
-
});
|
|
2733
|
-
return commentId;
|
|
2734
|
-
},
|
|
2735
|
-
openComment(commentId) {
|
|
2736
|
-
this.dispatch({
|
|
2737
|
-
type: "comment.open",
|
|
2738
|
-
commentId,
|
|
2739
|
-
origin: createOrigin("api", clock())
|
|
2740
|
-
});
|
|
2741
|
-
},
|
|
2742
|
-
resolveComment(commentId) {
|
|
2743
|
-
this.dispatch({
|
|
2744
|
-
type: "comment.resolve",
|
|
2745
|
-
commentId,
|
|
2746
|
-
resolvedBy: defaultAuthorId ?? "unknown",
|
|
2747
|
-
origin: createOrigin("api", clock())
|
|
2748
|
-
});
|
|
2749
|
-
},
|
|
2750
|
-
reopenComment(commentId) {
|
|
2751
|
-
this.dispatch({
|
|
2752
|
-
type: "comment.reopen",
|
|
2753
|
-
commentId,
|
|
2754
|
-
origin: createOrigin("api", clock())
|
|
2755
|
-
});
|
|
2756
|
-
},
|
|
2757
|
-
addCommentReply(commentId, body, authorId) {
|
|
2758
|
-
this.dispatch({
|
|
2759
|
-
type: "comment.add-reply",
|
|
2760
|
-
commentId,
|
|
2761
|
-
body,
|
|
2762
|
-
authorId: authorId ?? defaultAuthorId,
|
|
2763
|
-
origin: createOrigin("api", clock())
|
|
2764
|
-
});
|
|
2765
|
-
},
|
|
2766
|
-
editCommentBody(commentId, body) {
|
|
2767
|
-
this.dispatch({
|
|
2768
|
-
type: "comment.edit-body",
|
|
2769
|
-
commentId,
|
|
2770
|
-
body,
|
|
2771
|
-
origin: createOrigin("api", clock())
|
|
2772
|
-
});
|
|
2773
|
-
},
|
|
2774
|
-
acceptChange(changeId) {
|
|
2775
|
-
this.dispatch({
|
|
2776
|
-
type: "change.accept",
|
|
2777
|
-
changeId,
|
|
2778
|
-
origin: createOrigin("api", clock())
|
|
2779
|
-
});
|
|
2780
|
-
},
|
|
2781
|
-
rejectChange(changeId) {
|
|
2782
|
-
this.dispatch({
|
|
2783
|
-
type: "change.reject",
|
|
2784
|
-
changeId,
|
|
2785
|
-
origin: createOrigin("api", clock())
|
|
2786
|
-
});
|
|
2787
|
-
},
|
|
2788
|
-
acceptAllChanges() {
|
|
2789
|
-
this.dispatch({
|
|
2790
|
-
type: "change.accept-all",
|
|
2791
|
-
origin: createOrigin("api", clock())
|
|
2792
|
-
});
|
|
2793
|
-
},
|
|
2794
|
-
rejectAllChanges() {
|
|
2795
|
-
this.dispatch({
|
|
2796
|
-
type: "change.reject-all",
|
|
2797
|
-
origin: createOrigin("api", clock())
|
|
2798
|
-
});
|
|
2799
|
-
},
|
|
2800
|
-
openStory(target) {
|
|
2801
|
-
const normalizedTarget = target.kind === "header" || target.kind === "footer" ? normalizeHeaderFooterTarget(
|
|
2802
|
-
state.document,
|
|
2803
|
-
target,
|
|
2804
|
-
cachedRenderSnapshot.pageLayout?.sectionIndex
|
|
2805
|
-
) ?? target : target;
|
|
2806
|
-
if (storyTargetsEqual(activeStory, normalizedTarget)) {
|
|
2807
|
-
return true;
|
|
2808
|
-
}
|
|
2809
|
-
if (!isValidStoryTarget(state, normalizedTarget)) {
|
|
2810
|
-
return false;
|
|
2811
|
-
}
|
|
2812
|
-
switchActiveStory(normalizedTarget);
|
|
2813
|
-
return true;
|
|
2814
|
-
},
|
|
2815
|
-
closeStory() {
|
|
2816
|
-
if (activeStory.kind === "main") {
|
|
2817
|
-
return;
|
|
2818
|
-
}
|
|
2819
|
-
switchActiveStory(MAIN_STORY_TARGET);
|
|
2820
|
-
},
|
|
2821
|
-
getActiveStory() {
|
|
2822
|
-
return activeStory;
|
|
2823
|
-
},
|
|
2824
|
-
getViewState() {
|
|
2825
|
-
return getCachedViewStateSnapshot();
|
|
2826
|
-
},
|
|
2827
|
-
setViewMode(mode) {
|
|
2828
|
-
viewState = setViewMode(viewState, mode);
|
|
2829
|
-
cachedRenderSnapshot = refreshRenderSnapshot();
|
|
2830
|
-
for (const listener of listeners) {
|
|
2831
|
-
listener();
|
|
2832
|
-
}
|
|
2833
|
-
},
|
|
2834
|
-
setDocumentMode(mode) {
|
|
2835
|
-
viewState = setDocumentMode(viewState, mode);
|
|
2836
|
-
cachedRenderSnapshot = refreshRenderSnapshot();
|
|
2837
|
-
for (const listener of listeners) {
|
|
2838
|
-
listener();
|
|
2839
|
-
}
|
|
2840
|
-
},
|
|
2841
|
-
getProtectionSnapshot() {
|
|
2842
|
-
return cachedRenderSnapshot.protectionSnapshot;
|
|
2843
|
-
},
|
|
2844
|
-
setWorkspaceMode(mode) {
|
|
2845
|
-
viewState = setWorkspaceMode(viewState, mode);
|
|
2846
|
-
cachedRenderSnapshot = refreshRenderSnapshot();
|
|
2847
|
-
for (const listener of listeners) {
|
|
2848
|
-
listener();
|
|
2849
|
-
}
|
|
2850
|
-
},
|
|
2851
|
-
setZoom(level) {
|
|
2852
|
-
viewState = setZoomLevel(viewState, level);
|
|
2853
|
-
cachedRenderSnapshot = refreshRenderSnapshot();
|
|
2854
|
-
for (const listener of listeners) {
|
|
2855
|
-
listener();
|
|
2856
|
-
}
|
|
2857
|
-
},
|
|
2858
|
-
getPageLayoutSnapshot() {
|
|
2859
|
-
return getCachedPageLayoutSnapshot(state, activeStory);
|
|
2860
|
-
},
|
|
2861
|
-
getDocumentNavigationSnapshot() {
|
|
2862
|
-
return getCachedDocumentNavigationSnapshot(state, activeStory);
|
|
2863
|
-
},
|
|
2864
|
-
getFieldSnapshot() {
|
|
2865
|
-
return buildFieldSnapshot(state.document);
|
|
2866
|
-
},
|
|
2867
|
-
updateFields(options2) {
|
|
2868
|
-
const refreshed = refreshDocumentFields(
|
|
2869
|
-
state.document,
|
|
2870
|
-
state.selection.head,
|
|
2871
|
-
activeStory,
|
|
2872
|
-
options2
|
|
2873
|
-
);
|
|
2874
|
-
if (refreshed.changed) {
|
|
2875
|
-
this.dispatch({
|
|
2876
|
-
type: "document.replace",
|
|
2877
|
-
document: refreshed.document,
|
|
2878
|
-
mapping: createEmptyMapping(),
|
|
2879
|
-
protectionSelection: refreshed.protectionSelection,
|
|
2880
|
-
origin: createOrigin("api", clock())
|
|
2881
|
-
});
|
|
2882
|
-
}
|
|
2883
|
-
const snapshot = buildFieldSnapshot(refreshed.document);
|
|
2884
|
-
return {
|
|
2885
|
-
totalCount: snapshot.totalCount,
|
|
2886
|
-
updatedCount: refreshed.updatedCount,
|
|
2887
|
-
preserveOnlyCount: snapshot.preserveOnlyCount
|
|
2888
|
-
};
|
|
2889
|
-
},
|
|
2890
|
-
updateTableOfContents(options2) {
|
|
2891
|
-
const refreshed = refreshDocumentTableOfContents(
|
|
2892
|
-
state.document,
|
|
2893
|
-
state.selection.head,
|
|
2894
|
-
activeStory,
|
|
2895
|
-
options2
|
|
2896
|
-
);
|
|
2897
|
-
if (refreshed.changed) {
|
|
2898
|
-
this.dispatch({
|
|
2899
|
-
type: "document.replace",
|
|
2900
|
-
document: refreshed.document,
|
|
2901
|
-
mapping: createEmptyMapping(),
|
|
2902
|
-
protectionSelection: refreshed.protectionSelection,
|
|
2903
|
-
origin: createOrigin("api", clock())
|
|
2904
|
-
});
|
|
2905
|
-
}
|
|
2906
|
-
return refreshed.result;
|
|
2907
|
-
},
|
|
2908
|
-
getSessionState() {
|
|
2909
|
-
const compatibility = createDerivedCompatibility(state);
|
|
2910
|
-
return editorSessionStateFromPersistedSnapshot(
|
|
2911
|
-
createPersistedEditorSnapshot(state, {
|
|
2912
|
-
editorBuild,
|
|
2913
|
-
savedAt: clock(),
|
|
2914
|
-
compatibility,
|
|
2915
|
-
protectionSnapshot
|
|
2916
|
-
})
|
|
2917
|
-
);
|
|
2918
|
-
},
|
|
2919
|
-
getPersistedSnapshot() {
|
|
2920
|
-
return persistedSnapshotFromEditorSessionState(this.getSessionState(), {
|
|
2921
|
-
savedAt: clock()
|
|
2922
|
-
});
|
|
2923
|
-
},
|
|
2924
|
-
getCompatibilityReport() {
|
|
2925
|
-
return toPublicCompatibilityReport(createDerivedCompatibility(state));
|
|
2926
|
-
},
|
|
2927
|
-
getWarnings() {
|
|
2928
|
-
return state.warnings.map((warning) => toPublicWarning(warning));
|
|
2929
|
-
},
|
|
2930
|
-
async exportDocx(exportOptions) {
|
|
2931
|
-
if (!options.exportDocx) {
|
|
2932
|
-
const error = {
|
|
2933
|
-
errorId: createEntityId("error", {}, clock()),
|
|
2934
|
-
code: "export_failed",
|
|
2935
|
-
isFatal: false,
|
|
2936
|
-
message: "DOCX export requires an injected exporter until the IO substrate lands.",
|
|
2937
|
-
source: "export",
|
|
2938
|
-
details: {
|
|
2939
|
-
requestedOptions: exportOptions ?? {}
|
|
2940
|
-
}
|
|
2941
|
-
};
|
|
2942
|
-
emitError(error);
|
|
2943
|
-
throw new Error(error.message);
|
|
2944
|
-
}
|
|
2945
|
-
const result = await options.exportDocx(this.getSessionState(), exportOptions);
|
|
2946
|
-
emit({
|
|
2947
|
-
type: "export_completed",
|
|
2948
|
-
documentId: state.documentId,
|
|
2949
|
-
result
|
|
2950
|
-
});
|
|
2951
|
-
return result;
|
|
2952
|
-
},
|
|
2953
|
-
setWorkflowOverlay(overlay) {
|
|
2954
|
-
workflowOverlay = structuredClone(overlay);
|
|
2955
|
-
cachedRenderSnapshot = refreshRenderSnapshot();
|
|
2956
|
-
const snapshot = deriveWorkflowScopeSnapshot();
|
|
2957
|
-
emit({
|
|
2958
|
-
type: "workflow_overlay_changed",
|
|
2959
|
-
documentId: state.documentId,
|
|
2960
|
-
snapshot
|
|
2961
|
-
});
|
|
2962
|
-
if (workflowOverlay.activeWorkItemId !== void 0) {
|
|
2963
|
-
emit({
|
|
2964
|
-
type: "workflow_active_work_item_changed",
|
|
2965
|
-
documentId: state.documentId,
|
|
2966
|
-
activeWorkItemId: workflowOverlay.activeWorkItemId ?? null
|
|
2967
|
-
});
|
|
2968
|
-
}
|
|
2969
|
-
for (const listener of listeners) {
|
|
2970
|
-
listener();
|
|
2971
|
-
}
|
|
2972
|
-
},
|
|
2973
|
-
clearWorkflowOverlay() {
|
|
2974
|
-
workflowOverlay = null;
|
|
2975
|
-
cachedRenderSnapshot = refreshRenderSnapshot();
|
|
2976
|
-
emit({
|
|
2977
|
-
type: "workflow_active_work_item_changed",
|
|
2978
|
-
documentId: state.documentId,
|
|
2979
|
-
activeWorkItemId: null
|
|
2980
|
-
});
|
|
2981
|
-
emit({
|
|
2982
|
-
type: "workflow_overlay_changed",
|
|
2983
|
-
documentId: state.documentId,
|
|
2984
|
-
snapshot: {
|
|
2985
|
-
overlayPresent: false,
|
|
2986
|
-
activeWorkItemId: null,
|
|
2987
|
-
scopes: [],
|
|
2988
|
-
candidates: [],
|
|
2989
|
-
blockedReasons: []
|
|
2990
|
-
}
|
|
2991
|
-
});
|
|
2992
|
-
for (const listener of listeners) {
|
|
2993
|
-
listener();
|
|
2994
|
-
}
|
|
2995
|
-
},
|
|
2996
|
-
getWorkflowScopeSnapshot() {
|
|
2997
|
-
return getCachedWorkflowScopeSnapshot();
|
|
2998
|
-
},
|
|
2999
|
-
getInteractionGuardSnapshot() {
|
|
3000
|
-
return getCachedInteractionGuardSnapshot();
|
|
3001
|
-
},
|
|
3002
|
-
getWorkflowMarkupSnapshot() {
|
|
3003
|
-
return getCachedWorkflowMarkupSnapshot();
|
|
3004
|
-
},
|
|
3005
|
-
setHostAnnotationOverlay(overlay) {
|
|
3006
|
-
hostAnnotationOverlay = structuredClone(overlay);
|
|
3007
|
-
emit({
|
|
3008
|
-
type: "host_annotation_overlay_changed",
|
|
3009
|
-
documentId: state.documentId,
|
|
3010
|
-
snapshot: deriveHostAnnotationSnapshot()
|
|
3011
|
-
});
|
|
3012
|
-
for (const listener of listeners) {
|
|
3013
|
-
listener();
|
|
3014
|
-
}
|
|
3015
|
-
},
|
|
3016
|
-
clearHostAnnotationOverlay() {
|
|
3017
|
-
hostAnnotationOverlay = null;
|
|
3018
|
-
emit({
|
|
3019
|
-
type: "host_annotation_overlay_changed",
|
|
3020
|
-
documentId: state.documentId,
|
|
3021
|
-
snapshot: deriveHostAnnotationSnapshot()
|
|
3022
|
-
});
|
|
3023
|
-
for (const listener of listeners) {
|
|
3024
|
-
listener();
|
|
3025
|
-
}
|
|
3026
|
-
},
|
|
3027
|
-
getHostAnnotationSnapshot() {
|
|
3028
|
-
return deriveHostAnnotationSnapshot();
|
|
3029
|
-
},
|
|
3030
|
-
getWorkflowCandidateRanges(options2) {
|
|
3031
|
-
return deriveWorkflowCandidateRangesFromMarkup(this.getWorkflowMarkupSnapshot(), options2);
|
|
3032
|
-
},
|
|
3033
|
-
replaceWorkflowMarkupText(markupId, text) {
|
|
3034
|
-
const target = this.getWorkflowMarkupSnapshot().items.find((item) => item.markupId === markupId);
|
|
3035
|
-
if (!target || target.anchor.kind === "detached") {
|
|
3036
|
-
return;
|
|
3037
|
-
}
|
|
3038
|
-
const targetStory = target.storyTarget ?? MAIN_STORY_TARGET;
|
|
3039
|
-
if (!storyTargetsEqual(activeStory, targetStory)) {
|
|
3040
|
-
if (targetStory.kind === "main") {
|
|
3041
|
-
this.closeStory();
|
|
3042
|
-
} else if (!this.openStory(targetStory)) {
|
|
3043
|
-
return;
|
|
3044
|
-
}
|
|
3045
|
-
}
|
|
3046
|
-
this.replaceText(text, target.anchor);
|
|
3047
|
-
}
|
|
3048
|
-
};
|
|
3049
|
-
function applyHistory(direction) {
|
|
3050
|
-
const source = direction === "undo" ? history.past : history.future;
|
|
3051
|
-
const target = source.pop();
|
|
3052
|
-
if (!target) {
|
|
3053
|
-
return;
|
|
3054
|
-
}
|
|
3055
|
-
const counterpart = direction === "undo" ? history.future : history.past;
|
|
3056
|
-
counterpart.push(state);
|
|
3057
|
-
const previous = state;
|
|
3058
|
-
state = finalizeState(target, true, clock(), previous.revision);
|
|
3059
|
-
storySelections.set(storyTargetKey(activeStory), state.selection);
|
|
3060
|
-
cachedRenderSnapshot = refreshRenderSnapshot();
|
|
3061
|
-
notify(previous, state, {
|
|
3062
|
-
nextState: state,
|
|
3063
|
-
mapping: { steps: [] },
|
|
3064
|
-
effects: {
|
|
3065
|
-
warningsAdded: [],
|
|
3066
|
-
warningsCleared: []
|
|
3067
|
-
},
|
|
3068
|
-
historyBoundary: "skip",
|
|
3069
|
-
markDirty: true
|
|
3070
|
-
});
|
|
3071
|
-
}
|
|
3072
|
-
function commit(transaction) {
|
|
3073
|
-
const previous = state;
|
|
3074
|
-
if (transaction.historyBoundary === "push") {
|
|
3075
|
-
history.past.push(state);
|
|
3076
|
-
history.future = [];
|
|
3077
|
-
}
|
|
3078
|
-
protectionSnapshot = remapProtectionSnapshot(protectionSnapshot, transaction.mapping);
|
|
3079
|
-
state = finalizeState(transaction.nextState, transaction.markDirty, clock());
|
|
3080
|
-
storySelections.set(storyTargetKey(activeStory), state.selection);
|
|
3081
|
-
cachedRenderSnapshot = refreshRenderSnapshot();
|
|
3082
|
-
notify(previous, state, transaction);
|
|
3083
|
-
}
|
|
3084
|
-
function notify(previous, next, transaction) {
|
|
3085
|
-
if (previous.isDirty !== next.isDirty) {
|
|
3086
|
-
emit({
|
|
3087
|
-
type: "dirty_changed",
|
|
3088
|
-
documentId: next.documentId,
|
|
3089
|
-
isDirty: next.isDirty
|
|
3090
|
-
});
|
|
3091
|
-
}
|
|
3092
|
-
if (selectionChanged(previous.selection, next.selection)) {
|
|
3093
|
-
emit({
|
|
3094
|
-
type: "selection_changed",
|
|
3095
|
-
documentId: next.documentId,
|
|
3096
|
-
selection: toPublicSelectionSnapshot(next.selection, activeStory)
|
|
3097
|
-
});
|
|
3098
|
-
}
|
|
3099
|
-
if (transaction.effects.commentAdded) {
|
|
3100
|
-
emit({
|
|
3101
|
-
type: "comment_added",
|
|
3102
|
-
documentId: next.documentId,
|
|
3103
|
-
commentId: transaction.effects.commentAdded.commentId,
|
|
3104
|
-
anchor: toPublicAnchorProjection(transaction.effects.commentAdded.anchor)
|
|
3105
|
-
});
|
|
3106
|
-
}
|
|
3107
|
-
if (transaction.effects.commentResolved) {
|
|
3108
|
-
emit({
|
|
3109
|
-
type: "comment_resolved",
|
|
3110
|
-
documentId: next.documentId,
|
|
3111
|
-
commentId: transaction.effects.commentResolved.commentId
|
|
3112
|
-
});
|
|
3113
|
-
}
|
|
3114
|
-
if (transaction.effects.changeAccepted) {
|
|
3115
|
-
emit({
|
|
3116
|
-
type: "change_accepted",
|
|
3117
|
-
documentId: next.documentId,
|
|
3118
|
-
changeId: transaction.effects.changeAccepted.changeId
|
|
3119
|
-
});
|
|
3120
|
-
}
|
|
3121
|
-
if (transaction.effects.changeRejected) {
|
|
3122
|
-
emit({
|
|
3123
|
-
type: "change_rejected",
|
|
3124
|
-
documentId: next.documentId,
|
|
3125
|
-
changeId: transaction.effects.changeRejected.changeId
|
|
3126
|
-
});
|
|
3127
|
-
}
|
|
3128
|
-
if (transaction.effects.revisionAuthored) {
|
|
3129
|
-
emit({
|
|
3130
|
-
type: "change_authored",
|
|
3131
|
-
documentId: next.documentId,
|
|
3132
|
-
changeId: transaction.effects.revisionAuthored.changeId,
|
|
3133
|
-
kind: transaction.effects.revisionAuthored.kind
|
|
3134
|
-
});
|
|
3135
|
-
}
|
|
3136
|
-
if (transaction.effects.commandBlocked) {
|
|
3137
|
-
emit({
|
|
3138
|
-
type: "command_blocked",
|
|
3139
|
-
documentId: next.documentId,
|
|
3140
|
-
command: transaction.effects.commandBlocked.code,
|
|
3141
|
-
reasons: [{
|
|
3142
|
-
code: transaction.effects.commandBlocked.code,
|
|
3143
|
-
message: transaction.effects.commandBlocked.message
|
|
3144
|
-
}]
|
|
3145
|
-
});
|
|
3146
|
-
}
|
|
3147
|
-
for (const warning of transaction.effects.warningsAdded) {
|
|
3148
|
-
const publicWarning = toPublicWarning(warning);
|
|
3149
|
-
emit({
|
|
3150
|
-
type: "warning_added",
|
|
3151
|
-
documentId: next.documentId,
|
|
3152
|
-
warning: publicWarning
|
|
3153
|
-
});
|
|
3154
|
-
options.onWarning?.(publicWarning);
|
|
3155
|
-
}
|
|
3156
|
-
for (const cleared of transaction.effects.warningsCleared) {
|
|
3157
|
-
emit({
|
|
3158
|
-
type: "warning_cleared",
|
|
3159
|
-
documentId: next.documentId,
|
|
3160
|
-
warningId: cleared.warningId,
|
|
3161
|
-
code: cleared.code
|
|
3162
|
-
});
|
|
3163
|
-
}
|
|
3164
|
-
for (const listener of listeners) {
|
|
3165
|
-
listener();
|
|
3166
|
-
}
|
|
3167
|
-
}
|
|
3168
|
-
function applyTextCommandInActiveStory(command, options2 = {}) {
|
|
3169
|
-
const selection = options2.selection ?? state.selection;
|
|
3170
|
-
const blockedReasons = evaluateWorkflowBlockedReasons(selection, command.type);
|
|
3171
|
-
if (blockedReasons.length > 0) {
|
|
3172
|
-
emit({
|
|
3173
|
-
type: "command_blocked",
|
|
3174
|
-
documentId: state.documentId,
|
|
3175
|
-
command: options2.blockedCommandName ?? command.type,
|
|
3176
|
-
reasons: blockedReasons
|
|
3177
|
-
});
|
|
3178
|
-
return;
|
|
3179
|
-
}
|
|
3180
|
-
const timestamp = command.origin?.timestamp ?? clock();
|
|
3181
|
-
const context = {
|
|
3182
|
-
timestamp,
|
|
3183
|
-
documentMode: getEffectiveDocumentMode(selection),
|
|
3184
|
-
defaultAuthorId: defaultAuthorId ?? void 0
|
|
3185
|
-
};
|
|
3186
|
-
const baseState = selection === state.selection ? state : {
|
|
3187
|
-
...state,
|
|
3188
|
-
selection
|
|
3189
|
-
};
|
|
3190
|
-
if (activeStory.kind === "main") {
|
|
3191
|
-
commit(executeEditorCommand(baseState, command, context));
|
|
3192
|
-
return;
|
|
3193
|
-
}
|
|
3194
|
-
const localState = createEditorState({
|
|
3195
|
-
documentId: state.documentId,
|
|
3196
|
-
sessionId,
|
|
3197
|
-
sourceLabel: state.sourceLabel,
|
|
3198
|
-
readOnly: state.readOnly,
|
|
3199
|
-
canonicalDocument: {
|
|
3200
|
-
...state.document,
|
|
3201
|
-
content: {
|
|
3202
|
-
type: "doc",
|
|
3203
|
-
children: [...getStoryBlocks(state.document, activeStory)]
|
|
3204
|
-
},
|
|
3205
|
-
review: createSecondaryStoryLocalReviewState(state.document.review, activeStory)
|
|
3206
|
-
},
|
|
3207
|
-
compatibility: state.compatibility,
|
|
3208
|
-
warnings: state.warnings,
|
|
3209
|
-
fatalError: state.fatalError
|
|
3210
|
-
});
|
|
3211
|
-
localState.selection = selection;
|
|
3212
|
-
const localTransaction = executeEditorCommand(localState, command, context);
|
|
3213
|
-
if (!localTransaction.markDirty) {
|
|
3214
|
-
notify(state, state, {
|
|
3215
|
-
nextState: state,
|
|
3216
|
-
mapping: createEmptyMapping(),
|
|
3217
|
-
effects: localTransaction.effects,
|
|
3218
|
-
historyBoundary: "skip",
|
|
3219
|
-
markDirty: false
|
|
3220
|
-
});
|
|
3221
|
-
return;
|
|
3222
|
-
}
|
|
3223
|
-
const nextDocument = replaceStoryBlocks(
|
|
3224
|
-
state.document,
|
|
3225
|
-
activeStory,
|
|
3226
|
-
localTransaction.nextState.document.content.children
|
|
3227
|
-
);
|
|
3228
|
-
const nextDocumentWithReview = {
|
|
3229
|
-
...nextDocument,
|
|
3230
|
-
review: mergeSecondaryStoryReviewState(
|
|
3231
|
-
state.document.review,
|
|
3232
|
-
localTransaction.nextState.document.review,
|
|
3233
|
-
localTransaction.effects,
|
|
3234
|
-
activeStory
|
|
3235
|
-
)
|
|
3236
|
-
};
|
|
3237
|
-
const fullTransaction = executeEditorCommand(
|
|
3238
|
-
baseState,
|
|
3239
|
-
{
|
|
3240
|
-
type: "document.replace",
|
|
3241
|
-
document: nextDocumentWithReview,
|
|
3242
|
-
selection: localTransaction.nextState.selection,
|
|
3243
|
-
mapping: createEmptyMapping(),
|
|
3244
|
-
protectionSelection: selection,
|
|
3245
|
-
origin: command.origin
|
|
3246
|
-
},
|
|
3247
|
-
context
|
|
3248
|
-
);
|
|
3249
|
-
commit({
|
|
3250
|
-
...fullTransaction,
|
|
3251
|
-
effects: mergeTransactionEffects(fullTransaction.effects, localTransaction.effects)
|
|
3252
|
-
});
|
|
3253
|
-
}
|
|
3254
|
-
function mergeTransactionEffects(base, local) {
|
|
3255
|
-
return {
|
|
3256
|
-
warningsAdded: [...base.warningsAdded, ...local.warningsAdded],
|
|
3257
|
-
warningsCleared: [...base.warningsCleared, ...local.warningsCleared],
|
|
3258
|
-
commentAdded: base.commentAdded ?? local.commentAdded,
|
|
3259
|
-
commentResolved: base.commentResolved ?? local.commentResolved,
|
|
3260
|
-
commentReopened: base.commentReopened ?? local.commentReopened,
|
|
3261
|
-
commentReplyAdded: base.commentReplyAdded ?? local.commentReplyAdded,
|
|
3262
|
-
commentBodyEdited: base.commentBodyEdited ?? local.commentBodyEdited,
|
|
3263
|
-
changeAccepted: base.changeAccepted ?? local.changeAccepted,
|
|
3264
|
-
changeRejected: base.changeRejected ?? local.changeRejected,
|
|
3265
|
-
revisionAuthored: base.revisionAuthored ?? local.revisionAuthored,
|
|
3266
|
-
commandBlocked: base.commandBlocked ?? local.commandBlocked
|
|
3267
|
-
};
|
|
3268
|
-
}
|
|
3269
|
-
function mergeSecondaryStoryReviewState(currentReview, localReview, effects, storyTarget) {
|
|
3270
|
-
const nextReview = {
|
|
3271
|
-
comments: { ...currentReview.comments },
|
|
3272
|
-
revisions: { ...currentReview.revisions }
|
|
3273
|
-
};
|
|
3274
|
-
const currentStoryRevisionIds = Object.values(currentReview.revisions).filter((revision) => storyTargetsEqual(getRevisionStoryTarget(revision), storyTarget)).map((revision) => revision.changeId);
|
|
3275
|
-
for (const revisionId of currentStoryRevisionIds) {
|
|
3276
|
-
delete nextReview.revisions[revisionId];
|
|
3277
|
-
}
|
|
3278
|
-
for (const revision of Object.values(localReview.revisions)) {
|
|
3279
|
-
nextReview.revisions[revision.changeId] = {
|
|
3280
|
-
...revision,
|
|
3281
|
-
metadata: {
|
|
3282
|
-
...revision.metadata,
|
|
3283
|
-
storyTarget: createRevisionStoryTargetRecord(storyTarget)
|
|
3284
|
-
}
|
|
3285
|
-
};
|
|
3286
|
-
}
|
|
3287
|
-
if (effects.commentAdded) {
|
|
3288
|
-
const commentId = effects.commentAdded.commentId;
|
|
3289
|
-
const comment = localReview.comments[commentId];
|
|
3290
|
-
if (comment) {
|
|
3291
|
-
nextReview.comments[commentId] = comment;
|
|
3292
|
-
}
|
|
3293
|
-
}
|
|
3294
|
-
return nextReview;
|
|
3295
|
-
}
|
|
3296
|
-
function emit(event) {
|
|
3297
|
-
options.onEvent?.(event);
|
|
3298
|
-
for (const listener of eventListeners) {
|
|
3299
|
-
listener(event);
|
|
3300
|
-
}
|
|
3301
|
-
}
|
|
3302
|
-
function emitError(error) {
|
|
3303
|
-
const nextState = {
|
|
3304
|
-
...state,
|
|
3305
|
-
phase: error.isFatal ? "error" : state.phase,
|
|
3306
|
-
fatalError: error.isFatal ? error : state.fatalError
|
|
3307
|
-
};
|
|
3308
|
-
state = nextState;
|
|
3309
|
-
storySelections.set(storyTargetKey(activeStory), state.selection);
|
|
3310
|
-
cachedRenderSnapshot = refreshRenderSnapshot();
|
|
3311
|
-
const publicError = toPublicError(error);
|
|
3312
|
-
options.onError?.(publicError);
|
|
3313
|
-
emit({
|
|
3314
|
-
type: "error",
|
|
3315
|
-
documentId: state.documentId,
|
|
3316
|
-
error: publicError
|
|
3317
|
-
});
|
|
3318
|
-
for (const listener of listeners) {
|
|
3319
|
-
listener();
|
|
3320
|
-
}
|
|
3321
|
-
}
|
|
3322
|
-
function switchActiveStory(target) {
|
|
3323
|
-
const previousStory = activeStory;
|
|
3324
|
-
const previousSelection = state.selection;
|
|
3325
|
-
storySelections.set(storyTargetKey(previousStory), previousSelection);
|
|
3326
|
-
const restoredSelection = storySelections.get(storyTargetKey(target)) ?? createSelectionSnapshot(0, 0);
|
|
3327
|
-
activeStory = target;
|
|
3328
|
-
state = {
|
|
3329
|
-
...state,
|
|
3330
|
-
selection: restoredSelection
|
|
3331
|
-
};
|
|
3332
|
-
storySelections.set(storyTargetKey(target), restoredSelection);
|
|
3333
|
-
cachedRenderSnapshot = refreshRenderSnapshot();
|
|
3334
|
-
if (selectionChanged(previousSelection, restoredSelection)) {
|
|
3335
|
-
emit({
|
|
3336
|
-
type: "selection_changed",
|
|
3337
|
-
documentId: state.documentId,
|
|
3338
|
-
selection: toPublicSelectionSnapshot(restoredSelection, activeStory)
|
|
3339
|
-
});
|
|
3340
|
-
}
|
|
3341
|
-
emit({
|
|
3342
|
-
type: "story_changed",
|
|
3343
|
-
documentId: state.documentId,
|
|
3344
|
-
activeStory
|
|
3345
|
-
});
|
|
3346
|
-
for (const listener of listeners) {
|
|
3347
|
-
listener();
|
|
3348
|
-
}
|
|
3349
|
-
}
|
|
3350
|
-
}
|
|
3351
|
-
function createSessionId(documentId, timestamp) {
|
|
3352
|
-
return `session-${documentId}-${timestamp.replace(/[^0-9]/gu, "")}`;
|
|
3353
|
-
}
|
|
3354
|
-
function createOrigin(source, timestamp) {
|
|
3355
|
-
return {
|
|
3356
|
-
source,
|
|
3357
|
-
timestamp
|
|
3358
|
-
};
|
|
3359
|
-
}
|
|
3360
|
-
function createEntityId(prefix, existing, timestamp) {
|
|
3361
|
-
let counter = Object.keys(existing).length;
|
|
3362
|
-
let nextId = `${prefix}-${timestamp.replace(/[^0-9]/gu, "")}-${counter}`;
|
|
3363
|
-
while (existing[nextId]) {
|
|
3364
|
-
counter += 1;
|
|
3365
|
-
nextId = `${prefix}-${timestamp.replace(/[^0-9]/gu, "")}-${counter}`;
|
|
3366
|
-
}
|
|
3367
|
-
return nextId;
|
|
3368
|
-
}
|
|
3369
|
-
function finalizeState(state, markDirty, timestamp, baseRevision) {
|
|
3370
|
-
const revision = markDirty ? (baseRevision ?? state.revision) + 1 : state.revision;
|
|
3371
|
-
return {
|
|
3372
|
-
...state,
|
|
3373
|
-
document: {
|
|
3374
|
-
...state.document,
|
|
3375
|
-
updatedAt: markDirty ? timestamp : state.document.updatedAt
|
|
3376
|
-
},
|
|
3377
|
-
selection: state.selection,
|
|
3378
|
-
revision,
|
|
3379
|
-
revisionToken: `${state.sessionId}:${revision}`,
|
|
3380
|
-
isDirty: state.isDirty || markDirty
|
|
3381
|
-
};
|
|
3382
|
-
}
|
|
3383
|
-
function toRuntimeError(error) {
|
|
3384
|
-
if (typeof error === "object" && error && "message" in error) {
|
|
3385
|
-
return {
|
|
3386
|
-
errorId: createSessionId("runtime-error", (/* @__PURE__ */ new Date()).toISOString()),
|
|
3387
|
-
code: "internal_invariant",
|
|
3388
|
-
isFatal: false,
|
|
3389
|
-
message: String(error.message ?? "Runtime error"),
|
|
3390
|
-
source: "runtime"
|
|
3391
|
-
};
|
|
3392
|
-
}
|
|
3393
|
-
return {
|
|
3394
|
-
errorId: createSessionId("runtime-error", (/* @__PURE__ */ new Date()).toISOString()),
|
|
3395
|
-
code: "internal_invariant",
|
|
3396
|
-
isFatal: false,
|
|
3397
|
-
message: "Runtime error",
|
|
3398
|
-
source: "runtime"
|
|
3399
|
-
};
|
|
3400
|
-
}
|
|
3401
|
-
function toPublicDocumentStats(state) {
|
|
3402
|
-
const stats = deriveDocumentStats(state);
|
|
3403
|
-
return {
|
|
3404
|
-
storyLength: stats.characterCount,
|
|
3405
|
-
commentCount: stats.commentCount,
|
|
3406
|
-
revisionCount: stats.revisionCount,
|
|
3407
|
-
opaqueFragmentCount: countOpaqueFragments(state.document.preservation.opaqueFragments)
|
|
3408
|
-
};
|
|
3409
|
-
}
|
|
3410
|
-
function toPublicSelectionSnapshot(selection, storyTarget) {
|
|
3411
|
-
return {
|
|
3412
|
-
anchor: selection.anchor,
|
|
3413
|
-
head: selection.head,
|
|
3414
|
-
isCollapsed: selection.isCollapsed,
|
|
3415
|
-
activeRange: toPublicAnchorProjection(selection.activeRange),
|
|
3416
|
-
...storyTarget && storyTarget.kind !== "main" ? { storyTarget } : {}
|
|
3417
|
-
};
|
|
3418
|
-
}
|
|
3419
|
-
function toPublicAnchorProjection(anchor) {
|
|
3420
|
-
switch (anchor.kind) {
|
|
3421
|
-
case "range":
|
|
3422
|
-
return {
|
|
3423
|
-
kind: "range",
|
|
3424
|
-
from: anchor.range.from,
|
|
3425
|
-
to: anchor.range.to,
|
|
3426
|
-
assoc: anchor.assoc
|
|
3427
|
-
};
|
|
3428
|
-
case "node":
|
|
3429
|
-
return {
|
|
3430
|
-
kind: "node",
|
|
3431
|
-
at: anchor.at,
|
|
3432
|
-
assoc: anchor.assoc
|
|
3433
|
-
};
|
|
3434
|
-
case "detached":
|
|
3435
|
-
return {
|
|
3436
|
-
kind: "detached",
|
|
3437
|
-
lastKnownRange: anchor.lastKnownRange,
|
|
3438
|
-
reason: anchor.reason
|
|
3439
|
-
};
|
|
3440
|
-
}
|
|
3441
|
-
}
|
|
3442
|
-
function toInternalAnchorProjection(anchor) {
|
|
3443
|
-
switch (anchor.kind) {
|
|
3444
|
-
case "range":
|
|
3445
|
-
return createRangeAnchor(anchor.from, anchor.to, anchor.assoc);
|
|
3446
|
-
case "node":
|
|
3447
|
-
return createNodeAnchor(anchor.at, anchor.assoc);
|
|
3448
|
-
case "detached":
|
|
3449
|
-
return createDetachedAnchor(anchor.lastKnownRange, anchor.reason);
|
|
3450
|
-
}
|
|
3451
|
-
}
|
|
3452
|
-
function createSelectionFromPublicAnchor(anchor) {
|
|
3453
|
-
switch (anchor.kind) {
|
|
3454
|
-
case "range":
|
|
3455
|
-
return createSelectionSnapshot(anchor.from, anchor.to);
|
|
3456
|
-
case "node":
|
|
3457
|
-
return createSelectionSnapshot(anchor.at, anchor.at);
|
|
3458
|
-
case "detached":
|
|
3459
|
-
return createSelectionSnapshot(
|
|
3460
|
-
anchor.lastKnownRange.from,
|
|
3461
|
-
anchor.lastKnownRange.to
|
|
3462
|
-
);
|
|
3463
|
-
}
|
|
3464
|
-
}
|
|
3465
|
-
function toPublicCompatibilityReport(report) {
|
|
3466
|
-
return {
|
|
3467
|
-
reportVersion: report.reportVersion,
|
|
3468
|
-
generatedAt: report.generatedAt,
|
|
3469
|
-
blockExport: report.blockExport,
|
|
3470
|
-
featureEntries: report.featureEntries.map(
|
|
3471
|
-
(entry) => toPublicCompatibilityFeatureEntry(entry)
|
|
3472
|
-
),
|
|
3473
|
-
warnings: report.warnings.map((warning) => toPublicWarning(warning)),
|
|
3474
|
-
errors: report.errors.map((error) => toPublicError(error))
|
|
3475
|
-
};
|
|
3476
|
-
}
|
|
3477
|
-
function toPublicCompatibilityFeatureEntry(entry) {
|
|
3478
|
-
return {
|
|
3479
|
-
...entry,
|
|
3480
|
-
affectedAnchor: entry.affectedAnchor ? toPublicAnchorProjection(entry.affectedAnchor) : void 0
|
|
3481
|
-
};
|
|
3482
|
-
}
|
|
3483
|
-
function toPublicWarning(warning) {
|
|
3484
|
-
return {
|
|
3485
|
-
...warning,
|
|
3486
|
-
affectedAnchor: warning.affectedAnchor ? toPublicAnchorProjection(warning.affectedAnchor) : void 0
|
|
3487
|
-
};
|
|
3488
|
-
}
|
|
3489
|
-
function toPublicError(error) {
|
|
3490
|
-
return { ...error };
|
|
3491
|
-
}
|
|
3492
|
-
function countOpaqueFragments(opaqueFragments) {
|
|
3493
|
-
return Object.keys(opaqueFragments).length;
|
|
3494
|
-
}
|
|
3495
|
-
function createDerivedCompatibility(state) {
|
|
3496
|
-
const derived = buildCompatibilityReport({
|
|
3497
|
-
document: state.document,
|
|
3498
|
-
warnings: state.warnings,
|
|
3499
|
-
fatalError: state.fatalError,
|
|
3500
|
-
generatedAt: state.document.updatedAt
|
|
3501
|
-
});
|
|
3502
|
-
return mergeCompatibilityReports([state.compatibility, derived], {
|
|
3503
|
-
generatedAt: state.document.updatedAt,
|
|
3504
|
-
blockExport: state.compatibility.blockExport || derived.blockExport
|
|
3505
|
-
});
|
|
3506
|
-
}
|
|
3507
|
-
function toPublicCommentSidebarSnapshot(state) {
|
|
3508
|
-
const projection = createCommentSidebarProjection(
|
|
3509
|
-
createCommentStoreFromRuntimeComments(state.document.review.comments),
|
|
3510
|
-
state.runtime.activeCommentId
|
|
3511
|
-
);
|
|
3512
|
-
return {
|
|
3513
|
-
activeCommentId: state.runtime.activeCommentId,
|
|
3514
|
-
openCommentIds: projection.openCommentIds,
|
|
3515
|
-
resolvedCommentIds: projection.resolvedCommentIds,
|
|
3516
|
-
detachedCommentIds: projection.detachedCommentIds,
|
|
3517
|
-
totalCount: projection.totalCount,
|
|
3518
|
-
threads: projection.threads.map((thread) => {
|
|
3519
|
-
const sourceThread = state.document.review.comments[thread.commentId];
|
|
3520
|
-
const projectedEntries = sourceThread?.entries?.map((entry) => ({
|
|
3521
|
-
entryId: entry.entryId,
|
|
3522
|
-
authorId: entry.authorId,
|
|
3523
|
-
body: entry.body,
|
|
3524
|
-
createdAt: entry.createdAt
|
|
3525
|
-
})) ?? (sourceThread?.body ? [
|
|
3526
|
-
{
|
|
3527
|
-
entryId: `${thread.commentId}-entry-1`,
|
|
3528
|
-
authorId: sourceThread.authorId ?? sourceThread.createdBy ?? "unknown",
|
|
3529
|
-
body: sourceThread.body,
|
|
3530
|
-
createdAt: sourceThread.createdAt
|
|
3531
|
-
}
|
|
3532
|
-
] : []);
|
|
3533
|
-
return {
|
|
3534
|
-
commentId: thread.commentId,
|
|
3535
|
-
status: thread.status,
|
|
3536
|
-
anchor: toPublicAnchorProjection(
|
|
3537
|
-
sourceThread?.anchor ?? createDetachedAnchor({ from: 0, to: 0 }, "importAmbiguity")
|
|
3538
|
-
),
|
|
3539
|
-
excerpt: thread.excerpt,
|
|
3540
|
-
entryCount: thread.entryCount,
|
|
3541
|
-
createdAt: thread.createdAt,
|
|
3542
|
-
createdBy: thread.createdBy,
|
|
3543
|
-
warningCount: thread.warningCount,
|
|
3544
|
-
anchorLabel: thread.anchorLabel,
|
|
3545
|
-
isActive: thread.isActive,
|
|
3546
|
-
resolvedAt: thread.resolvedAt,
|
|
3547
|
-
resolvedBy: thread.resolvedBy,
|
|
3548
|
-
entries: projectedEntries
|
|
3549
|
-
};
|
|
3550
|
-
})
|
|
3551
|
-
};
|
|
3552
|
-
}
|
|
3553
|
-
function toPublicTrackedChangesSnapshot(state) {
|
|
3554
|
-
const projection = createRevisionSidebarProjection(
|
|
3555
|
-
createRevisionStoreFromDocument(state)
|
|
3556
|
-
);
|
|
3557
|
-
const storyPlainTextCache = /* @__PURE__ */ new Map();
|
|
3558
|
-
return {
|
|
3559
|
-
pendingChangeIds: projection.activeRevisionIds,
|
|
3560
|
-
acceptedChangeIds: projection.acceptedRevisionIds,
|
|
3561
|
-
rejectedChangeIds: projection.rejectedRevisionIds,
|
|
3562
|
-
detachedChangeIds: projection.detachedRevisionIds,
|
|
3563
|
-
actionableChangeIds: projection.actionableRevisionIds,
|
|
3564
|
-
preserveOnlyChangeIds: projection.preserveOnlyRevisionIds,
|
|
3565
|
-
totalCount: projection.totalCount,
|
|
3566
|
-
revisions: projection.revisions.map((revision) => {
|
|
3567
|
-
const sourceRevision = state.document.review.revisions[revision.revisionId];
|
|
3568
|
-
const storyTarget = getRevisionStoryTarget(sourceRevision);
|
|
3569
|
-
const preview = describeRevisionPreview(
|
|
3570
|
-
revision,
|
|
3571
|
-
sourceRevision?.anchor ?? createDetachedAnchor({ from: 0, to: 0 }, "importAmbiguity"),
|
|
3572
|
-
getStoryPlainText(state.document, storyTarget, storyPlainTextCache)
|
|
3573
|
-
);
|
|
3574
|
-
return {
|
|
3575
|
-
revisionId: revision.revisionId,
|
|
3576
|
-
kind: revision.kind,
|
|
3577
|
-
label: revision.label,
|
|
3578
|
-
status: revision.status,
|
|
3579
|
-
actionability: revision.actionability,
|
|
3580
|
-
storyTarget,
|
|
3581
|
-
anchor: toPublicAnchorProjection(
|
|
3582
|
-
sourceRevision?.anchor ?? createDetachedAnchor({ from: 0, to: 0 }, "importAmbiguity")
|
|
3583
|
-
),
|
|
3584
|
-
anchorLabel: revision.anchorLabel,
|
|
3585
|
-
createdAt: revision.createdAt,
|
|
3586
|
-
authorId: revision.authorId,
|
|
3587
|
-
warningCount: revision.warningCount,
|
|
3588
|
-
canAccept: revision.canAccept,
|
|
3589
|
-
canReject: revision.canReject,
|
|
3590
|
-
importedRevisionForm: sourceRevision?.metadata?.importedRevisionForm,
|
|
3591
|
-
preserveOnlyReason: revision.preserveOnlyReason,
|
|
3592
|
-
excerpt: preview.excerpt,
|
|
3593
|
-
detail: preview.detail
|
|
3594
|
-
};
|
|
3595
|
-
})
|
|
3596
|
-
};
|
|
3597
|
-
}
|
|
3598
|
-
function createRevisionStoreFromDocument(state) {
|
|
3599
|
-
return {
|
|
3600
|
-
version: "revision-store/1",
|
|
3601
|
-
revisions: Object.fromEntries(
|
|
3602
|
-
Object.values(state.document.review.revisions).map((revision) => [
|
|
3603
|
-
revision.changeId,
|
|
3604
|
-
{
|
|
3605
|
-
revisionId: revision.changeId,
|
|
3606
|
-
kind: revision.kind,
|
|
3607
|
-
anchor: revision.anchor,
|
|
3608
|
-
authorId: revision.authorId ?? "unknown",
|
|
3609
|
-
createdAt: revision.createdAt,
|
|
3610
|
-
status: revision.status === "open" ? "active" : revision.status,
|
|
3611
|
-
warningIds: [...revision.warningIds ?? []],
|
|
3612
|
-
metadata: {
|
|
3613
|
-
source: revision.metadata?.source ?? "runtime",
|
|
3614
|
-
storyTarget: revision.metadata?.storyTarget,
|
|
3615
|
-
preserveOnlyReason: revision.metadata?.preserveOnlyReason,
|
|
3616
|
-
importedRevisionForm: revision.metadata?.importedRevisionForm,
|
|
3617
|
-
originalRevisionType: revision.metadata?.originalRevisionType,
|
|
3618
|
-
ooxmlRevisionId: revision.metadata?.ooxmlRevisionId
|
|
3619
|
-
}
|
|
3620
|
-
}
|
|
3621
|
-
])
|
|
3622
|
-
)
|
|
3623
|
-
};
|
|
3624
|
-
}
|
|
3625
|
-
function getRevisionStoryTarget(revision) {
|
|
3626
|
-
const storyTarget = revision?.metadata?.storyTarget;
|
|
3627
|
-
return storyTarget ? { ...storyTarget } : MAIN_STORY_TARGET;
|
|
3628
|
-
}
|
|
3629
|
-
function createSecondaryStoryLocalReviewState(review, storyTarget) {
|
|
3630
|
-
return {
|
|
3631
|
-
comments: {},
|
|
3632
|
-
revisions: Object.fromEntries(
|
|
3633
|
-
Object.values(review.revisions).filter((revision) => storyTargetsEqual(getRevisionStoryTarget(revision), storyTarget)).map((revision) => [
|
|
3634
|
-
revision.changeId,
|
|
3635
|
-
{
|
|
3636
|
-
...revision,
|
|
3637
|
-
metadata: {
|
|
3638
|
-
...revision.metadata,
|
|
3639
|
-
storyTarget: createRevisionStoryTargetRecord(storyTarget)
|
|
3640
|
-
}
|
|
3641
|
-
}
|
|
3642
|
-
])
|
|
3643
|
-
)
|
|
3644
|
-
};
|
|
3645
|
-
}
|
|
3646
|
-
function getStoryPlainText(document, storyTarget, cache) {
|
|
3647
|
-
const key = storyTargetKey(storyTarget);
|
|
3648
|
-
const cached = cache.get(key);
|
|
3649
|
-
if (cached !== void 0) {
|
|
3650
|
-
return cached;
|
|
3651
|
-
}
|
|
3652
|
-
const plainText = createEditorSurfaceSnapshot(
|
|
3653
|
-
document,
|
|
3654
|
-
createSelectionSnapshot(0, 0),
|
|
3655
|
-
storyTarget
|
|
3656
|
-
).plainText;
|
|
3657
|
-
cache.set(key, plainText);
|
|
3658
|
-
return plainText;
|
|
3659
|
-
}
|
|
3660
|
-
function createRevisionStoryTargetRecord(storyTarget) {
|
|
3661
|
-
return { ...storyTarget };
|
|
3662
|
-
}
|
|
3663
|
-
function listBlockExportReasons(report) {
|
|
3664
|
-
return [
|
|
3665
|
-
...report.featureEntries.filter((entry) => entry.featureClass === "unsupported-fatal").map((entry) => entry.message),
|
|
3666
|
-
...report.errors.filter((error) => error.isFatal).map((error) => error.message)
|
|
3667
|
-
];
|
|
3668
|
-
}
|
|
3669
|
-
function describeRevisionPreview(revision, anchor, plainText) {
|
|
3670
|
-
const { from, to } = toAnchorBounds(anchor);
|
|
3671
|
-
const excerpt = summarizeRevisionExcerpt(plainText, from, to, revision.label);
|
|
3672
|
-
if (revision.actionability === "preserve-only") {
|
|
3673
|
-
return {
|
|
3674
|
-
excerpt,
|
|
3675
|
-
detail: revision.preserveOnlyReason ?? "Visible for review, but this change remains preserve-only in the current runtime."
|
|
3676
|
-
};
|
|
3677
|
-
}
|
|
3678
|
-
if (revision.status === "accepted") {
|
|
3679
|
-
return {
|
|
3680
|
-
excerpt,
|
|
3681
|
-
detail: "Accepted in the live review runtime and retained here for audit visibility."
|
|
3682
|
-
};
|
|
3683
|
-
}
|
|
3684
|
-
if (revision.status === "rejected") {
|
|
3685
|
-
return {
|
|
3686
|
-
excerpt,
|
|
3687
|
-
detail: "Rejected in the live review runtime and retained here for audit visibility."
|
|
3688
|
-
};
|
|
3689
|
-
}
|
|
3690
|
-
return {
|
|
3691
|
-
excerpt,
|
|
3692
|
-
detail: revision.kind === "deletion" ? "Deleted content stays reviewable here until it is accepted or rejected." : "Runtime-backed change. Review it here or reopen the anchor in the canvas."
|
|
3693
|
-
};
|
|
3694
|
-
}
|
|
3695
|
-
function toAnchorBounds(anchor) {
|
|
3696
|
-
switch (anchor.kind) {
|
|
3697
|
-
case "range":
|
|
3698
|
-
return {
|
|
3699
|
-
from: Math.min(anchor.range.from, anchor.range.to),
|
|
3700
|
-
to: Math.max(anchor.range.from, anchor.range.to)
|
|
3701
|
-
};
|
|
3702
|
-
case "node":
|
|
3703
|
-
return {
|
|
3704
|
-
from: anchor.at,
|
|
3705
|
-
to: anchor.at + 1
|
|
3706
|
-
};
|
|
3707
|
-
case "detached":
|
|
3708
|
-
return {
|
|
3709
|
-
from: Math.min(anchor.lastKnownRange.from, anchor.lastKnownRange.to),
|
|
3710
|
-
to: Math.max(anchor.lastKnownRange.from, anchor.lastKnownRange.to)
|
|
3711
|
-
};
|
|
3712
|
-
}
|
|
3713
|
-
}
|
|
3714
|
-
function summarizeRevisionExcerpt(plainText, from, to, fallback) {
|
|
3715
|
-
const normalizedFrom = Math.max(0, Math.min(from, plainText.length));
|
|
3716
|
-
const normalizedTo = Math.max(normalizedFrom, Math.min(to, plainText.length));
|
|
3717
|
-
const collapsed = plainText.slice(normalizedFrom, normalizedTo).replace(/\s+/g, " ").trim();
|
|
3718
|
-
if (!collapsed) {
|
|
3719
|
-
return fallback;
|
|
3720
|
-
}
|
|
3721
|
-
return collapsed.length > 96 ? `${collapsed.slice(0, 93)}...` : collapsed;
|
|
3722
|
-
}
|
|
3723
|
-
function isValidStoryTarget(state, target) {
|
|
3724
|
-
if (target.kind === "main") return true;
|
|
3725
|
-
const subParts = state.document.subParts;
|
|
3726
|
-
if (!subParts) return false;
|
|
3727
|
-
switch (target.kind) {
|
|
3728
|
-
case "header":
|
|
3729
|
-
return Boolean(normalizeHeaderFooterTarget(state.document, target));
|
|
3730
|
-
case "footer":
|
|
3731
|
-
return Boolean(normalizeHeaderFooterTarget(state.document, target));
|
|
3732
|
-
case "footnote":
|
|
3733
|
-
return Boolean(subParts.footnoteCollection?.footnotes?.[target.noteId]);
|
|
3734
|
-
case "endnote":
|
|
3735
|
-
return Boolean(subParts.footnoteCollection?.endnotes?.[target.noteId]);
|
|
3736
|
-
}
|
|
3737
|
-
}
|
|
3738
|
-
function derivePageLayoutSnapshot(state, activeStory, storySelections) {
|
|
3739
|
-
const subParts = state.document.subParts;
|
|
3740
|
-
const sections = buildResolvedSections(state.document);
|
|
3741
|
-
if (!subParts && sections.length === 0) {
|
|
3742
|
-
return null;
|
|
3743
|
-
}
|
|
3744
|
-
const activeSection = resolveActiveSection(
|
|
3745
|
-
state,
|
|
3746
|
-
activeStory,
|
|
3747
|
-
sections,
|
|
3748
|
-
storySelections
|
|
3749
|
-
);
|
|
3750
|
-
return buildPageLayoutSnapshot(
|
|
3751
|
-
activeSection?.index ?? 0,
|
|
3752
|
-
activeSection?.properties ?? subParts?.finalSectionProperties,
|
|
3753
|
-
subParts
|
|
3754
|
-
);
|
|
3755
|
-
}
|
|
3756
|
-
var NON_MUTATION_COMMANDS = /* @__PURE__ */ new Set([
|
|
3757
|
-
"selection.set",
|
|
3758
|
-
"runtime.set-read-only",
|
|
3759
|
-
"runtime.focus",
|
|
3760
|
-
"warning.add",
|
|
3761
|
-
"warning.clear",
|
|
3762
|
-
"comment.open"
|
|
3763
|
-
]);
|
|
3764
|
-
var SUGGESTING_UNSUPPORTED_COMMANDS = /* @__PURE__ */ new Set([
|
|
3765
|
-
"paragraph.split"
|
|
3766
|
-
]);
|
|
3767
|
-
var SUGGESTING_SECONDARY_STORY_UNSUPPORTED_COMMANDS = /* @__PURE__ */ new Set([
|
|
3768
|
-
"text.insert",
|
|
3769
|
-
"text.delete-backward",
|
|
3770
|
-
"text.delete-forward",
|
|
3771
|
-
"text.insert-tab",
|
|
3772
|
-
"text.insert-hard-break"
|
|
3773
|
-
]);
|
|
3774
|
-
function isMutationCommand(command) {
|
|
3775
|
-
return !NON_MUTATION_COMMANDS.has(command.type);
|
|
3776
|
-
}
|
|
3777
|
-
function buildFieldSnapshot(document) {
|
|
3778
|
-
const entries = [];
|
|
3779
|
-
let index = 0;
|
|
3780
|
-
for (const block of document.content.children) {
|
|
3781
|
-
index = collectFieldsFromBlock(block, entries, index);
|
|
3782
|
-
}
|
|
3783
|
-
index = collectFieldsFromSubParts(document.subParts, entries, index);
|
|
3784
|
-
const supportedCount = entries.filter((e) => e.supported).length;
|
|
3785
|
-
return {
|
|
3786
|
-
totalCount: entries.length,
|
|
3787
|
-
supportedCount,
|
|
3788
|
-
preserveOnlyCount: entries.length - supportedCount,
|
|
3789
|
-
fields: entries
|
|
3790
|
-
};
|
|
3791
|
-
}
|
|
3792
|
-
function collectFieldsFromBlock(block, entries, index) {
|
|
3793
|
-
if (block.type === "paragraph") {
|
|
3794
|
-
for (const child of block.children) {
|
|
3795
|
-
index = collectFieldsFromInline(child, entries, index);
|
|
3796
|
-
}
|
|
3797
|
-
} else if (block.type === "table") {
|
|
3798
|
-
for (const row of block.rows) {
|
|
3799
|
-
for (const cell of row.cells) {
|
|
3800
|
-
for (const child of cell.children) {
|
|
3801
|
-
index = collectFieldsFromBlock(child, entries, index);
|
|
3802
|
-
}
|
|
3803
|
-
}
|
|
3804
|
-
}
|
|
3805
|
-
} else if (block.type === "sdt" || block.type === "custom_xml") {
|
|
3806
|
-
for (const child of block.children) {
|
|
3807
|
-
index = collectFieldsFromBlock(child, entries, index);
|
|
3808
|
-
}
|
|
3809
|
-
}
|
|
3810
|
-
return index;
|
|
3811
|
-
}
|
|
3812
|
-
function collectFieldsFromInline(node, entries, index) {
|
|
3813
|
-
if (node.type === "field") {
|
|
3814
|
-
const fieldFamily = node.fieldFamily ?? "UNKNOWN";
|
|
3815
|
-
const supported = isSupportedFieldFamily(fieldFamily);
|
|
3816
|
-
const displayText = extractFieldDisplayText(node);
|
|
3817
|
-
entries.push({
|
|
3818
|
-
index,
|
|
3819
|
-
fieldFamily,
|
|
3820
|
-
supported,
|
|
3821
|
-
instruction: node.instruction,
|
|
3822
|
-
fieldTarget: node.fieldTarget,
|
|
3823
|
-
refreshStatus: node.refreshStatus ?? (supported ? "stale" : "preserve-only"),
|
|
3824
|
-
displayText
|
|
3825
|
-
});
|
|
3826
|
-
index++;
|
|
3827
|
-
for (const child of node.children) {
|
|
3828
|
-
index = collectFieldsFromInline(child, entries, index);
|
|
3829
|
-
}
|
|
3830
|
-
} else if (node.type === "hyperlink") {
|
|
3831
|
-
for (const child of node.children) {
|
|
3832
|
-
index = collectFieldsFromInline(child, entries, index);
|
|
3833
|
-
}
|
|
3834
|
-
}
|
|
3835
|
-
return index;
|
|
3836
|
-
}
|
|
3837
|
-
function extractFieldDisplayText(field) {
|
|
3838
|
-
return flattenInlineDisplayText(field.children);
|
|
3839
|
-
}
|
|
3840
|
-
function flattenInlineDisplayText(children) {
|
|
3841
|
-
return children.map((child) => {
|
|
3842
|
-
switch (child.type) {
|
|
3843
|
-
case "text":
|
|
3844
|
-
return child.text;
|
|
3845
|
-
case "tab":
|
|
3846
|
-
return " ";
|
|
3847
|
-
case "hard_break":
|
|
3848
|
-
case "column_break":
|
|
3849
|
-
return "\n";
|
|
3850
|
-
case "hyperlink":
|
|
3851
|
-
case "field":
|
|
3852
|
-
return flattenInlineDisplayText(child.children);
|
|
3853
|
-
case "footnote_ref":
|
|
3854
|
-
return child.noteId;
|
|
3855
|
-
default:
|
|
3856
|
-
return "";
|
|
3857
|
-
}
|
|
3858
|
-
}).join("");
|
|
3859
|
-
}
|
|
3860
|
-
function refreshDocumentFields(document, selectionHead, activeStory, options) {
|
|
3861
|
-
const supportedOnly = options?.supportedOnly ?? true;
|
|
3862
|
-
const bookmarkMap = buildBookmarkNameMap(document);
|
|
3863
|
-
const paragraphs = collectParagraphContexts(document.content.children);
|
|
3864
|
-
const navigation = createDocumentNavigationSnapshot(document, selectionHead, activeStory);
|
|
3865
|
-
let updatedCount = 0;
|
|
3866
|
-
let changed = false;
|
|
3867
|
-
let changedFrom;
|
|
3868
|
-
let changedTo;
|
|
3869
|
-
const nextChildren = refreshBlocksWithCursor(document.content.children, (field, range) => {
|
|
3870
|
-
if (!field.fieldFamily || !isSupportedFieldFamily(field.fieldFamily)) {
|
|
3871
|
-
return field;
|
|
3872
|
-
}
|
|
3873
|
-
if (supportedOnly && field.fieldFamily === "TOC") {
|
|
3874
|
-
return field;
|
|
3875
|
-
}
|
|
3876
|
-
const display = resolveSupportedFieldDisplay(
|
|
3877
|
-
field,
|
|
3878
|
-
document,
|
|
3879
|
-
bookmarkMap,
|
|
3880
|
-
paragraphs,
|
|
3881
|
-
navigation
|
|
3882
|
-
);
|
|
3883
|
-
if (!display) {
|
|
3884
|
-
return field;
|
|
3885
|
-
}
|
|
3886
|
-
updatedCount += 1;
|
|
3887
|
-
const nextField = {
|
|
3888
|
-
...field,
|
|
3889
|
-
children: buildInlineNodesFromDisplayText(display.displayText),
|
|
3890
|
-
refreshStatus: display.refreshStatus
|
|
3891
|
-
};
|
|
3892
|
-
if (nextField.refreshStatus !== field.refreshStatus || flattenInlineDisplayText(nextField.children) !== flattenInlineDisplayText(field.children)) {
|
|
3893
|
-
changed = true;
|
|
3894
|
-
changedFrom = changedFrom === void 0 ? range.from : Math.min(changedFrom, range.from);
|
|
3895
|
-
changedTo = changedTo === void 0 ? range.to : Math.max(changedTo, range.to);
|
|
3896
|
-
}
|
|
3897
|
-
return nextField;
|
|
3898
|
-
}).blocks;
|
|
3899
|
-
if (!changed) {
|
|
3900
|
-
return { document, updatedCount, changed: false };
|
|
3901
|
-
}
|
|
3902
|
-
const nextDocument = {
|
|
3903
|
-
...document,
|
|
3904
|
-
content: {
|
|
3905
|
-
...document.content,
|
|
3906
|
-
children: nextChildren
|
|
3907
|
-
}
|
|
3908
|
-
};
|
|
3909
|
-
const nextRegistry = buildFieldRegistry({
|
|
3910
|
-
content: nextDocument.content,
|
|
3911
|
-
styles: nextDocument.styles,
|
|
3912
|
-
subParts: nextDocument.subParts
|
|
3913
|
-
});
|
|
3914
|
-
nextDocument.fieldRegistry = nextRegistry;
|
|
3915
|
-
let protectionSelection;
|
|
3916
|
-
if (changedFrom !== void 0 && changedTo !== void 0) {
|
|
3917
|
-
protectionSelection = createSelectionSnapshot(changedFrom, changedTo);
|
|
3918
|
-
}
|
|
3919
|
-
return {
|
|
3920
|
-
document: nextDocument,
|
|
3921
|
-
updatedCount,
|
|
3922
|
-
changed: true,
|
|
3923
|
-
...protectionSelection ? { protectionSelection } : {}
|
|
3924
|
-
};
|
|
3925
|
-
}
|
|
3926
|
-
function refreshDocumentTableOfContents(document, selectionHead, activeStory, options) {
|
|
3927
|
-
const navigation = createDocumentNavigationSnapshot(document, selectionHead, activeStory);
|
|
3928
|
-
let changed = false;
|
|
3929
|
-
let resultEntries = [];
|
|
3930
|
-
let changedFrom;
|
|
3931
|
-
let changedTo;
|
|
3932
|
-
const nextChildren = refreshBlocksWithCursor(document.content.children, (field, range) => {
|
|
3933
|
-
if (field.fieldFamily !== "TOC") {
|
|
3934
|
-
return field;
|
|
3935
|
-
}
|
|
3936
|
-
const levelRange = options?.maxLevel ? { from: 1, to: options.maxLevel } : parseTocLevelRange(field.instruction);
|
|
3937
|
-
const entries = navigation.headings.filter((heading) => heading.level >= levelRange.from && heading.level <= levelRange.to).map((heading) => ({
|
|
3938
|
-
level: heading.level,
|
|
3939
|
-
text: heading.text,
|
|
3940
|
-
pageIndex: heading.pageIndex
|
|
3941
|
-
}));
|
|
3942
|
-
if (resultEntries.length === 0) {
|
|
3943
|
-
resultEntries = entries;
|
|
3944
|
-
}
|
|
3945
|
-
const nextField = {
|
|
3946
|
-
...field,
|
|
3947
|
-
children: buildTocInlineNodes(entries),
|
|
3948
|
-
refreshStatus: "current"
|
|
3949
|
-
};
|
|
3950
|
-
if (flattenInlineDisplayText(nextField.children) !== flattenInlineDisplayText(field.children)) {
|
|
3951
|
-
changed = true;
|
|
3952
|
-
changedFrom = changedFrom === void 0 ? range.from : Math.min(changedFrom, range.from);
|
|
3953
|
-
changedTo = changedTo === void 0 ? range.to : Math.max(changedTo, range.to);
|
|
3954
|
-
}
|
|
3955
|
-
return nextField;
|
|
3956
|
-
}).blocks;
|
|
3957
|
-
if (!changed) {
|
|
3958
|
-
return {
|
|
3959
|
-
document,
|
|
3960
|
-
result: { entryCount: resultEntries.length, entries: resultEntries },
|
|
3961
|
-
changed: false
|
|
3962
|
-
};
|
|
3963
|
-
}
|
|
3964
|
-
const nextDocument = {
|
|
3965
|
-
...document,
|
|
3966
|
-
content: {
|
|
3967
|
-
...document.content,
|
|
3968
|
-
children: nextChildren
|
|
3969
|
-
}
|
|
3970
|
-
};
|
|
3971
|
-
const nextRegistry = buildFieldRegistry({
|
|
3972
|
-
content: nextDocument.content,
|
|
3973
|
-
styles: nextDocument.styles,
|
|
3974
|
-
subParts: nextDocument.subParts
|
|
3975
|
-
});
|
|
3976
|
-
nextDocument.fieldRegistry = nextRegistry.tocStructure ? {
|
|
3977
|
-
...nextRegistry,
|
|
3978
|
-
tocStructure: {
|
|
3979
|
-
...nextRegistry.tocStructure,
|
|
3980
|
-
status: "current"
|
|
3981
|
-
}
|
|
3982
|
-
} : nextRegistry;
|
|
3983
|
-
let protectionSelection;
|
|
3984
|
-
if (changedFrom !== void 0 && changedTo !== void 0) {
|
|
3985
|
-
protectionSelection = createSelectionSnapshot(changedFrom, changedTo);
|
|
3986
|
-
}
|
|
3987
|
-
return {
|
|
3988
|
-
document: nextDocument,
|
|
3989
|
-
result: { entryCount: resultEntries.length, entries: resultEntries },
|
|
3990
|
-
changed: true,
|
|
3991
|
-
...protectionSelection ? { protectionSelection } : {}
|
|
3992
|
-
};
|
|
3993
|
-
}
|
|
3994
|
-
function refreshBlocksWithCursor(blocks, visitField, cursor = 0, previousParagraph = false) {
|
|
3995
|
-
const nextBlocks = blocks.map((block) => {
|
|
3996
|
-
if (block.type === "paragraph") {
|
|
3997
|
-
const paragraphStart = previousParagraph ? cursor + 1 : cursor;
|
|
3998
|
-
const refreshedChildren = refreshInlineNodesWithCursor(
|
|
3999
|
-
block.children,
|
|
4000
|
-
visitField,
|
|
4001
|
-
paragraphStart
|
|
4002
|
-
);
|
|
4003
|
-
cursor = paragraphStart + refreshedChildren.cursor;
|
|
4004
|
-
previousParagraph = true;
|
|
4005
|
-
return {
|
|
4006
|
-
...block,
|
|
4007
|
-
children: refreshedChildren.nodes
|
|
4008
|
-
};
|
|
4009
|
-
}
|
|
4010
|
-
if (block.type === "table") {
|
|
4011
|
-
cursor += 1;
|
|
4012
|
-
previousParagraph = false;
|
|
4013
|
-
return {
|
|
4014
|
-
...block,
|
|
4015
|
-
rows: block.rows.map((row) => ({
|
|
4016
|
-
...row,
|
|
4017
|
-
cells: row.cells.map((cell) => ({
|
|
4018
|
-
...cell,
|
|
4019
|
-
children: (() => {
|
|
4020
|
-
const refreshed = refreshBlocksWithCursor(cell.children, visitField, cursor, false);
|
|
4021
|
-
cursor = refreshed.cursor;
|
|
4022
|
-
return refreshed.blocks;
|
|
4023
|
-
})()
|
|
4024
|
-
}))
|
|
4025
|
-
}))
|
|
4026
|
-
};
|
|
4027
|
-
}
|
|
4028
|
-
if (block.type === "sdt" || block.type === "custom_xml") {
|
|
4029
|
-
const refreshed = refreshBlocksWithCursor(
|
|
4030
|
-
block.children,
|
|
4031
|
-
visitField,
|
|
4032
|
-
cursor,
|
|
4033
|
-
previousParagraph
|
|
4034
|
-
);
|
|
4035
|
-
cursor = refreshed.cursor;
|
|
4036
|
-
previousParagraph = refreshed.previousParagraph;
|
|
4037
|
-
return {
|
|
4038
|
-
...block,
|
|
4039
|
-
children: refreshed.blocks
|
|
4040
|
-
};
|
|
4041
|
-
}
|
|
4042
|
-
cursor += 1;
|
|
4043
|
-
previousParagraph = false;
|
|
4044
|
-
return block;
|
|
4045
|
-
});
|
|
4046
|
-
return { blocks: nextBlocks, cursor, previousParagraph };
|
|
4047
|
-
}
|
|
4048
|
-
function refreshInlineNodesWithCursor(nodes, visitField, cursor = 0) {
|
|
4049
|
-
const nextNodes = nodes.map((node) => {
|
|
4050
|
-
if (node.type === "field") {
|
|
4051
|
-
const fieldStart = cursor;
|
|
4052
|
-
const refreshedChildren = refreshInlineNodesWithCursor(node.children, visitField, cursor);
|
|
4053
|
-
const fieldLength = measureInlineNodes(node.children);
|
|
4054
|
-
cursor = fieldStart + fieldLength;
|
|
4055
|
-
return visitField({
|
|
4056
|
-
...node,
|
|
4057
|
-
children: refreshedChildren.nodes
|
|
4058
|
-
}, {
|
|
4059
|
-
from: fieldStart,
|
|
4060
|
-
to: fieldStart + fieldLength
|
|
4061
|
-
});
|
|
4062
|
-
}
|
|
4063
|
-
if (node.type === "hyperlink") {
|
|
4064
|
-
cursor += measureInlineNodes(node.children);
|
|
4065
|
-
return {
|
|
4066
|
-
...node,
|
|
4067
|
-
// Hyperlinks only contain text-like children in the canonical model.
|
|
4068
|
-
children: [...node.children]
|
|
4069
|
-
};
|
|
4070
|
-
}
|
|
4071
|
-
cursor += measureInlineNode(node);
|
|
4072
|
-
return node;
|
|
4073
|
-
});
|
|
4074
|
-
return { nodes: nextNodes, cursor };
|
|
4075
|
-
}
|
|
4076
|
-
function buildInlineNodesFromDisplayText(text) {
|
|
4077
|
-
if (text.length === 0) {
|
|
4078
|
-
return [];
|
|
4079
|
-
}
|
|
4080
|
-
const children = [];
|
|
4081
|
-
let buffer = "";
|
|
4082
|
-
const flushBuffer = () => {
|
|
4083
|
-
if (buffer.length > 0) {
|
|
4084
|
-
children.push({ type: "text", text: buffer });
|
|
4085
|
-
buffer = "";
|
|
4086
|
-
}
|
|
4087
|
-
};
|
|
4088
|
-
for (const character of text) {
|
|
4089
|
-
if (character === " ") {
|
|
4090
|
-
flushBuffer();
|
|
4091
|
-
children.push({ type: "tab" });
|
|
4092
|
-
continue;
|
|
4093
|
-
}
|
|
4094
|
-
if (character === "\n") {
|
|
4095
|
-
flushBuffer();
|
|
4096
|
-
children.push({ type: "hard_break" });
|
|
4097
|
-
continue;
|
|
4098
|
-
}
|
|
4099
|
-
buffer += character;
|
|
4100
|
-
}
|
|
4101
|
-
flushBuffer();
|
|
4102
|
-
return children;
|
|
4103
|
-
}
|
|
4104
|
-
function buildTocInlineNodes(entries) {
|
|
4105
|
-
const children = [];
|
|
4106
|
-
entries.forEach((entry, index) => {
|
|
4107
|
-
children.push({ type: "text", text: entry.text });
|
|
4108
|
-
children.push({ type: "tab" });
|
|
4109
|
-
children.push({ type: "text", text: String(entry.pageIndex + 1) });
|
|
4110
|
-
if (index < entries.length - 1) {
|
|
4111
|
-
children.push({ type: "hard_break" });
|
|
4112
|
-
}
|
|
4113
|
-
});
|
|
4114
|
-
return children;
|
|
4115
|
-
}
|
|
4116
|
-
function collectFieldsFromSubParts(subParts, entries, index) {
|
|
4117
|
-
if (!subParts) {
|
|
4118
|
-
return index;
|
|
4119
|
-
}
|
|
4120
|
-
let nextIndex = index;
|
|
4121
|
-
for (const header of subParts.headers ?? []) {
|
|
4122
|
-
for (const block of header.blocks) {
|
|
4123
|
-
nextIndex = collectFieldsFromBlock(block, entries, nextIndex);
|
|
4124
|
-
}
|
|
4125
|
-
}
|
|
4126
|
-
for (const footer of subParts.footers ?? []) {
|
|
4127
|
-
for (const block of footer.blocks) {
|
|
4128
|
-
nextIndex = collectFieldsFromBlock(block, entries, nextIndex);
|
|
4129
|
-
}
|
|
4130
|
-
}
|
|
4131
|
-
if (subParts.footnoteCollection) {
|
|
4132
|
-
for (const note of Object.values(subParts.footnoteCollection.footnotes)) {
|
|
4133
|
-
for (const block of note.blocks) {
|
|
4134
|
-
nextIndex = collectFieldsFromBlock(block, entries, nextIndex);
|
|
4135
|
-
}
|
|
4136
|
-
}
|
|
4137
|
-
for (const note of Object.values(subParts.footnoteCollection.endnotes)) {
|
|
4138
|
-
for (const block of note.blocks) {
|
|
4139
|
-
nextIndex = collectFieldsFromBlock(block, entries, nextIndex);
|
|
4140
|
-
}
|
|
4141
|
-
}
|
|
4142
|
-
}
|
|
4143
|
-
return nextIndex;
|
|
4144
|
-
}
|
|
4145
|
-
function resolveSupportedFieldDisplay(field, document, bookmarkMap, paragraphs, navigation) {
|
|
4146
|
-
if (!field.fieldFamily || !isSupportedFieldFamily(field.fieldFamily)) {
|
|
4147
|
-
return void 0;
|
|
4148
|
-
}
|
|
4149
|
-
if (!field.fieldTarget) {
|
|
4150
|
-
return field.fieldFamily === "TOC" ? void 0 : { displayText: "", refreshStatus: "unresolvable" };
|
|
4151
|
-
}
|
|
4152
|
-
if (field.fieldFamily === "REF") {
|
|
4153
|
-
const result = resolveRefFieldText(document, bookmarkMap, field.fieldTarget);
|
|
4154
|
-
return result ? { displayText: result.text, refreshStatus: result.refreshStatus } : { displayText: "", refreshStatus: "unresolvable" };
|
|
4155
|
-
}
|
|
4156
|
-
const bookmark = bookmarkMap.get(field.fieldTarget);
|
|
4157
|
-
if (!bookmark) {
|
|
4158
|
-
return { displayText: "", refreshStatus: "unresolvable" };
|
|
4159
|
-
}
|
|
4160
|
-
if (field.fieldFamily === "PAGEREF") {
|
|
4161
|
-
const paragraph = paragraphs[bookmark.paragraphIndex];
|
|
4162
|
-
if (!paragraph) {
|
|
4163
|
-
return { displayText: "", refreshStatus: "unresolvable" };
|
|
4164
|
-
}
|
|
4165
|
-
const pageIndex = findPageForOffset(navigation.pages, paragraph.startOffset);
|
|
4166
|
-
return { displayText: String(pageIndex + 1), refreshStatus: "current" };
|
|
4167
|
-
}
|
|
4168
|
-
if (field.fieldFamily === "NOTEREF") {
|
|
4169
|
-
const paragraph = paragraphs[bookmark.paragraphIndex]?.paragraph;
|
|
4170
|
-
if (!paragraph) {
|
|
4171
|
-
return { displayText: "", refreshStatus: "unresolvable" };
|
|
4172
|
-
}
|
|
4173
|
-
const noteText = resolveNoteReferenceText(paragraph, bookmark.bookmarkId);
|
|
4174
|
-
return noteText ? { displayText: noteText, refreshStatus: "current" } : { displayText: "", refreshStatus: "unresolvable" };
|
|
4175
|
-
}
|
|
4176
|
-
return void 0;
|
|
4177
|
-
}
|
|
4178
|
-
function collectParagraphContexts(blocks) {
|
|
4179
|
-
const paragraphs = [];
|
|
4180
|
-
collectParagraphContextsFromBlocks(blocks, paragraphs, 0, false);
|
|
4181
|
-
return paragraphs;
|
|
4182
|
-
}
|
|
4183
|
-
function collectParagraphContextsFromBlocks(blocks, paragraphs, cursor, previousParagraph) {
|
|
4184
|
-
let nextCursor = cursor;
|
|
4185
|
-
let nextPreviousParagraph = previousParagraph;
|
|
4186
|
-
for (const block of blocks) {
|
|
4187
|
-
if (block.type === "paragraph") {
|
|
4188
|
-
if (nextPreviousParagraph) {
|
|
4189
|
-
nextCursor += 1;
|
|
4190
|
-
}
|
|
4191
|
-
paragraphs.push({ paragraph: block, startOffset: nextCursor });
|
|
4192
|
-
nextCursor += measureInlineNodes(block.children);
|
|
4193
|
-
nextPreviousParagraph = true;
|
|
4194
|
-
continue;
|
|
4195
|
-
}
|
|
4196
|
-
if (block.type === "table") {
|
|
4197
|
-
nextCursor += 1;
|
|
4198
|
-
nextPreviousParagraph = false;
|
|
4199
|
-
for (const row of block.rows) {
|
|
4200
|
-
for (const cell of row.cells) {
|
|
4201
|
-
const result = collectParagraphContextsFromBlocks(
|
|
4202
|
-
cell.children,
|
|
4203
|
-
paragraphs,
|
|
4204
|
-
nextCursor,
|
|
4205
|
-
false
|
|
4206
|
-
);
|
|
4207
|
-
nextCursor = result.cursor;
|
|
4208
|
-
}
|
|
4209
|
-
}
|
|
4210
|
-
continue;
|
|
4211
|
-
}
|
|
4212
|
-
if (block.type === "sdt" || block.type === "custom_xml") {
|
|
4213
|
-
const result = collectParagraphContextsFromBlocks(
|
|
4214
|
-
block.children,
|
|
4215
|
-
paragraphs,
|
|
4216
|
-
nextCursor,
|
|
4217
|
-
nextPreviousParagraph
|
|
4218
|
-
);
|
|
4219
|
-
nextCursor = result.cursor;
|
|
4220
|
-
nextPreviousParagraph = result.previousParagraph;
|
|
4221
|
-
continue;
|
|
4222
|
-
}
|
|
4223
|
-
nextCursor += 1;
|
|
4224
|
-
nextPreviousParagraph = false;
|
|
4225
|
-
}
|
|
4226
|
-
return { cursor: nextCursor, previousParagraph: nextPreviousParagraph };
|
|
4227
|
-
}
|
|
4228
|
-
function measureInlineNodes(nodes) {
|
|
4229
|
-
return nodes.reduce((size, node) => size + measureInlineNode(node), 0);
|
|
4230
|
-
}
|
|
4231
|
-
function measureInlineNode(node) {
|
|
4232
|
-
switch (node.type) {
|
|
4233
|
-
case "text":
|
|
4234
|
-
return node.text.length;
|
|
4235
|
-
case "tab":
|
|
4236
|
-
case "hard_break":
|
|
4237
|
-
case "column_break":
|
|
4238
|
-
case "footnote_ref":
|
|
4239
|
-
case "image":
|
|
4240
|
-
case "opaque_inline":
|
|
4241
|
-
case "bookmark_start":
|
|
4242
|
-
case "bookmark_end":
|
|
4243
|
-
return 1;
|
|
4244
|
-
case "hyperlink":
|
|
4245
|
-
case "field":
|
|
4246
|
-
return measureInlineNodes(node.children);
|
|
4247
|
-
default:
|
|
4248
|
-
return 1;
|
|
4249
|
-
}
|
|
4250
|
-
}
|
|
4251
|
-
function resolveNoteReferenceText(paragraph, bookmarkId) {
|
|
4252
|
-
let inside = false;
|
|
4253
|
-
let sawBoundary = false;
|
|
4254
|
-
for (const child of paragraph.children) {
|
|
4255
|
-
if (child.type === "bookmark_start" && child.bookmarkId === bookmarkId) {
|
|
4256
|
-
inside = true;
|
|
4257
|
-
sawBoundary = true;
|
|
4258
|
-
continue;
|
|
4259
|
-
}
|
|
4260
|
-
if (child.type === "bookmark_end" && child.bookmarkId === bookmarkId) {
|
|
4261
|
-
break;
|
|
4262
|
-
}
|
|
4263
|
-
if (!inside) {
|
|
4264
|
-
continue;
|
|
4265
|
-
}
|
|
4266
|
-
if (child.type === "footnote_ref") {
|
|
4267
|
-
return child.noteId;
|
|
4268
|
-
}
|
|
4269
|
-
}
|
|
4270
|
-
return sawBoundary ? void 0 : void 0;
|
|
4271
|
-
}
|
|
4272
|
-
function getCommandSelection(command, fallbackSelection) {
|
|
4273
|
-
if ("protectionSelection" in command && command.protectionSelection) {
|
|
4274
|
-
return command.protectionSelection;
|
|
4275
|
-
}
|
|
4276
|
-
if ("selection" in command && command.selection) {
|
|
4277
|
-
return command.selection;
|
|
4278
|
-
}
|
|
4279
|
-
return fallbackSelection;
|
|
4280
|
-
}
|
|
4281
|
-
function isBlockedByProtection(protection, selection) {
|
|
4282
|
-
const enforcedRanges = protection.ranges.filter(
|
|
4283
|
-
(range) => range.enforced && typeof range.start === "number" && typeof range.end === "number"
|
|
4284
|
-
);
|
|
4285
|
-
if (enforcedRanges.length === 0) {
|
|
4286
|
-
return false;
|
|
4287
|
-
}
|
|
4288
|
-
const from = Math.min(selection.anchor, selection.head);
|
|
4289
|
-
const to = Math.max(selection.anchor, selection.head);
|
|
4290
|
-
return !enforcedRanges.some(
|
|
4291
|
-
(range) => from >= range.start && to <= range.end
|
|
4292
|
-
);
|
|
4293
|
-
}
|
|
4294
|
-
function remapProtectionSnapshot(protection, mapping) {
|
|
4295
|
-
if (mapping.steps.length === 0 || protection.ranges.length === 0) {
|
|
4296
|
-
return protection;
|
|
4297
|
-
}
|
|
4298
|
-
let changed = false;
|
|
4299
|
-
const nextRanges = protection.ranges.map((range) => {
|
|
4300
|
-
if (!range.enforced || typeof range.start !== "number" || typeof range.end !== "number") {
|
|
4301
|
-
return range;
|
|
4302
|
-
}
|
|
4303
|
-
const mapped = mapRange(
|
|
4304
|
-
{ from: range.start, to: range.end },
|
|
4305
|
-
{ start: -1, end: 1 },
|
|
4306
|
-
mapping
|
|
4307
|
-
);
|
|
4308
|
-
if (mapped.kind === "detached") {
|
|
4309
|
-
changed = true;
|
|
4310
|
-
return {
|
|
4311
|
-
...range,
|
|
4312
|
-
start: void 0,
|
|
4313
|
-
end: void 0,
|
|
4314
|
-
enforced: false,
|
|
4315
|
-
enforcementReason: "preserve-only: permission range could not be remapped after runtime edits"
|
|
4316
|
-
};
|
|
4317
|
-
}
|
|
4318
|
-
if (mapped.range.from !== range.start || mapped.range.to !== range.end) {
|
|
4319
|
-
changed = true;
|
|
4320
|
-
return {
|
|
4321
|
-
...range,
|
|
4322
|
-
start: mapped.range.from,
|
|
4323
|
-
end: mapped.range.to
|
|
4324
|
-
};
|
|
4325
|
-
}
|
|
4326
|
-
return range;
|
|
4327
|
-
});
|
|
4328
|
-
if (!changed) {
|
|
4329
|
-
return protection;
|
|
4330
|
-
}
|
|
4331
|
-
return {
|
|
4332
|
-
...protection,
|
|
4333
|
-
ranges: nextRanges,
|
|
4334
|
-
enforcedRangeCount: nextRanges.filter((range) => range.enforced).length,
|
|
4335
|
-
preservedRangeCount: nextRanges.filter((range) => !range.enforced).length
|
|
4336
|
-
};
|
|
4337
|
-
}
|
|
4338
|
-
|
|
4339
|
-
export {
|
|
4340
|
-
createDocumentRuntime
|
|
4341
|
-
};
|
|
4342
|
-
//# sourceMappingURL=chunk-KD2QRQPY.js.map
|