@fluidframework/tree 2.92.0 → 2.93.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/README.md +1 -1
- package/api-report/tree.alpha.api.md +57 -29
- package/api-report/tree.beta.api.md +41 -12
- package/api-report/tree.legacy.beta.api.md +41 -12
- package/dist/api.d.ts +6 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js.map +1 -1
- package/dist/core/tree/anchorSet.d.ts.map +1 -1
- package/dist/core/tree/anchorSet.js +21 -0
- package/dist/core/tree/anchorSet.js.map +1 -1
- package/dist/entrypoints/alpha.d.ts +1 -1
- package/dist/entrypoints/alpha.d.ts.map +1 -1
- package/dist/entrypoints/alpha.js +4 -4
- package/dist/entrypoints/alpha.js.map +1 -1
- package/dist/entrypoints/beta.d.ts +1 -1
- package/dist/entrypoints/beta.d.ts.map +1 -1
- package/dist/entrypoints/beta.js +3 -1
- package/dist/entrypoints/beta.js.map +1 -1
- package/dist/entrypoints/legacy.d.ts +1 -1
- package/dist/entrypoints/legacy.d.ts.map +1 -1
- package/dist/entrypoints/legacy.js +3 -1
- package/dist/entrypoints/legacy.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkTree.d.ts +2 -2
- package/dist/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkTree.js +2 -1
- package/dist/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/uniformChunk.d.ts +13 -5
- package/dist/feature-libraries/chunked-forest/uniformChunk.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/uniformChunk.js +22 -18
- package/dist/feature-libraries/chunked-forest/uniformChunk.js.map +1 -1
- package/dist/feature-libraries/indexing/anchorTreeIndex.d.ts +1 -0
- package/dist/feature-libraries/indexing/anchorTreeIndex.d.ts.map +1 -1
- package/dist/feature-libraries/indexing/anchorTreeIndex.js +3 -1
- package/dist/feature-libraries/indexing/anchorTreeIndex.js.map +1 -1
- package/dist/feature-libraries/indexing/types.d.ts +4 -3
- package/dist/feature-libraries/indexing/types.d.ts.map +1 -1
- package/dist/feature-libraries/indexing/types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/serializableDomainSchema.d.ts +5 -5
- package/dist/serializableDomainSchema.d.ts.map +1 -1
- package/dist/serializableDomainSchema.js.map +1 -1
- package/dist/shared-tree/treeAlpha.d.ts +6 -2
- package/dist/shared-tree/treeAlpha.d.ts.map +1 -1
- package/dist/shared-tree/treeAlpha.js.map +1 -1
- package/dist/simple-tree/api/discrepancies.js +4 -1
- package/dist/simple-tree/api/discrepancies.js.map +1 -1
- package/dist/simple-tree/api/identifierIndex.d.ts +2 -2
- package/dist/simple-tree/api/identifierIndex.js +1 -1
- package/dist/simple-tree/api/identifierIndex.js.map +1 -1
- package/dist/simple-tree/api/index.d.ts +2 -2
- package/dist/simple-tree/api/index.d.ts.map +1 -1
- package/dist/simple-tree/api/index.js +3 -2
- package/dist/simple-tree/api/index.js.map +1 -1
- package/dist/simple-tree/api/schemaFactoryAlpha.d.ts +31 -2
- package/dist/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -1
- package/dist/simple-tree/api/schemaFactoryAlpha.js +17 -1
- package/dist/simple-tree/api/schemaFactoryAlpha.js.map +1 -1
- package/dist/simple-tree/api/simpleTreeIndex.d.ts +5 -5
- package/dist/simple-tree/api/simpleTreeIndex.js +1 -1
- package/dist/simple-tree/api/simpleTreeIndex.js.map +1 -1
- package/dist/simple-tree/api/storedSchema.d.ts.map +1 -1
- package/dist/simple-tree/api/storedSchema.js +4 -1
- package/dist/simple-tree/api/storedSchema.js.map +1 -1
- package/dist/simple-tree/api/treeAlpha.d.ts +70 -13
- package/dist/simple-tree/api/treeAlpha.d.ts.map +1 -1
- package/dist/simple-tree/api/treeAlpha.js.map +1 -1
- package/dist/simple-tree/api/treeChangeEvents.d.ts +1 -1
- package/dist/simple-tree/api/treeChangeEvents.js.map +1 -1
- package/dist/simple-tree/api/treeNodeApi.d.ts +60 -1
- package/dist/simple-tree/api/treeNodeApi.d.ts.map +1 -1
- package/dist/simple-tree/api/treeNodeApi.js +68 -6
- package/dist/simple-tree/api/treeNodeApi.js.map +1 -1
- package/dist/simple-tree/core/toStored.d.ts +7 -0
- package/dist/simple-tree/core/toStored.d.ts.map +1 -1
- package/dist/simple-tree/core/toStored.js.map +1 -1
- package/dist/simple-tree/core/unhydratedFlexTree.d.ts +17 -3
- package/dist/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
- package/dist/simple-tree/core/unhydratedFlexTree.js +114 -12
- package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
- package/dist/simple-tree/fieldSchema.d.ts +6 -1
- package/dist/simple-tree/fieldSchema.d.ts.map +1 -1
- package/dist/simple-tree/fieldSchema.js +3 -0
- package/dist/simple-tree/fieldSchema.js.map +1 -1
- package/dist/simple-tree/index.d.ts +2 -2
- package/dist/simple-tree/index.d.ts.map +1 -1
- package/dist/simple-tree/index.js +4 -3
- package/dist/simple-tree/index.js.map +1 -1
- package/dist/simple-tree/node-kinds/index.d.ts +1 -1
- package/dist/simple-tree/node-kinds/index.d.ts.map +1 -1
- package/dist/simple-tree/node-kinds/index.js.map +1 -1
- package/dist/simple-tree/node-kinds/map/index.d.ts +1 -1
- package/dist/simple-tree/node-kinds/map/index.d.ts.map +1 -1
- package/dist/simple-tree/node-kinds/map/index.js.map +1 -1
- package/dist/simple-tree/node-kinds/map/mapNode.d.ts +13 -0
- package/dist/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
- package/dist/simple-tree/node-kinds/map/mapNode.js +6 -1
- package/dist/simple-tree/node-kinds/map/mapNode.js.map +1 -1
- package/dist/simple-tree/node-kinds/map/mapNodeTypes.d.ts +6 -6
- package/dist/simple-tree/node-kinds/map/mapNodeTypes.d.ts.map +1 -1
- package/dist/simple-tree/node-kinds/map/mapNodeTypes.js.map +1 -1
- package/dist/simple-tree/simpleSchema.d.ts +17 -0
- package/dist/simple-tree/simpleSchema.d.ts.map +1 -1
- package/dist/simple-tree/simpleSchema.js.map +1 -1
- package/dist/simple-tree/toStoredSchema.d.ts.map +1 -1
- package/dist/simple-tree/toStoredSchema.js +23 -1
- package/dist/simple-tree/toStoredSchema.js.map +1 -1
- package/dist/tableSchema.d.ts +4 -5
- package/dist/tableSchema.d.ts.map +1 -1
- package/dist/tableSchema.js +12 -23
- package/dist/tableSchema.js.map +1 -1
- package/dist/text/textDomain.d.ts.map +1 -1
- package/dist/text/textDomain.js +27 -0
- package/dist/text/textDomain.js.map +1 -1
- package/dist/text/textDomainFormatted.d.ts +4 -4
- package/dist/util/index.d.ts +1 -1
- package/dist/util/index.d.ts.map +1 -1
- package/dist/util/index.js +2 -3
- package/dist/util/index.js.map +1 -1
- package/dist/util/utils.d.ts +0 -1
- package/dist/util/utils.d.ts.map +1 -1
- package/dist/util/utils.js +1 -6
- package/dist/util/utils.js.map +1 -1
- package/eslint.config.mts +1 -1
- package/lib/api.d.ts +6 -1
- package/lib/api.d.ts.map +1 -1
- package/lib/api.js.map +1 -1
- package/lib/core/tree/anchorSet.d.ts.map +1 -1
- package/lib/core/tree/anchorSet.js +21 -0
- package/lib/core/tree/anchorSet.js.map +1 -1
- package/lib/entrypoints/alpha.d.ts +1 -1
- package/lib/entrypoints/alpha.d.ts.map +1 -1
- package/lib/entrypoints/alpha.js +1 -1
- package/lib/entrypoints/alpha.js.map +1 -1
- package/lib/entrypoints/beta.d.ts +1 -1
- package/lib/entrypoints/beta.d.ts.map +1 -1
- package/lib/entrypoints/beta.js +1 -1
- package/lib/entrypoints/beta.js.map +1 -1
- package/lib/entrypoints/legacy.d.ts +1 -1
- package/lib/entrypoints/legacy.d.ts.map +1 -1
- package/lib/entrypoints/legacy.js +1 -1
- package/lib/entrypoints/legacy.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkTree.d.ts +2 -2
- package/lib/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkTree.js +2 -1
- package/lib/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/uniformChunk.d.ts +13 -5
- package/lib/feature-libraries/chunked-forest/uniformChunk.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/uniformChunk.js +22 -18
- package/lib/feature-libraries/chunked-forest/uniformChunk.js.map +1 -1
- package/lib/feature-libraries/indexing/anchorTreeIndex.d.ts +1 -0
- package/lib/feature-libraries/indexing/anchorTreeIndex.d.ts.map +1 -1
- package/lib/feature-libraries/indexing/anchorTreeIndex.js +3 -1
- package/lib/feature-libraries/indexing/anchorTreeIndex.js.map +1 -1
- package/lib/feature-libraries/indexing/types.d.ts +4 -3
- package/lib/feature-libraries/indexing/types.d.ts.map +1 -1
- package/lib/feature-libraries/indexing/types.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/serializableDomainSchema.d.ts +5 -5
- package/lib/serializableDomainSchema.d.ts.map +1 -1
- package/lib/serializableDomainSchema.js +4 -1
- package/lib/serializableDomainSchema.js.map +1 -1
- package/lib/shared-tree/treeAlpha.d.ts +6 -2
- package/lib/shared-tree/treeAlpha.d.ts.map +1 -1
- package/lib/shared-tree/treeAlpha.js.map +1 -1
- package/lib/simple-tree/api/discrepancies.js +4 -1
- package/lib/simple-tree/api/discrepancies.js.map +1 -1
- package/lib/simple-tree/api/identifierIndex.d.ts +2 -2
- package/lib/simple-tree/api/identifierIndex.js +1 -1
- package/lib/simple-tree/api/identifierIndex.js.map +1 -1
- package/lib/simple-tree/api/index.d.ts +2 -2
- package/lib/simple-tree/api/index.d.ts.map +1 -1
- package/lib/simple-tree/api/index.js +1 -1
- package/lib/simple-tree/api/index.js.map +1 -1
- package/lib/simple-tree/api/schemaFactoryAlpha.d.ts +31 -2
- package/lib/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -1
- package/lib/simple-tree/api/schemaFactoryAlpha.js +19 -3
- package/lib/simple-tree/api/schemaFactoryAlpha.js.map +1 -1
- package/lib/simple-tree/api/simpleTreeIndex.d.ts +5 -5
- package/lib/simple-tree/api/simpleTreeIndex.js +1 -1
- package/lib/simple-tree/api/simpleTreeIndex.js.map +1 -1
- package/lib/simple-tree/api/storedSchema.d.ts.map +1 -1
- package/lib/simple-tree/api/storedSchema.js +4 -1
- package/lib/simple-tree/api/storedSchema.js.map +1 -1
- package/lib/simple-tree/api/treeAlpha.d.ts +70 -13
- package/lib/simple-tree/api/treeAlpha.d.ts.map +1 -1
- package/lib/simple-tree/api/treeAlpha.js.map +1 -1
- package/lib/simple-tree/api/treeChangeEvents.d.ts +1 -1
- package/lib/simple-tree/api/treeChangeEvents.js.map +1 -1
- package/lib/simple-tree/api/treeNodeApi.d.ts +60 -1
- package/lib/simple-tree/api/treeNodeApi.d.ts.map +1 -1
- package/lib/simple-tree/api/treeNodeApi.js +66 -6
- package/lib/simple-tree/api/treeNodeApi.js.map +1 -1
- package/lib/simple-tree/core/toStored.d.ts +7 -0
- package/lib/simple-tree/core/toStored.d.ts.map +1 -1
- package/lib/simple-tree/core/toStored.js.map +1 -1
- package/lib/simple-tree/core/unhydratedFlexTree.d.ts +17 -3
- package/lib/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
- package/lib/simple-tree/core/unhydratedFlexTree.js +115 -13
- package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
- package/lib/simple-tree/fieldSchema.d.ts +6 -1
- package/lib/simple-tree/fieldSchema.d.ts.map +1 -1
- package/lib/simple-tree/fieldSchema.js +3 -0
- package/lib/simple-tree/fieldSchema.js.map +1 -1
- package/lib/simple-tree/index.d.ts +2 -2
- package/lib/simple-tree/index.d.ts.map +1 -1
- package/lib/simple-tree/index.js +1 -1
- package/lib/simple-tree/index.js.map +1 -1
- package/lib/simple-tree/node-kinds/index.d.ts +1 -1
- package/lib/simple-tree/node-kinds/index.d.ts.map +1 -1
- package/lib/simple-tree/node-kinds/index.js.map +1 -1
- package/lib/simple-tree/node-kinds/map/index.d.ts +1 -1
- package/lib/simple-tree/node-kinds/map/index.d.ts.map +1 -1
- package/lib/simple-tree/node-kinds/map/index.js.map +1 -1
- package/lib/simple-tree/node-kinds/map/mapNode.d.ts +13 -0
- package/lib/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
- package/lib/simple-tree/node-kinds/map/mapNode.js +6 -1
- package/lib/simple-tree/node-kinds/map/mapNode.js.map +1 -1
- package/lib/simple-tree/node-kinds/map/mapNodeTypes.d.ts +6 -6
- package/lib/simple-tree/node-kinds/map/mapNodeTypes.d.ts.map +1 -1
- package/lib/simple-tree/node-kinds/map/mapNodeTypes.js.map +1 -1
- package/lib/simple-tree/simpleSchema.d.ts +17 -0
- package/lib/simple-tree/simpleSchema.d.ts.map +1 -1
- package/lib/simple-tree/simpleSchema.js.map +1 -1
- package/lib/simple-tree/toStoredSchema.d.ts.map +1 -1
- package/lib/simple-tree/toStoredSchema.js +24 -2
- package/lib/simple-tree/toStoredSchema.js.map +1 -1
- package/lib/tableSchema.d.ts +4 -5
- package/lib/tableSchema.d.ts.map +1 -1
- package/lib/tableSchema.js +12 -23
- package/lib/tableSchema.js.map +1 -1
- package/lib/text/textDomain.d.ts.map +1 -1
- package/lib/text/textDomain.js +29 -0
- package/lib/text/textDomain.js.map +1 -1
- package/lib/text/textDomainFormatted.d.ts +4 -4
- package/lib/tsdoc-metadata.json +1 -1
- package/lib/util/index.d.ts +1 -1
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +1 -1
- package/lib/util/index.js.map +1 -1
- package/lib/util/utils.d.ts +0 -1
- package/lib/util/utils.d.ts.map +1 -1
- package/lib/util/utils.js +0 -1
- package/lib/util/utils.js.map +1 -1
- package/package.json +30 -35
- package/src/api.ts +10 -0
- package/src/core/tree/anchorSet.ts +25 -0
- package/src/entrypoints/alpha.ts +20 -16
- package/src/entrypoints/beta.ts +7 -1
- package/src/entrypoints/legacy.ts +8 -10
- package/src/feature-libraries/chunked-forest/chunkTree.ts +3 -2
- package/src/feature-libraries/chunked-forest/uniformChunk.ts +42 -20
- package/src/feature-libraries/indexing/anchorTreeIndex.ts +1 -0
- package/src/feature-libraries/indexing/types.ts +5 -3
- package/src/index.ts +4 -0
- package/src/packageVersion.ts +1 -1
- package/src/serializableDomainSchema.ts +6 -0
- package/src/shared-tree/treeAlpha.ts +6 -2
- package/src/simple-tree/api/discrepancies.ts +6 -1
- package/src/simple-tree/api/identifierIndex.ts +2 -2
- package/src/simple-tree/api/index.ts +4 -0
- package/src/simple-tree/api/schemaFactoryAlpha.ts +67 -2
- package/src/simple-tree/api/simpleTreeIndex.ts +6 -6
- package/src/simple-tree/api/storedSchema.ts +4 -1
- package/src/simple-tree/api/treeAlpha.ts +75 -12
- package/src/simple-tree/api/treeChangeEvents.ts +1 -1
- package/src/simple-tree/api/treeNodeApi.ts +101 -7
- package/src/simple-tree/core/toStored.ts +8 -0
- package/src/simple-tree/core/unhydratedFlexTree.ts +134 -10
- package/src/simple-tree/fieldSchema.ts +10 -0
- package/src/simple-tree/index.ts +5 -0
- package/src/simple-tree/node-kinds/index.ts +1 -0
- package/src/simple-tree/node-kinds/map/index.ts +1 -0
- package/src/simple-tree/node-kinds/map/mapNode.ts +20 -3
- package/src/simple-tree/node-kinds/map/mapNodeTypes.ts +6 -6
- package/src/simple-tree/simpleSchema.ts +20 -0
- package/src/simple-tree/toStoredSchema.ts +28 -1
- package/src/tableSchema.ts +16 -28
- package/src/text/textDomain.ts +68 -1
- package/src/util/index.ts +0 -1
- package/src/util/utils.ts +0 -2
- package/.mocharc.customBenchmarks.cjs +0 -25
|
@@ -5,14 +5,17 @@
|
|
|
5
5
|
|
|
6
6
|
import type { NodeKind, TreeNode, WithType } from "../core/index.js";
|
|
7
7
|
|
|
8
|
+
import type { TreeChangeEventsBeta } from "./treeBeta.js";
|
|
8
9
|
import type { TreeChangeEvents } from "./treeChangeEvents.js";
|
|
10
|
+
import type { ArrayNodeDeltaOp, ArrayNodeTreeChangedDeltaOp } from "./treeNodeApi.js";
|
|
9
11
|
export type {
|
|
10
12
|
ArrayNodeDeltaOp,
|
|
11
13
|
ArrayNodeInsertOp,
|
|
12
14
|
ArrayNodeRemoveOp,
|
|
13
15
|
ArrayNodeRetainOp,
|
|
16
|
+
ArrayNodeTreeChangedDeltaOp,
|
|
17
|
+
ArrayNodeTreeChangedRetainOp,
|
|
14
18
|
} from "./treeNodeApi.js";
|
|
15
|
-
import type { ArrayNodeDeltaOp } from "./treeNodeApi.js";
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* Data included for {@link TreeChangeEventsAlpha.nodeChanged} when the node is an object, map, or record node.
|
|
@@ -35,18 +38,16 @@ export interface NodeChangedDataProperties<TNode extends TreeNode = TreeNode> {
|
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
/**
|
|
38
|
-
* Data
|
|
41
|
+
* Data carried by the {@link TreeChangeEventsAlpha.nodeChanged} event for array nodes.
|
|
39
42
|
* @sealed @alpha
|
|
40
43
|
*/
|
|
41
44
|
export interface NodeChangedDataDelta {
|
|
42
45
|
/**
|
|
43
46
|
* The sequential operations describing what changed in the array node.
|
|
44
47
|
* @remarks
|
|
45
|
-
* The value may be `undefined` in
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* - The document was updated in a way that required multiple internal change passes in a single
|
|
49
|
-
* operation (for example, a data change combined with a schema upgrade).
|
|
48
|
+
* The value may be `undefined` when the document was updated in a way that required multiple
|
|
49
|
+
* internal change passes in a single operation (for example, a data change combined with a
|
|
50
|
+
* schema upgrade).
|
|
50
51
|
*
|
|
51
52
|
* See {@link ArrayNodeDeltaOp} for op semantics.
|
|
52
53
|
*/
|
|
@@ -54,7 +55,30 @@ export interface NodeChangedDataDelta {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
|
-
*
|
|
58
|
+
* Data carried by the {@link TreeChangeEventsAlpha.treeChanged} event for array nodes.
|
|
59
|
+
* @remarks
|
|
60
|
+
* Extends {@link NodeChangedDataDelta}: the retain ops in the delta additionally carry a
|
|
61
|
+
* {@link ArrayNodeTreeChangedRetainOp.subtreeChanged} flag indicating whether any descendant
|
|
62
|
+
* of the retained element changed.
|
|
63
|
+
* @sealed @alpha
|
|
64
|
+
*/
|
|
65
|
+
export interface NodeChangedDataTreeDelta {
|
|
66
|
+
/**
|
|
67
|
+
* The sequential operations describing what changed in the array node,
|
|
68
|
+
* including subtree-change information on retain ops.
|
|
69
|
+
* @remarks
|
|
70
|
+
* The value may be `undefined` when the document was updated in a way that required multiple
|
|
71
|
+
* internal change passes in a single operation (for example, a data change combined with a
|
|
72
|
+
* schema upgrade).
|
|
73
|
+
*
|
|
74
|
+
* See {@link ArrayNodeTreeChangedDeltaOp} for op semantics.
|
|
75
|
+
*/
|
|
76
|
+
readonly delta: readonly ArrayNodeTreeChangedDeltaOp[] | undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The data passed to {@link TreeChangeEventsAlpha.nodeChanged} and, for array nodes,
|
|
81
|
+
* to {@link TreeChangeEventsAlpha.treeChanged}.
|
|
58
82
|
* @remarks
|
|
59
83
|
* - For array nodes: {@link NodeChangedDataDelta} (includes a {@link NodeChangedDataDelta.delta | delta} payload).
|
|
60
84
|
* - For object, map, and record nodes: {@link NodeChangedDataProperties} (includes {@link NodeChangedDataProperties.changedProperties | changedProperties}).
|
|
@@ -69,22 +93,61 @@ export type NodeChangedDataAlpha<TNode extends TreeNode = TreeNode> =
|
|
|
69
93
|
: NodeChangedDataProperties<TNode> | NodeChangedDataDelta;
|
|
70
94
|
|
|
71
95
|
/**
|
|
72
|
-
* Extension of {@link TreeChangeEvents} with a richer `nodeChanged` event
|
|
96
|
+
* Extension of {@link TreeChangeEvents} with a richer `nodeChanged` event and a
|
|
97
|
+
* delta-carrying `treeChanged` event for array nodes.
|
|
73
98
|
* @remarks
|
|
74
99
|
* Provides a `nodeChanged` event that includes a delta payload for array nodes and
|
|
75
100
|
* requires `changedProperties` for object, map, and record nodes.
|
|
101
|
+
* Also provides a `treeChanged` event that, for array nodes, carries a {@link NodeChangedDataDelta}
|
|
102
|
+
* payload describing both shallow and deep changes.
|
|
103
|
+
* For non-array nodes, the `treeChanged` signature is the same as the base event.
|
|
104
|
+
*
|
|
76
105
|
* Use via `TreeAlpha.on`.
|
|
77
106
|
* @sealed @alpha
|
|
78
107
|
*/
|
|
79
108
|
export interface TreeChangeEventsAlpha<TNode extends TreeNode = TreeNode>
|
|
80
109
|
extends TreeChangeEvents {
|
|
81
110
|
/**
|
|
82
|
-
*
|
|
83
|
-
* a {@link NodeChangedDataDelta.delta | delta} payload describing the changes as a sequence
|
|
84
|
-
* of {@link ArrayNodeDeltaOp} values.
|
|
111
|
+
* Emitted when a shallow change occurs on this node, i.e., when the node's direct children change.
|
|
85
112
|
*
|
|
86
113
|
* @remarks
|
|
114
|
+
* For array nodes: the event data includes a {@link NodeChangedDataDelta.delta | delta} payload
|
|
115
|
+
* as a sequence of {@link ArrayNodeDeltaOp} values. Does not fire for deep changes (e.g. a
|
|
116
|
+
* property of an array element changed without any shallow array change). Subscribe to
|
|
117
|
+
* {@link TreeChangeEventsAlpha.treeChanged} on the array to receive a delta for those cases as well.
|
|
118
|
+
*
|
|
119
|
+
* For object, map, and record nodes: the event data includes
|
|
120
|
+
* {@link NodeChangedDataProperties.changedProperties | changedProperties}.
|
|
121
|
+
* @privateRemarks
|
|
87
122
|
* This defines a property which is a function instead of using the method syntax to avoid function bi-variance issues with the input data to the callback.
|
|
88
123
|
*/
|
|
89
124
|
nodeChanged: (data: NodeChangedDataAlpha<TNode>) => void;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Emitted when something in the subtree rooted at this node changes.
|
|
128
|
+
*
|
|
129
|
+
* @remarks
|
|
130
|
+
* For array nodes: emitted when any change occurred within the array, including both
|
|
131
|
+
* shallow changes (insert, remove, move) and deep changes (e.g. a property of an element
|
|
132
|
+
* changed). The event data carries a {@link NodeChangedDataTreeDelta.delta | delta} payload
|
|
133
|
+
* describing what changed. The delta uses {@link ArrayNodeTreeChangedRetainOp.subtreeChanged}
|
|
134
|
+
* to flag elements that have deep changes, without describing the details of those deep changes.
|
|
135
|
+
* To inspect deep changes, subscribe to `nodeChanged` or `treeChanged` on the individual
|
|
136
|
+
* element nodes.
|
|
137
|
+
*
|
|
138
|
+
* When this array is nested inside another array, the outer array's `treeChanged` still
|
|
139
|
+
* fires with a delta, but that delta only shows `subtreeChanged: true` for the element
|
|
140
|
+
* position containing this inner array — it does not include the inner array's detailed
|
|
141
|
+
* insert/remove/retain ops. To receive those detailed ops, subscribe to `treeChanged`
|
|
142
|
+
* directly on the inner array.
|
|
143
|
+
* Ancestor non-array nodes still receive the base (no-payload) `treeChanged` via normal
|
|
144
|
+
* subtree propagation.
|
|
145
|
+
*
|
|
146
|
+
* For non-array nodes: same as the base {@link TreeChangeEvents.treeChanged}.
|
|
147
|
+
* @privateRemarks
|
|
148
|
+
* This defines a property which is a function instead of using the method syntax to avoid function bi-variance issues with the input data to the callback.
|
|
149
|
+
*/
|
|
150
|
+
treeChanged: TNode extends WithType<string, NodeKind.Array>
|
|
151
|
+
? (data: NodeChangedDataTreeDelta) => void
|
|
152
|
+
: TreeChangeEventsBeta<TNode>["treeChanged"];
|
|
90
153
|
}
|
|
@@ -36,7 +36,7 @@ export interface TreeChangeEvents {
|
|
|
36
36
|
*
|
|
37
37
|
* - Object nodes define a change as being when the value of one of its properties changes (i.e., the property's value is set, including when set to `undefined`).
|
|
38
38
|
*
|
|
39
|
-
* - Array nodes define a change as when an element is added, removed, moved or replaced.
|
|
39
|
+
* - Array nodes define a change as when an element is added, removed, moved, or replaced.
|
|
40
40
|
*
|
|
41
41
|
* - Map nodes define a change as when an entry is added, updated, or removed.
|
|
42
42
|
*
|
|
@@ -41,7 +41,7 @@ import type { TreeChangeEvents } from "./treeChangeEvents.js";
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* A `"retain"` op in an {@link ArrayNodeDeltaOp} sequence.
|
|
44
|
-
* Represents elements that were
|
|
44
|
+
* Represents elements that were neither inserted into nor removed from the array.
|
|
45
45
|
* @sealed @alpha
|
|
46
46
|
*/
|
|
47
47
|
export interface ArrayNodeRetainOp {
|
|
@@ -49,6 +49,36 @@ export interface ArrayNodeRetainOp {
|
|
|
49
49
|
readonly count: number;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* A `"retain"` op in an {@link ArrayNodeTreeChangedDeltaOp} sequence, used in
|
|
54
|
+
* {@link NodeChangedDataTreeDelta} payloads delivered to
|
|
55
|
+
* {@link TreeChangeEventsAlpha.treeChanged} on array nodes.
|
|
56
|
+
*
|
|
57
|
+
* Extends {@link ArrayNodeRetainOp} with a {@link ArrayNodeTreeChangedRetainOp.subtreeChanged}
|
|
58
|
+
* flag that indicates whether any descendant of the retained element changed.
|
|
59
|
+
* @sealed @alpha
|
|
60
|
+
*/
|
|
61
|
+
export interface ArrayNodeTreeChangedRetainOp extends ArrayNodeRetainOp {
|
|
62
|
+
/**
|
|
63
|
+
* Whether any descendant of this retained element changed.
|
|
64
|
+
* `true` if the element's subtree changed; `false` if nothing changed within it.
|
|
65
|
+
* @remarks
|
|
66
|
+
* Subscribe to `nodeChanged` or `treeChanged` on the element node itself for details.
|
|
67
|
+
*/
|
|
68
|
+
readonly subtreeChanged: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* A single operation in an array-node delta delivered by {@link TreeChangeEventsAlpha.treeChanged}.
|
|
73
|
+
* Extends {@link ArrayNodeDeltaOp}: retain ops carry a {@link ArrayNodeTreeChangedRetainOp.subtreeChanged}
|
|
74
|
+
* flag indicating whether any descendant of the retained element changed.
|
|
75
|
+
* @alpha
|
|
76
|
+
*/
|
|
77
|
+
export type ArrayNodeTreeChangedDeltaOp =
|
|
78
|
+
| ArrayNodeTreeChangedRetainOp
|
|
79
|
+
| ArrayNodeInsertOp
|
|
80
|
+
| ArrayNodeRemoveOp;
|
|
81
|
+
|
|
52
82
|
/**
|
|
53
83
|
* An `"insert"` op in an {@link ArrayNodeDeltaOp} sequence.
|
|
54
84
|
* Represents elements added to the array.
|
|
@@ -247,13 +277,25 @@ export const treeNodeApi: TreeNodeApi = {
|
|
|
247
277
|
} else if (isArrayNodeSchema(nodeSchema)) {
|
|
248
278
|
return kernel.events.on("childrenChangedAfterBatch", ({ fieldMarks }) => {
|
|
249
279
|
const marks = fieldMarks.get(EmptyKey);
|
|
280
|
+
// nodeChanged fires only for shallow changes (insert, remove, move).
|
|
281
|
+
// Deep changes (e.g. a property of an element changed) are
|
|
282
|
+
// surfaced via TreeChangeEventsAlpha.treeChanged with a delta payload instead.
|
|
283
|
+
// When marks are undefined (marks could not be composed across multiple
|
|
284
|
+
// internal passes), we conservatively fire nodeChanged rather than silently
|
|
285
|
+
// dropping the event, even though the underlying change may have been
|
|
286
|
+
// purely deep. This is a known limitation of the current eventing stack.
|
|
287
|
+
const hasShallowChange =
|
|
288
|
+
marks === undefined ||
|
|
289
|
+
marks.some((m) => m.attach !== undefined || m.detach !== undefined);
|
|
290
|
+
if (!hasShallowChange) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
250
293
|
// `marks` is undefined when the field was modified across multiple batches
|
|
251
294
|
// within a single flush (e.g. due to an interleaved schema change) and the
|
|
252
295
|
// marks could not be composed. Emit `undefined` so callers know the delta is
|
|
253
296
|
// unavailable rather than receiving stale marks from only the first batch.
|
|
254
297
|
// TODO: Once the eventing stack is rewritten to walk the composed delta at
|
|
255
|
-
// flush time, `marks` will always be defined. Remove the `undefined` fallback
|
|
256
|
-
// and simplify to: `const delta = deltaMarksToArrayOps(marks);`
|
|
298
|
+
// flush time, `marks` will always be defined. Remove the `undefined` fallback.
|
|
257
299
|
const delta = marks === undefined ? undefined : deltaMarksToArrayOps(marks);
|
|
258
300
|
listener({ delta });
|
|
259
301
|
});
|
|
@@ -264,6 +306,18 @@ export const treeNodeApi: TreeNodeApi = {
|
|
|
264
306
|
}
|
|
265
307
|
}
|
|
266
308
|
case "treeChanged": {
|
|
309
|
+
if (isArrayNodeSchema(kernel.schema)) {
|
|
310
|
+
// For array nodes, treeChanged fires via childrenChangedAfterBatch so that a
|
|
311
|
+
// delta payload can be provided. This covers both shallow changes
|
|
312
|
+
// (insert/remove/move) and deep element changes. Stable (non-alpha) listeners
|
|
313
|
+
// typed as () => void will silently ignore the extra argument at runtime.
|
|
314
|
+
return kernel.events.on("childrenChangedAfterBatch", ({ fieldMarks }) => {
|
|
315
|
+
const marks = fieldMarks.get(EmptyKey);
|
|
316
|
+
const delta =
|
|
317
|
+
marks === undefined ? undefined : deltaMarksToArrayOpsForTreeChanged(marks);
|
|
318
|
+
(listener as (data: { readonly delta: typeof delta }) => void)({ delta });
|
|
319
|
+
});
|
|
320
|
+
}
|
|
267
321
|
return kernel.events.on("subtreeChangedAfterBatch", () => listener({}));
|
|
268
322
|
}
|
|
269
323
|
default: {
|
|
@@ -298,19 +352,21 @@ export const treeNodeApi: TreeNodeApi = {
|
|
|
298
352
|
|
|
299
353
|
/**
|
|
300
354
|
* Converts an array of internal {@link DeltaMark}s for a sequence field into sequential
|
|
301
|
-
* array delta ops suitable for inclusion in {@link
|
|
355
|
+
* array delta ops suitable for inclusion in {@link NodeChangedDataDelta.delta}.
|
|
302
356
|
*
|
|
303
357
|
* Each mark in the delta describes a contiguous run of positions in the original array:
|
|
304
|
-
* - A mark with only `count` (no attach/detach) → `"retain"`
|
|
358
|
+
* - A mark with only `count` (no attach/detach) → `"retain"` with no subtree information
|
|
305
359
|
* - A mark with only `attach` → `"insert"` (new elements added)
|
|
306
360
|
* - A mark with only `detach` → `"remove"` (elements removed)
|
|
307
361
|
* - A mark with both `attach` and `detach` → `"remove"` + `"insert"`
|
|
308
362
|
*
|
|
363
|
+
* @param marks - The low-level delta marks for the array's sequence field.
|
|
364
|
+
*
|
|
309
365
|
* @privateRemarks
|
|
310
366
|
* The case where both `attach` and `detach` are set is unreachable today: the sequence-field
|
|
311
367
|
* encoder never emits such marks for array (EmptyKey) fields. It is handled defensively.
|
|
312
368
|
*/
|
|
313
|
-
function deltaMarksToArrayOps(marks: readonly DeltaMark[]): ArrayNodeDeltaOp[] {
|
|
369
|
+
export function deltaMarksToArrayOps(marks: readonly DeltaMark[]): ArrayNodeDeltaOp[] {
|
|
314
370
|
const ops: ArrayNodeDeltaOp[] = [];
|
|
315
371
|
for (const mark of marks) {
|
|
316
372
|
if (mark.detach !== undefined) {
|
|
@@ -319,13 +375,51 @@ function deltaMarksToArrayOps(marks: readonly DeltaMark[]): ArrayNodeDeltaOp[] {
|
|
|
319
375
|
if (mark.attach !== undefined) {
|
|
320
376
|
ops.push({ type: "insert", count: mark.count });
|
|
321
377
|
} else if (mark.detach === undefined) {
|
|
322
|
-
//
|
|
378
|
+
// Retain: elements were not added or removed.
|
|
323
379
|
ops.push({ type: "retain", count: mark.count });
|
|
324
380
|
}
|
|
325
381
|
}
|
|
326
382
|
return ops;
|
|
327
383
|
}
|
|
328
384
|
|
|
385
|
+
/**
|
|
386
|
+
* Converts an array of internal {@link DeltaMark}s for a sequence field into sequential
|
|
387
|
+
* {@link ArrayNodeTreeChangedDeltaOp}s suitable for inclusion in
|
|
388
|
+
* {@link NodeChangedDataTreeDelta.delta} (delivered to {@link TreeChangeEventsAlpha.treeChanged}).
|
|
389
|
+
*
|
|
390
|
+
* Same conversion rules as {@link deltaMarksToArrayOps}, but retain ops additionally carry a
|
|
391
|
+
* {@link ArrayNodeTreeChangedRetainOp.subtreeChanged} flag derived from whether the mark has
|
|
392
|
+
* a `fields` property (indicating a descendant changed).
|
|
393
|
+
*
|
|
394
|
+
* @param marks - The low-level delta marks for the array's sequence field.
|
|
395
|
+
*
|
|
396
|
+
* @privateRemarks
|
|
397
|
+
* The case where both `attach` and `detach` are set is unreachable today: the sequence-field
|
|
398
|
+
* encoder never emits such marks for array (EmptyKey) fields. It is handled defensively.
|
|
399
|
+
*/
|
|
400
|
+
export function deltaMarksToArrayOpsForTreeChanged(
|
|
401
|
+
marks: readonly DeltaMark[],
|
|
402
|
+
): ArrayNodeTreeChangedDeltaOp[] {
|
|
403
|
+
const ops: ArrayNodeTreeChangedDeltaOp[] = [];
|
|
404
|
+
for (const mark of marks) {
|
|
405
|
+
if (mark.detach !== undefined) {
|
|
406
|
+
ops.push({ type: "remove", count: mark.count });
|
|
407
|
+
}
|
|
408
|
+
if (mark.attach !== undefined) {
|
|
409
|
+
ops.push({ type: "insert", count: mark.count });
|
|
410
|
+
} else if (mark.detach === undefined) {
|
|
411
|
+
// Retain: elements were not added or removed (but may have deep changes).
|
|
412
|
+
// When `fields` is set, `count` is guaranteed to be 1 (DeltaMark invariant).
|
|
413
|
+
ops.push({
|
|
414
|
+
type: "retain",
|
|
415
|
+
count: mark.count,
|
|
416
|
+
subtreeChanged: mark.fields !== undefined,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return ops;
|
|
421
|
+
}
|
|
422
|
+
|
|
329
423
|
/**
|
|
330
424
|
* Returns a schema for a value if the value is a {@link TreeNode} or a {@link TreeLeafValue}.
|
|
331
425
|
* Returns undefined for other values.
|
|
@@ -15,6 +15,14 @@ export interface StoredFromViewSchemaGenerationOptions {
|
|
|
15
15
|
* Due to caching, the behavior of this function must be pure.
|
|
16
16
|
*/
|
|
17
17
|
includeStaged(upgrade: SchemaUpgrade): boolean;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Determines whether to treat a {@link SchemaFactoryAlpha.stagedOptional | staged optional} field as optional
|
|
21
|
+
* (rather than required) in the resulting stored schema.
|
|
22
|
+
* @remarks
|
|
23
|
+
* Due to caching, the behavior of this function must be pure.
|
|
24
|
+
*/
|
|
25
|
+
includeStagedOptional(upgrade: SchemaUpgrade): boolean;
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
/**
|
|
@@ -11,6 +11,9 @@ import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
|
11
11
|
import {
|
|
12
12
|
type AnchorEvents,
|
|
13
13
|
dummyRoot,
|
|
14
|
+
EmptyKey,
|
|
15
|
+
type DeltaDetachedNodeId,
|
|
16
|
+
type DeltaMark,
|
|
14
17
|
type FieldKey,
|
|
15
18
|
type FieldKindIdentifier,
|
|
16
19
|
type ITreeCursorSynchronous,
|
|
@@ -84,6 +87,13 @@ type UnhydratedFlexTreeNodeEvents = Pick<
|
|
|
84
87
|
/** A node's parent field and its index in that field */
|
|
85
88
|
type LocationInField = FlexTreeNode["parentField"];
|
|
86
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Placeholder `DeltaDetachedNodeId` used as the attach/detach id in synthetic delta marks produced
|
|
92
|
+
* by the unhydrated sequence-field editor. Only the *presence* of the id is checked by
|
|
93
|
+
* {@link deltaMarksToArrayOps}, so the value itself is arbitrary.
|
|
94
|
+
*/
|
|
95
|
+
const syntheticDetachedNodeId: DeltaDetachedNodeId = { minor: 0 };
|
|
96
|
+
|
|
87
97
|
/**
|
|
88
98
|
* The {@link Unhydrated} implementation of {@link FlexTreeNode}.
|
|
89
99
|
*/
|
|
@@ -270,24 +280,88 @@ export class UnhydratedFlexTreeNode
|
|
|
270
280
|
return this.data.value;
|
|
271
281
|
}
|
|
272
282
|
|
|
273
|
-
|
|
283
|
+
/**
|
|
284
|
+
* Emit a `childrenChangedAfterBatch` event for this node, then propagate deep-change
|
|
285
|
+
* signals to ancestor array nodes and subtree-changed signals up the entire ancestor chain.
|
|
286
|
+
* @param key - The field key that changed.
|
|
287
|
+
* @param marks - Optional delta marks describing the change to the field. When provided, they
|
|
288
|
+
* are included in the `fieldMarks` payload so that array-node listeners can build a delta.
|
|
289
|
+
* When omitted (e.g. for non-sequence fields), `fieldMarks` is empty.
|
|
290
|
+
*/
|
|
291
|
+
public emitChangedEvent(key: FieldKey, marks?: readonly DeltaMark[]): void {
|
|
274
292
|
this._events.emit("childrenChangedAfterBatch", {
|
|
275
293
|
changedFields: new Set([key]),
|
|
276
|
-
|
|
277
|
-
fieldMarks: new Map(),
|
|
294
|
+
fieldMarks: marks === undefined ? new Map() : new Map([[key, marks]]),
|
|
278
295
|
});
|
|
279
296
|
|
|
280
|
-
//
|
|
297
|
+
// Emit subtree-changed events for this node and its non-array ancestors first,
|
|
298
|
+
// so that node.treeChanged fires before any ancestor array.treeChanged.
|
|
299
|
+
// Array ancestors and the nodes above them are handled by
|
|
300
|
+
// #emitDeepChangesToAncestorArrays, which propagates subtree events above
|
|
301
|
+
// each array boundary in the correct order.
|
|
281
302
|
this.#emitSubtreeChangedEvents();
|
|
303
|
+
|
|
304
|
+
// Mirrors the onlyDeepChanges block in anchorSet.ts for unhydrated nodes.
|
|
305
|
+
this.#emitDeepChangesToAncestorArrays();
|
|
282
306
|
}
|
|
283
307
|
|
|
284
308
|
/**
|
|
285
|
-
* Emit
|
|
309
|
+
* Emit `childrenChangedAfterBatch` on each ancestor array node with synthetic
|
|
310
|
+
* marks indicating a deep change at this node's position within the array.
|
|
311
|
+
* After emitting on each array ancestor, propagates subtree-changed events
|
|
312
|
+
* upward from that array so that ancestor nodes above the array receive their
|
|
313
|
+
* `treeChanged` events after the array's own event.
|
|
314
|
+
*/
|
|
315
|
+
#emitDeepChangesToAncestorArrays(): void {
|
|
316
|
+
const location = this.parentField;
|
|
317
|
+
const parentField = location.parent;
|
|
318
|
+
const parentNode = parentField.parent;
|
|
319
|
+
|
|
320
|
+
if (parentNode === undefined || !(parentNode instanceof UnhydratedFlexTreeNode)) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Only emit on array ancestors (EmptyKey); object/map ancestors don't carry delta payloads.
|
|
325
|
+
if (parentField.key === EmptyKey) {
|
|
326
|
+
const index = location.index;
|
|
327
|
+
const syntheticMarks: DeltaMark[] = [];
|
|
328
|
+
if (index > 0) {
|
|
329
|
+
syntheticMarks.push({ count: index });
|
|
330
|
+
}
|
|
331
|
+
// `fields` presence (not content) signals a deep change to deltaMarksToArrayOps.
|
|
332
|
+
syntheticMarks.push({ count: 1, fields: new Map([[EmptyKey, { marks: [] }]]) });
|
|
333
|
+
|
|
334
|
+
parentNode._events.emit("childrenChangedAfterBatch", {
|
|
335
|
+
changedFields: new Set([EmptyKey]),
|
|
336
|
+
fieldMarks: new Map([[EmptyKey, syntheticMarks]]),
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// Propagate subtree-changed events from the array upward so that
|
|
340
|
+
// ancestors above this array receive treeChanged after the array itself.
|
|
341
|
+
parentNode.#emitSubtreeChangedEvents();
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
parentNode.#emitDeepChangesToAncestorArrays();
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Emit `subtreeChangedAfterBatch` on this node and propagate upward to
|
|
349
|
+
* ancestors, stopping before the first ancestor array node.
|
|
350
|
+
* Propagation stops at an array boundary because
|
|
351
|
+
* {@link UnhydratedFlexTreeNode.#emitDeepChangesToAncestorArrays} is
|
|
352
|
+
* responsible for emitting on array ancestors and the nodes above them
|
|
353
|
+
* in the correct order.
|
|
286
354
|
*/
|
|
287
355
|
#emitSubtreeChangedEvents(): void {
|
|
288
356
|
this._events.emit("subtreeChangedAfterBatch");
|
|
289
357
|
|
|
290
|
-
const
|
|
358
|
+
const parentField = this.parentField.parent;
|
|
359
|
+
if (parentField.key === EmptyKey) {
|
|
360
|
+
// This node is an array element; stop here so that array ancestor
|
|
361
|
+
// events fire in the correct order relative to this node's treeChanged.
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const parent = parentField.parent;
|
|
291
365
|
assert(
|
|
292
366
|
parent === undefined || parent instanceof UnhydratedFlexTreeNode,
|
|
293
367
|
0xb76 /* Unhydrated node's parent should be an unhydrated node */,
|
|
@@ -445,6 +519,12 @@ export class UnhydratedFlexTreeField
|
|
|
445
519
|
*/
|
|
446
520
|
protected edit(
|
|
447
521
|
edit: (mapTrees: UnhydratedFlexTreeNode[]) => void | UnhydratedFlexTreeNode[],
|
|
522
|
+
/**
|
|
523
|
+
* Delta marks describing this edit, forwarded to {@link UnhydratedFlexTreeNode.emitChangedEvent}.
|
|
524
|
+
* Sequence-field subclasses pass pre-computed marks so that array-node listeners receive a
|
|
525
|
+
* meaningful delta; other field kinds omit this parameter.
|
|
526
|
+
*/
|
|
527
|
+
marks?: readonly DeltaMark[],
|
|
448
528
|
): void {
|
|
449
529
|
// Clear parents for all old map trees.
|
|
450
530
|
for (const tree of this.children) {
|
|
@@ -458,7 +538,7 @@ export class UnhydratedFlexTreeField
|
|
|
458
538
|
tree.adoptBy(this, index);
|
|
459
539
|
}
|
|
460
540
|
|
|
461
|
-
this.parent?.emitChangedEvent(this.key);
|
|
541
|
+
this.parent?.emitChangedEvent(this.key, marks);
|
|
462
542
|
}
|
|
463
543
|
|
|
464
544
|
public getFieldPath(): NormalizedFieldUpPath {
|
|
@@ -541,6 +621,10 @@ export class UnhydratedSequenceField
|
|
|
541
621
|
assert(c instanceof UnhydratedFlexTreeNode, 0xbb8 /* Expected unhydrated node */);
|
|
542
622
|
}
|
|
543
623
|
const newContentChecked = newContent as readonly UnhydratedFlexTreeNode[];
|
|
624
|
+
const insertCount = newContentChecked.length;
|
|
625
|
+
const marks: DeltaMark[] = [];
|
|
626
|
+
if (index > 0) marks.push({ count: index });
|
|
627
|
+
marks.push({ count: insertCount, attach: syntheticDetachedNodeId });
|
|
544
628
|
this.edit((mapTrees) => {
|
|
545
629
|
if (newContent.length < 1000) {
|
|
546
630
|
// For "smallish arrays" (`1000` is not empirically derived), the `splice` function is appropriate...
|
|
@@ -549,23 +633,27 @@ export class UnhydratedSequenceField
|
|
|
549
633
|
// ...but we avoid using `splice` + spread for very large input arrays since there is a limit on how many elements can be spread (too many will overflow the stack).
|
|
550
634
|
return [...mapTrees.slice(0, index), ...newContentChecked, ...mapTrees.slice(index)];
|
|
551
635
|
}
|
|
552
|
-
});
|
|
636
|
+
}, marks);
|
|
553
637
|
},
|
|
554
638
|
remove: (index, count): UnhydratedFlexTreeNode[] => {
|
|
555
639
|
for (let i = index; i < index + count; i++) {
|
|
556
640
|
const c = this.children[i];
|
|
557
641
|
assert(c !== undefined, 0xa0b /* Unexpected sparse array */);
|
|
558
642
|
}
|
|
643
|
+
const marks: DeltaMark[] = [];
|
|
644
|
+
if (index > 0) marks.push({ count: index });
|
|
645
|
+
marks.push({ count, detach: syntheticDetachedNodeId });
|
|
559
646
|
let removed: UnhydratedFlexTreeNode[] | undefined;
|
|
560
647
|
this.edit((mapTrees) => {
|
|
561
648
|
removed = mapTrees.splice(index, count);
|
|
562
|
-
});
|
|
649
|
+
}, marks);
|
|
563
650
|
return removed ?? fail(0xb4a /* Expected removed to be set by edit */);
|
|
564
651
|
},
|
|
565
652
|
move: (sourceIndex, count, destIndex, source?): void => {
|
|
566
653
|
const sourceField = source ?? this;
|
|
567
654
|
if (sourceField === this) {
|
|
568
655
|
// Within-field move: do both operations in a single edit to emit only one event
|
|
656
|
+
const marks = buildUnhydratedMoveMarks(sourceIndex, count, destIndex);
|
|
569
657
|
this.edit((mapTrees) => {
|
|
570
658
|
const removed = mapTrees.splice(sourceIndex, count);
|
|
571
659
|
// Adjust destination index if it comes after the source
|
|
@@ -581,7 +669,7 @@ export class UnhydratedSequenceField
|
|
|
581
669
|
...mapTrees.slice(adjustedDest),
|
|
582
670
|
];
|
|
583
671
|
}
|
|
584
|
-
});
|
|
672
|
+
}, marks);
|
|
585
673
|
} else {
|
|
586
674
|
// Cross-field move: remove from source, insert into destination
|
|
587
675
|
// Each field emits one event (correct behavior for different fields)
|
|
@@ -605,6 +693,42 @@ export class UnhydratedSequenceField
|
|
|
605
693
|
|
|
606
694
|
// #endregion Fields
|
|
607
695
|
|
|
696
|
+
/**
|
|
697
|
+
* Builds {@link DeltaMark}s describing a within-field move for use in
|
|
698
|
+
* {@link UnhydratedFlexTreeNode.emitChangedEvent}.
|
|
699
|
+
*
|
|
700
|
+
* @remarks
|
|
701
|
+
* Forward move (`sourceIndex < destIndex`):
|
|
702
|
+
* `[retain(src), detach(n), retain(mid), attach(n)]`
|
|
703
|
+
*
|
|
704
|
+
* Backward move (`destIndex < sourceIndex`):
|
|
705
|
+
* `[retain(dst), attach(n), retain(mid), detach(n)]`
|
|
706
|
+
*
|
|
707
|
+
* A no-op move (`sourceIndex === destIndex`) returns an empty array; the event
|
|
708
|
+
* should not fire in that case, but the empty marks are harmless if it does.
|
|
709
|
+
*/
|
|
710
|
+
function buildUnhydratedMoveMarks(
|
|
711
|
+
sourceIndex: number,
|
|
712
|
+
count: number,
|
|
713
|
+
destIndex: number,
|
|
714
|
+
): readonly DeltaMark[] {
|
|
715
|
+
const marks: DeltaMark[] = [];
|
|
716
|
+
if (sourceIndex < destIndex) {
|
|
717
|
+
if (sourceIndex > 0) marks.push({ count: sourceIndex });
|
|
718
|
+
marks.push({ count, detach: syntheticDetachedNodeId });
|
|
719
|
+
const between = destIndex - sourceIndex - count;
|
|
720
|
+
if (between > 0) marks.push({ count: between });
|
|
721
|
+
marks.push({ count, attach: syntheticDetachedNodeId });
|
|
722
|
+
} else if (destIndex < sourceIndex) {
|
|
723
|
+
if (destIndex > 0) marks.push({ count: destIndex });
|
|
724
|
+
marks.push({ count, attach: syntheticDetachedNodeId });
|
|
725
|
+
const between = sourceIndex - destIndex;
|
|
726
|
+
if (between > 0) marks.push({ count: between });
|
|
727
|
+
marks.push({ count, detach: syntheticDetachedNodeId });
|
|
728
|
+
}
|
|
729
|
+
return marks;
|
|
730
|
+
}
|
|
731
|
+
|
|
608
732
|
/** Creates a field with the given attributes */
|
|
609
733
|
export function createField(
|
|
610
734
|
...args: ConstructorParameters<typeof UnhydratedFlexTreeField>
|
|
@@ -28,6 +28,7 @@ import type {
|
|
|
28
28
|
TreeLeafValue,
|
|
29
29
|
InsertableTreeNodeFromImplicitAllowedTypes,
|
|
30
30
|
AllowedTypesFull,
|
|
31
|
+
SchemaUpgrade,
|
|
31
32
|
} from "./core/index.js";
|
|
32
33
|
import { AnnotatedAllowedTypesInternal, normalizeAllowedTypes } from "./core/index.js";
|
|
33
34
|
import type {
|
|
@@ -182,6 +183,11 @@ export interface FieldPropsAlpha<TCustomMetadata = unknown>
|
|
|
182
183
|
* Sets {@link SimpleFieldSchema.persistedMetadata}.
|
|
183
184
|
*/
|
|
184
185
|
readonly persistedMetadata?: JsonCompatibleReadOnlyObject | undefined;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* If defined, indicates that this field is a {@link SchemaStaticsAlpha.stagedOptional | staged optional} field.
|
|
189
|
+
*/
|
|
190
|
+
readonly stagedOptionalUpgrade?: SchemaUpgrade;
|
|
185
191
|
}
|
|
186
192
|
|
|
187
193
|
/**
|
|
@@ -412,6 +418,10 @@ export class FieldSchemaAlpha<
|
|
|
412
418
|
return this.propsAlpha?.persistedMetadata;
|
|
413
419
|
}
|
|
414
420
|
|
|
421
|
+
public get isStagedOptional(): false | SchemaUpgrade {
|
|
422
|
+
return this.propsAlpha?.stagedOptionalUpgrade ?? false;
|
|
423
|
+
}
|
|
424
|
+
|
|
415
425
|
static {
|
|
416
426
|
createFieldSchemaPrivate = <
|
|
417
427
|
Kind2 extends FieldKind,
|
package/src/simple-tree/index.ts
CHANGED
|
@@ -95,10 +95,14 @@ export {
|
|
|
95
95
|
type ArrayNodeInsertOp,
|
|
96
96
|
type ArrayNodeRemoveOp,
|
|
97
97
|
type ArrayNodeRetainOp,
|
|
98
|
+
type ArrayNodeTreeChangedDeltaOp,
|
|
99
|
+
type ArrayNodeTreeChangedRetainOp,
|
|
100
|
+
deltaMarksToArrayOps,
|
|
98
101
|
type NodeChangedData,
|
|
99
102
|
type NodeChangedDataAlpha,
|
|
100
103
|
type NodeChangedDataDelta,
|
|
101
104
|
type NodeChangedDataProperties,
|
|
105
|
+
type NodeChangedDataTreeDelta,
|
|
102
106
|
borrowCursorFromTreeNodeOrValue,
|
|
103
107
|
exportConcise,
|
|
104
108
|
importConcise,
|
|
@@ -270,6 +274,7 @@ export {
|
|
|
270
274
|
MapNodeSchema,
|
|
271
275
|
isMapNodeSchema,
|
|
272
276
|
type TreeMapNode,
|
|
277
|
+
type TreeMapNodeAlpha,
|
|
273
278
|
type MapNodeInsertableData,
|
|
274
279
|
type FieldHasDefault,
|
|
275
280
|
type FieldHasDefaultAlpha,
|