@fluid-experimental/tree 0.59.1000-61898 → 0.59.1001

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.
Files changed (72) hide show
  1. package/README.md +156 -43
  2. package/dist/ChangeTypes.d.ts +9 -14
  3. package/dist/ChangeTypes.d.ts.map +1 -1
  4. package/dist/ChangeTypes.js.map +1 -1
  5. package/dist/Checkout.d.ts.map +1 -1
  6. package/dist/Checkout.js +3 -2
  7. package/dist/Checkout.js.map +1 -1
  8. package/dist/LogViewer.d.ts +2 -3
  9. package/dist/LogViewer.d.ts.map +1 -1
  10. package/dist/LogViewer.js +5 -4
  11. package/dist/LogViewer.js.map +1 -1
  12. package/dist/NodeIdUtilities.d.ts +26 -11
  13. package/dist/NodeIdUtilities.d.ts.map +1 -1
  14. package/dist/NodeIdUtilities.js.map +1 -1
  15. package/dist/SharedTree.d.ts +61 -22
  16. package/dist/SharedTree.d.ts.map +1 -1
  17. package/dist/SharedTree.js +61 -26
  18. package/dist/SharedTree.js.map +1 -1
  19. package/dist/Transaction.d.ts +1 -2
  20. package/dist/Transaction.d.ts.map +1 -1
  21. package/dist/Transaction.js +4 -8
  22. package/dist/Transaction.js.map +1 -1
  23. package/dist/TransactionInternal.d.ts +3 -6
  24. package/dist/TransactionInternal.d.ts.map +1 -1
  25. package/dist/TransactionInternal.js +8 -4
  26. package/dist/TransactionInternal.js.map +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/docs/Write-Format.md +19 -0
  31. package/lib/ChangeTypes.d.ts +9 -14
  32. package/lib/ChangeTypes.d.ts.map +1 -1
  33. package/lib/ChangeTypes.js.map +1 -1
  34. package/lib/Checkout.d.ts.map +1 -1
  35. package/lib/Checkout.js +3 -2
  36. package/lib/Checkout.js.map +1 -1
  37. package/lib/LogViewer.d.ts +2 -3
  38. package/lib/LogViewer.d.ts.map +1 -1
  39. package/lib/LogViewer.js +5 -4
  40. package/lib/LogViewer.js.map +1 -1
  41. package/lib/NodeIdUtilities.d.ts +26 -11
  42. package/lib/NodeIdUtilities.d.ts.map +1 -1
  43. package/lib/NodeIdUtilities.js.map +1 -1
  44. package/lib/SharedTree.d.ts +61 -22
  45. package/lib/SharedTree.d.ts.map +1 -1
  46. package/lib/SharedTree.js +61 -26
  47. package/lib/SharedTree.js.map +1 -1
  48. package/lib/Transaction.d.ts +1 -2
  49. package/lib/Transaction.d.ts.map +1 -1
  50. package/lib/Transaction.js +4 -8
  51. package/lib/Transaction.js.map +1 -1
  52. package/lib/TransactionInternal.d.ts +3 -6
  53. package/lib/TransactionInternal.d.ts.map +1 -1
  54. package/lib/TransactionInternal.js +8 -4
  55. package/lib/TransactionInternal.js.map +1 -1
  56. package/lib/index.d.ts +1 -1
  57. package/lib/index.d.ts.map +1 -1
  58. package/lib/index.js.map +1 -1
  59. package/lib/test/LogViewer.tests.js +13 -10
  60. package/lib/test/LogViewer.tests.js.map +1 -1
  61. package/lib/test/Virtualization.tests.js +1 -2
  62. package/lib/test/Virtualization.tests.js.map +1 -1
  63. package/package.json +18 -18
  64. package/src/ChangeTypes.ts +9 -14
  65. package/src/Checkout.ts +3 -3
  66. package/src/LogViewer.ts +4 -4
  67. package/src/NodeIdUtilities.ts +26 -11
  68. package/src/SharedTree.ts +67 -24
  69. package/src/Transaction.ts +5 -10
  70. package/src/TransactionInternal.ts +9 -10
  71. package/src/index.ts +0 -1
  72. package/docs/Future.md +0 -155
package/README.md CHANGED
@@ -2,41 +2,61 @@
2
2
 
