edytor 2.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -4
- package/dist/block/block.svelte.js +2 -4
- package/dist/clipboard/htmlFlow.d.ts +20 -7
- package/dist/clipboard/htmlFlow.js +23 -15
- package/dist/clipboard/serializeClipboardFragment.d.ts +37 -4
- package/dist/clipboard/serializeClipboardFragment.js +6 -4
- package/dist/clipboard/textBlocks.d.ts +8 -0
- package/dist/clipboard/textBlocks.js +6 -2
- package/dist/cloudflare/DocumentRoom.d.ts +13 -9
- package/dist/cloudflare/DocumentRoom.js +10 -6
- package/dist/cloudflare/room/admission.js +3 -3
- package/dist/cloudflare/room/context.d.ts +28 -27
- package/dist/cloudflare/room/context.js +2 -2
- package/dist/cloudflare/room/purge.d.ts +6 -3
- package/dist/cloudflare/room/purge.js +44 -19
- package/dist/cloudflare/room/updates.d.ts +3 -4
- package/dist/cloudflare/room/updates.js +6 -8
- package/dist/cloudflare/routeDocumentSocket.d.ts +17 -0
- package/dist/cloudflare/routeDocumentSocket.js +53 -0
- package/dist/collaboration/comments/client.d.ts +1 -1
- package/dist/collaboration/comments/client.js +1 -1
- package/dist/collaboration/remoteSelection.js +3 -3
- package/dist/components/Edytor.svelte +2 -10
- package/dist/components/Edytor.svelte.d.ts +1 -3
- package/dist/crdt/admission.d.ts +5 -10
- package/dist/crdt/admission.js +5 -11
- package/dist/crdt/attribution/attribution.d.ts +31 -12
- package/dist/crdt/attribution/attribution.js +56 -18
- package/dist/crdt/attribution/block.d.ts +3 -3
- package/dist/crdt/attribution/block.js +7 -8
- package/dist/crdt/attribution/index.d.ts +1 -1
- package/dist/crdt/attribution/index.js +1 -1
- package/dist/crdt/data.d.ts +62 -31
- package/dist/crdt/data.js +211 -103
- package/dist/crdt/doc/delete.d.ts +1 -1
- package/dist/crdt/doc/delete.js +13 -30
- package/dist/crdt/doc/funnel.d.ts +7 -6
- package/dist/crdt/doc/funnel.js +39 -33
- package/dist/crdt/doc/gate.d.ts +3 -20
- package/dist/crdt/doc/gate.js +2 -41
- package/dist/crdt/doc/history.d.ts +25 -9
- package/dist/crdt/doc/history.js +152 -42
- package/dist/crdt/doc/layout.js +11 -22
- package/dist/crdt/doc/meta.js +12 -17
- package/dist/crdt/doc/moves.d.ts +1 -1
- package/dist/crdt/doc/moves.js +52 -32
- package/dist/crdt/doc/reads.js +2 -2
- package/dist/crdt/doc/seed.js +2 -2
- package/dist/crdt/doc/split-merge.js +12 -15
- package/dist/crdt/doc/steps.d.ts +25 -13
- package/dist/crdt/doc/steps.js +52 -122
- package/dist/crdt/doc/types.d.ts +21 -9
- package/dist/crdt/document.d.ts +21 -19
- package/dist/crdt/document.js +26 -23
- package/dist/crdt/edytor-doc.d.ts +66 -68
- package/dist/crdt/edytor-doc.js +21 -20
- package/dist/crdt/engine-api.d.ts +33 -1
- package/dist/crdt/engine.d.ts +0 -1
- package/dist/crdt/engine.js +1 -4
- package/dist/crdt/flow.d.ts +1 -1
- package/dist/crdt/flow.js +25 -27
- package/dist/crdt/index.d.ts +29 -28
- package/dist/crdt/index.js +3 -3
- package/dist/crdt/placement/display.d.ts +5 -30
- package/dist/crdt/placement/display.js +39 -144
- package/dist/crdt/placement/keys.d.ts +58 -0
- package/dist/crdt/placement/keys.js +90 -0
- package/dist/crdt/placement/model.d.ts +119 -118
- package/dist/crdt/placement/model.js +242 -142
- package/dist/crdt/placement/resolve.d.ts +123 -35
- package/dist/crdt/placement/resolve.js +187 -153
- package/dist/crdt/placement/slots.d.ts +134 -0
- package/dist/crdt/placement/slots.js +152 -0
- package/dist/crdt/protocol.d.ts +2 -2
- package/dist/crdt/protocol.js +2 -2
- package/dist/crdt/providers/index.d.ts +1 -1
- package/dist/crdt/providers/room.d.ts +26 -11
- package/dist/crdt/providers/room.js +77 -27
- package/dist/crdt/providers/websocket.d.ts +1 -1
- package/dist/crdt/providers/websocket.js +33 -32
- package/dist/crdt/purge.d.ts +17 -8
- package/dist/crdt/purge.js +236 -126
- package/dist/crdt/restore.d.ts +2 -2
- package/dist/crdt/restore.js +18 -34
- package/dist/crdt/schema.d.ts +22 -21
- package/dist/crdt/schema.js +29 -23
- package/dist/crdt/semantics.js +3 -1
- package/dist/crdt/storage.d.ts +1 -1
- package/dist/crdt/storage.js +1 -1
- package/dist/crdt/structs.d.ts +15 -15
- package/dist/crdt/structs.js +8 -22
- package/dist/crdt/text/index/cache.js +4 -0
- package/dist/crdt/text/index/claims.js +12 -0
- package/dist/crdt/text/index/fold.d.ts +2 -3
- package/dist/crdt/text/index/fold.js +194 -44
- package/dist/crdt/text/index/layout.js +5 -8
- package/dist/crdt/text/index/placement.d.ts +26 -18
- package/dist/crdt/text/index/placement.js +404 -138
- package/dist/crdt/text/index/records.d.ts +3 -3
- package/dist/crdt/text/index/records.js +24 -31
- package/dist/crdt/text/index/shared.d.ts +11 -3
- package/dist/crdt/text/index/shared.js +12 -3
- package/dist/crdt/text/index/state.d.ts +21 -17
- package/dist/crdt/text/index/state.js +15 -17
- package/dist/crdt/text/index/streams.d.ts +10 -5
- package/dist/crdt/text/index/streams.js +78 -27
- package/dist/crdt/text/items.d.ts +10 -3
- package/dist/crdt/text/items.js +7 -0
- package/dist/crdt/text/model.d.ts +77 -62
- package/dist/crdt/text/model.js +84 -169
- package/dist/crdt/text/ranges.d.ts +1 -1
- package/dist/crdt/text/ranges.js +3 -3
- package/dist/crdt/text/rows.d.ts +13 -7
- package/dist/crdt/text/rows.js +24 -7
- package/dist/crdt/text/runs.d.ts +17 -12
- package/dist/crdt/text/runs.js +24 -7
- package/dist/crdt/text/streams.d.ts +26 -13
- package/dist/crdt/text/streams.js +41 -14
- package/dist/crdt/vendor/yjs/UPSTREAM.md +568 -21
- package/dist/crdt/vendor/yjs/dts/global.d.ts +2 -0
- package/dist/crdt/vendor/yjs/dts/index.d.ts +1 -1
- package/dist/crdt/vendor/yjs/dts/structs/AbstractStruct.d.ts +7 -0
- package/dist/crdt/vendor/yjs/dts/structs/Item.d.ts +194 -10
- package/dist/crdt/vendor/yjs/dts/utils/Doc.d.ts +6 -3
- package/dist/crdt/vendor/yjs/dts/utils/StructStore.d.ts +5 -18
- package/dist/crdt/vendor/yjs/dts/utils/Transaction.d.ts +15 -1
- package/dist/crdt/vendor/yjs/dts/utils/UpdateDecoder.d.ts +14 -6
- package/dist/crdt/vendor/yjs/dts/utils/UpdateEncoder.d.ts +33 -6
- package/dist/crdt/vendor/yjs/dts/utils/ids.d.ts +1 -65
- package/dist/crdt/vendor/yjs/dts/utils/marks.d.ts +6 -1
- package/dist/crdt/vendor/yjs/dts/ynode.d.ts +43 -7
- package/dist/crdt/vendor/yjs/global.d.ts +2 -0
- package/dist/crdt/vendor/yjs/src/index.js +1 -1
- package/dist/crdt/vendor/yjs/src/structs/AbstractStruct.js +10 -0
- package/dist/crdt/vendor/yjs/src/structs/Item.js +610 -51
- package/dist/crdt/vendor/yjs/src/utils/BlockSet.js +18 -9
- package/dist/crdt/vendor/yjs/src/utils/Doc.js +5 -3
- package/dist/crdt/vendor/yjs/src/utils/StructStore.js +5 -0
- package/dist/crdt/vendor/yjs/src/utils/Transaction.js +36 -13
- package/dist/crdt/vendor/yjs/src/utils/UpdateDecoder.js +88 -18
- package/dist/crdt/vendor/yjs/src/utils/UpdateEncoder.js +119 -32
- package/dist/crdt/vendor/yjs/src/utils/encoding.js +13 -1
- package/dist/crdt/vendor/yjs/src/utils/ids.js +7 -7
- package/dist/crdt/vendor/yjs/src/utils/marks.js +193 -8
- package/dist/crdt/vendor/yjs/src/utils/redo.js +1 -1
- package/dist/crdt/vendor/yjs/src/utils/transaction-helpers.js +1 -1
- package/dist/crdt/vendor/yjs/src/utils/updates.js +3 -3
- package/dist/crdt/vendor/yjs/src/ynode.js +177 -12
- package/dist/dnd/autoScroll.d.ts +15 -7
- package/dist/dnd/autoScroll.js +10 -15
- package/dist/dnd/dropIndicator.js +2 -5
- package/dist/dnd/external.d.ts +6 -0
- package/dist/dnd/external.js +17 -0
- package/dist/dnd/geometry.d.ts +2 -0
- package/dist/dnd/geometry.js +3 -4
- package/dist/dnd/placement.d.ts +1 -1
- package/dist/dnd/pragmatic.d.ts +3 -1
- package/dist/dnd/pragmatic.js +12 -2
- package/dist/dnd/vendor/pragmatic/UPSTREAM.md +51 -18
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/drop-target-for-external.d.ts +4 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/drop-target-for-external.js +6 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/element-adapter.d.ts +0 -2
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/element-adapter.js +4 -22
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/external-adapter-types.d.ts +26 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/external-adapter.d.ts +30 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/external-adapter.js +203 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/get-available-items.js +13 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/get-available-types.js +9 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/is-an-available-type.js +19 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/monitor-for-external.d.ts +4 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/adapter/monitor-for-external.js +6 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/honey-pot-fix/make-honey-pot-fix.js +4 -16
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/internal-types.d.ts +1 -8
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/make-adapter/make-drop-target.js +5 -6
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/make-adapter/make-monitor.js +2 -3
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.d.ts +1 -1
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.js +6 -24
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/contains-files.d.ts +2 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/contains-files.js +5 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/get-files.d.ts +3 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/get-files.js +12 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/public-utils/external/native-types.d.ts +12 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/changing-window/is-entering-window-in-safari.js +10 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/changing-window/is-entering-window.js +55 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/entry-point/external.d.ts +4 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/entry-point/external.js +8 -0
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/internal-types.d.ts +0 -4
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/over-element/get-scroll-by.js +16 -72
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/over-element/try-scroll.js +1 -9
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/shared/configuration.js +4 -29
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/shared/get-scroll-change.js +2 -3
- package/dist/edytor.svelte.d.ts +2 -5
- package/dist/edytor.svelte.js +21 -32
- package/dist/events/beforeInputCommands.js +2 -2
- package/dist/events/onBeforeInput.js +1 -1
- package/dist/events/onDrop.d.ts +0 -6
- package/dist/events/onDrop.js +10 -23
- package/dist/events/onInput.d.ts +0 -12
- package/dist/events/onInput.js +1 -67
- package/dist/events/onPageHide.d.ts +3 -0
- package/dist/events/onPageHide.js +16 -0
- package/dist/export/forms.d.ts +627 -0
- package/dist/export/forms.js +749 -0
- package/dist/export/index.d.ts +170 -0
- package/dist/export/index.js +161 -0
- package/dist/export/markdown.d.ts +41 -0
- package/dist/export/markdown.js +585 -0
- package/dist/export/markdownWriter.d.ts +9 -0
- package/dist/export/markdownWriter.js +133 -0
- package/dist/export/mdx.d.ts +15 -0
- package/dist/export/mdx.js +33 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/kinds.js +1 -1
- package/dist/plugins/anchored.svelte.d.ts +21 -25
- package/dist/plugins/anchored.svelte.js +23 -39
- package/dist/plugins/blockHandles/BlockHandleController.svelte.js +24 -32
- package/dist/plugins/blockHandles/dragPreview.d.ts +26 -7
- package/dist/plugins/blockHandles/dragPreview.js +33 -0
- package/dist/plugins/blockMenu/BlockMenuController.svelte.d.ts +5 -0
- package/dist/plugins/blockMenu/BlockMenuController.svelte.js +7 -2
- package/dist/plugins/blockMenu/blockMenuPlugin.js +5 -50
- package/dist/plugins/chrome.d.ts +27 -5
- package/dist/plugins/chrome.js +24 -9
- package/dist/plugins/code/CodePlugin.svelte +12 -9
- package/dist/plugins/code/header.svelte.js +7 -11
- package/dist/plugins/code/languageMenu.svelte.d.ts +5 -2
- package/dist/plugins/code/languageMenu.svelte.js +13 -20
- package/dist/plugins/columns/ColumnsPlugin.svelte +7 -20
- package/dist/plugins/columns/resize.svelte.d.ts +2 -3
- package/dist/plugins/columns/resize.svelte.js +2 -5
- package/dist/plugins/comments/CommentsController.svelte.d.ts +6 -0
- package/dist/plugins/comments/CommentsController.svelte.js +20 -0
- package/dist/plugins/equation/EquationPlugin.svelte +12 -22
- package/dist/plugins/equation/equation.svelte.d.ts +7 -15
- package/dist/plugins/equation/equation.svelte.js +13 -50
- package/dist/plugins/equation/tex.d.ts +17 -0
- package/dist/plugins/equation/tex.js +42 -0
- package/dist/plugins/fileDrop.d.ts +38 -23
- package/dist/plugins/fileDrop.js +82 -76
- package/dist/plugins/find/FindController.svelte.d.ts +5 -0
- package/dist/plugins/find/FindController.svelte.js +14 -14
- package/dist/plugins/find/findPlugin.js +1 -15
- package/dist/plugins/image/ImageChrome.svelte +8 -2
- package/dist/plugins/image/ImagePlugin.svelte +15 -52
- package/dist/plugins/image/controls.svelte.js +16 -2
- package/dist/plugins/image/toolbar.svelte.d.ts +5 -4
- package/dist/plugins/image/toolbar.svelte.js +21 -31
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/list.svelte.d.ts +9 -0
- package/dist/plugins/list.svelte.js +18 -0
- package/dist/plugins/marquee/marqueePlugin.js +0 -4
- package/dist/plugins/media/AudioPlugin.svelte +1 -1
- package/dist/plugins/media/BookmarkPlugin.svelte +6 -97
- package/dist/plugins/media/EmbedPlugin.svelte +5 -90
- package/dist/plugins/media/EmptySlot.svelte +36 -20
- package/dist/plugins/media/EmptySlot.svelte.d.ts +6 -15
- package/dist/plugins/media/FilePlugin.svelte +1 -19
- package/dist/plugins/media/MediaEmpty.svelte +2 -55
- package/dist/plugins/media/MediaEmpty.svelte.d.ts +18 -14
- package/dist/plugins/media/SourceBlock.svelte +142 -52
- package/dist/plugins/media/SourceBlock.svelte.d.ts +10 -4
- package/dist/plugins/media/VideoPlugin.svelte +1 -1
- package/dist/plugins/media/empty.svelte.js +2 -7
- package/dist/plugins/media/media.d.ts +2 -63
- package/dist/plugins/media/media.js +1 -194
- package/dist/plugins/media/sources.d.ts +60 -0
- package/dist/plugins/media/sources.js +165 -0
- package/dist/plugins/media/urlPaste.svelte.d.ts +2 -1
- package/dist/plugins/media/urlPaste.svelte.js +12 -21
- package/dist/plugins/mention/MentionPlugin.svelte +8 -35
- package/dist/plugins/page/PagePlugin.svelte +2 -9
- package/dist/plugins/page/page.js +1 -1
- package/dist/plugins/pageLink/PageLinkPlugin.svelte +6 -13
- package/dist/plugins/richtext/RichTextPlugin.svelte +85 -197
- package/dist/plugins/richtext/body.js +1 -1
- package/dist/plugins/richtext/calloutIcons.svelte.d.ts +2 -2
- package/dist/plugins/richtext/calloutIcons.svelte.js +5 -7
- package/dist/plugins/richtext/richTextOperations.d.ts +1 -19
- package/dist/plugins/richtext/richTextOperations.js +3 -49
- package/dist/plugins/slashMenu/SlashMenuController.svelte.d.ts +2 -0
- package/dist/plugins/slashMenu/SlashMenuController.svelte.js +7 -0
- package/dist/plugins/slashMenu/slashMenuPlugin.js +5 -14
- package/dist/plugins/table/TableChrome.svelte +2 -3
- package/dist/plugins/table/TablePlugin.svelte +20 -54
- package/dist/plugins/table/chrome.svelte.d.ts +5 -2
- package/dist/plugins/table/chrome.svelte.js +30 -54
- package/dist/plugins/table/table.js +3 -3
- package/dist/plugins/toc/TocPlugin.svelte +2 -4
- package/dist/plugins/toolbar/ToolbarController.svelte.d.ts +7 -0
- package/dist/plugins/toolbar/ToolbarController.svelte.js +20 -13
- package/dist/plugins/toolbar/toolbarPlugin.js +19 -53
- package/dist/plugins/triggers/TriggerController.svelte.d.ts +7 -2
- package/dist/plugins/triggers/TriggerController.svelte.js +11 -4
- package/dist/plugins/triggers/place.js +1 -2
- package/dist/plugins/triggers/triggers.d.ts +6 -1
- package/dist/plugins/triggers/triggers.js +12 -13
- package/dist/plugins/uploads.svelte.d.ts +5 -2
- package/dist/plugins/uploads.svelte.js +25 -15
- package/dist/plugins.d.ts +26 -0
- package/dist/plugins.js +0 -24
- package/dist/selection/replaceSelection.js +2 -2
- package/dist/selection/selection.svelte.d.ts +4 -10
- package/dist/selection/selection.svelte.js +7 -11
- package/dist/session/bindings.js +1 -1
- package/dist/session/commands.d.ts +7 -11
- package/dist/session/commands.js +13 -19
- package/dist/session/inputRules.js +1 -1
- package/dist/session/navigation.js +1 -1
- package/dist/session/suggestions.svelte.d.ts +0 -11
- package/dist/session/suggestions.svelte.js +15 -3
- package/dist/session/uploads.d.ts +8 -8
- package/dist/surface/lines.js +1 -3
- package/dist/surface/observer.svelte.d.ts +17 -1
- package/dist/surface/observer.svelte.js +74 -19
- package/dist/surface/overlay.d.ts +0 -14
- package/dist/surface/overlay.js +0 -25
- package/dist/surface/projector.svelte.d.ts +15 -3
- package/dist/surface/projector.svelte.js +60 -9
- package/dist/text/text.svelte.js +3 -13
- package/dist/utils/sanitize.d.ts +38 -0
- package/dist/utils/sanitize.js +82 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +5 -0
- package/package.json +19 -2
- package/dist/crdt/placement/rank.d.ts +0 -87
- package/dist/crdt/placement/rank.js +0 -332
- package/dist/crdt/placement/source.d.ts +0 -43
- package/dist/crdt/placement/source.js +0 -66
- package/dist/crdt/text/delete-index.d.ts +0 -129
- package/dist/crdt/text/delete-index.js +0 -365
- package/dist/crdt/text/deletes.d.ts +0 -76
- package/dist/crdt/text/deletes.js +0 -362
- package/dist/crdt/text/index/anchored.d.ts +0 -17
- package/dist/crdt/text/index/anchored.js +0 -197
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/max-z-index.js +0 -3
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop/util/supports-popover.js +0 -16
- package/dist/dnd/vendor/pragmatic/pragmatic-drag-and-drop-auto-scroll/shared/is-axis-allowed.js +0 -3
- package/dist/plugins/code/LanguageMenu.svelte +0 -25
- package/dist/plugins/code/LanguageMenu.svelte.d.ts +0 -9
- package/dist/plugins/equation/EquationEditor.svelte +0 -27
- package/dist/plugins/equation/EquationEditor.svelte.d.ts +0 -9
- package/dist/plugins/image/ImageToolbarHost.svelte +0 -37
- package/dist/plugins/image/ImageToolbarHost.svelte.d.ts +0 -9
- package/dist/plugins/richtext/CalloutIconPicker.svelte +0 -26
- package/dist/plugins/richtext/CalloutIconPicker.svelte.d.ts +0 -9
package/dist/crdt/data.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { DATA_LEAF_PREFIX } from './schema.js';
|
|
2
|
-
import { rankAfter } from './placement/rank.js';
|
|
3
2
|
import { hash32 } from './rand.js';
|
|
4
3
|
import { jsonEquals } from '../utils/json.js';
|
|
4
|
+
import { entriesOf, isDataSlot, placeAfter, removeUnit, triples } from './placement/slots.js';
|
|
5
|
+
import { asEngineDoc } from './structs.js';
|
|
5
6
|
export const isObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
6
|
-
const tree = (v) => ({ v, k: new Map() });
|
|
7
|
-
const kid = (t, s) => t.k.get(s) ?? t.k.set(s, tree()).get(s);
|
|
7
|
+
const tree = (p = '', v) => ({ p, v, k: new Map() });
|
|
8
|
+
const kid = (t, s) => t.k.get(s) ?? t.k.set(s, tree(t.p === '' ? s : `${t.p}/${s}`)).get(s);
|
|
8
9
|
const enc = (k) => k.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
9
10
|
const dec = (s) => s.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
10
11
|
const itemish = (s) => /^~[a-z]/.test(s);
|
|
@@ -15,52 +16,50 @@ const itemish = (s) => /^~[a-z]/.test(s);
|
|
|
15
16
|
export const keySegment = (k) => (k.startsWith('~') ? `~0${k.slice(1)}` : k);
|
|
16
17
|
/** The object key a path segment names (`keySegment`'s inverse). */
|
|
17
18
|
export const segmentKey = (s) => (s.startsWith('~0') ? `~${s.slice(2)}` : s);
|
|
18
|
-
/** A rank's characters (`placement/rank.ts`: variable-length digits, `!` before a tie). */
|
|
19
|
-
const RANK = /^[-\w?!]+$/;
|
|
20
19
|
const index = (k) => (/^(0|[1-9]\d*)$/.test(k) ? Number(k) : -1);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const placeOf = (t, id) => rank(t.k.get(`${id}>`)?.v) ?? rank(t.k.get(`${id}#`)?.v);
|
|
24
|
-
/** `t`'s live items (made, `id#`, and not removed: a move never revives one), in order. */
|
|
25
|
-
const itemsOf = (t) => {
|
|
26
|
-
const out = [];
|
|
27
|
-
for (const [s, c] of t.k)
|
|
28
|
-
if (s.endsWith('#') && itemish(s) && rank(c.v))
|
|
29
|
-
out.push({ id: s.slice(0, -1), rank: placeOf(t, s.slice(0, -1)) });
|
|
30
|
-
// ` ` sorts below every rank character: a rank before its extensions, then by id.
|
|
31
|
-
return out.sort((a, b) => (`${a.rank} ${a.id}` < `${b.rank} ${b.id}` ? -1 : 1));
|
|
32
|
-
};
|
|
20
|
+
/** `t`'s live items in order. */
|
|
21
|
+
const itemsOf = (t) => t.items ?? [];
|
|
33
22
|
const isArr = (t) => Array.isArray(t.v) || itemsOf(t).length > 0;
|
|
34
23
|
/** The item `seg` names among `items`: by its id (`~…`) or by its index. */
|
|
35
|
-
const itemAt = (items, seg) => itemish(seg) ? items.find((i) => i
|
|
24
|
+
const itemAt = (items, seg) => itemish(seg) ? items.find((i) => i === seg) : items[index(seg)];
|
|
36
25
|
/** Whether `t` holds a non-empty object or array as one leaf (no subtree under it). */
|
|
37
|
-
const closed = (t) => t.k.size === 0 &&
|
|
38
|
-
|
|
26
|
+
const closed = (t) => t.k.size === 0 &&
|
|
27
|
+
itemsOf(t).length === 0 &&
|
|
28
|
+
t.v !== null &&
|
|
29
|
+
typeof t.v === 'object' &&
|
|
30
|
+
Object.keys(t.v).length > 0;
|
|
31
|
+
/** `t` with a container leaf's value as its subtree: its keys, or derived items (slotless until written). */
|
|
39
32
|
const open = (t) => {
|
|
40
33
|
if (closed(t)) {
|
|
41
34
|
const value = t.v;
|
|
42
35
|
t.v = undefined;
|
|
43
36
|
derived.assign(t, value);
|
|
37
|
+
if (t.items !== undefined)
|
|
38
|
+
t.unslotted = new Set(t.items);
|
|
44
39
|
}
|
|
45
40
|
return t;
|
|
46
41
|
};
|
|
47
42
|
/** The JSON `t` reads as (`undefined` for nothing): a fresh value. */
|
|
48
43
|
const valueOf = (t) => {
|
|
49
44
|
if (closed(t))
|
|
50
|
-
return valueOf(open(tree(t.v)));
|
|
45
|
+
return valueOf(open(tree(t.p, t.v)));
|
|
51
46
|
const items = itemsOf(t);
|
|
52
47
|
if (items.length)
|
|
53
|
-
return items.map((
|
|
48
|
+
return items.map((id) => valueOf(t.k.get(id) ?? tree()) ?? null);
|
|
54
49
|
const keys = [...t.k]
|
|
55
50
|
.map(([s, c]) => [dec(s), itemish(s) ? undefined : valueOf(c)])
|
|
56
51
|
.filter(([, v]) => v !== undefined);
|
|
57
52
|
// Own properties only: a `__proto__` key (a peer's too) is data, never a prototype.
|
|
58
53
|
return keys.length ? Object.fromEntries(keys) : t.v;
|
|
59
54
|
};
|
|
60
|
-
const treeOf = (leaves) => {
|
|
55
|
+
const treeOf = (leaves, slots) => {
|
|
61
56
|
const root = tree();
|
|
62
57
|
for (const [key, v] of [...leaves].sort(([a], [b]) => (a < b ? -1 : 1)))
|
|
63
58
|
key.slice(DATA_LEAF_PREFIX.length).split('/').reduce(kid, root).v = v;
|
|
59
|
+
for (const [p, ids] of slots) {
|
|
60
|
+
const t = p === '' ? root : p.split('/').reduce(kid, root);
|
|
61
|
+
t.items = ids;
|
|
62
|
+
}
|
|
64
63
|
return root;
|
|
65
64
|
};
|
|
66
65
|
const leavesFrom = (t, prefix = DATA_LEAF_PREFIX, out = new Map()) => {
|
|
@@ -142,50 +141,74 @@ const canon = (v) => JSON.stringify(v, (_, x) => (isObject(x) ? Object.fromEntri
|
|
|
142
141
|
/** New items holding `values`. */
|
|
143
142
|
const added = (values) => values.map((value) => ({ value }));
|
|
144
143
|
/**
|
|
145
|
-
* The tree edits. New items take ids
|
|
146
|
-
*
|
|
147
|
-
*
|
|
144
|
+
* The tree edits. New items take ids from `rand`; without `rand` they are
|
|
145
|
+
* derived from their indexes and `client` (a new array's hash), so equal
|
|
146
|
+
* values write equal items everywhere. The sequence writes they need
|
|
147
|
+
* (slots, moves, removals) go to `out`.
|
|
148
148
|
*/
|
|
149
|
-
const edits = (rand, client = 0) => {
|
|
150
|
-
const pick = rand ?? (() => 0);
|
|
149
|
+
const edits = (rand, client = 0, out) => {
|
|
151
150
|
const fresh = (t, i) => {
|
|
152
151
|
for (;;) {
|
|
153
152
|
const id = rand
|
|
154
153
|
? `~${Math.floor(36 ** 7 * (10 + 26 * rand())).toString(36)}`
|
|
155
154
|
: `~l${i++}.${client.toString(36)}`;
|
|
156
|
-
if (!
|
|
155
|
+
if (!t.k.has(id) && !itemsOf(t).includes(id))
|
|
157
156
|
return id;
|
|
158
157
|
}
|
|
159
158
|
};
|
|
160
|
-
const remove = (t, id) =>
|
|
159
|
+
const remove = (t, id) => {
|
|
160
|
+
const item = t.k.get(id);
|
|
161
|
+
if (item !== undefined)
|
|
162
|
+
drop(item);
|
|
163
|
+
t.k.delete(id);
|
|
164
|
+
if (t.items !== undefined)
|
|
165
|
+
t.items = t.items.filter((x) => x !== id);
|
|
166
|
+
if (t.unslotted?.delete(id) !== true)
|
|
167
|
+
out?.push({ seq: 'remove', path: t.p, ids: [id] });
|
|
168
|
+
};
|
|
169
|
+
/** What `t` held goes with it: the slots of every array at or under it. */
|
|
170
|
+
const drop = (t) => {
|
|
171
|
+
for (const id of itemsOf(t))
|
|
172
|
+
remove(t, id);
|
|
173
|
+
for (const c of t.k.values())
|
|
174
|
+
drop(c);
|
|
175
|
+
};
|
|
161
176
|
/**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
177
|
+
* Give `entries` (kept items, moved items, new values) their places in
|
|
178
|
+
* `t`, in order: each new item's slot and each moved item's record go
|
|
179
|
+
* right after the entry before it (YATA's origin rule keeps what one
|
|
180
|
+
* writer puts after an item together, whatever a peer inserts there
|
|
181
|
+
* meanwhile), consecutive ones as one write.
|
|
166
182
|
*/
|
|
167
|
-
const between = (left, right) => rankAfter(left, right, client, pick);
|
|
168
|
-
/** Give `entries` (kept items, moved items, new values) their places in `t`, in order. */
|
|
169
183
|
const lay = (t, entries) => {
|
|
170
|
-
|
|
171
|
-
let
|
|
172
|
-
let
|
|
184
|
+
const ids = [];
|
|
185
|
+
let after = null;
|
|
186
|
+
let run = null;
|
|
173
187
|
for (let p = 0; p < entries.length; p++) {
|
|
174
188
|
const e = entries[p];
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
189
|
+
let id = e.id;
|
|
190
|
+
let seq = null;
|
|
191
|
+
if (id === undefined) {
|
|
192
|
+
id = fresh(t, p);
|
|
193
|
+
assign(kid(t, id), e.value);
|
|
194
|
+
seq = 'insert';
|
|
178
195
|
}
|
|
179
|
-
if (
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
196
|
+
else if (t.unslotted?.delete(id))
|
|
197
|
+
seq = 'insert';
|
|
198
|
+
else if (!e.keep)
|
|
199
|
+
seq = 'move';
|
|
200
|
+
ids.push(id);
|
|
201
|
+
if (seq !== null && out !== undefined) {
|
|
202
|
+
if (run !== null && run.seq === seq)
|
|
203
|
+
run.ids.push(id);
|
|
204
|
+
else
|
|
205
|
+
out.push((run = { seq, path: t.p, after, ids: [id] }));
|
|
183
206
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
assign(kid(t, id), e.value);
|
|
207
|
+
else
|
|
208
|
+
run = null;
|
|
209
|
+
after = id;
|
|
188
210
|
}
|
|
211
|
+
t.items = ids;
|
|
189
212
|
};
|
|
190
213
|
/** Make `t` read as `value`, writing only what differs: objects key by key, arrays item by item. */
|
|
191
214
|
const assign = (t, value) => {
|
|
@@ -193,16 +216,20 @@ const edits = (rand, client = 0) => {
|
|
|
193
216
|
return arrange(t, value);
|
|
194
217
|
// Anything else replaces what `t` held, but an object's equal keys.
|
|
195
218
|
const object = isObject(value) && Object.keys(value).length > 0;
|
|
219
|
+
for (const id of itemsOf(t))
|
|
220
|
+
remove(t, id);
|
|
196
221
|
for (const s of [...t.k.keys()])
|
|
197
|
-
if (!object || itemish(s) || !Object.hasOwn(value, dec(s)))
|
|
222
|
+
if (!object || itemish(s) || !Object.hasOwn(value, dec(s))) {
|
|
223
|
+
drop(t.k.get(s));
|
|
198
224
|
t.k.delete(s);
|
|
225
|
+
}
|
|
199
226
|
t.v = object ? undefined : Array.isArray(value) ? [] : value;
|
|
200
227
|
if (object)
|
|
201
228
|
for (const [k, v] of Object.entries(value))
|
|
202
229
|
assign(kid(t, enc(k)), v);
|
|
203
230
|
// A new array's items derive from it: two peers making the same one make one.
|
|
204
231
|
if (Array.isArray(value))
|
|
205
|
-
edits(undefined, hash32(canon(value))).lay(t, added(value));
|
|
232
|
+
edits(undefined, hash32(canon(value)), out).lay(t, added(value));
|
|
206
233
|
};
|
|
207
234
|
/**
|
|
208
235
|
* An array reassigned: the items a longest common run keeps equal stay;
|
|
@@ -211,23 +238,23 @@ const edits = (rand, client = 0) => {
|
|
|
211
238
|
*/
|
|
212
239
|
const arrange = (t, next) => {
|
|
213
240
|
const old = itemsOf(t);
|
|
214
|
-
const was = old.map((
|
|
241
|
+
const was = old.map((id) => canon(valueOf(t.k.get(id) ?? tree()) ?? null));
|
|
215
242
|
const entries = [];
|
|
216
243
|
let [i, j] = [0, 0];
|
|
217
244
|
for (const [mi, mj] of [...common(was, next.map(canon)), [old.length, next.length]]) {
|
|
218
245
|
for (let n = 0; n < Math.max(mi - i, mj - j); n++) {
|
|
219
246
|
const o = i + n < mi ? old[i + n] : undefined;
|
|
220
247
|
if (j + n >= mj)
|
|
221
|
-
remove(t, o
|
|
222
|
-
else if (
|
|
248
|
+
remove(t, o);
|
|
249
|
+
else if (o === undefined)
|
|
223
250
|
entries.push({ value: next[j + n] });
|
|
224
251
|
else {
|
|
225
|
-
entries.push({ id: o
|
|
226
|
-
assign(kid(t, o
|
|
252
|
+
entries.push({ id: o, keep: true });
|
|
253
|
+
assign(kid(t, o), next[j + n]);
|
|
227
254
|
}
|
|
228
255
|
}
|
|
229
256
|
if (mi < old.length)
|
|
230
|
-
entries.push({ id: old[mi]
|
|
257
|
+
entries.push({ id: old[mi], keep: true });
|
|
231
258
|
[i, j] = [mi + 1, mj + 1];
|
|
232
259
|
}
|
|
233
260
|
t.v = [];
|
|
@@ -243,7 +270,7 @@ const edits = (rand, client = 0) => {
|
|
|
243
270
|
return t;
|
|
244
271
|
if (isArr(open(t))) {
|
|
245
272
|
const item = itemAt(itemsOf(t), k);
|
|
246
|
-
t = item
|
|
273
|
+
t = item === undefined ? undefined : kid(t, item);
|
|
247
274
|
}
|
|
248
275
|
else if (itemish(k))
|
|
249
276
|
return undefined;
|
|
@@ -260,7 +287,7 @@ const edits = (rand, client = 0) => {
|
|
|
260
287
|
if (!at)
|
|
261
288
|
return false;
|
|
262
289
|
const items = isArr(at) ? itemsOf(at) : undefined;
|
|
263
|
-
const list = items?.map((
|
|
290
|
+
const list = items?.map((id) => ({ id, keep: true })) ?? [];
|
|
264
291
|
const k = path.at(-1);
|
|
265
292
|
if (order) {
|
|
266
293
|
const ids = Array.isArray(order) ? order.map((i) => list[i]?.id) : [];
|
|
@@ -289,9 +316,14 @@ const edits = (rand, client = 0) => {
|
|
|
289
316
|
return false; // an item where no array is
|
|
290
317
|
if (value !== undefined)
|
|
291
318
|
assign(reach(at, [k]), value);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
319
|
+
else {
|
|
320
|
+
const gone = at.k.get(enc(segmentKey(k)));
|
|
321
|
+
if (gone !== undefined)
|
|
322
|
+
drop(gone);
|
|
323
|
+
// The last key of an object deleted keeps the object.
|
|
324
|
+
if (at.k.delete(enc(segmentKey(k))) && at !== root && valueOf(at) === undefined)
|
|
325
|
+
at.v = {};
|
|
326
|
+
}
|
|
295
327
|
return true;
|
|
296
328
|
}
|
|
297
329
|
else {
|
|
@@ -319,104 +351,180 @@ const leavesOf = (node) => {
|
|
|
319
351
|
out.set(key, node.getAttr(key));
|
|
320
352
|
return out;
|
|
321
353
|
};
|
|
322
|
-
/** The
|
|
323
|
-
const
|
|
354
|
+
/** The data slots of `node`'s sequence as displayed: per array path, its item ids in order (an id once), and each id's entries. */
|
|
355
|
+
const slotsOf = (node) => {
|
|
356
|
+
const slots = new Map();
|
|
357
|
+
const entries = new Map();
|
|
358
|
+
if (node.doc == null)
|
|
359
|
+
return { slots, entries };
|
|
360
|
+
for (const e of entriesOf(asEngineDoc(node.doc), node)) {
|
|
361
|
+
if (!isDataSlot(e.value))
|
|
362
|
+
continue;
|
|
363
|
+
const { p, i } = e.value;
|
|
364
|
+
const key = `${p}\u0000${i}`;
|
|
365
|
+
const list = entries.get(key);
|
|
366
|
+
if (list === undefined) {
|
|
367
|
+
entries.set(key, [e]);
|
|
368
|
+
const ids = slots.get(p);
|
|
369
|
+
if (ids === undefined)
|
|
370
|
+
slots.set(p, [i]);
|
|
371
|
+
else
|
|
372
|
+
ids.push(i);
|
|
373
|
+
}
|
|
374
|
+
else
|
|
375
|
+
list.push(e);
|
|
376
|
+
}
|
|
377
|
+
return { slots, entries };
|
|
378
|
+
};
|
|
379
|
+
/** The leaves of `value` under `prefix`, and the slots of its arrays' items, derived from them. */
|
|
380
|
+
const writesOfValue = (value) => {
|
|
324
381
|
const t = tree();
|
|
325
|
-
|
|
326
|
-
|
|
382
|
+
const out = [];
|
|
383
|
+
edits(undefined, 0, out).assign(t, value);
|
|
384
|
+
return [...leavesFrom(t), ...out];
|
|
327
385
|
};
|
|
328
|
-
/** A new node's data, as leaves. */
|
|
329
|
-
export const
|
|
386
|
+
/** A new node's data, as the writes that give it (its leaves and its arrays' slots). */
|
|
387
|
+
export const dataWrites = (data) => writesOfValue(isObject(data) ? data : {});
|
|
330
388
|
/** A path of the data as a leaf key (`d/` and its pointer). */
|
|
331
389
|
export const leafKey = (path) => DATA_LEAF_PREFIX + path.map((k) => enc(k)).join('/');
|
|
390
|
+
/** A path of the data as a slot's `p` (its pointer without `d/`). */
|
|
391
|
+
const slotPath = (key) => key.slice(DATA_LEAF_PREFIX.length);
|
|
332
392
|
/**
|
|
333
|
-
*
|
|
334
|
-
* declares) holding one leaf: the value of everything at and under it.
|
|
393
|
+
* The leaves of `root` with every atomic path (`data.atomic`: a leaf key a
|
|
394
|
+
* kind declares) holding one leaf: the value of everything at and under it.
|
|
335
395
|
*/
|
|
336
|
-
const collapse = (
|
|
337
|
-
if (atomic.length === 0)
|
|
338
|
-
return leaves;
|
|
339
|
-
const root = treeOf(leaves);
|
|
396
|
+
const collapse = (root, atomic) => {
|
|
340
397
|
for (const key of atomic) {
|
|
341
398
|
let t = root;
|
|
342
|
-
for (const s of key
|
|
399
|
+
for (const s of slotPath(key).split('/'))
|
|
343
400
|
t = t?.k.get(s);
|
|
344
|
-
if (t === undefined || t.k.size === 0)
|
|
401
|
+
if (t === undefined || (t.k.size === 0 && itemsOf(t).length === 0))
|
|
345
402
|
continue;
|
|
346
403
|
t.v = valueOf(t);
|
|
347
404
|
t.k.clear();
|
|
405
|
+
t.items = undefined;
|
|
406
|
+
t.unslotted = undefined;
|
|
348
407
|
}
|
|
349
408
|
return leavesFrom(root);
|
|
350
409
|
};
|
|
410
|
+
/** Whether `path` (a slot's `p`) lies at or under one of the atomic leaf keys. */
|
|
411
|
+
const underAtomic = (path, atomic) => atomic.some((key) => {
|
|
412
|
+
const a = slotPath(key);
|
|
413
|
+
return path === a || path.startsWith(`${a}/`);
|
|
414
|
+
});
|
|
351
415
|
/** `node`'s data (`undefined` when it has none). */
|
|
352
|
-
export const readData = (node) => valueOf(treeOf(leavesOf(node)));
|
|
416
|
+
export const readData = (node) => valueOf(treeOf(leavesOf(node), slotsOf(node).slots));
|
|
353
417
|
/**
|
|
354
418
|
* The ids of the items of the array at `path` (keys, item indexes or ids)
|
|
355
419
|
* in `node`'s data, in order; `[]` where no array is.
|
|
356
420
|
*/
|
|
357
|
-
export const itemIds = (node, path) => idsAt(treeOf(leavesOf(node)), path);
|
|
421
|
+
export const itemIds = (node, path) => idsAt(treeOf(leavesOf(node), slotsOf(node).slots), path);
|
|
358
422
|
const idsAt = (root, path) => {
|
|
359
423
|
let t = root;
|
|
360
424
|
for (const k of path)
|
|
361
425
|
if (t && isArr(open(t))) {
|
|
362
426
|
const item = itemAt(itemsOf(t), k);
|
|
363
|
-
t = item
|
|
427
|
+
t = item === undefined ? undefined : t.k.get(item);
|
|
364
428
|
}
|
|
365
429
|
else
|
|
366
430
|
t = itemish(k) ? undefined : t?.k.get(enc(segmentKey(k)));
|
|
367
|
-
return t ? itemsOf(open(t))
|
|
431
|
+
return t ? itemsOf(open(t)) : [];
|
|
368
432
|
};
|
|
369
433
|
/**
|
|
370
434
|
* `node`'s data as it reads once `patches` are applied (nothing written),
|
|
371
435
|
* with the ids of the array items at a path (`itemIds`): an item a patch
|
|
372
|
-
* makes has no
|
|
436
|
+
* makes has no slot yet (`''`), so a later patch names it by index.
|
|
373
437
|
* `null` when a patch fits no value.
|
|
374
438
|
*/
|
|
375
439
|
export const previewData = (node, patches) => {
|
|
376
440
|
const base = node ? leavesOf(node) : new Map();
|
|
377
|
-
const
|
|
441
|
+
const { slots } = node ? slotsOf(node) : { slots: new Map() };
|
|
442
|
+
const root = treeOf(base, slots);
|
|
378
443
|
if (!patches.every((p) => edits().apply(root, p)))
|
|
379
444
|
return null;
|
|
380
|
-
const known = new Set([...
|
|
445
|
+
const known = new Set([...slots.values()].flat());
|
|
381
446
|
return {
|
|
382
447
|
data: valueOf(root) ?? {},
|
|
383
|
-
ids: (path) => idsAt(root, path).map((id) => (known.has(
|
|
448
|
+
ids: (path) => idsAt(root, path).map((id) => (known.has(id) ? id : ''))
|
|
384
449
|
};
|
|
385
450
|
};
|
|
386
451
|
/** `data` with `patches` applied in order, as a fresh value (a root patch replaces it); `null` when one fits no value. */
|
|
387
452
|
export const applyPatch = (data, patches) => {
|
|
388
|
-
const root =
|
|
453
|
+
const root = tree();
|
|
454
|
+
derived.assign(root, data);
|
|
389
455
|
if (!patches.every((p) => derived.apply(root, p)))
|
|
390
456
|
return null;
|
|
391
457
|
return valueOf(root) ?? {};
|
|
392
458
|
};
|
|
393
459
|
/**
|
|
394
|
-
* The
|
|
395
|
-
* items get ids from `rand
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
* An unchanged value
|
|
460
|
+
* The writes that give `node` the data `patches` make of its own (new
|
|
461
|
+
* items get ids from `rand`), or `null` when a patch fits no value there:
|
|
462
|
+
* only the leaves of the keys and items a patch touches change, so a
|
|
463
|
+
* concurrent edit of another key or item is kept, and only the slots of
|
|
464
|
+
* the items it makes, moves or removes. An atomic path is written as one
|
|
465
|
+
* leaf and the leaves and slots under it are dropped. An unchanged value
|
|
466
|
+
* writes nothing.
|
|
400
467
|
*/
|
|
401
468
|
export const patchWrites = (node, patches, client = 0, rand, atomic = []) => {
|
|
402
469
|
const now = leavesOf(node);
|
|
403
|
-
const
|
|
470
|
+
const { slots } = slotsOf(node);
|
|
471
|
+
const root = treeOf(now, slots);
|
|
404
472
|
const before = valueOf(root);
|
|
405
|
-
const
|
|
473
|
+
const seq = [];
|
|
474
|
+
const { apply } = edits(rand, client, seq);
|
|
406
475
|
if (!patches.every((p) => apply(root, p)))
|
|
407
476
|
return null;
|
|
408
477
|
if (jsonEquals(before, valueOf(root)))
|
|
409
478
|
return [];
|
|
410
|
-
const want = collapse(
|
|
411
|
-
|
|
479
|
+
const want = collapse(root, atomic);
|
|
480
|
+
const leaves = [...new Set([...now.keys(), ...want.keys()])]
|
|
412
481
|
.filter((key) => !jsonEquals(now.get(key), want.get(key)))
|
|
413
482
|
.map((key) => [key, want.get(key)]);
|
|
483
|
+
return [...leaves, ...seq.filter((w) => !underAtomic(w.path, atomic))];
|
|
414
484
|
};
|
|
415
|
-
/**
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
485
|
+
/**
|
|
486
|
+
* Write `writes` on `node`: its attrs, and its arrays' slots in its one
|
|
487
|
+
* sequence (`placement/slots.ts`). On a detached node (a block or atom being
|
|
488
|
+
* created) the slots are appended in order; on an integrated one each write
|
|
489
|
+
* goes after the item it names, read from the sequence as it stands.
|
|
490
|
+
*/
|
|
491
|
+
export const writeData = (node, writes) => {
|
|
492
|
+
let appended = 0;
|
|
493
|
+
for (const w of writes) {
|
|
494
|
+
if (Array.isArray(w)) {
|
|
495
|
+
const [key, value] = w;
|
|
496
|
+
if (value === undefined)
|
|
497
|
+
node.deleteAttr(key);
|
|
498
|
+
else
|
|
499
|
+
node.setAttr(key, value);
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
const { seq, path, ids } = w;
|
|
503
|
+
const payloads = ids.map((i) => ({ p: path, i }));
|
|
504
|
+
if (node.doc == null) {
|
|
505
|
+
// A new node: its items in order, none to move or remove yet.
|
|
506
|
+
if (seq === 'insert') {
|
|
507
|
+
node.insert(appended, payloads);
|
|
508
|
+
appended += payloads.length;
|
|
509
|
+
}
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
const doc = asEngineDoc(node.doc);
|
|
513
|
+
const { slots, entries } = slotsOf(node);
|
|
514
|
+
/** Every displayed slot of item `id` of the array (two peers may have written one). */
|
|
515
|
+
const of = (id) => entries.get(`${path}\u0000${id}`) ?? [];
|
|
516
|
+
if (seq === 'remove') {
|
|
517
|
+
for (const id of ids)
|
|
518
|
+
for (const e of of(id))
|
|
519
|
+
removeUnit(doc, e.unit);
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
// After the item named; at the array's start: before its first item.
|
|
523
|
+
const { after } = w;
|
|
524
|
+
placeAfter(doc, node, after === null ? null : (of(after)[0] ?? null), after === null ? (of(slots.get(path)?.[0])[0] ?? null) : null, seq === 'insert' ? payloads : null, seq === 'move'
|
|
525
|
+
? triples(ids.flatMap((id) => of(id)
|
|
526
|
+
.slice(0, 1)
|
|
527
|
+
.map((e) => e.unit)))
|
|
528
|
+
: null);
|
|
529
|
+
}
|
|
422
530
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Block deletion (`del.blocks.promote`): only the members leave, the
|
|
3
3
|
* unselected children of a deleted block take its slot.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import type { BlockId } from '../placement/model.js';
|
|
6
6
|
import type { Prepared } from './types.js';
|
|
7
7
|
import type { OpsContext } from './steps.js';
|
|
8
8
|
/** The delete ops of one facade, prepared. */
|
package/dist/crdt/doc/delete.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Block deletion (`del.blocks.promote`): only the members leave, the
|
|
3
|
-
* unselected children of a deleted block take its slot.
|
|
4
|
-
*/
|
|
5
|
-
import { promotedRank } from '../placement/model.js';
|
|
6
1
|
import { ref } from './plan.js';
|
|
7
2
|
/** The delete ops of one facade, prepared. */
|
|
8
3
|
export const deleteOps = (c) => {
|
|
9
|
-
const { view, blockTypeOf, childrenIds, positionOf, ancestorsOf, itemKindOf, isLayout, isLayoutItem, isTable, isTableRow, live, REFUSED, plan,
|
|
4
|
+
const { view, blockTypeOf, childrenIds, positionOf, ancestorsOf, itemKindOf, isLayout, isLayoutItem, isTable, isTableRow, live, REFUSED, plan, settle, emptyingAll, emptied, deleting, remove } = c;
|
|
10
5
|
/**
|
|
11
6
|
* Delete a set of blocks (`del.blocks.promote`): this writer's mark on
|
|
12
7
|
* every member and on what it displays through merge claims (wins over
|
|
@@ -52,41 +47,29 @@ export const deleteOps = (c) => {
|
|
|
52
47
|
const pos = positionOf(root);
|
|
53
48
|
const chunk = [];
|
|
54
49
|
const kept = [];
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
// takes the slot in
|
|
58
|
-
//
|
|
59
|
-
const walk = (b
|
|
50
|
+
// The kept children keep their home slots: the read shows them in the
|
|
51
|
+
// root's slot, in its order (a block a peer puts under a member
|
|
52
|
+
// meanwhile takes the slot in that order too); only their kinds are
|
|
53
|
+
// written, as the slot's parent settles them.
|
|
54
|
+
const walk = (b) => {
|
|
60
55
|
chunk.push(b);
|
|
61
56
|
for (const kid of kids.get(b) ?? []) {
|
|
62
|
-
const rank = promotedRank(slotRank, kid.rank);
|
|
63
57
|
if (set.has(kid.id))
|
|
64
|
-
walk(kid.id
|
|
58
|
+
walk(kid.id);
|
|
65
59
|
else
|
|
66
|
-
kept.push({ id: kid.id, from: b
|
|
60
|
+
kept.push({ id: kid.id, from: b });
|
|
67
61
|
}
|
|
68
62
|
};
|
|
69
|
-
walk(root
|
|
63
|
+
walk(root);
|
|
70
64
|
members.push(...chunk);
|
|
71
65
|
if (kept.length > 0)
|
|
72
66
|
promoting.add(root);
|
|
73
|
-
// A layout shows only its items: a deleted item's blocks
|
|
74
|
-
// after
|
|
67
|
+
// A layout shows only its items: a deleted item's blocks show right
|
|
68
|
+
// after the layout (`layout.only-items`), settled for its parent.
|
|
75
69
|
const item = pos.parent === null ? undefined : itemKindOf(pos.parent);
|
|
76
|
-
const
|
|
77
|
-
const out = kept.filter(at);
|
|
78
|
-
const inside = kept.filter((k) => !at(k));
|
|
79
|
-
const lpos = out.length > 0 ? positionOf(pos.parent) : null;
|
|
80
|
-
const lrank = lpos && kids.get(lpos.parent)[lpos.index].rank;
|
|
70
|
+
const out = (k) => item !== undefined && blockTypeOf(k.id) !== item;
|
|
81
71
|
return [
|
|
82
|
-
...
|
|
83
|
-
...inside.flatMap((k) => settle(k.from, [k.id], pos.parent)),
|
|
84
|
-
...(lpos === null
|
|
85
|
-
? []
|
|
86
|
-
: [
|
|
87
|
-
...moveTo(out.map((k) => k.id), lpos.parent, lpos.index + 1, out.map((k) => promotedRank(lrank, k.rank))),
|
|
88
|
-
...out.flatMap((k) => settle(k.from, [k.id], lpos.parent))
|
|
89
|
-
]),
|
|
72
|
+
...kept.flatMap((k) => settle(k.from, [k.id], out(k) ? positionOf(pos.parent).parent : pos.parent)),
|
|
90
73
|
deleting(root, chunk)
|
|
91
74
|
];
|
|
92
75
|
});
|
|
@@ -2,13 +2,14 @@ import type { BlockAttributionApi } from '../attribution/block.js';
|
|
|
2
2
|
import type { EdytorDocConfig, OpResult, Prepared } from './types.js';
|
|
3
3
|
import type { DocBase, DocReads } from './reads.js';
|
|
4
4
|
/**
|
|
5
|
-
* Raised when
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* bare `bindEdytorDoc` facade has no document
|
|
5
|
+
* Raised when an operation runs against a torn-down document: every attach
|
|
6
|
+
* reference released, or its facade disposed (terminal for writes; reads
|
|
7
|
+
* stay dead-safe: a stale handle may still be inspected). Distinct from
|
|
8
|
+
* `DocumentNotReadyError`: destroyed is terminal, pending may still resolve.
|
|
9
|
+
* Kept in this module because a bare `bindEdytorDoc` facade has no document
|
|
10
|
+
* layer above it.
|
|
10
11
|
*/
|
|
11
|
-
export declare class
|
|
12
|
+
export declare class DocumentDestroyedError extends Error {
|
|
12
13
|
constructor(service?: string);
|
|
13
14
|
}
|
|
14
15
|
/** What the write funnel writes with: the reads, the attribution writer and the facade's configuration. */
|