3
3
  A [Fluid](https://fluidframework.com/) SharedObject Tree with:
4
4
 
5
- - Transactional editing
5
+ - Transactional editing and snapshot isolation
6
6
  - Strong node identities
7
7
  - High quality automatic merge resolution
8
- - Full History Inspection, Manipulation and Metadata
8
+ - A flexible operation set that includes Move
9
+ - History inspection, manipulation and metadata
9
10
 
10
11
  Revisions of the tree (see [EditLog](./src/EditLog.ts) and [TreeView](./src/TreeView.ts)) are created from sequences of Edits.
11
12
 
12
13
  Semantically, the current state of the tree is defined as:
13
14
 
14
- The initial tree, modified by all edits in order.
15
+ The [initial tree](./src/InitialTree.ts), modified by all edits in order.
15
16
 
16
17
  The order of the edits is:
17
18
 
18
19
  1. All acknowledged edits, in the order agreed upon by Fluid's consensus.
19
- 2. All local edits (not acknowledged by Fluid yet), in the order they were created.
20
+ 2. All local edits (not acknowledged by Fluid yet), in the order they were applied.
21
+
22
+ **Important: this DDS is no longer in active development, and a non-experimental, officially supported SharedTree is in active development by the Fluid team that will expand on its rich feature set.**
20
23
 
21
24
  # Getting Started
22
25
 
23
26
  ## Tree Abstraction
24
27
 
25
- The tree abstraction used for `SharedTree` is summarized by the [TreeNode](./src/persisted-types/0.0.2.ts) class. Nodes have _traits_, a _definition_, an _identity_, and optionally a payload to contain extra arbitrary data.
28
+ The tree abstraction used for `SharedTree` is composed of nodes with four main attributes: a _definition_, an _identity_, zero or more _traits_, and an optional _payload_ to contain arbitrary serializable data.
26
29
 
27
30
  ### Definition
28
31
 
29
- The definition of a node provides the node's meaning. It is typically used to associate the node with metadata such as a schema for what this tree represents.
32
+ The definition of a node conveys the node's semantic meaning. It is typically used to associate the node with metadata such as a schema for what this tree represents.
30
33
 
31
34
  ### Identifier
32
35
 
33
- A node's identifier is a globally unique way to refer to it. This enables collaborative editing specifications by ensuring that each element of a document can be identified.
36
+ A node's identifier is a unique key associated with that node. The identifier can be used to retrieve a node from a the current view of a SharedTree, and provides a way to refer to existing nodes when performing edits to the tree.
34
37
 
35
38
  ### Traits
36
39
 
37
- Traits are what give a node the structure of a tree. Intuitively, a trait is a named sequence of content nodes. Organizing a node's children underneath traits (rather than in a freeform list, as many trees do) allows more natural construction of documents.
40
+ Traits are sequences of child nodes underneath a parent node. Each trait is identified by a label and may contain one or more children. Organizing a node's children underneath traits (rather than in a single freeform list, as many trees do) allows more intuitive construction of documents.
41
+
42
+ ```typescript
43
+ // A parent node with three traits, labelled "name", "employees" and "products"
44
+ {
45
+ definition: 'Company',
46
+ identifier: 42,
47
+ traits: {
48
+ name: [{...}] // Traits may contain just one child node...
49
+ employees: [{...}, {...}, {...}], // ...or many children
50
+ products: [{...}, {...}]
51
+ }
52
+ }
53
+ ```
54
+
55
+ ### Payload
56
+
57
+ The payload of a node is a bag of arbitrary state with only one requirement: it must be JSON-serializable. Payloads allow the tree to store data that can't be efficiently encoded by nodes themselves (for example, strings or numbers)
38
58
 
39
- ### Example
59
+ ## Example Tree
40
60
 
41
61
  Consider a document which consists of the point (4, 9) in 2-dimensional space. One way this document could be encoded into the tree format expected by a `SharedTree` might look like this:
42
62
 
@@ -46,9 +66,9 @@ const pointDefinition = '3781c3b1-41e6-43c5-9ffd-13916071d4dc';
46
66
  const numberDefinition = '3e5a1652-983f-4533-bb59-130ac8f3714e';
47
67
 
48
68
  // These identifiers refer to *the particular* point/number nodes in the tree below.
49
- const pointIdentifier = '668b4277-ed5b-41f6-90ce-d2f666a59e41';
50
- const xIdentifier = 'f067342f-5307-460e-a67a-41d2448231f3';
51
- const yIdentifier = '6a23b443-8735-4c1d-8f88-3aca5ba07939';
69
+ const pointIdentifier = 100;
70
+ const xIdentifier = 101;
71
+ const yIdentifier = 102;
52
72
 
53
73
  const pointDocument: Node = {
54
74
  definition: pointDefinition
@@ -68,7 +88,7 @@ const pointDocument: Node = {
68
88
  };
69
89
  ```
70
90
 
71
- Note that this example isn't meant to be taken verbatim as valid code -- it cheats a bit with payload representation for the sake of simplicity. It is, however, truthful to tree structure.
91
+ Note that this example isn't meant to be taken verbatim as valid code -- it cheats a bit with payload representation for the sake of simplicity, and isn't validly constructing the node's identifiers. It is, however, truthful to tree structure.
72
92
 
73
93
  ## Creating a SharedTree
74
94
 
@@ -78,30 +98,59 @@ SharedTree follows typical [Fluid DDS conventions](https://fluidframework.com/do
78
98
  const tree = SharedTree.create(runtime);
79
99
  ```
80
100
 
81
- Upon creation, the tree will contain a single node: `initialTree`.
101
+ Upon creation, the tree will contain a single node: the [initialTree](./src/InitialTree.ts). All SharedTrees begin with this initial node as their root node, which cannot be deleted or moved. It provides an anchor for new nodes to be inserted underneath it.
82
102
 
83
- ## Editing
103
+ ## Reading
84
104
 
85
- For simple edits (ones in which transactionality isn't important), `SharedTree` provides convenient, imperative APIs along the following lines:
105
+ SharedTree provides [TreeView](./src/TreeView.ts)s which are immutable snapshots of the tree at a given revision. These views can be generated for the current (i.e. the most up-to-date after applying all known edits) state of the tree, or can be created for the state of the tree after a specific revision in the tree's history of edits.
106
+
107
+ ### Reading the current state of the tree
108
+
109
+ The `currentView` property on SharedTree is the easiest way to get the view of the latest revision.
86
110
 
87
111
  ```typescript
88
- tree.editor.insert(fooNode, StablePlace.atStartOf({ parent: initialTree.identifier, label: 'foo' }));
89
- tree.editor.insert(barNode, StablePlace.atStartOf({ parent: initialTree.identifier, label: 'bar' }));
112
+ function getChildrenUnderTrait(sharedTree: SharedTree, parentId: NodeId, traitLabel: TraitLabel): TreeViewNode[] {
113
+ // Get the most up-to-date view of the tree at this moment.
114
+ const view = sharedTree.currentView;
115
+ // Get the IDs of children in some trait with `getTrait`:
116
+ const childIds = view.getTrait({ label: traitLabel, parent: parentId });
117
+ // Get the node for a given ID with `getViewNode`:
118
+ return childIds.map((id) => view.getViewNode(id));
119
+ }
90
120
  ```
91
121
 
92
- This would insert `fooNode` at the start of the "foo" trait underneath the initial tree's root node, and `barNode` underneath the "bar" trait.
93
- Each operation would be performed in its own `Edit`, which is `SharedTree`'s transactional atom.
122
+ > Note that `view` will never change, even if the shared tree applies or receives more edits. If you want the updated view after additional edits happen, you must call `sharedTree.currentView` again.
94
123
 
95
- If it is undesirable that one of the above operations could fail to apply while the other could succeed, you should instead leverage `Checkout`. A `Checkout`--whose name is inspired from source control--can be thought of as a local view of the `SharedTree` which provides [snapshot isolation](https://en.wikipedia.org/wiki/Snapshot_isolation#:~:text=In%20databases%2C%20and%20transaction%20processing,the%20transaction%20itself%20will%20successfully). Editing the `SharedTree` using a `Checkout` can be done by opening an edit, applying a number of changes, and closing the edit.
124
+ ### Reading an arbitrary revision of the tree
125
+
126
+ If you want to inspect the tree at some state prior to the current view, SharedTree provides a [LogViewer](./src/LogViewer.ts) to obtain views at a specific revision.
96
127
 
97
128
  ```typescript
98
- const checkout = new EagerCheckout(tree);
99
- checkout.openEdit();
100
- checkout.applyChanges(Change.insertTree(fooNode, StablePlace.atStartOf({ parent: initialTree, label: 'foo' })));
101
- checkout.applyChanges(Change.insertTree(barNode, StablePlace.atStartOf({ parent: initialTree, label: 'bar' })));
102
- checkout.closeEdit();
129
+ function getViewAfterEdit(sharedTree: SharedTree, editId: EditId): TreeView {
130
+ // First, find which revision corresponds to a given edit
131
+ const revision = sharedTree.edits.getIndexOfId(editId);
132
+ // Then, ask the logViewer to create a view at that specific revision
133
+ return sharedTree.logViewer.getRevisionViewInSession(revision);
134
+ }
103
135
  ```
104
136
 
137
+ ## Editing
138
+
139
+ For simple edits (ones in which transactionality isn't important), `SharedTree` provides convenient, imperative APIs along the following lines:
140
+
141
+ ```typescript
142
+ const view = sharedTree.currentView;
143
+ sharedTree.applyEdit(Change.insertTree(fooNode, StablePlace.atStartOf({ parent: view.root, label: 'foo' }));
144
+ sharedTree.applyEdit(Change.move(barNode, StablePlace.after(fooNode.identifier)));
145
+ ```
146
+
147
+ This would insert `fooNode` at the start of the "foo" trait underneath the root node, and move `barNode` from wherever it is in the tree to after the `foodNode` in the "foo" trait.
148
+ Each operation would be performed in its own `Edit`, which is `SharedTree`'s transactional atom (one revision corresponds to one edit).
149
+
150
+ An `Edit` is the basic unit of transactionality in `SharedTree`. It specifies how to modify a document via a sequence of changes (see [ChangeTypes](./src/ChangeTypes.ts)). Each edit, when applied to a version of the document (a TreeView), produces a new version of the document.
151
+
152
+ Once an edit is acknowledged by the Fluid service (and thus it has a sequence number, and will be included in summaries), the version of the document it applies to is fixed: it will not be applied to any revision other than the one produced by its preceding edit. There may be operations that will create new edits based on existing ones and apply them in a different context (e.g. undo), but these are logically considered new edits.
153
+
105
154
  "Move" and "delete" operations have the added complexity of needing to specify locations (`StableRange`s) within the `SharedTree` which should be moved (or deleted, respectively). A `StableRange` consists of a start `StablePlace` and an end `StablePlace`.
106
155
  `StablePlace`s are not nodes, but instead places where nodes could be inserted. Each place consists of an "anchor," which is either a trait or another node.
107
156
 
@@ -119,28 +168,78 @@ Once concurrent edits are considered, the different ways to anchor this `StableR
119
168
 
120
169
  Also note that there are some more convenient shorthands for several of these specifications. See `StableRange` documentation for more information.
121
170
 
122
- # Status
171
+ ### Change Atomicity
123
172
 
124
- SharedTree is in active, but still relatively early development. As such, it is lacking in some areas (such as performance testing). For an idea of some future features we'd like to support, see [Future Plans](./docs/Future.md).
173
+ One or both of the above calls to `tree.applyEdit ` could fail to apply. It may be desirable to group changes to the tree such that all the changes are successful and apply at once, or in the case that any of them fail, none of them apply. There are three approaches available to accomplish this.
125
174
 
126
- Implementation-wise:
175
+ #### Apply all changes together
127
176
 
128
- - Document format may change only in major releases, and SharedTree is committed to backwards compatibility (support for older documents). For more information on this commitment, see the notes in [persisted-types](./src/persisted-types/README.md).
129
- - APIs are not yet stable, and those beyond what's needed for the MVP (ex: history editing and inspection) are not provided yet. Core APIs are not likely to significantly change.
130
- - Performance is generally reasonable. However, this assessment was made using integration-style performance tests of consuming applications. Though it's on the road-map, there are currently no rigorous performance tests which are isolated to SharedTree.
177
+ The two edits above can simply have their changes concatenated into a single edit.
131
178
 
132
- Design wise:
179
+ ```typescript
180
+ sharedTree.applyEdit([
181
+ ...Change.insertTree(fooNode, StablePlace.atStartOf({ parent: view.root, label: 'foo' }),
182
+ ...Change.move(barNode, StablePlace.after(fooNode.identifier))
183
+ ]);
184
+ ```
185
+
186
+ #### Use a Transaction
187
+
188
+ The above approach is only possible once all the changes are known. A client may instead wish to build up a sequence of changes over time and observe their affects on the view, but wait until later to submit them in an edit. A [Transaction](./src/Transaction.ts) is a lightweight tool to accomplish this.
189
+
190
+ ```typescript
191
+ const transaction = new Transaction(sharedTree);
192
+ transaction.apply(Change.insertTree(fooNode, StablePlace.atStartOf({ parent: view.root, label: 'foo' }));
193
+ const viewAfterFirstEdit = transaction.currentView; // This is the view after applying the above change. It is not the current view of the SharedTree (which has not had the above change applied).
194
+ transaction.apply(Change.move(barNode, StablePlace.after(fooNode.identifier)));
195
+ transaction.closeAndCommit(); // If all changes were successful, this will apply them together as a single edit to the SharedTree. The transaction is now "closed" and any future changes will be ignored.
196
+ ```
197
+
198
+ > If any changes applied to a transaction fail, the transaction will automatically close.
199
+
200
+ #### Use a Checkout
201
+
202
+ A [Checkout](./src/Checkout.ts) is similar to a `Transaction` in that it applies changes over time, but it has some additional features:
203
+
204
+ - Multiple edits can be submitted over the lifetime of a single `Checkout`.
133
205
 
134
- - SharedTree is always created with an uninitialized state. It is up to the application to initialize the tree to something else if needed.
135
- - There are still open questions regarding how SharedTree will relate to the rest of the Fluid ecosystem.
136
- For example, we do not have suggested design patterns for when users of SharedTree should store references to other Fluid DataObjects versus storing the data for children as subtrees.
206
+ ```typescript
207
+ const checkout = new EagerCheckout(sharedTree);
208
+ checkout.openEdit();
209
+ checkout.applyChanges(Change.insertTree(fooNode, StablePlace.atStartOf({ parent: initialTree, label: 'foo' })));
210
+ checkout.applyChanges(Change.move(barNode, StablePlace.after(fooNode.identifier)));
211
+ checkout.closeEdit(); // This submits the changes to the tree in an edit
212
+ checkout.openEdit();
213
+ checkout.applyChanges(Change.delete(barNode.identifier));
214
+ checkout.closeEdit(); // This submits another edit to the tree
215
+ ```
137
216
 
138
- # Edits
217
+ > If a change failed to apply, `closeEdit` will throw an error. Detect this case by checking `getEditStatus` and calling `abortEdit` instead.
139
218
 
140
- An `Edit` is the basic unit of transactionality in `SharedTree`. It specifies how to modify a document via a sequence of changes (see [persisted-types](./src/persisted-types/0.0.2.ts)). Each edit, when applied to a version of the document (a TreeView), produces a new version of the document.
219
+ - Change notifications are emitted when any changes are applied to the `Checkout`. This allows updating of application state even in response to changes within an ongoing edit. Notifications are also emitted when the underlying SharedTree's view changes, _unless there is an ongoing edit (i.e., `openEdit` has been called)_.
141
220
 
142
- Once an edit is acknowledged by the Fluid service (and thus it has a sequence number, and will be included in summaries), the version of the document it applies to is fixed: it will not be applied to any revision other than the one produced by its preceding edit.
143
- There may be operations that will create new edits based on existing ones and apply them in a different context, but these are logically considered new edits.
221
+ ```typescript
222
+ const checkout = new EagerCheckout(sharedTree);
223
+ checkout.on('viewChange', (before: TreeView, after: TreeView) => {
224
+ // Use the delta object as a convenient way to see which nodes were added, deleted, or changed between views
225
+ const delta = after.delta(before);
226
+ }));
227
+
228
+ ```
229
+
230
+ - Checkouts can rebase an edit in progress.
231
+
232
+ ```typescript
233
+ const checkout = new EagerCheckout(sharedTree);
234
+ checkout.openEdit();
235
+ checkout.applyChanges(Change.insertTree(fooNode, StablePlace.atStartOf({ parent: initialTree, label: 'foo' })));
236
+ // ... Edits are applied to the tree (e.g. by other clients)
237
+ checkout.rebaseCurrentEdit(); // Rebases the current changes in this edit to the SharedTree's current view.
238
+ checkout.applyChanges(Change.move(barNode, StablePlace.after(fooNode.identifier)));
239
+ checkout.closeEdit(); // This submits the changes to the tree in an edit
240
+ ```
241
+
242
+ - Checkout implementations can choose how often they synchronize their view with the underlying `SharedTree` when not in an edit (i.e. snapshot isolated). If you want to synchronize as frequently as possible (this is likely), use `EagerCheckout`. If you prefer to control the cadence for synchronization, `LazyCheckout` can manage this through `Checkout.waitForPendingUpdates`.
144
243
 
145
244
  ## Conflicts
146
245
 
@@ -154,10 +253,12 @@ This flexibility allows the majority of edits to be encoded in a way where their
154
253
  and in the rare cases where this can not be done, they will conflict instead of being applied in a non-intention preserving way:
155
254
  SharedTree generally follows this policy that it is better to fail to apply a change than to apply it in a way that violates user expectation or intention.
156
255
 
157
- When a change fails to apply, or a constraint indicates that it applied, but may not have been ideal, it is called conflicted. Currently, if a change fails to apply due to a conflict, it is dropped. Improving this policy is in our [future plans](./docs/Future.md).
256
+ When a change fails to apply, or a constraint indicates that it applied, but may not have been ideal, it is called conflicted. Currently, if a change fails to apply due to a conflict, it is dropped.
158
257
 
159
258
  ### Constraints
160
259
 
260
+ > Constraints are mostly unsupported at this time. They will be supported in the upcoming SharedTree v2 implementation.
261
+
161
262
  A `Constraint` can be added to an Edit's list of changes which can be used to detect cases where an Edit could still apply (not-conflict) but may lose its original semantics due to reordering.
162
263
 
163
264
  For example, two edits could be made concurrently: one that sorts a list alphabetically and one that adds an item to the list.
@@ -200,13 +301,25 @@ In this situation, edit 1 is dropped.
200
301
  | Malformed Change | A change which can not possibly be applied to any tree without error. For example, a StablePlace with no sibling and also no trait. |
201
302
  | Malformed Edit | An edit which contains one or more malformed changes, or an edit with a sequence of changes that could not possibly be applied sequentially without error. (e.g. parent a detached node twice). |
202
303
 
203
- # Undo
304
+ # Undo/Redo
204
305
 
205
306
  Undo in a collaborative context is complex since the change being undone may not be the most recent change.
206
- This means undo and redo really need to be treated as arbitrary history edits, adding and removing changes as specific points in the past, and reconciling the impact of that with the edits after it.
307
+ This means undo and redo really need to be treated as arbitrary history edits, adding and removing changes as specific points in the past, and reconciling the impact of that with the edits after it. Both `SharedTree` and `Checkout` expose `revert` as a method to revert arbitrary edits.
308
+
309
+ ```typescript
310
+ const editId = sharedTree.applyEdit(Change.insertTree(fooNode, StablePlace.atStartOf({ parent: view.root, label: 'foo' }));
311
+ const undoEditId = sharedTree.revert(editId); // Undoes the insert
312
+ const redoEditId = sharedTree.revert(undoEditId); // Redoes the insert
313
+ ```
207
314
 
208
315
  ## Summaries
209
316
 
317
+ ### History
318
+
319
+ A `SharedTree` can optionally preserve its "history", i.e. all edits that were sequenced over time. This has storage and performance overhead, and is disabled by default. An instance of a SharedTree object will always contain all edits that were created/received during its lifetime, thus enabling undo, redo and history traversal of those edits.
320
+
321
+ > Currently, `SharedTree` documents created with history enabled can never have their history removed.
322
+
210
323
  ### History Virtualization
211
324
 
212
325
  The summaries generated by SharedTree include the current view and edit history. However, new clients that load the summary can be used with the current view alone. This allows the history to be virtualized to decrease load time of clients for large edit histories.
@@ -30,22 +30,23 @@ export declare enum ChangeType {
30
30
  *
31
31
  * `Change` objects can be conveniently constructed with the helper methods exported on a constant of the same name.
32
32
  * @example
33
- * TreeChange.insert(sourceId, destination)
33
+ * Change.insert(sourceId, destination)
34
34
  * @public
35
35
  */
36
36
  export declare type Change = Insert | Detach | Build | SetValue | Constraint;
37
37
  /**
38
- * Node or sequence of Nodes for use in a Build change.
39
- *
40
- * Other formats for sub-sequences of Nodes can be added here, and those formats should be supported in blobs as well.
41
- * Future formats will include referenced blobs containing sequences of Nodes,
42
- * template based metadata and identity deduplication, and possibly compressed and binary formats.
43
- * These optimized formats should also be used within tree views.
38
+ * Node or a detached sequence of nodes (referred to by a detached sequence ID) for use in a Build change.
39
+ * See `BuildTreeNode` for more.
44
40
  * @public
45
41
  */
46
42
  export declare type BuildNode = BuildTreeNode | number;
47
43
  /**
48
- * Node for use in a Build change.
44
+ * Node for use in a Build change, which is composed of a definition describing what this nodes type, an identifier identifying this node
45
+ * within the tree, and a payload containing an opaque serializable piece of data.
46
+ * An identifier can be provided explicitly if the node must be referred to before the results of the `Change` containing this
47
+ * BuildTreeNode can be observed. If `identifier` is not supplied, one will be generated for it in an especially efficient manner
48
+ * that allows for compact storage and transmission and thus this property should be omitted if convenient.
49
+ * See the SharedTree readme for more on the tree format.
49
50
  */
50
51
  export interface BuildTreeNode extends HasVariadicTraits<BuildNode> {
51
52
  definition: string;
@@ -59,12 +60,6 @@ export interface BuildTreeNode extends HasVariadicTraits<BuildNode> {
59
60
  * Valid if (transitively) all DetachedSequenceId are used according to their rules (use here counts as a destination),
60
61
  * and all Nodes' identifiers are previously unused.
61
62
  *
62
- * TODO: Design Decision:
63
- * If allowing 'moving from nowhere' to restore nodes: all new Nodes must have never before used identifiers.
64
- * Otherwise could just forbid identifiers currently reachable?
65
- * Could also allow introducing a node with a particular identifier to mean replacing that node with the new one
66
- * (could include optional constraint to require/prevent this).
67
- *
68
63
  * @public
69
64
  */
70
65
  export interface Build {
@@ -1 +1 @@
1
- {"version":3,"file":"ChangeTypes.d.ts","sourceRoot":"","sources":["../src/ChangeTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAAC,MAAM;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE;QACjB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;KACtE,CAAC;CACF;AAED;;;GAGG;AACH,oBAAY,UAAU;IACrB,MAAM,IAAA;IACN,MAAM,IAAA;IACN,KAAK,IAAA;IACL,QAAQ,IAAA;IACR,UAAU,IAAA;CACV;AAED;;;;;;;GAOG;AACH,oBAAY,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,CAAC;AAErE;;;;;;;;GAQG;AACH,oBAAY,SAAS,GAAG,aAAa,GAAG,MAAM,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,iBAAiB,CAAC,SAAS,CAAC;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,KAAK;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IACzD,QAAQ,CAAC,IAAI,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACvC;AAED;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACtB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,UAAU,CAAC,MAAM,CAAC;CACxC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,UAAU,CAAC,MAAM,CAAC;CACxC;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IAEH,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,OAAO,UAAU,CAAC,QAAQ,CAAC;CAC1C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAElC;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC;IAElC;;OAEG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAE5B;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAElC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,UAAU,CAAC,UAAU,CAAC;CAC5C;AAGD;;GAEG;AACH,eAAO,MAAM,MAAM;oBACF,SAAS,GAAG,iBAAiB,SAAS,CAAC,eAAe,MAAM,KAAG,KAAK;qBAMnE,MAAM,eAAe,WAAW,KAAG,MAAM;qBAMzC,WAAW,uCAAyB,MAAM;+BAMhC,MAAM,WAAW,OAAO,KAAG,QAAQ;iCAMjC,MAAM,KAAG,QAAQ;8BAQhC,WAAW,UAChB,gBAAgB;;;;;qIAMtB,UAAU;IAWb,yDAAyD;IAEzD;;OAEG;0BACmB,WAAW,KAAG,MAAM;IAE1C;;OAEG;wBACiB,SAAS,GAAG,iBAAiB,SAAS,CAAC,eAAe,WAAW,KAAG,MAAM,EAAE;IAKhG;;OAEG;mBACY,WAAW,eAAe,WAAW,KAAG,MAAM,EAAE;CAI/D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAEpB;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAEnC;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC;CACxC;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;CAC1B;AAED;;;;;;GAMG;AAGH;;GAEG;AACH,eAAO,MAAM,WAAW;IACvB;;OAEG;mBACY,SAAS,MAAM,CAAC,GAAG,MAAM,KAAG,WAAW;IAItD;;OAEG;kBACW,SAAS,MAAM,CAAC,GAAG,MAAM,KAAG,WAAW;IACrD;;OAEG;uBACgB,aAAa,KAAG,WAAW;IAC9C;;OAEG;qBACc,aAAa,KAAG,WAAW;CAC5C,CAAC;AAGF;;GAEG;AACH,eAAO,MAAM,WAAW;IACvB;;;;OAIG;kBACW,WAAW;kBAAe,WAAW,KAAK,WAAW;;IAUnE;;;OAGG;iBACU,SAAS,MAAM,CAAC,GAAG,MAAM,KAAG,WAAW;IAIpD;;;;OAIG;iBACU,aAAa,KAAG,WAAW;CAIxC,CAAC"}
1
+ {"version":3,"file":"ChangeTypes.d.ts","sourceRoot":"","sources":["../src/ChangeTypes.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ChangeTypes.js","sourceRoot":"","sources":["../src/ChangeTypes.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { NodeId, TraitLabel, UuidString } from './Identifiers';\nimport { assert, assertNotUndefined } from './Common';\nimport { ConstraintEffect, NodeData, Payload, Side, TreeNodeSequence } from './persisted-types';\nimport { TraitLocation } from './TreeView';\nimport { getNodeId } from './NodeIdUtilities';\n\n/**\n * An object which may have traits with children of the given type underneath it\n * @public\n */\nexport interface HasVariadicTraits<TChild> {\n\treadonly traits?: {\n\t\treadonly [key: string]: TChild | TreeNodeSequence<TChild> | undefined;\n\t};\n}\n\n/**\n * The type of a Change\n * @public\n */\nexport enum ChangeType {\n\tInsert,\n\tDetach,\n\tBuild,\n\tSetValue,\n\tConstraint,\n}\n\n/**\n * A change that composes an Edit.\n *\n * `Change` objects can be conveniently constructed with the helper methods exported on a constant of the same name.\n * @example\n * TreeChange.insert(sourceId, destination)\n * @public\n */\nexport type Change = Insert | Detach | Build | SetValue | Constraint;\n\n/**\n * Node or sequence of Nodes for use in a Build change.\n *\n * Other formats for sub-sequences of Nodes can be added here, and those formats should be supported in blobs as well.\n * Future formats will include referenced blobs containing sequences of Nodes,\n * template based metadata and identity deduplication, and possibly compressed and binary formats.\n * These optimized formats should also be used within tree views.\n * @public\n */\nexport type BuildNode = BuildTreeNode | number;\n\n/**\n * Node for use in a Build change.\n */\nexport interface BuildTreeNode extends HasVariadicTraits<BuildNode> {\n\tdefinition: string;\n\tidentifier?: NodeId;\n\tpayload?: Payload;\n}\n\n/**\n * Constructs a sequence of nodes, associates it with the supplied ID, and stores it for use in later changes.\n * Does not modify the document.\n *\n * Valid if (transitively) all DetachedSequenceId are used according to their rules (use here counts as a destination),\n * and all Nodes' identifiers are previously unused.\n *\n * TODO: Design Decision:\n * If allowing 'moving from nowhere' to restore nodes: all new Nodes must have never before used identifiers.\n * Otherwise could just forbid identifiers currently reachable?\n * Could also allow introducing a node with a particular identifier to mean replacing that node with the new one\n * (could include optional constraint to require/prevent this).\n *\n * @public\n */\nexport interface Build {\n\treadonly destination: number;\n\treadonly source: BuildNode | TreeNodeSequence<BuildNode>;\n\treadonly type: typeof ChangeType.Build;\n}\n\n/**\n * Inserts a sequence of nodes at the specified destination.\n * The source can be constructed either by a Build (used to insert new nodes) or a Detach (amounts to a \"move\" operation).\n * @public\n */\nexport interface Insert {\n\treadonly destination: StablePlace;\n\treadonly source: number;\n\treadonly type: typeof ChangeType.Insert;\n}\n\n/**\n * Removes a sequence of nodes from the tree.\n * If a destination is specified, the detached sequence is associated with that ID and held for possible reuse\n * by later changes in this same Edit (such as by an Insert).\n * A Detach without a destination is a deletion of the specified sequence, as is a Detach with a destination that is not used later.\n * @public\n */\nexport interface Detach {\n\treadonly destination?: number;\n\treadonly source: StableRange;\n\treadonly type: typeof ChangeType.Detach;\n}\n\n/**\n * Modifies the payload of a node.\n * @public\n */\nexport interface SetValue {\n\treadonly nodeToModify: NodeId;\n\t/**\n\t * Sets or clears the payload.\n\t * To improve ease of forwards compatibility, an explicit `null` value is used to represent the clearing of a payload.\n\t * SetValue may use `undefined` in future API versions to mean \"don't change the payload\" (which is useful if e.g. other\n\t * fields are added to SetValue that can be changed without altering the payload)\n\t */\n\t// eslint-disable-next-line @rushstack/no-new-null\n\treadonly payload: Payload | null;\n\treadonly type: typeof ChangeType.SetValue;\n}\n\n/**\n * A set of constraints on the validity of an Edit.\n * A Constraint is used to detect when an Edit, due to other concurrent edits, may have unintended effects or merge in\n * non-semantic ways. It is processed in order like any other Change in an Edit. It can cause an edit to fail if the\n * various constraints are not met at the time of evaluation (ex: the parentNode has changed due to concurrent editing).\n * Does not modify the document.\n * @public\n */\nexport interface Constraint {\n\t/**\n\t * Selects a sequence of nodes which will be checked against the constraints specified by the optional fields.\n\t * If `toConstrain` is invalid, it will be treated like a constraint being unmet.\n\t * Depending on `effect` this may or may not make the Edit invalid.\n\t *\n\t * When a constraint is not met, the effects is specified by `effect`.\n\t */\n\treadonly toConstrain: StableRange;\n\n\t/**\n\t * Require that the identities of all the nodes in toConstrain hash to this value.\n\t * Hash is order dependent.\n\t * TODO: implement and specify exact hash function.\n\t *\n\t * This is an efficient (O(1) space) way to constrain a sequence of nodes to have specific identities.\n\t */\n\treadonly identityHash?: UuidString;\n\n\t/**\n\t * Require that the number of nodes in toConstrain is this value.\n\t */\n\treadonly length?: number;\n\n\t/**\n\t * Require that the contents of all of the nodes in toConstrain hash to this value.\n\t * Hash is an order dependant deep hash, which includes all subtree content recursively.\n\t * TODO: implement and specify exact hash function.\n\t *\n\t * This is an efficient (O(1) space) way to constrain a sequence of nodes have exact values (transitively).\n\t */\n\treadonly contentHash?: UuidString;\n\n\t/**\n\t * Require that parent under which toConstrain is located has this identifier.\n\t */\n\treadonly parentNode?: NodeId;\n\n\t/**\n\t * Require that the trait under which toConstrain is located has this label.\n\t */\n\treadonly label?: TraitLabel;\n\n\t/**\n\t * What to do if a constraint is not met.\n\t */\n\treadonly effect: ConstraintEffect;\n\n\t/**\n\t * Marker for which kind of Change this is.\n\t */\n\treadonly type: typeof ChangeType.Constraint;\n}\n\n// Note: Documentation of this constant is merged with documentation of the `Change` interface.\n/**\n * @public\n */\nexport const Change = {\n\tbuild: (source: BuildNode | TreeNodeSequence<BuildNode>, destination: number): Build => ({\n\t\tdestination,\n\t\tsource,\n\t\ttype: ChangeType.Build,\n\t}),\n\n\tinsert: (source: number, destination: StablePlace): Insert => ({\n\t\tdestination,\n\t\tsource,\n\t\ttype: ChangeType.Insert,\n\t}),\n\n\tdetach: (source: StableRange, destination?: number): Detach => ({\n\t\tdestination,\n\t\tsource,\n\t\ttype: ChangeType.Detach,\n\t}),\n\n\tsetPayload: (nodeToModify: NodeId, payload: Payload): SetValue => ({\n\t\tnodeToModify,\n\t\tpayload,\n\t\ttype: ChangeType.SetValue,\n\t}),\n\n\tclearPayload: (nodeToModify: NodeId): SetValue => ({\n\t\tnodeToModify,\n\t\t// Rationale: 'undefined' is reserved for future use (see 'SetValue' interface above.)\n\t\tpayload: null,\n\t\ttype: ChangeType.SetValue,\n\t}),\n\n\tconstraint: (\n\t\ttoConstrain: StableRange,\n\t\teffect: ConstraintEffect,\n\t\tidentityHash?: UuidString,\n\t\tlength?: number,\n\t\tcontentHash?: UuidString,\n\t\tparentNode?: NodeId,\n\t\tlabel?: TraitLabel\n\t): Constraint => ({\n\t\ttoConstrain,\n\t\teffect,\n\t\tidentityHash,\n\t\tlength,\n\t\tcontentHash,\n\t\tparentNode,\n\t\tlabel,\n\t\ttype: ChangeType.Constraint,\n\t}),\n\n\t/** Helpers for making high-level composite operations */\n\n\t/**\n\t * @returns a change that deletes the supplied part of the tree.\n\t */\n\tdelete: (stableRange: StableRange): Change => Change.detach(stableRange),\n\n\t/**\n\t * @returns changes that insert 'nodes' into the specified location in the tree.\n\t */\n\tinsertTree: (nodes: BuildNode | TreeNodeSequence<BuildNode>, destination: StablePlace): Change[] => {\n\t\tconst build = Change.build(nodes, 0);\n\t\treturn [build, Change.insert(build.destination, destination)];\n\t},\n\n\t/**\n\t * @returns changes that moves the specified content to a new location in the tree.\n\t */\n\tmove: (source: StableRange, destination: StablePlace): Change[] => {\n\t\tconst detach = Change.detach(source, 0);\n\t\treturn [detach, Change.insert(assertNotUndefined(detach.destination), destination)];\n\t},\n};\n\n/**\n * A location in a trait.\n * This is NOT the location of a node, but a location where a node could be inserted:\n * it is next to a sibling or at one end of the trait.\n *\n * To be well formed, either `sibling` or `trait` must be defined, but not both.\n *\n * Any given insertion location can be described by two `StablePlace` objects, one with `Side.After` and one with `Side.Before`.\n * For example, in a trait containing two strings \"foo\" and \"bar\", there are 6 different `StablePlace`s corresponding to 3 locations in the\n * trait a new node could be inserted: at the start, before \"foo\", after \"foo\", before \"bar\", after \"bar\", and at the end.\n * Neither of the two ways to specify the same location are considered to be after each other.\n *\n * The anchor (`referenceSibling` or `referenceTrait`) used for a particular `StablePlace` can have an impact in collaborative scenarios.\n *\n * `StablePlace` objects can be conveniently constructed with the helper methods exported on a constant of the same name.\n * @example\n * StablePlace.before(node)\n * StablePlace.atStartOf(trait)\n * @public\n */\nexport interface StablePlace {\n\t/**\n\t * Where this StablePlace is relative to the sibling (if specified), or an end of the trait (if no sibling specified).\n\t * If 'After' and there is no sibling, this StablePlace is after the front of the trait.\n\t * If 'Before' and there is no sibling, this StablePlace is before the back of the trait.\n\t */\n\treadonly side: Side;\n\n\t/**\n\t * The sibling to which this 'StablePlace' is anchored (by 'side').\n\t * If specified, referenceTrait must be unspecified.\n\t */\n\treadonly referenceSibling?: NodeId;\n\n\t/**\n\t * The trait to which this 'StablePlace' is anchored (by 'side').\n\t * If specified, referenceSibling must be unspecified.\n\t */\n\treadonly referenceTrait?: TraitLocation;\n}\n\n/**\n * Specifies the range of nodes from `start` to `end` within a trait.\n * Valid iff start and end are valid and are within the same trait and the start does not occur after the end in the trait.\n *\n * See {@link (StablePlace:interface)} for what it means for a place to be \"after\" another place.\n *\n * `StableRange` objects can be conveniently constructed with the helper methods exported on a constant of the same name.\n * @example\n * StableRange.from(StablePlace.before(startNode)).to(StablePlace.after(endNode))\n * @public\n */\nexport interface StableRange {\n\treadonly start: StablePlace;\n\treadonly end: StablePlace;\n}\n\n/**\n * The remainder of this file consists of ergonomic factory methods for persisted types, or common combinations thereof (e.g. \"Move\" as a\n * combination of a \"Detach\" change and an \"Insert\" change).\n *\n * None of these helpers are persisted in documents, and therefore changes to their semantics need only follow standard semantic versioning\n * practices.\n */\n\n// Note: Documentation of this constant is merged with documentation of the `StablePlace` interface.\n/**\n * @public\n */\nexport const StablePlace = {\n\t/**\n\t * @returns The location directly before `node`.\n\t */\n\tbefore: (node: NodeData<NodeId> | NodeId): StablePlace => ({\n\t\tside: Side.Before,\n\t\treferenceSibling: getNodeId(node),\n\t}),\n\t/**\n\t * @returns The location directly after `node`.\n\t */\n\tafter: (node: NodeData<NodeId> | NodeId): StablePlace => ({ side: Side.After, referenceSibling: getNodeId(node) }),\n\t/**\n\t * @returns The location at the start of `trait`.\n\t */\n\tatStartOf: (trait: TraitLocation): StablePlace => ({ side: Side.After, referenceTrait: trait }),\n\t/**\n\t * @returns The location at the end of `trait`.\n\t */\n\tatEndOf: (trait: TraitLocation): StablePlace => ({ side: Side.Before, referenceTrait: trait }),\n};\n\n// Note: Documentation of this constant is merged with documentation of the `StableRange` interface.\n/**\n * @public\n */\nexport const StableRange = {\n\t/**\n\t * Factory for producing a `StableRange` from a start `StablePlace` to an end `StablePlace`.\n\t * @example\n\t * StableRange.from(StablePlace.before(startNode)).to(StablePlace.after(endNode))\n\t */\n\tfrom: (start: StablePlace): { to: (end: StablePlace) => StableRange } => ({\n\t\tto: (end: StablePlace): StableRange => {\n\t\t\tif (start.referenceTrait && end.referenceTrait) {\n\t\t\t\tconst message = 'StableRange must be constructed with endpoints from the same trait';\n\t\t\t\tassert(start.referenceTrait.parent === end.referenceTrait.parent, message);\n\t\t\t\tassert(start.referenceTrait.label === end.referenceTrait.label, message);\n\t\t\t}\n\t\t\treturn { start, end };\n\t\t},\n\t}),\n\t/**\n\t * @returns a `StableRange` which contains only the provided `node`.\n\t * Both the start and end `StablePlace` objects used to anchor this `StableRange` are in terms of the passed in node.\n\t */\n\tonly: (node: NodeData<NodeId> | NodeId): StableRange => ({\n\t\tstart: StablePlace.before(node),\n\t\tend: StablePlace.after(node),\n\t}),\n\t/**\n\t * @returns a `StableRange` which contains everything in the trait.\n\t * This is anchored using the provided `trait`, and is independent of the actual contents of the trait:\n\t * it does not use sibling anchoring.\n\t */\n\tall: (trait: TraitLocation): StableRange => ({\n\t\tstart: StablePlace.atStartOf(trait),\n\t\tend: StablePlace.atEndOf(trait),\n\t}),\n};\n"]}
1
+ {"version":3,"file":"ChangeTypes.js","sourceRoot":"","sources":["../src/ChangeTypes.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { NodeId, TraitLabel, UuidString } from './Identifiers';\nimport { assert, assertNotUndefined } from './Common';\nimport { ConstraintEffect, NodeData, Payload, Side, TreeNodeSequence } from './persisted-types';\nimport { TraitLocation } from './TreeView';\nimport { getNodeId } from './NodeIdUtilities';\n\n/**\n * An object which may have traits with children of the given type underneath it\n * @public\n */\nexport interface HasVariadicTraits<TChild> {\n\treadonly traits?: {\n\t\treadonly [key: string]: TChild | TreeNodeSequence<TChild> | undefined;\n\t};\n}\n\n/**\n * The type of a Change\n * @public\n */\nexport enum ChangeType {\n\tInsert,\n\tDetach,\n\tBuild,\n\tSetValue,\n\tConstraint,\n}\n\n/**\n * A change that composes an Edit.\n *\n * `Change` objects can be conveniently constructed with the helper methods exported on a constant of the same name.\n * @example\n * Change.insert(sourceId, destination)\n * @public\n */\nexport type Change = Insert | Detach | Build | SetValue | Constraint;\n\n/**\n * Node or a detached sequence of nodes (referred to by a detached sequence ID) for use in a Build change.\n * See `BuildTreeNode` for more.\n * @public\n */\nexport type BuildNode = BuildTreeNode | number;\n\n/**\n * Node for use in a Build change, which is composed of a definition describing what this nodes type, an identifier identifying this node\n * within the tree, and a payload containing an opaque serializable piece of data.\n * An identifier can be provided explicitly if the node must be referred to before the results of the `Change` containing this\n * BuildTreeNode can be observed. If `identifier` is not supplied, one will be generated for it in an especially efficient manner\n * that allows for compact storage and transmission and thus this property should be omitted if convenient.\n * See the SharedTree readme for more on the tree format.\n */\nexport interface BuildTreeNode extends HasVariadicTraits<BuildNode> {\n\tdefinition: string;\n\tidentifier?: NodeId;\n\tpayload?: Payload;\n}\n\n/**\n * Constructs a sequence of nodes, associates it with the supplied ID, and stores it for use in later changes.\n * Does not modify the document.\n *\n * Valid if (transitively) all DetachedSequenceId are used according to their rules (use here counts as a destination),\n * and all Nodes' identifiers are previously unused.\n *\n * @public\n */\nexport interface Build {\n\treadonly destination: number;\n\treadonly source: BuildNode | TreeNodeSequence<BuildNode>;\n\treadonly type: typeof ChangeType.Build;\n}\n\n/**\n * Inserts a sequence of nodes at the specified destination.\n * The source can be constructed either by a Build (used to insert new nodes) or a Detach (amounts to a \"move\" operation).\n * @public\n */\nexport interface Insert {\n\treadonly destination: StablePlace;\n\treadonly source: number;\n\treadonly type: typeof ChangeType.Insert;\n}\n\n/**\n * Removes a sequence of nodes from the tree.\n * If a destination is specified, the detached sequence is associated with that ID and held for possible reuse\n * by later changes in this same Edit (such as by an Insert).\n * A Detach without a destination is a deletion of the specified sequence, as is a Detach with a destination that is not used later.\n * @public\n */\nexport interface Detach {\n\treadonly destination?: number;\n\treadonly source: StableRange;\n\treadonly type: typeof ChangeType.Detach;\n}\n\n/**\n * Modifies the payload of a node.\n * @public\n */\nexport interface SetValue {\n\treadonly nodeToModify: NodeId;\n\t/**\n\t * Sets or clears the payload.\n\t * To improve ease of forwards compatibility, an explicit `null` value is used to represent the clearing of a payload.\n\t * SetValue may use `undefined` in future API versions to mean \"don't change the payload\" (which is useful if e.g. other\n\t * fields are added to SetValue that can be changed without altering the payload)\n\t */\n\t// eslint-disable-next-line @rushstack/no-new-null\n\treadonly payload: Payload | null;\n\treadonly type: typeof ChangeType.SetValue;\n}\n\n/**\n * A set of constraints on the validity of an Edit.\n * A Constraint is used to detect when an Edit, due to other concurrent edits, may have unintended effects or merge in\n * non-semantic ways. It is processed in order like any other Change in an Edit. It can cause an edit to fail if the\n * various constraints are not met at the time of evaluation (ex: the parentNode has changed due to concurrent editing).\n * Does not modify the document.\n * @public\n */\nexport interface Constraint {\n\t/**\n\t * Selects a sequence of nodes which will be checked against the constraints specified by the optional fields.\n\t * If `toConstrain` is invalid, it will be treated like a constraint being unmet.\n\t * Depending on `effect` this may or may not make the Edit invalid.\n\t *\n\t * When a constraint is not met, the effects is specified by `effect`.\n\t */\n\treadonly toConstrain: StableRange;\n\n\t/**\n\t * Require that the identities of all the nodes in toConstrain hash to this value.\n\t * Hash is order dependent.\n\t * TODO: implement and specify exact hash function.\n\t *\n\t * This is an efficient (O(1) space) way to constrain a sequence of nodes to have specific identities.\n\t */\n\treadonly identityHash?: UuidString;\n\n\t/**\n\t * Require that the number of nodes in toConstrain is this value.\n\t */\n\treadonly length?: number;\n\n\t/**\n\t * Require that the contents of all of the nodes in toConstrain hash to this value.\n\t * Hash is an order dependant deep hash, which includes all subtree content recursively.\n\t * TODO: implement and specify exact hash function.\n\t *\n\t * This is an efficient (O(1) space) way to constrain a sequence of nodes have exact values (transitively).\n\t */\n\treadonly contentHash?: UuidString;\n\n\t/**\n\t * Require that parent under which toConstrain is located has this identifier.\n\t */\n\treadonly parentNode?: NodeId;\n\n\t/**\n\t * Require that the trait under which toConstrain is located has this label.\n\t */\n\treadonly label?: TraitLabel;\n\n\t/**\n\t * What to do if a constraint is not met.\n\t */\n\treadonly effect: ConstraintEffect;\n\n\t/**\n\t * Marker for which kind of Change this is.\n\t */\n\treadonly type: typeof ChangeType.Constraint;\n}\n\n// Note: Documentation of this constant is merged with documentation of the `Change` interface.\n/**\n * @public\n */\nexport const Change = {\n\tbuild: (source: BuildNode | TreeNodeSequence<BuildNode>, destination: number): Build => ({\n\t\tdestination,\n\t\tsource,\n\t\ttype: ChangeType.Build,\n\t}),\n\n\tinsert: (source: number, destination: StablePlace): Insert => ({\n\t\tdestination,\n\t\tsource,\n\t\ttype: ChangeType.Insert,\n\t}),\n\n\tdetach: (source: StableRange, destination?: number): Detach => ({\n\t\tdestination,\n\t\tsource,\n\t\ttype: ChangeType.Detach,\n\t}),\n\n\tsetPayload: (nodeToModify: NodeId, payload: Payload): SetValue => ({\n\t\tnodeToModify,\n\t\tpayload,\n\t\ttype: ChangeType.SetValue,\n\t}),\n\n\tclearPayload: (nodeToModify: NodeId): SetValue => ({\n\t\tnodeToModify,\n\t\t// Rationale: 'undefined' is reserved for future use (see 'SetValue' interface above.)\n\t\tpayload: null,\n\t\ttype: ChangeType.SetValue,\n\t}),\n\n\tconstraint: (\n\t\ttoConstrain: StableRange,\n\t\teffect: ConstraintEffect,\n\t\tidentityHash?: UuidString,\n\t\tlength?: number,\n\t\tcontentHash?: UuidString,\n\t\tparentNode?: NodeId,\n\t\tlabel?: TraitLabel\n\t): Constraint => ({\n\t\ttoConstrain,\n\t\teffect,\n\t\tidentityHash,\n\t\tlength,\n\t\tcontentHash,\n\t\tparentNode,\n\t\tlabel,\n\t\ttype: ChangeType.Constraint,\n\t}),\n\n\t/** Helpers for making high-level composite operations */\n\n\t/**\n\t * @returns a change that deletes the supplied part of the tree.\n\t */\n\tdelete: (stableRange: StableRange): Change => Change.detach(stableRange),\n\n\t/**\n\t * @returns changes that insert 'nodes' into the specified location in the tree.\n\t */\n\tinsertTree: (nodes: BuildNode | TreeNodeSequence<BuildNode>, destination: StablePlace): Change[] => {\n\t\tconst build = Change.build(nodes, 0);\n\t\treturn [build, Change.insert(build.destination, destination)];\n\t},\n\n\t/**\n\t * @returns changes that moves the specified content to a new location in the tree.\n\t */\n\tmove: (source: StableRange, destination: StablePlace): Change[] => {\n\t\tconst detach = Change.detach(source, 0);\n\t\treturn [detach, Change.insert(assertNotUndefined(detach.destination), destination)];\n\t},\n};\n\n/**\n * A location in a trait.\n * This is NOT the location of a node, but a location where a node could be inserted:\n * it is next to a sibling or at one end of the trait.\n *\n * To be well formed, either `sibling` or `trait` must be defined, but not both.\n *\n * Any given insertion location can be described by two `StablePlace` objects, one with `Side.After` and one with `Side.Before`.\n * For example, in a trait containing two strings \"foo\" and \"bar\", there are 6 different `StablePlace`s corresponding to 3 locations in the\n * trait a new node could be inserted: at the start, before \"foo\", after \"foo\", before \"bar\", after \"bar\", and at the end.\n * Neither of the two ways to specify the same location are considered to be after each other.\n *\n * The anchor (`referenceSibling` or `referenceTrait`) used for a particular `StablePlace` can have an impact in collaborative scenarios.\n *\n * `StablePlace` objects can be conveniently constructed with the helper methods exported on a constant of the same name.\n * @example\n * StablePlace.before(node)\n * StablePlace.atStartOf(trait)\n * @public\n */\nexport interface StablePlace {\n\t/**\n\t * Where this StablePlace is relative to the sibling (if specified), or an end of the trait (if no sibling specified).\n\t * If 'After' and there is no sibling, this StablePlace is after the front of the trait.\n\t * If 'Before' and there is no sibling, this StablePlace is before the back of the trait.\n\t */\n\treadonly side: Side;\n\n\t/**\n\t * The sibling to which this 'StablePlace' is anchored (by 'side').\n\t * If specified, referenceTrait must be unspecified.\n\t */\n\treadonly referenceSibling?: NodeId;\n\n\t/**\n\t * The trait to which this 'StablePlace' is anchored (by 'side').\n\t * If specified, referenceSibling must be unspecified.\n\t */\n\treadonly referenceTrait?: TraitLocation;\n}\n\n/**\n * Specifies the range of nodes from `start` to `end` within a trait.\n * Valid iff start and end are valid and are within the same trait and the start does not occur after the end in the trait.\n *\n * See {@link (StablePlace:interface)} for what it means for a place to be \"after\" another place.\n *\n * `StableRange` objects can be conveniently constructed with the helper methods exported on a constant of the same name.\n * @example\n * StableRange.from(StablePlace.before(startNode)).to(StablePlace.after(endNode))\n * @public\n */\nexport interface StableRange {\n\treadonly start: StablePlace;\n\treadonly end: StablePlace;\n}\n\n/**\n * The remainder of this file consists of ergonomic factory methods for persisted types, or common combinations thereof (e.g. \"Move\" as a\n * combination of a \"Detach\" change and an \"Insert\" change).\n *\n * None of these helpers are persisted in documents, and therefore changes to their semantics need only follow standard semantic versioning\n * practices.\n */\n\n// Note: Documentation of this constant is merged with documentation of the `StablePlace` interface.\n/**\n * @public\n */\nexport const StablePlace = {\n\t/**\n\t * @returns The location directly before `node`.\n\t */\n\tbefore: (node: NodeData<NodeId> | NodeId): StablePlace => ({\n\t\tside: Side.Before,\n\t\treferenceSibling: getNodeId(node),\n\t}),\n\t/**\n\t * @returns The location directly after `node`.\n\t */\n\tafter: (node: NodeData<NodeId> | NodeId): StablePlace => ({ side: Side.After, referenceSibling: getNodeId(node) }),\n\t/**\n\t * @returns The location at the start of `trait`.\n\t */\n\tatStartOf: (trait: TraitLocation): StablePlace => ({ side: Side.After, referenceTrait: trait }),\n\t/**\n\t * @returns The location at the end of `trait`.\n\t */\n\tatEndOf: (trait: TraitLocation): StablePlace => ({ side: Side.Before, referenceTrait: trait }),\n};\n\n// Note: Documentation of this constant is merged with documentation of the `StableRange` interface.\n/**\n * @public\n */\nexport const StableRange = {\n\t/**\n\t * Factory for producing a `StableRange` from a start `StablePlace` to an end `StablePlace`.\n\t * @example\n\t * StableRange.from(StablePlace.before(startNode)).to(StablePlace.after(endNode))\n\t */\n\tfrom: (start: StablePlace): { to: (end: StablePlace) => StableRange } => ({\n\t\tto: (end: StablePlace): StableRange => {\n\t\t\tif (start.referenceTrait && end.referenceTrait) {\n\t\t\t\tconst message = 'StableRange must be constructed with endpoints from the same trait';\n\t\t\t\tassert(start.referenceTrait.parent === end.referenceTrait.parent, message);\n\t\t\t\tassert(start.referenceTrait.label === end.referenceTrait.label, message);\n\t\t\t}\n\t\t\treturn { start, end };\n\t\t},\n\t}),\n\t/**\n\t * @returns a `StableRange` which contains only the provided `node`.\n\t * Both the start and end `StablePlace` objects used to anchor this `StableRange` are in terms of the passed in node.\n\t */\n\tonly: (node: NodeData<NodeId> | NodeId): StableRange => ({\n\t\tstart: StablePlace.before(node),\n\t\tend: StablePlace.after(node),\n\t}),\n\t/**\n\t * @returns a `StableRange` which contains everything in the trait.\n\t * This is anchored using the provided `trait`, and is independent of the actual contents of the trait:\n\t * it does not use sibling anchoring.\n\t */\n\tall: (trait: TraitLocation): StableRange => ({\n\t\tstart: StablePlace.atStartOf(trait),\n\t\tend: StablePlace.atEndOf(trait),\n\t}),\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"Checkout.d.ts","sourceRoot":"","sources":["../src/Checkout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAE9E,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAsB,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGrE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC;;;GAGG;AACH,oBAAY,aAAa;IACxB;;;OAGG;IACH,UAAU,eAAe;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,WAAW;IACnD,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,KAAK,IAAI,OAAE;CAC7E;AAED;;;GAGG;AACH,oBAAY,oBAAoB;IAC/B;;;;OAIG;IACH,SAAS,IAAA;IACT;;;;OAIG;IACH,OAAO,IAAA;IACP;;OAEG;IACH,KAAK,IAAA;CACL;AAED;;;;;;;;;;;;;;GAcG;AACH,8BAAsB,QAAS,SAAQ,6BAA6B,CAAC,eAAe,CAAE,YAAW,WAAW;IAC3G;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,KAAK,mBAAmB,IAAI,YAAY,CAAC;IAE3D;;;OAGG;IACH,OAAO,CAAC,YAAY,CAAW;IAE/B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAuB;IAE5D;;OAEG;IACH,SAAgB,IAAI,EAAE,UAAU,CAAC;IAEjC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAmB;IAErD;;;;;;OAMG;IACH,OAAO,CAAC,WAAW,CAAC,CAAqB;IAElC,QAAQ,EAAE,OAAO,CAAS;IAEjC,SAAS,aAAa,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB;IAexG;;;OAGG;IACH,IAAW,WAAW,IAAI,QAAQ,CAEjC;IAED;;;OAGG;IACI,WAAW,IAAI,OAAO;IAI7B;;;OAGG;IACI,QAAQ,IAAI,IAAI;IAKvB;;;;;;;OAOG;IACI,SAAS,IAAI,MAAM;IAa1B;;;OAGG;IACH,SAAS,CAAC,sBAAsB,CAAC,IAAI,EAAE,IAAI,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAK9F;;;;;OAKG;IACH,SAAS,CAAC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAWrE;;;;OAIG;IACI,YAAY,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAO/C;;;;OAIG;IACH,SAAS,CAAC,uBAAuB,CAAC,GAAG,OAAO,EAAE,cAAc,EAAE,GAAG,UAAU;IAS3E;;;OAGG;IACI,SAAS,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM;IAM9C;;;;OAIG;IACI,YAAY,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS;IAc7D;;;;;;;;;;OAUG;IACI,iBAAiB,IAAI,oBAAoB,CAAC,KAAK,GAAG,oBAAoB,CAAC,OAAO;IAuBrF;;;OAGG;IACI,SAAS,IAAI,IAAI;IAOxB;;;;OAIG;IACI,aAAa,IAAI,UAAU;IAQlC;;;OAGG;IACI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAWnC;;;;OAIG;IACH,SAAS,CAAC,UAAU,IAAI,IAAI;IAU5B;;OAEG;aACa,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAEtD;;;OAGG;aACa,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAErD;;;OAGG;IACI,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;CAUnC"}
1
+ {"version":3,"file":"Checkout.d.ts","sourceRoot":"","sources":["../src/Checkout.ts"],"names":[],"mappings":"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"}
package/dist/Checkout.js CHANGED
@@ -8,6 +8,7 @@ exports.Checkout = exports.EditValidationResult = exports.CheckoutEvent = void 0
8
8
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
9
9
  const Common_1 = require("./Common");
10
10
  const LogViewer_1 = require("./LogViewer");
11
+ const TransactionInternal_1 = require("./TransactionInternal");
11
12
  const persisted_types_1 = require("./persisted-types");
12
13
  const EventTypes_1 = require("./EventTypes");
13
14
  const EditUtilities_1 = require("./EditUtilities");
@@ -97,7 +98,7 @@ class Checkout extends telemetry_utils_1.EventEmitterWithErrorHandling {
97
98
  */
98
99
  openEdit() {
99
100
  Common_1.assert(this.currentEdit === undefined, 'An edit is already open.');
100
- this.currentEdit = this.tree.transactionFactory(this.latestCommittedView);
101
+ this.currentEdit = TransactionInternal_1.TransactionInternal.factory(this.latestCommittedView);
101
102
  }
102
103
  /**
103
104
  * Ends the ongoing edit operation and commits it to the history.
@@ -206,7 +207,7 @@ class Checkout extends telemetry_utils_1.EventEmitterWithErrorHandling {
206
207
  // When closed, the result might indicate Malformed due to unused detached entities.
207
208
  // This is not an error, as the edit was still open and can still use those entities.
208
209
  const priorResults = this.currentEdit.close();
209
- const rebasedEdit = this.tree.transactionFactory(this.latestCommittedView).applyChanges(priorResults.changes);
210
+ const rebasedEdit = TransactionInternal_1.TransactionInternal.factory(this.latestCommittedView).applyChanges(priorResults.changes);
210
211
  Common_1.assert(rebasedEdit.status !== persisted_types_1.EditStatus.Malformed, 'Malformed changes should have been caught on original application.');
211
212
  let status;
212
213
  if (rebasedEdit.status === persisted_types_1.EditStatus.Invalid) {
@@ -1 +1 @@
1
- {"version":3,"file":"Checkout.js","sourceRoot":"","sources":["../src/Checkout.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,qEAAgF;AAEhF,qCAAkC;AAElC,2CAA+C;AAK/C,uDAAqE;AACrE,6CAA+C;AAC/C,mDAA4C;AAG5C;;;GAGG;AACH,IAAY,aAMX;AAND,WAAY,aAAa;IACxB;;;OAGG;IACH,0CAAyB,CAAA;AAC1B,CAAC,EANW,aAAa,GAAb,qBAAa,KAAb,qBAAa,QAMxB;AASD;;;GAGG;AACH,IAAY,oBAiBX;AAjBD,WAAY,oBAAoB;IAC/B;;;;OAIG;IACH,yEAAS,CAAA;IACT;;;;OAIG;IACH,qEAAO,CAAA;IACP;;OAEG;IACH,iEAAK,CAAA;AACN,CAAC,EAjBW,oBAAoB,GAApB,4BAAoB,KAApB,4BAAoB,QAiB/B;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAsB,QAAS,SAAQ,+CAA8C;IA0CpF,YAAsB,IAAgB,EAAE,WAAyB,EAAE,eAAqC;QACvG,KAAK,CAAC,CAAC,MAAM,EAAE,KAAc,EAAE,EAAE;YAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QALG,aAAQ,GAAY,KAAK,CAAC;QAMhC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,IAAI,CAAC,SAAS,YAAY,4BAAgB,EAAE;YAC/C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC;SACvC;QACD,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,oBAAoB,GAAG,eAAe,CAAC;QAE5C,qEAAqE;QACrE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,4BAAe,CAAC,aAAa,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACxE,CAAC;IAED;;;OAGG;IACH,IAAW,WAAW;;QACrB,mBAAO,IAAI,CAAC,WAAW,0CAAE,IAAI,mCAAI,IAAI,CAAC,mBAAmB,CAAC;IAC3D,CAAC;IAED;;;OAGG;IACI,WAAW;QACjB,OAAO,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC;IACvC,CAAC;IAED;;;OAGG;IACI,QAAQ;QACd,eAAM,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,0BAA0B,CAAC,CAAC;QACnE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC3E,CAAC;IAED;;;;;;;OAOG;IACI,SAAS;QACf,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;QAC7B,eAAM,CAAC,WAAW,KAAK,SAAS,EAAE,sBAAsB,CAAC,CAAC;QAC1D,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC;QAC1C,eAAM,CAAC,aAAa,CAAC,MAAM,KAAK,4BAAU,CAAC,OAAO,EAAE,yDAAyD,CAAC,CAAC;QAE/G,MAAM,EAAE,GAAW,yBAAS,EAAE,CAAC;QAE/B,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;QACtC,OAAO,EAAE,CAAC;IACX,CAAC;IAED;;;OAGG;IACO,sBAAsB,CAAC,IAA0B,EAAE,MAA0B;;QACtF,yHAAyH;QACzH,MAAA,IAAI,CAAC,gBAAgB,0CAAE,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE;IAC5D,CAAC;IAED;;;;;OAKG;IACO,aAAa,CAAC,EAAU,EAAE,MAA0B;QAC7D,MAAM,IAAI,GAAyB,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QAEnE,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAE1C,8EAA8E;QAC9E,+DAA+D;QAC/D,4DAA4D;QAC5D,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACI,YAAY,CAAC,GAAG,OAAiB;QACvC,eAAM,CAAC,IAAI,CAAC,WAAW,EAAE,qDAAqD,CAAC,CAAC;QAChF,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrG,eAAM,CAAC,MAAM,KAAK,4BAAU,CAAC,OAAO,EAAE,0DAA0D,CAAC,CAAC;QAClG,IAAI,CAAC,UAAU,EAAE,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACO,uBAAuB,CAAC,GAAG,OAAyB;QAC7D,eAAM,CAAC,IAAI,CAAC,WAAW,EAAE,qDAAqD,CAAC,CAAC;QAChF,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC1D,IAAI,MAAM,KAAK,4BAAU,CAAC,OAAO,EAAE;YAClC,IAAI,CAAC,UAAU,EAAE,CAAC;SAClB;QACD,OAAO,MAAM,CAAC;IACf,CAAC;IAED;;;OAGG;IACI,SAAS,CAAC,GAAG,OAAiB;QACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACI,YAAY,CAAC,GAAG,OAAiB;QACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEhB,eAAM,CAAC,IAAI,CAAC,WAAW,EAAE,qDAAqD,CAAC,CAAC;QAChF,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrG,IAAI,MAAM,KAAK,4BAAU,CAAC,OAAO,EAAE;YAClC,IAAI,CAAC,UAAU,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;SACxB;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;;;;;;;;;OAUG;IACI,iBAAiB;QACvB,eAAM,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,sBAAsB,CAAC,CAAC;QAC/D,eAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,4BAAU,CAAC,OAAO,EAAE,qCAAqC,CAAC,CAAC;QAC9F,oFAAoF;QACpF,qFAAqF;QACrF,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC9G,eAAM,CACL,WAAW,CAAC,MAAM,KAAK,4BAAU,CAAC,SAAS,EAC3C,oEAAoE,CACpE,CAAC;QACF,IAAI,MAAiE,CAAC;QACtE,IAAI,WAAW,CAAC,MAAM,KAAK,4BAAU,CAAC,OAAO,EAAE;YAC9C,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC;YACtC,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;SAC7B;aAAM;YACN,MAAM,GAAG,oBAAoB,CAAC,KAAK,CAAC;YACpC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;SAC/B;QACD,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,OAAO,MAAM,CAAC;IACf,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;QAC7B,eAAM,CAAC,WAAW,KAAK,SAAS,EAAE,sBAAsB,CAAC,CAAC;QAC1D,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,IAAI,CAAC,UAAU,EAAE,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACI,aAAa;QACnB,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;QAC7B,eAAM,CAAC,WAAW,KAAK,SAAS,EAAE,sBAAsB,CAAC,CAAC;QAC1D,yDAAyD;QACzD,+GAA+G;QAC/G,OAAO,WAAW,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,MAAc;QAC3B,eAAM,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC;QACnE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9D,IAAI,OAAO,KAAK,SAAS,EAAE;YAC1B,IAAI,CAAC,uBAAuB,CAAC,GAAG,OAAO,CAAC,CAAC;SACzC;IACF,CAAC;IAED;;;;OAIG;IACO,UAAU;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;YAC5C,6GAA6G;YAC7G,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;SACvD;IACF,CAAC;IAaD;;;OAGG;IACI,OAAO,CAAC,KAAa;QAC3B,IAAI,IAAI,CAAC,QAAQ,EAAE;YAClB,OAAO;SACP;QAED,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,6BAA6B;QAC7B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,4BAAe,CAAC,aAAa,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACzE,CAAC;CACD;AAzSD,4BAySC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { EventEmitterWithErrorHandling } from '@fluidframework/telemetry-utils';\nimport { IDisposable, IErrorEvent } from '@fluidframework/common-definitions';\nimport { assert } from './Common';\nimport { EditId } from './Identifiers';\nimport { CachingLogViewer } from './LogViewer';\nimport { TreeView } from './TreeView';\nimport { RevisionView } from './RevisionView';\nimport { EditCommittedHandler, SharedTree } from './SharedTree';\nimport { GenericTransaction, ValidEditingResult } from './TransactionInternal';\nimport { ChangeInternal, Edit, EditStatus } from './persisted-types';\nimport { SharedTreeEvent } from './EventTypes';\nimport { newEditId } from './EditUtilities';\nimport { Change } from './ChangeTypes';\n\n/**\n * An event emitted by a `Checkout` to indicate a state change. See {@link ICheckoutEvents} for event argument information.\n * @public\n */\nexport enum CheckoutEvent {\n\t/**\n\t * `currentView` has changed.\n\t * Passed a before and after TreeView.\n\t */\n\tViewChange = 'viewChange',\n}\n\n/**\n * Events which may be emitted by `Checkout`. See {@link CheckoutEvent} for documentation of event semantics.\n */\nexport interface ICheckoutEvents extends IErrorEvent {\n\t(event: 'viewChange', listener: (before: TreeView, after: TreeView) => void);\n}\n\n/**\n * The result of validation of an Edit.\n * @public\n */\nexport enum EditValidationResult {\n\t/**\n\t * The edit contained one or more malformed changes (e.g. was missing required fields such as `id`),\n\t * or contained a sequence of changes that could not possibly be applied sequentially without error\n\t * (e.g. an edit which tries to insert the same detached node twice).\n\t */\n\tMalformed,\n\t/**\n\t * The edit is well-formed but cannot be applied to the current view, generally because concurrent changes\n\t * caused one or more merge conflicts.\n\t * For example, the edit refers to the `StablePlace` after node `C`, but `C` has since been deleted.\n\t */\n\tInvalid,\n\t/**\n\t * The edit is well-formed and can be applied to the current view.\n\t */\n\tValid,\n}\n\n/**\n * A mutable Checkout of a SharedTree, allowing viewing and interactive transactional editing.\n * Provides {@link https://en.wikipedia.org/wiki/Snapshot_isolation | snapshot-isolation} while editing.\n *\n * A Checkout always shows a consistent sequence of versions of the SharedTree, but it may skip intermediate versions, and may fall behind.\n * In this case consistent means the sequence of versions could occur with fully synchronous shared tree access,\n * though the timing of sequenced edits arriving to the Checkout may be later than they actually arrive in the SharedTree.\n * Specifically no sequenced edits will arrive during an ongoing edit (to implement snapshot isolation):\n * they will be applied asynchronously some time after the ongoing edit is ended.\n *\n * Events emitted by `Checkout` are documented in {@link CheckoutEvent}.\n * Exceptions thrown during event handling will be emitted as error events, which are automatically surfaced as error events on the\n * `SharedTree` used at construction time.\n * @public\n */\nexport abstract class Checkout extends EventEmitterWithErrorHandling<ICheckoutEvents> implements IDisposable {\n\t/**\n\t * The view of the latest committed revision.\n\t * Does not include changes from any open edits.\n\t *\n\t * When this changes, emitChange must be called.\n\t */\n\tprotected abstract get latestCommittedView(): RevisionView;\n\n\t/**\n\t * The last view for which invalidation was sent.\n\t * Updated by emitChange.\n\t */\n\tprivate previousView: TreeView;\n\n\t/**\n\t * A handler for 'committedEdit' SharedTreeEvent\n\t */\n\tprivate readonly editCommittedHandler: EditCommittedHandler;\n\n\t/**\n\t * The shared tree this checkout views/edits.\n\t */\n\tpublic readonly tree: SharedTree;\n\n\t/**\n\t * `tree`'s log viewer as a CachingLogViewer if it is one, otherwise undefined.\n\t * Used for optimizations if provided.\n\t */\n\tprivate readonly cachingLogViewer?: CachingLogViewer;\n\n\t/**\n\t * Holds the state required to manage the currently open edit.\n\t * Undefined if there is currently not an open edit.\n\t *\n\t * Since `currentView` exposes the the intermediate state from this edit,\n\t * operations that modify `currentEdit.view` must call `emitChange` to handle invalidation.\n\t */\n\tprivate currentEdit?: GenericTransaction;\n\n\tpublic disposed: boolean = false;\n\n\tprotected constructor(tree: SharedTree, currentView: RevisionView, onEditCommitted: EditCommittedHandler) {\n\t\tsuper((_event, error: unknown) => {\n\t\t\tthis.tree.emit('error', error);\n\t\t});\n\t\tthis.tree = tree;\n\t\tif (tree.logViewer instanceof CachingLogViewer) {\n\t\t\tthis.cachingLogViewer = tree.logViewer;\n\t\t}\n\t\tthis.previousView = currentView;\n\t\tthis.editCommittedHandler = onEditCommitted;\n\n\t\t// If there is an ongoing edit, emitChange will no-op, which is fine.\n\t\tthis.tree.on(SharedTreeEvent.EditCommitted, this.editCommittedHandler);\n\t}\n\n\t/**\n\t * @returns the current view of the tree, including the result of changes applied so far during an edit.\n\t * Note that any external edits (from other clients) will not added to view while there is a `currentEdit`.\n\t */\n\tpublic get currentView(): TreeView {\n\t\treturn this.currentEdit?.view ?? this.latestCommittedView;\n\t}\n\n\t/**\n\t * @returns true iff there is an open edit.\n\t * @internal\n\t */\n\tpublic hasOpenEdit(): boolean {\n\t\treturn this.currentEdit !== undefined;\n\t}\n\n\t/**\n\t * Opens a new edit operation.\n\t * Changes accumulate in the edit via calls to `applyChanges()`.\n\t */\n\tpublic openEdit(): void {\n\t\tassert(this.currentEdit === undefined, 'An edit is already open.');\n\t\tthis.currentEdit = this.tree.transactionFactory(this.latestCommittedView);\n\t}\n\n\t/**\n\t * Ends the ongoing edit operation and commits it to the history.\n\t *\n\t * Malformed edits are considered an error, and will assert:\n\t * All named detached sequences must have been used or theEdit is malformed.\n\t *\n\t * @returns the `id` of the committed edit\n\t */\n\tpublic closeEdit(): EditId {\n\t\tconst { currentEdit } = this;\n\t\tassert(currentEdit !== undefined, 'An edit is not open.');\n\t\tthis.currentEdit = undefined;\n\t\tconst editingResult = currentEdit.close();\n\t\tassert(editingResult.status === EditStatus.Applied, 'Locally constructed edits must be well-formed and valid');\n\n\t\tconst id: EditId = newEditId();\n\n\t\tthis.handleNewEdit(id, editingResult);\n\t\treturn id;\n\t}\n\n\t/**\n\t * Inform the Checkout that a particular edit is know to have a specific result when applied to a particular TreeView.\n\t * This may be used as a caching hint to avoid recomputation.\n\t */\n\tprotected hintKnownEditingResult(edit: Edit<ChangeInternal>, result: ValidEditingResult): void {\n\t\t// As an optimization, inform logViewer of this editing result so it can reuse it if applied to the same before revision.\n\t\tthis.cachingLogViewer?.setKnownEditingResult(edit, result);\n\t}\n\n\t/**\n\t * Take any needed action between when an edit is completed.\n\t * Usually this will include submitting it to a SharedTree.\n\t *\n\t * Override this to customize.\n\t */\n\tprotected handleNewEdit(id: EditId, result: ValidEditingResult): void {\n\t\tconst edit: Edit<ChangeInternal> = { id, changes: result.changes };\n\n\t\tthis.hintKnownEditingResult(edit, result);\n\n\t\t// Since external edits could have been applied while currentEdit was pending,\n\t\t// do not use the produced view: just go to the newest revision\n\t\t// (which processLocalEdit will do, including invalidation).\n\t\tthis.tree.applyEditInternal(edit);\n\t}\n\n\t/**\n\t * Applies the supplied changes to the tree and emits a change event.\n\t * Must be called during an ongoing edit (see `openEdit()`/`closeEdit()`).\n\t * `changes` must be well-formed and valid: it is an error if they do not apply cleanly.\n\t */\n\tpublic applyChanges(...changes: Change[]): void {\n\t\tassert(this.currentEdit, 'Changes must be applied as part of an ongoing edit.');\n\t\tconst { status } = this.currentEdit.applyChanges(changes.map((c) => this.tree.internalizeChange(c)));\n\t\tassert(status === EditStatus.Applied, 'Locally constructed edits must be well-formed and valid.');\n\t\tthis.emitChange();\n\t}\n\n\t/**\n\t * Applies the supplied changes to the tree and emits a change event.\n\t * Must be called during an ongoing edit (see `openEdit()`/`closeEdit()`).\n\t * `changes` must be well-formed and valid: it is an error if they do not apply cleanly.\n\t */\n\tprotected tryApplyChangesInternal(...changes: ChangeInternal[]): EditStatus {\n\t\tassert(this.currentEdit, 'Changes must be applied as part of an ongoing edit.');\n\t\tconst { status } = this.currentEdit.applyChanges(changes);\n\t\tif (status === EditStatus.Applied) {\n\t\t\tthis.emitChange();\n\t\t}\n\t\treturn status;\n\t}\n\n\t/**\n\t * Convenience helper for applying an edit containing the given changes.\n\t * Opens an edit, applies the given changes, and closes the edit. See (`openEdit()`/`applyChanges()`/`closeEdit()`).\n\t */\n\tpublic applyEdit(...changes: Change[]): EditId {\n\t\tthis.openEdit();\n\t\tthis.applyChanges(...changes);\n\t\treturn this.closeEdit();\n\t}\n\n\t/**\n\t * Apply an edit, if valid, otherwise does nothing (the edit is not added to the history).\n\t * If the edit applied, its changes will be immediately visible on this checkout, though it still may end up invalid once sequenced due to concurrent edits.\n\t * @returns The EditId if the edit was valid and thus applied, and undefined if it was invalid and thus not applied.\n\t */\n\tpublic tryApplyEdit(...changes: Change[]): EditId | undefined {\n\t\tthis.openEdit();\n\n\t\tassert(this.currentEdit, 'Changes must be applied as part of an ongoing edit.');\n\t\tconst { status } = this.currentEdit.applyChanges(changes.map((c) => this.tree.internalizeChange(c)));\n\t\tif (status === EditStatus.Applied) {\n\t\t\tthis.emitChange();\n\t\t\treturn this.closeEdit();\n\t\t}\n\n\t\tthis.abortEdit();\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Rebases the ongoing edit to the latest revision loaded by this 'Checkout'.\n\t * If the rebase succeeds (none of the changes in the ongoing edit became invalid), the ongoing edit will remain open and the current\n\t * view will reflect those changes.\n\t *\n\t * If the rebase fails (changes become invalid), the ongoing edit will be aborted and\n\t * currentView will return to showing the newest committed revision as it always does when there is no ongoing edit.\n\t *\n\t * Must only be called during an open edit.\n\t * @returns - the result of the rebase.\n\t */\n\tpublic rebaseCurrentEdit(): EditValidationResult.Valid | EditValidationResult.Invalid {\n\t\tassert(this.currentEdit !== undefined, 'An edit is not open.');\n\t\tassert(this.currentEdit.status === EditStatus.Applied, 'Local edits should always be valid.');\n\t\t// When closed, the result might indicate Malformed due to unused detached entities.\n\t\t// This is not an error, as the edit was still open and can still use those entities.\n\t\tconst priorResults = this.currentEdit.close();\n\t\tconst rebasedEdit = this.tree.transactionFactory(this.latestCommittedView).applyChanges(priorResults.changes);\n\t\tassert(\n\t\t\trebasedEdit.status !== EditStatus.Malformed,\n\t\t\t'Malformed changes should have been caught on original application.'\n\t\t);\n\t\tlet status: EditValidationResult.Valid | EditValidationResult.Invalid;\n\t\tif (rebasedEdit.status === EditStatus.Invalid) {\n\t\t\tstatus = EditValidationResult.Invalid;\n\t\t\tthis.currentEdit = undefined;\n\t\t} else {\n\t\t\tstatus = EditValidationResult.Valid;\n\t\t\tthis.currentEdit = rebasedEdit;\n\t\t}\n\t\tthis.emitChange();\n\t\treturn status;\n\t}\n\n\t/**\n\t * Ends the ongoing edit operation without committing it to the history.\n\t * Can only be called if an edit is open.\n\t */\n\tpublic abortEdit(): void {\n\t\tconst { currentEdit } = this;\n\t\tassert(currentEdit !== undefined, 'An edit is not open.');\n\t\tthis.currentEdit = undefined;\n\t\tthis.emitChange();\n\t}\n\n\t/**\n\t * @returns the {@link EditStatus} of the current edit.\n\t * Has no side effects.\n\t * Can only be called if an edit is open.\n\t */\n\tpublic getEditStatus(): EditStatus {\n\t\tconst { currentEdit } = this;\n\t\tassert(currentEdit !== undefined, 'An edit is not open.');\n\t\t// TODO: could this ever be anything other than 'Applied'\n\t\t// TODO: shouldn't this be an EditValidationResult since 'Applied' does not indicate the edit has been applied?\n\t\treturn currentEdit.status;\n\t}\n\n\t/**\n\t * Reverts a collection of edits.\n\t * @param editIds - the edits to revert\n\t */\n\tpublic revert(editId: EditId): void {\n\t\tassert(this.currentEdit !== undefined);\n\t\tconst index = this.tree.edits.getIndexOfId(editId);\n\t\tconst edit = this.tree.editsInternal.getEditInSessionAtIndex(index);\n\t\tconst before = this.tree.logViewer.getRevisionViewInSession(index);\n\t\tconst changes = this.tree.revertChanges(edit.changes, before);\n\t\tif (changes !== undefined) {\n\t\t\tthis.tryApplyChangesInternal(...changes);\n\t\t}\n\t}\n\n\t/**\n\t * Send invalidation message for all changes since last call to emitChange.\n\t * This must be called every time `currentView` could have changed.\n\t * It is ok to make excessive calls to this: change notifications will be cheaply de-duplicated.\n\t */\n\tprotected emitChange(): void {\n\t\tconst current = this.currentView;\n\t\tconst previous = this.previousView;\n\t\tif (!previous.hasEqualForest(current, true)) {\n\t\t\t// Set previousView before calling emit to make reentrant case work (where the event handler causes an edit).\n\t\t\tthis.previousView = current;\n\t\t\tthis.emit(CheckoutEvent.ViewChange, previous, current);\n\t\t}\n\t}\n\n\t/**\n\t * @returns a Promise which completes after all currently known edits are available in this checkout.\n\t */\n\tpublic abstract waitForPendingUpdates(): Promise<void>;\n\n\t/**\n\t * @returns a Promise which completes after edits that were closed on this checkout (before calling this) have been\n\t * submitted to Fluid. This does NOT wait for the Fluid service to ack them\n\t */\n\tpublic abstract waitForEditsToSubmit(): Promise<void>;\n\n\t/**\n\t * release all unmanaged resources\n\t * e.g. unregister event listeners\n\t */\n\tpublic dispose(error?: Error): void {\n\t\tif (this.disposed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.disposed = true;\n\n\t\t// remove registered listener\n\t\tthis.tree.off(SharedTreeEvent.EditCommitted, this.editCommittedHandler);\n\t}\n}\n"]}
1
+ {"version":3,"file":"Checkout.js","sourceRoot":"","sources":["../src/Checkout.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { EventEmitterWithErrorHandling } from '@fluidframework/telemetry-utils';\nimport { IDisposable, IErrorEvent } from '@fluidframework/common-definitions';\nimport { assert } from './Common';\nimport { EditId } from './Identifiers';\nimport { CachingLogViewer } from './LogViewer';\nimport { TreeView } from './TreeView';\nimport { RevisionView } from './RevisionView';\nimport { EditCommittedHandler, SharedTree } from './SharedTree';\nimport { GenericTransaction, TransactionInternal, ValidEditingResult } from './TransactionInternal';\nimport { ChangeInternal, Edit, EditStatus } from './persisted-types';\nimport { SharedTreeEvent } from './EventTypes';\nimport { newEditId } from './EditUtilities';\nimport { Change } from './ChangeTypes';\n\n/**\n * An event emitted by a `Checkout` to indicate a state change. See {@link ICheckoutEvents} for event argument information.\n * @public\n */\nexport enum CheckoutEvent {\n\t/**\n\t * `currentView` has changed.\n\t * Passed a before and after TreeView.\n\t */\n\tViewChange = 'viewChange',\n}\n\n/**\n * Events which may be emitted by `Checkout`. See {@link CheckoutEvent} for documentation of event semantics.\n */\nexport interface ICheckoutEvents extends IErrorEvent {\n\t(event: 'viewChange', listener: (before: TreeView, after: TreeView) => void);\n}\n\n/**\n * The result of validation of an Edit.\n * @public\n */\nexport enum EditValidationResult {\n\t/**\n\t * The edit contained one or more malformed changes (e.g. was missing required fields such as `id`),\n\t * or contained a sequence of changes that could not possibly be applied sequentially without error\n\t * (e.g. an edit which tries to insert the same detached node twice).\n\t */\n\tMalformed,\n\t/**\n\t * The edit is well-formed but cannot be applied to the current view, generally because concurrent changes\n\t * caused one or more merge conflicts.\n\t * For example, the edit refers to the `StablePlace` after node `C`, but `C` has since been deleted.\n\t */\n\tInvalid,\n\t/**\n\t * The edit is well-formed and can be applied to the current view.\n\t */\n\tValid,\n}\n\n/**\n * A mutable Checkout of a SharedTree, allowing viewing and interactive transactional editing.\n * Provides {@link https://en.wikipedia.org/wiki/Snapshot_isolation | snapshot-isolation} while editing.\n *\n * A Checkout always shows a consistent sequence of versions of the SharedTree, but it may skip intermediate versions, and may fall behind.\n * In this case consistent means the sequence of versions could occur with fully synchronous shared tree access,\n * though the timing of sequenced edits arriving to the Checkout may be later than they actually arrive in the SharedTree.\n * Specifically no sequenced edits will arrive during an ongoing edit (to implement snapshot isolation):\n * they will be applied asynchronously some time after the ongoing edit is ended.\n *\n * Events emitted by `Checkout` are documented in {@link CheckoutEvent}.\n * Exceptions thrown during event handling will be emitted as error events, which are automatically surfaced as error events on the\n * `SharedTree` used at construction time.\n * @public\n */\nexport abstract class Checkout extends EventEmitterWithErrorHandling<ICheckoutEvents> implements IDisposable {\n\t/**\n\t * The view of the latest committed revision.\n\t * Does not include changes from any open edits.\n\t *\n\t * When this changes, emitChange must be called.\n\t */\n\tprotected abstract get latestCommittedView(): RevisionView;\n\n\t/**\n\t * The last view for which invalidation was sent.\n\t * Updated by emitChange.\n\t */\n\tprivate previousView: TreeView;\n\n\t/**\n\t * A handler for 'committedEdit' SharedTreeEvent\n\t */\n\tprivate readonly editCommittedHandler: EditCommittedHandler;\n\n\t/**\n\t * The shared tree this checkout views/edits.\n\t */\n\tpublic readonly tree: SharedTree;\n\n\t/**\n\t * `tree`'s log viewer as a CachingLogViewer if it is one, otherwise undefined.\n\t * Used for optimizations if provided.\n\t */\n\tprivate readonly cachingLogViewer?: CachingLogViewer;\n\n\t/**\n\t * Holds the state required to manage the currently open edit.\n\t * Undefined if there is currently not an open edit.\n\t *\n\t * Since `currentView` exposes the the intermediate state from this edit,\n\t * operations that modify `currentEdit.view` must call `emitChange` to handle invalidation.\n\t */\n\tprivate currentEdit?: GenericTransaction;\n\n\tpublic disposed: boolean = false;\n\n\tprotected constructor(tree: SharedTree, currentView: RevisionView, onEditCommitted: EditCommittedHandler) {\n\t\tsuper((_event, error: unknown) => {\n\t\t\tthis.tree.emit('error', error);\n\t\t});\n\t\tthis.tree = tree;\n\t\tif (tree.logViewer instanceof CachingLogViewer) {\n\t\t\tthis.cachingLogViewer = tree.logViewer;\n\t\t}\n\t\tthis.previousView = currentView;\n\t\tthis.editCommittedHandler = onEditCommitted;\n\n\t\t// If there is an ongoing edit, emitChange will no-op, which is fine.\n\t\tthis.tree.on(SharedTreeEvent.EditCommitted, this.editCommittedHandler);\n\t}\n\n\t/**\n\t * @returns the current view of the tree, including the result of changes applied so far during an edit.\n\t * Note that any external edits (from other clients) will not added to view while there is a `currentEdit`.\n\t */\n\tpublic get currentView(): TreeView {\n\t\treturn this.currentEdit?.view ?? this.latestCommittedView;\n\t}\n\n\t/**\n\t * @returns true iff there is an open edit.\n\t * @internal\n\t */\n\tpublic hasOpenEdit(): boolean {\n\t\treturn this.currentEdit !== undefined;\n\t}\n\n\t/**\n\t * Opens a new edit operation.\n\t * Changes accumulate in the edit via calls to `applyChanges()`.\n\t */\n\tpublic openEdit(): void {\n\t\tassert(this.currentEdit === undefined, 'An edit is already open.');\n\t\tthis.currentEdit = TransactionInternal.factory(this.latestCommittedView);\n\t}\n\n\t/**\n\t * Ends the ongoing edit operation and commits it to the history.\n\t *\n\t * Malformed edits are considered an error, and will assert:\n\t * All named detached sequences must have been used or theEdit is malformed.\n\t *\n\t * @returns the `id` of the committed edit\n\t */\n\tpublic closeEdit(): EditId {\n\t\tconst { currentEdit } = this;\n\t\tassert(currentEdit !== undefined, 'An edit is not open.');\n\t\tthis.currentEdit = undefined;\n\t\tconst editingResult = currentEdit.close();\n\t\tassert(editingResult.status === EditStatus.Applied, 'Locally constructed edits must be well-formed and valid');\n\n\t\tconst id: EditId = newEditId();\n\n\t\tthis.handleNewEdit(id, editingResult);\n\t\treturn id;\n\t}\n\n\t/**\n\t * Inform the Checkout that a particular edit is know to have a specific result when applied to a particular TreeView.\n\t * This may be used as a caching hint to avoid recomputation.\n\t */\n\tprotected hintKnownEditingResult(edit: Edit<ChangeInternal>, result: ValidEditingResult): void {\n\t\t// As an optimization, inform logViewer of this editing result so it can reuse it if applied to the same before revision.\n\t\tthis.cachingLogViewer?.setKnownEditingResult(edit, result);\n\t}\n\n\t/**\n\t * Take any needed action between when an edit is completed.\n\t * Usually this will include submitting it to a SharedTree.\n\t *\n\t * Override this to customize.\n\t */\n\tprotected handleNewEdit(id: EditId, result: ValidEditingResult): void {\n\t\tconst edit: Edit<ChangeInternal> = { id, changes: result.changes };\n\n\t\tthis.hintKnownEditingResult(edit, result);\n\n\t\t// Since external edits could have been applied while currentEdit was pending,\n\t\t// do not use the produced view: just go to the newest revision\n\t\t// (which processLocalEdit will do, including invalidation).\n\t\tthis.tree.applyEditInternal(edit);\n\t}\n\n\t/**\n\t * Applies the supplied changes to the tree and emits a change event.\n\t * Must be called during an ongoing edit (see `openEdit()`/`closeEdit()`).\n\t * `changes` must be well-formed and valid: it is an error if they do not apply cleanly.\n\t */\n\tpublic applyChanges(...changes: Change[]): void {\n\t\tassert(this.currentEdit, 'Changes must be applied as part of an ongoing edit.');\n\t\tconst { status } = this.currentEdit.applyChanges(changes.map((c) => this.tree.internalizeChange(c)));\n\t\tassert(status === EditStatus.Applied, 'Locally constructed edits must be well-formed and valid.');\n\t\tthis.emitChange();\n\t}\n\n\t/**\n\t * Applies the supplied changes to the tree and emits a change event.\n\t * Must be called during an ongoing edit (see `openEdit()`/`closeEdit()`).\n\t * `changes` must be well-formed and valid: it is an error if they do not apply cleanly.\n\t */\n\tprotected tryApplyChangesInternal(...changes: ChangeInternal[]): EditStatus {\n\t\tassert(this.currentEdit, 'Changes must be applied as part of an ongoing edit.');\n\t\tconst { status } = this.currentEdit.applyChanges(changes);\n\t\tif (status === EditStatus.Applied) {\n\t\t\tthis.emitChange();\n\t\t}\n\t\treturn status;\n\t}\n\n\t/**\n\t * Convenience helper for applying an edit containing the given changes.\n\t * Opens an edit, applies the given changes, and closes the edit. See (`openEdit()`/`applyChanges()`/`closeEdit()`).\n\t */\n\tpublic applyEdit(...changes: Change[]): EditId {\n\t\tthis.openEdit();\n\t\tthis.applyChanges(...changes);\n\t\treturn this.closeEdit();\n\t}\n\n\t/**\n\t * Apply an edit, if valid, otherwise does nothing (the edit is not added to the history).\n\t * If the edit applied, its changes will be immediately visible on this checkout, though it still may end up invalid once sequenced due to concurrent edits.\n\t * @returns The EditId if the edit was valid and thus applied, and undefined if it was invalid and thus not applied.\n\t */\n\tpublic tryApplyEdit(...changes: Change[]): EditId | undefined {\n\t\tthis.openEdit();\n\n\t\tassert(this.currentEdit, 'Changes must be applied as part of an ongoing edit.');\n\t\tconst { status } = this.currentEdit.applyChanges(changes.map((c) => this.tree.internalizeChange(c)));\n\t\tif (status === EditStatus.Applied) {\n\t\t\tthis.emitChange();\n\t\t\treturn this.closeEdit();\n\t\t}\n\n\t\tthis.abortEdit();\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Rebases the ongoing edit to the latest revision loaded by this 'Checkout'.\n\t * If the rebase succeeds (none of the changes in the ongoing edit became invalid), the ongoing edit will remain open and the current\n\t * view will reflect those changes.\n\t *\n\t * If the rebase fails (changes become invalid), the ongoing edit will be aborted and\n\t * currentView will return to showing the newest committed revision as it always does when there is no ongoing edit.\n\t *\n\t * Must only be called during an open edit.\n\t * @returns - the result of the rebase.\n\t */\n\tpublic rebaseCurrentEdit(): EditValidationResult.Valid | EditValidationResult.Invalid {\n\t\tassert(this.currentEdit !== undefined, 'An edit is not open.');\n\t\tassert(this.currentEdit.status === EditStatus.Applied, 'Local edits should always be valid.');\n\t\t// When closed, the result might indicate Malformed due to unused detached entities.\n\t\t// This is not an error, as the edit was still open and can still use those entities.\n\t\tconst priorResults = this.currentEdit.close();\n\t\tconst rebasedEdit = TransactionInternal.factory(this.latestCommittedView).applyChanges(priorResults.changes);\n\t\tassert(\n\t\t\trebasedEdit.status !== EditStatus.Malformed,\n\t\t\t'Malformed changes should have been caught on original application.'\n\t\t);\n\t\tlet status: EditValidationResult.Valid | EditValidationResult.Invalid;\n\t\tif (rebasedEdit.status === EditStatus.Invalid) {\n\t\t\tstatus = EditValidationResult.Invalid;\n\t\t\tthis.currentEdit = undefined;\n\t\t} else {\n\t\t\tstatus = EditValidationResult.Valid;\n\t\t\tthis.currentEdit = rebasedEdit;\n\t\t}\n\t\tthis.emitChange();\n\t\treturn status;\n\t}\n\n\t/**\n\t * Ends the ongoing edit operation without committing it to the history.\n\t * Can only be called if an edit is open.\n\t */\n\tpublic abortEdit(): void {\n\t\tconst { currentEdit } = this;\n\t\tassert(currentEdit !== undefined, 'An edit is not open.');\n\t\tthis.currentEdit = undefined;\n\t\tthis.emitChange();\n\t}\n\n\t/**\n\t * @returns the {@link EditStatus} of the current edit.\n\t * Has no side effects.\n\t * Can only be called if an edit is open.\n\t */\n\tpublic getEditStatus(): EditStatus {\n\t\tconst { currentEdit } = this;\n\t\tassert(currentEdit !== undefined, 'An edit is not open.');\n\t\t// TODO: could this ever be anything other than 'Applied'\n\t\t// TODO: shouldn't this be an EditValidationResult since 'Applied' does not indicate the edit has been applied?\n\t\treturn currentEdit.status;\n\t}\n\n\t/**\n\t * Reverts a collection of edits.\n\t * @param editIds - the edits to revert\n\t */\n\tpublic revert(editId: EditId): void {\n\t\tassert(this.currentEdit !== undefined);\n\t\tconst index = this.tree.edits.getIndexOfId(editId);\n\t\tconst edit = this.tree.editsInternal.getEditInSessionAtIndex(index);\n\t\tconst before = this.tree.logViewer.getRevisionViewInSession(index);\n\t\tconst changes = this.tree.revertChanges(edit.changes, before);\n\t\tif (changes !== undefined) {\n\t\t\tthis.tryApplyChangesInternal(...changes);\n\t\t}\n\t}\n\n\t/**\n\t * Send invalidation message for all changes since last call to emitChange.\n\t * This must be called every time `currentView` could have changed.\n\t * It is ok to make excessive calls to this: change notifications will be cheaply de-duplicated.\n\t */\n\tprotected emitChange(): void {\n\t\tconst current = this.currentView;\n\t\tconst previous = this.previousView;\n\t\tif (!previous.hasEqualForest(current, true)) {\n\t\t\t// Set previousView before calling emit to make reentrant case work (where the event handler causes an edit).\n\t\t\tthis.previousView = current;\n\t\t\tthis.emit(CheckoutEvent.ViewChange, previous, current);\n\t\t}\n\t}\n\n\t/**\n\t * @returns a Promise which completes after all currently known edits are available in this checkout.\n\t */\n\tpublic abstract waitForPendingUpdates(): Promise<void>;\n\n\t/**\n\t * @returns a Promise which completes after edits that were closed on this checkout (before calling this) have been\n\t * submitted to Fluid. This does NOT wait for the Fluid service to ack them\n\t */\n\tpublic abstract waitForEditsToSubmit(): Promise<void>;\n\n\t/**\n\t * release all unmanaged resources\n\t * e.g. unregister event listeners\n\t */\n\tpublic dispose(error?: Error): void {\n\t\tif (this.disposed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.disposed = true;\n\n\t\t// remove registered listener\n\t\tthis.tree.off(SharedTreeEvent.EditCommitted, this.editCommittedHandler);\n\t}\n}\n"]}