@fluidframework/tree 2.101.1 → 2.102.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 +4 -0
- package/api-report/tree.alpha.api.md +19 -0
- package/dist/codec/codec.d.ts +22 -53
- package/dist/codec/codec.d.ts.map +1 -1
- package/dist/codec/codec.js +7 -44
- package/dist/codec/codec.js.map +1 -1
- package/dist/codec/index.d.ts +1 -1
- package/dist/codec/index.d.ts.map +1 -1
- package/dist/codec/index.js +2 -2
- package/dist/codec/index.js.map +1 -1
- package/dist/codec/versioned/codec.d.ts +56 -28
- package/dist/codec/versioned/codec.d.ts.map +1 -1
- package/dist/codec/versioned/codec.js +29 -12
- package/dist/codec/versioned/codec.js.map +1 -1
- package/dist/codec/versioned/index.d.ts +1 -1
- package/dist/codec/versioned/index.d.ts.map +1 -1
- package/dist/codec/versioned/index.js +2 -2
- package/dist/codec/versioned/index.js.map +1 -1
- package/dist/core/tree/deltaUtil.d.ts +2 -2
- package/dist/core/tree/deltaUtil.js +2 -2
- package/dist/core/tree/deltaUtil.js.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecV1.d.ts.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecV1.js +3 -2
- package/dist/core/tree/detachedFieldIndexCodecV1.js.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecV2.d.ts.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecV2.js +4 -2
- package/dist/core/tree/detachedFieldIndexCodecV2.js.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecs.d.ts +3 -3
- package/dist/core/tree/detachedFieldIndexCodecs.d.ts.map +1 -1
- package/dist/core/tree/detachedFieldIndexCodecs.js +1 -1
- package/dist/core/tree/detachedFieldIndexCodecs.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkTree.d.ts +38 -1
- package/dist/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkTree.js +62 -4
- package/dist/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkedForest.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkedForest.js +18 -4
- package/dist/feature-libraries/chunked-forest/chunkedForest.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/chunkDecoding.d.ts +34 -2
- package/dist/feature-libraries/chunked-forest/codec/chunkDecoding.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/chunkDecoding.js +106 -3
- package/dist/feature-libraries/chunked-forest/codec/chunkDecoding.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/codecs.d.ts +5 -5
- package/dist/feature-libraries/chunked-forest/codec/codecs.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/codecs.js +2 -2
- package/dist/feature-libraries/chunked-forest/codec/codecs.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/compressedEncode.d.ts +7 -7
- package/dist/feature-libraries/chunked-forest/codec/compressedEncode.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/compressedEncode.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/format/formatV2.d.ts +25 -5
- package/dist/feature-libraries/chunked-forest/codec/format/formatV2.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/format/formatV2.js +9 -3
- package/dist/feature-libraries/chunked-forest/codec/format/formatV2.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/format/formatVText.d.ts +105 -0
- package/dist/feature-libraries/chunked-forest/codec/format/formatVText.d.ts.map +1 -0
- package/dist/feature-libraries/chunked-forest/codec/format/formatVText.js +44 -0
- package/dist/feature-libraries/chunked-forest/codec/format/formatVText.js.map +1 -0
- package/dist/feature-libraries/chunked-forest/codec/format/index.d.ts +2 -1
- package/dist/feature-libraries/chunked-forest/codec/format/index.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/format/index.js +5 -1
- package/dist/feature-libraries/chunked-forest/codec/format/index.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/format/versions.d.ts +38 -4
- package/dist/feature-libraries/chunked-forest/codec/format/versions.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/format/versions.js +7 -1
- package/dist/feature-libraries/chunked-forest/codec/format/versions.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/nodeEncoder.d.ts +7 -7
- package/dist/feature-libraries/chunked-forest/codec/nodeEncoder.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/nodeEncoder.js +1 -2
- package/dist/feature-libraries/chunked-forest/codec/nodeEncoder.js.map +1 -1
- package/dist/feature-libraries/forest-summary/codec.d.ts +5 -4
- package/dist/feature-libraries/forest-summary/codec.d.ts.map +1 -1
- package/dist/feature-libraries/forest-summary/codec.js +2 -2
- package/dist/feature-libraries/forest-summary/codec.js.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
- package/dist/feature-libraries/schema-index/codec.d.ts +2 -2
- package/dist/feature-libraries/schema-index/codec.d.ts.map +1 -1
- package/dist/feature-libraries/schema-index/codec.js +1 -1
- package/dist/feature-libraries/schema-index/codec.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -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/shared-tree/isAuditableFromOutcome.d.ts +20 -0
- package/dist/shared-tree/isAuditableFromOutcome.d.ts.map +1 -0
- package/dist/shared-tree/isAuditableFromOutcome.js +36 -0
- package/dist/shared-tree/isAuditableFromOutcome.js.map +1 -0
- package/dist/shared-tree/treeCheckout.d.ts +2 -0
- package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
- package/dist/shared-tree/treeCheckout.js +37 -8
- package/dist/shared-tree/treeCheckout.js.map +1 -1
- package/dist/shared-tree-core/editManagerCodecs.d.ts +3 -3
- package/dist/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
- package/dist/shared-tree-core/editManagerCodecs.js +2 -2
- package/dist/shared-tree-core/editManagerCodecs.js.map +1 -1
- package/dist/shared-tree-core/messageCodecs.d.ts +3 -3
- package/dist/shared-tree-core/messageCodecs.d.ts.map +1 -1
- package/dist/shared-tree-core/messageCodecs.js +2 -2
- package/dist/shared-tree-core/messageCodecs.js.map +1 -1
- package/dist/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
- package/dist/simple-tree/core/treeNodeKernel.js +25 -11
- package/dist/simple-tree/core/treeNodeKernel.js.map +1 -1
- package/dist/text/codePointUtils.d.ts +48 -0
- package/dist/text/codePointUtils.d.ts.map +1 -0
- package/dist/text/codePointUtils.js +80 -0
- package/dist/text/codePointUtils.js.map +1 -0
- package/dist/text/index.d.ts +1 -0
- package/dist/text/index.d.ts.map +1 -1
- package/dist/text/index.js +4 -1
- package/dist/text/index.js.map +1 -1
- package/dist/text/textDomain.d.ts +93 -1
- package/dist/text/textDomain.d.ts.map +1 -1
- package/dist/text/textDomain.js +65 -8
- package/dist/text/textDomain.js.map +1 -1
- package/dist/text/textDomainFormatted.d.ts +24 -6
- package/dist/text/textDomainFormatted.d.ts.map +1 -1
- package/dist/text/textDomainFormatted.js +29 -1
- package/dist/text/textDomainFormatted.js.map +1 -1
- package/dist/treeFactory.d.ts.map +1 -1
- package/dist/treeFactory.js +9 -7
- package/dist/treeFactory.js.map +1 -1
- package/dist/util/breakable.d.ts +7 -1
- package/dist/util/breakable.d.ts.map +1 -1
- package/dist/util/breakable.js +18 -4
- package/dist/util/breakable.js.map +1 -1
- package/lib/codec/codec.d.ts +22 -53
- package/lib/codec/codec.d.ts.map +1 -1
- package/lib/codec/codec.js +7 -44
- package/lib/codec/codec.js.map +1 -1
- package/lib/codec/index.d.ts +1 -1
- package/lib/codec/index.d.ts.map +1 -1
- package/lib/codec/index.js +1 -1
- package/lib/codec/index.js.map +1 -1
- package/lib/codec/versioned/codec.d.ts +56 -28
- package/lib/codec/versioned/codec.d.ts.map +1 -1
- package/lib/codec/versioned/codec.js +27 -10
- package/lib/codec/versioned/codec.js.map +1 -1
- package/lib/codec/versioned/index.d.ts +1 -1
- package/lib/codec/versioned/index.d.ts.map +1 -1
- package/lib/codec/versioned/index.js +1 -1
- package/lib/codec/versioned/index.js.map +1 -1
- package/lib/core/tree/deltaUtil.d.ts +2 -2
- package/lib/core/tree/deltaUtil.js +2 -2
- package/lib/core/tree/deltaUtil.js.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecV1.d.ts.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecV1.js +3 -2
- package/lib/core/tree/detachedFieldIndexCodecV1.js.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecV2.d.ts.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecV2.js +5 -3
- package/lib/core/tree/detachedFieldIndexCodecV2.js.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecs.d.ts +3 -3
- package/lib/core/tree/detachedFieldIndexCodecs.d.ts.map +1 -1
- package/lib/core/tree/detachedFieldIndexCodecs.js +2 -2
- package/lib/core/tree/detachedFieldIndexCodecs.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkTree.d.ts +38 -1
- package/lib/feature-libraries/chunked-forest/chunkTree.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkTree.js +61 -4
- package/lib/feature-libraries/chunked-forest/chunkTree.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkedForest.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkedForest.js +20 -6
- package/lib/feature-libraries/chunked-forest/chunkedForest.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/chunkDecoding.d.ts +34 -2
- package/lib/feature-libraries/chunked-forest/codec/chunkDecoding.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/chunkDecoding.js +102 -2
- package/lib/feature-libraries/chunked-forest/codec/chunkDecoding.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/codecs.d.ts +5 -5
- package/lib/feature-libraries/chunked-forest/codec/codecs.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/codecs.js +3 -3
- package/lib/feature-libraries/chunked-forest/codec/codecs.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/compressedEncode.d.ts +7 -7
- package/lib/feature-libraries/chunked-forest/codec/compressedEncode.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/compressedEncode.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/format/formatV2.d.ts +25 -5
- package/lib/feature-libraries/chunked-forest/codec/format/formatV2.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/format/formatV2.js +8 -2
- package/lib/feature-libraries/chunked-forest/codec/format/formatV2.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/format/formatVText.d.ts +105 -0
- package/lib/feature-libraries/chunked-forest/codec/format/formatVText.d.ts.map +1 -0
- package/lib/feature-libraries/chunked-forest/codec/format/formatVText.js +41 -0
- package/lib/feature-libraries/chunked-forest/codec/format/formatVText.js.map +1 -0
- package/lib/feature-libraries/chunked-forest/codec/format/index.d.ts +2 -1
- package/lib/feature-libraries/chunked-forest/codec/format/index.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/format/index.js +2 -1
- package/lib/feature-libraries/chunked-forest/codec/format/index.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/format/versions.d.ts +38 -4
- package/lib/feature-libraries/chunked-forest/codec/format/versions.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/format/versions.js +6 -0
- package/lib/feature-libraries/chunked-forest/codec/format/versions.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/nodeEncoder.d.ts +7 -7
- package/lib/feature-libraries/chunked-forest/codec/nodeEncoder.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/nodeEncoder.js +2 -3
- package/lib/feature-libraries/chunked-forest/codec/nodeEncoder.js.map +1 -1
- package/lib/feature-libraries/forest-summary/codec.d.ts +5 -4
- package/lib/feature-libraries/forest-summary/codec.d.ts.map +1 -1
- package/lib/feature-libraries/forest-summary/codec.js +3 -3
- package/lib/feature-libraries/forest-summary/codec.js.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeTypes.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeTypes.js.map +1 -1
- package/lib/feature-libraries/schema-index/codec.d.ts +2 -2
- package/lib/feature-libraries/schema-index/codec.d.ts.map +1 -1
- package/lib/feature-libraries/schema-index/codec.js +2 -2
- package/lib/feature-libraries/schema-index/codec.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +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/shared-tree/isAuditableFromOutcome.d.ts +20 -0
- package/lib/shared-tree/isAuditableFromOutcome.d.ts.map +1 -0
- package/lib/shared-tree/isAuditableFromOutcome.js +32 -0
- package/lib/shared-tree/isAuditableFromOutcome.js.map +1 -0
- package/lib/shared-tree/treeCheckout.d.ts +2 -0
- package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
- package/lib/shared-tree/treeCheckout.js +37 -8
- package/lib/shared-tree/treeCheckout.js.map +1 -1
- package/lib/shared-tree-core/editManagerCodecs.d.ts +3 -3
- package/lib/shared-tree-core/editManagerCodecs.d.ts.map +1 -1
- package/lib/shared-tree-core/editManagerCodecs.js +3 -3
- package/lib/shared-tree-core/editManagerCodecs.js.map +1 -1
- package/lib/shared-tree-core/messageCodecs.d.ts +3 -3
- package/lib/shared-tree-core/messageCodecs.d.ts.map +1 -1
- package/lib/shared-tree-core/messageCodecs.js +3 -3
- package/lib/shared-tree-core/messageCodecs.js.map +1 -1
- package/lib/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
- package/lib/simple-tree/core/treeNodeKernel.js +25 -11
- package/lib/simple-tree/core/treeNodeKernel.js.map +1 -1
- package/lib/text/codePointUtils.d.ts +48 -0
- package/lib/text/codePointUtils.d.ts.map +1 -0
- package/lib/text/codePointUtils.js +75 -0
- package/lib/text/codePointUtils.js.map +1 -0
- package/lib/text/index.d.ts +1 -0
- package/lib/text/index.d.ts.map +1 -1
- package/lib/text/index.js +1 -0
- package/lib/text/index.js.map +1 -1
- package/lib/text/textDomain.d.ts +93 -1
- package/lib/text/textDomain.d.ts.map +1 -1
- package/lib/text/textDomain.js +56 -0
- package/lib/text/textDomain.js.map +1 -1
- package/lib/text/textDomainFormatted.d.ts +24 -6
- package/lib/text/textDomainFormatted.d.ts.map +1 -1
- package/lib/text/textDomainFormatted.js +30 -2
- package/lib/text/textDomainFormatted.js.map +1 -1
- package/lib/treeFactory.d.ts.map +1 -1
- package/lib/treeFactory.js +2 -0
- package/lib/treeFactory.js.map +1 -1
- package/lib/util/breakable.d.ts +7 -1
- package/lib/util/breakable.d.ts.map +1 -1
- package/lib/util/breakable.js +18 -4
- package/lib/util/breakable.js.map +1 -1
- package/package.json +24 -24
- package/src/codec/codec.ts +82 -73
- package/src/codec/index.ts +2 -1
- package/src/codec/versioned/codec.ts +173 -73
- package/src/codec/versioned/index.ts +2 -1
- package/src/core/tree/deltaUtil.ts +2 -2
- package/src/core/tree/detachedFieldIndexCodecV1.ts +3 -2
- package/src/core/tree/detachedFieldIndexCodecV2.ts +5 -3
- package/src/core/tree/detachedFieldIndexCodecs.ts +2 -2
- package/src/feature-libraries/chunked-forest/chunkTree.ts +85 -1
- package/src/feature-libraries/chunked-forest/chunkedForest.ts +27 -7
- package/src/feature-libraries/chunked-forest/codec/chunkDecoding.ts +143 -7
- package/src/feature-libraries/chunked-forest/codec/codecs.ts +30 -28
- package/src/feature-libraries/chunked-forest/codec/compressedEncode.ts +7 -7
- package/src/feature-libraries/chunked-forest/codec/format/formatV2.ts +11 -7
- package/src/feature-libraries/chunked-forest/codec/format/formatVText.ts +83 -0
- package/src/feature-libraries/chunked-forest/codec/format/index.ts +6 -1
- package/src/feature-libraries/chunked-forest/codec/format/versions.ts +25 -4
- package/src/feature-libraries/chunked-forest/codec/nodeEncoder.ts +14 -18
- package/src/feature-libraries/forest-summary/codec.ts +9 -4
- package/src/feature-libraries/modular-schema/modularChangeTypes.ts +1 -1
- package/src/feature-libraries/schema-index/codec.ts +2 -5
- package/src/index.ts +6 -1
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/isAuditableFromOutcome.ts +34 -0
- package/src/shared-tree/treeCheckout.ts +52 -9
- package/src/shared-tree-core/editManagerCodecs.ts +4 -6
- package/src/shared-tree-core/messageCodecs.ts +4 -4
- package/src/simple-tree/core/treeNodeKernel.ts +27 -13
- package/src/text/codePointUtils.ts +81 -0
- package/src/text/index.ts +1 -0
- package/src/text/textDomain.ts +155 -2
- package/src/text/textDomainFormatted.ts +73 -2
- package/src/treeFactory.ts +5 -0
- package/src/util/breakable.ts +27 -6
|
@@ -10,6 +10,7 @@ import { strictEnum, type Values } from "../../../../util/index.js";
|
|
|
10
10
|
import { EncodedFieldBatchGeneric } from "./formatGeneric.js";
|
|
11
11
|
import { EncodedChunkShapeV1 } from "./formatV1.js";
|
|
12
12
|
import { EncodedChunkShapeV2 } from "./formatV2.js";
|
|
13
|
+
import { EncodedChunkShapeVTextExperimental } from "./formatVText.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* The format version for the field batch.
|
|
@@ -29,6 +30,10 @@ export const FieldBatchFormatVersion = strictEnum("FieldBatchFormatVersion", {
|
|
|
29
30
|
* {@link EncodedIncrementalChunkShape} was added in this version.
|
|
30
31
|
*/
|
|
31
32
|
v2: 2,
|
|
33
|
+
/**
|
|
34
|
+
* Experimental codec with optimizations for text.
|
|
35
|
+
*/
|
|
36
|
+
vTextExperimental: "text",
|
|
32
37
|
});
|
|
33
38
|
|
|
34
39
|
/**
|
|
@@ -68,6 +73,17 @@ export const EncodedFieldBatchV2 = EncodedFieldBatchGeneric(
|
|
|
68
73
|
EncodedChunkShapeV2,
|
|
69
74
|
);
|
|
70
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Encoded {@link FieldBatch} using the experimental text optimized format.
|
|
78
|
+
*/
|
|
79
|
+
export type EncodedFieldBatchVTextExperimental = Static<
|
|
80
|
+
typeof EncodedFieldBatchVTextExperimental
|
|
81
|
+
>;
|
|
82
|
+
export const EncodedFieldBatchVTextExperimental = EncodedFieldBatchGeneric(
|
|
83
|
+
FieldBatchFormatVersion.vTextExperimental,
|
|
84
|
+
EncodedChunkShapeVTextExperimental,
|
|
85
|
+
);
|
|
86
|
+
|
|
71
87
|
/**
|
|
72
88
|
* Encoded {@link FieldBatch}, which might use V2 features, but might also have been from a V1 encoder.
|
|
73
89
|
* @remarks
|
|
@@ -88,9 +104,14 @@ export type EncodedFieldBatchV1OrV2 = EncodedFieldBatchV1 | EncodedFieldBatchV2;
|
|
|
88
104
|
export type EncodedFieldBatchV1AndV2 = EncodedFieldBatchV1 & EncodedFieldBatchV2;
|
|
89
105
|
|
|
90
106
|
/**
|
|
91
|
-
*
|
|
107
|
+
* An encoded chunk shape from any known {@link FieldBatchFormatVersion}.
|
|
108
|
+
*
|
|
92
109
|
* @remarks
|
|
93
|
-
*
|
|
94
|
-
*
|
|
110
|
+
* Use this when working with chunk shapes uniformly across versions — for example, in the
|
|
111
|
+
* shared decoder dispatcher and in encoder shape base classes. New format versions should
|
|
112
|
+
* add their chunk shape variant to this union.
|
|
95
113
|
*/
|
|
96
|
-
export type
|
|
114
|
+
export type EncodedChunkShape =
|
|
115
|
+
| EncodedChunkShapeV1
|
|
116
|
+
| EncodedChunkShapeV2
|
|
117
|
+
| EncodedChunkShapeVTextExperimental;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { assert, fail } from "@fluidframework/core-utils/internal";
|
|
7
|
-
import { isStableId } from "@fluidframework/id-compressor/internal";
|
|
7
|
+
import { isFinalId, isStableId } from "@fluidframework/id-compressor/internal";
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
type FieldKey,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
encodeValue,
|
|
26
26
|
} from "./compressedEncode.js";
|
|
27
27
|
import type {
|
|
28
|
-
|
|
28
|
+
EncodedChunkShape,
|
|
29
29
|
EncodedFieldShape,
|
|
30
30
|
EncodedValueShape,
|
|
31
31
|
} from "./format/index.js";
|
|
@@ -36,10 +36,7 @@ import type {
|
|
|
36
36
|
* The fact this is also a Shape is an implementation detail of the encoder: that allows the shape it uses to be itself,
|
|
37
37
|
* which is an easy way to keep all the related code together without extra objects.
|
|
38
38
|
*/
|
|
39
|
-
export class NodeShapeBasedEncoder
|
|
40
|
-
extends Shape<EncodedChunkShapeV1OrV2>
|
|
41
|
-
implements NodeEncoder
|
|
42
|
-
{
|
|
39
|
+
export class NodeShapeBasedEncoder extends Shape<EncodedChunkShape> implements NodeEncoder {
|
|
43
40
|
/**
|
|
44
41
|
* Set of keys for fields that are encoded using {@link NodeShapeBasedEncoder.specializedFieldEncoders}.
|
|
45
42
|
* TODO: Ensure uniform chunks, encoding and identifier generation sort fields the same.
|
|
@@ -82,8 +79,7 @@ export class NodeShapeBasedEncoder
|
|
|
82
79
|
// This is not the case for forest summaries at the time of writing, so non-finalized ids are instead written using
|
|
83
80
|
// their long form (by falling through to the original cursor value).
|
|
84
81
|
// A scenario where such ids can appear in the summary is in the attach summary of a tree being attached to an already-attached container.
|
|
85
|
-
|
|
86
|
-
if (!context.isSummary || opSpaceId >= 0) {
|
|
82
|
+
if (!context.isSummary || isFinalId(opSpaceId)) {
|
|
87
83
|
return opSpaceId;
|
|
88
84
|
}
|
|
89
85
|
}
|
|
@@ -95,7 +91,7 @@ export class NodeShapeBasedEncoder
|
|
|
95
91
|
public encodeNode(
|
|
96
92
|
cursor: ITreeCursorSynchronous,
|
|
97
93
|
context: EncoderContext,
|
|
98
|
-
outputBuffer: BufferFormat<
|
|
94
|
+
outputBuffer: BufferFormat<EncodedChunkShape>,
|
|
99
95
|
): void {
|
|
100
96
|
if (this.type === undefined) {
|
|
101
97
|
outputBuffer.push(new IdentifierToken(cursor.type));
|
|
@@ -109,7 +105,7 @@ export class NodeShapeBasedEncoder
|
|
|
109
105
|
cursor.exitField();
|
|
110
106
|
}
|
|
111
107
|
|
|
112
|
-
const otherFieldsBuffer: BufferFormat<
|
|
108
|
+
const otherFieldsBuffer: BufferFormat<EncodedChunkShape> = [];
|
|
113
109
|
|
|
114
110
|
forEachField(cursor, () => {
|
|
115
111
|
const key = cursor.getFieldKey();
|
|
@@ -130,8 +126,8 @@ export class NodeShapeBasedEncoder
|
|
|
130
126
|
|
|
131
127
|
public encodeShape(
|
|
132
128
|
identifiers: DeduplicationTable<string>,
|
|
133
|
-
shapes: DeduplicationTable<Shape<
|
|
134
|
-
):
|
|
129
|
+
shapes: DeduplicationTable<Shape<EncodedChunkShape>>,
|
|
130
|
+
): EncodedChunkShape {
|
|
135
131
|
return {
|
|
136
132
|
c: {
|
|
137
133
|
type: encodeOptionalIdentifier(this.type, identifiers),
|
|
@@ -144,7 +140,7 @@ export class NodeShapeBasedEncoder
|
|
|
144
140
|
|
|
145
141
|
public countReferencedShapesAndIdentifiers(
|
|
146
142
|
identifiers: Counter<string>,
|
|
147
|
-
shapeDiscovered: (shape: Shape<
|
|
143
|
+
shapeDiscovered: (shape: Shape<EncodedChunkShape>) => void,
|
|
148
144
|
): void {
|
|
149
145
|
if (this.type !== undefined) {
|
|
150
146
|
identifiers.add(this.type);
|
|
@@ -160,7 +156,7 @@ export class NodeShapeBasedEncoder
|
|
|
160
156
|
}
|
|
161
157
|
}
|
|
162
158
|
|
|
163
|
-
public get shape(): Shape<
|
|
159
|
+
public get shape(): Shape<EncodedChunkShape> {
|
|
164
160
|
return this;
|
|
165
161
|
}
|
|
166
162
|
}
|
|
@@ -168,7 +164,7 @@ export class NodeShapeBasedEncoder
|
|
|
168
164
|
export function encodeFieldShapes(
|
|
169
165
|
fieldEncoders: readonly KeyedFieldEncoder[],
|
|
170
166
|
identifiers: DeduplicationTable<string>,
|
|
171
|
-
shapes: DeduplicationTable<Shape<
|
|
167
|
+
shapes: DeduplicationTable<Shape<EncodedChunkShape>>,
|
|
172
168
|
): EncodedFieldShape[] | undefined {
|
|
173
169
|
if (fieldEncoders.length === 0) {
|
|
174
170
|
return undefined;
|
|
@@ -197,14 +193,14 @@ function encodeOptionalIdentifier(
|
|
|
197
193
|
|
|
198
194
|
function encodeOptionalFieldShape(
|
|
199
195
|
encoder: FieldEncoder | undefined,
|
|
200
|
-
shapes: DeduplicationTable<Shape<
|
|
196
|
+
shapes: DeduplicationTable<Shape<EncodedChunkShape>>,
|
|
201
197
|
): number | undefined {
|
|
202
198
|
return encoder === undefined ? undefined : dedupShape(encoder.shape, shapes);
|
|
203
199
|
}
|
|
204
200
|
|
|
205
201
|
function dedupShape(
|
|
206
|
-
shape: Shape<
|
|
207
|
-
shapes: DeduplicationTable<Shape<
|
|
202
|
+
shape: Shape<EncodedChunkShape>,
|
|
203
|
+
shapes: DeduplicationTable<Shape<EncodedChunkShape>>,
|
|
208
204
|
): number {
|
|
209
205
|
return shapes.valueToIndex.get(shape) ?? fail(0xb51 /* missing shape */);
|
|
210
206
|
}
|
|
@@ -7,9 +7,10 @@ import { assert, oob } from "@fluidframework/core-utils/internal";
|
|
|
7
7
|
import { lowestMinVersionForCollab } from "@fluidframework/runtime-utils/internal";
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
VersionDispatchingCodecBuilder,
|
|
11
11
|
type CodecAndSchema,
|
|
12
12
|
type CodecWriteOptions,
|
|
13
|
+
type VersionDispatchingCodec,
|
|
13
14
|
FluidClientVersion,
|
|
14
15
|
} from "../../codec/index.js";
|
|
15
16
|
import type { FieldKey, ITreeCursorSynchronous } from "../../core/index.js";
|
|
@@ -24,7 +25,11 @@ import { ForestFormatVersion, FormatCommon } from "./formatCommon.js";
|
|
|
24
25
|
* Uses field cursors
|
|
25
26
|
*/
|
|
26
27
|
export type FieldSet = ReadonlyMap<FieldKey, ITreeCursorSynchronous>;
|
|
27
|
-
export type ForestCodec =
|
|
28
|
+
export type ForestCodec = VersionDispatchingCodec<
|
|
29
|
+
FieldSet,
|
|
30
|
+
FieldBatchEncodingContext,
|
|
31
|
+
ForestFormatVersion
|
|
32
|
+
>;
|
|
28
33
|
|
|
29
34
|
function makeForestSummarizerCodec(
|
|
30
35
|
options: CodecWriteOptions,
|
|
@@ -64,9 +69,9 @@ function makeForestSummarizerCodec(
|
|
|
64
69
|
}
|
|
65
70
|
|
|
66
71
|
/**
|
|
67
|
-
* {@link
|
|
72
|
+
* {@link VersionDispatchingCodecBuilder} for forest summarizer codecs.
|
|
68
73
|
*/
|
|
69
|
-
export const forestCodecBuilder =
|
|
74
|
+
export const forestCodecBuilder = VersionDispatchingCodecBuilder.build("Forest", [
|
|
70
75
|
{
|
|
71
76
|
minVersionForCollab: lowestMinVersionForCollab,
|
|
72
77
|
formatVersion: ForestFormatVersion.v1,
|
|
@@ -17,7 +17,7 @@ import type { TreeChunk } from "../chunked-forest/index.js";
|
|
|
17
17
|
|
|
18
18
|
import type { CrossFieldTarget } from "./crossFieldQueries.js";
|
|
19
19
|
|
|
20
|
-
export interface ModularChangeset extends HasFieldChanges {
|
|
20
|
+
export interface ModularChangeset extends Readonly<HasFieldChanges> {
|
|
21
21
|
/**
|
|
22
22
|
* The numerically highest `ChangesetLocalId` used in this changeset.
|
|
23
23
|
* If undefined then this changeset contains no IDs.
|
|
@@ -6,10 +6,7 @@
|
|
|
6
6
|
import { fail } from "@fluidframework/core-utils/internal";
|
|
7
7
|
import { lowestMinVersionForCollab } from "@fluidframework/runtime-utils/internal";
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
ClientVersionDispatchingCodecBuilder,
|
|
11
|
-
FluidClientVersion,
|
|
12
|
-
} from "../../codec/index.js";
|
|
9
|
+
import { VersionDispatchingCodecBuilder, FluidClientVersion } from "../../codec/index.js";
|
|
13
10
|
import {
|
|
14
11
|
SchemaFormatVersion,
|
|
15
12
|
type TreeNodeSchemaIdentifier,
|
|
@@ -100,7 +97,7 @@ function decodeV2(f: FormatV2): TreeStoredSchema {
|
|
|
100
97
|
/**
|
|
101
98
|
* Creates a codec which performs synchronous monolithic encoding of schema content.
|
|
102
99
|
*/
|
|
103
|
-
export const schemaCodecBuilder =
|
|
100
|
+
export const schemaCodecBuilder = VersionDispatchingCodecBuilder.build("Schema", [
|
|
104
101
|
{
|
|
105
102
|
minVersionForCollab: lowestMinVersionForCollab,
|
|
106
103
|
formatVersion: SchemaFormatVersion.v1,
|
package/src/index.ts
CHANGED
|
@@ -403,5 +403,10 @@ export { FluidSerializableAsTree } from "./serializableDomainSchema.js";
|
|
|
403
403
|
export { TableSchema, type System_TableSchema } from "./tableSchema.js";
|
|
404
404
|
export { asAlpha, asBeta } from "./api.js";
|
|
405
405
|
|
|
406
|
-
export {
|
|
406
|
+
export {
|
|
407
|
+
TextAsTree,
|
|
408
|
+
FormattedTextAsTree,
|
|
409
|
+
codePointCount,
|
|
410
|
+
utf16LengthForCodePoints,
|
|
411
|
+
} from "./text/index.js";
|
|
407
412
|
export { ExtensibleUnionNode } from "./extensibleUnionNode.js";
|
package/src/packageVersion.ts
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { SharedTreeChange } from "./sharedTreeChangeTypes.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Determines whether a {@link SharedTreeChange} is auditable for HitL purposes
|
|
10
|
+
* by inspecting the resulting state after the change is applied.
|
|
11
|
+
*
|
|
12
|
+
* Returns `false` if any of the following is true:
|
|
13
|
+
* - The change contains more than one inner change.
|
|
14
|
+
* - The change contains a schema change.
|
|
15
|
+
* - The change contains a data change with violated constraints.
|
|
16
|
+
*
|
|
17
|
+
* Otherwise returns `true` (including for an empty change, which has nothing
|
|
18
|
+
* a viewer of the post-apply state would be unable to see).
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
export function isAuditableFromOutcome(change: SharedTreeChange): boolean {
|
|
22
|
+
if (change.changes.length > 1) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
for (const inner of change.changes) {
|
|
26
|
+
if (inner.type === "schema") {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
if ((inner.innerChange.constraintViolationCount ?? 0) > 0) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
@@ -134,6 +134,20 @@ function* collectTreeLabels(node: LabelTree): IterableIterator<unknown> {
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Deep-clones a {@link LabelTree} so the result is independent of the source.
|
|
139
|
+
* @remarks
|
|
140
|
+
* Used when capturing the label tree on a revertible so that subsequent mutations
|
|
141
|
+
* (by the framework or by external listeners reading {@link TransactionLabels.tree})
|
|
142
|
+
* cannot affect the labels the revertible will emit.
|
|
143
|
+
*/
|
|
144
|
+
function cloneLabelTree(tree: LabelTree): LabelTree {
|
|
145
|
+
return {
|
|
146
|
+
label: tree.label,
|
|
147
|
+
sublabels: tree.sublabels.map(cloneLabelTree),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
137
151
|
/**
|
|
138
152
|
* Builds the labels set for a change event from the label tree.
|
|
139
153
|
* If the tree exists and contains at least one defined label, returns a set of all
|
|
@@ -713,6 +727,12 @@ export class TreeCheckout implements ITreeCheckout {
|
|
|
713
727
|
const kind = event.type === "append" ? event.kind : CommitKind.Default;
|
|
714
728
|
const { change, revision } = commit;
|
|
715
729
|
|
|
730
|
+
// Snapshot the label tree for this commit before any listener runs, so the captured
|
|
731
|
+
// value is stable against mutations to `metadata.labels.tree` (which aliases the
|
|
732
|
+
// live `labelTreeNode`).
|
|
733
|
+
const commitLabelTree =
|
|
734
|
+
this.labelTreeNode === undefined ? undefined : cloneLabelTree(this.labelTreeNode);
|
|
735
|
+
|
|
716
736
|
const getRevertible = hasSchemaChange(change)
|
|
717
737
|
? undefined
|
|
718
738
|
: (onRevertibleDisposed?: (revertible: RevertibleAlpha) => void) => {
|
|
@@ -731,6 +751,7 @@ export class TreeCheckout implements ITreeCheckout {
|
|
|
731
751
|
kind,
|
|
732
752
|
this,
|
|
733
753
|
onRevertibleDisposed,
|
|
754
|
+
commitLabelTree,
|
|
734
755
|
);
|
|
735
756
|
this.revertibleCommitBranches.set(
|
|
736
757
|
revision,
|
|
@@ -1010,6 +1031,8 @@ export class TreeCheckout implements ITreeCheckout {
|
|
|
1010
1031
|
* @param kind - The {@link CommitKind} that produced this revertible (e.g., Default, Undo, Redo).
|
|
1011
1032
|
* @param checkout - The {@link TreeCheckout} instance this revertible belongs to.
|
|
1012
1033
|
* @param onRevertibleDisposed - Callback function that will be called when the revertible is disposed.
|
|
1034
|
+
* @param labelTree - The {@link LabelTree} (if any) active when the original commit was produced.
|
|
1035
|
+
* The revert commit inherits these labels so that commits and their reverts can be associated.
|
|
1013
1036
|
* @returns A {@link RevertibleAlpha} object.
|
|
1014
1037
|
*/
|
|
1015
1038
|
private createRevertible(
|
|
@@ -1017,6 +1040,7 @@ export class TreeCheckout implements ITreeCheckout {
|
|
|
1017
1040
|
kind: CommitKind,
|
|
1018
1041
|
checkout: TreeCheckout,
|
|
1019
1042
|
onRevertibleDisposed: ((revertible: RevertibleAlpha) => void) | undefined,
|
|
1043
|
+
labelTree: LabelTree | undefined,
|
|
1020
1044
|
): RevertibleAlpha {
|
|
1021
1045
|
const commitBranches = checkout.revertibleCommitBranches;
|
|
1022
1046
|
|
|
@@ -1032,7 +1056,7 @@ export class TreeCheckout implements ITreeCheckout {
|
|
|
1032
1056
|
throw new UsageError("Unable to revert a revertible that has been disposed.");
|
|
1033
1057
|
}
|
|
1034
1058
|
|
|
1035
|
-
const revertMetrics = checkout.revertRevertible(revision, kind);
|
|
1059
|
+
const revertMetrics = checkout.revertRevertible(revision, kind, labelTree);
|
|
1036
1060
|
checkout.logger?.sendTelemetryEvent({
|
|
1037
1061
|
eventName: TreeCheckout.revertTelemetryEventName,
|
|
1038
1062
|
...revertMetrics,
|
|
@@ -1062,7 +1086,13 @@ export class TreeCheckout implements ITreeCheckout {
|
|
|
1062
1086
|
|
|
1063
1087
|
targetCheckout.revertibleCommitBranches.set(revision, revertibleBranch.fork());
|
|
1064
1088
|
|
|
1065
|
-
return this.createRevertible(
|
|
1089
|
+
return this.createRevertible(
|
|
1090
|
+
revision,
|
|
1091
|
+
kind,
|
|
1092
|
+
targetCheckout,
|
|
1093
|
+
onRevertibleDisposed,
|
|
1094
|
+
labelTree,
|
|
1095
|
+
);
|
|
1066
1096
|
},
|
|
1067
1097
|
dispose: () => {
|
|
1068
1098
|
if (revertible.status === RevertibleStatus.Disposed) {
|
|
@@ -1323,7 +1353,11 @@ export class TreeCheckout implements ITreeCheckout {
|
|
|
1323
1353
|
this.revertibles.delete(revertible);
|
|
1324
1354
|
}
|
|
1325
1355
|
|
|
1326
|
-
private revertRevertible(
|
|
1356
|
+
private revertRevertible(
|
|
1357
|
+
revision: RevisionTag,
|
|
1358
|
+
kind: CommitKind,
|
|
1359
|
+
labelTree: LabelTree | undefined,
|
|
1360
|
+
): RevertMetrics {
|
|
1327
1361
|
this.editLock.checkUnlocked("Reverting a commit");
|
|
1328
1362
|
if (this.transaction.size > 0) {
|
|
1329
1363
|
throw new UsageError("Undo is not yet supported during transactions.");
|
|
@@ -1366,12 +1400,21 @@ export class TreeCheckout implements ITreeCheckout {
|
|
|
1366
1400
|
);
|
|
1367
1401
|
}
|
|
1368
1402
|
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1403
|
+
// Install the original commit's label tree so the revert commit's metadata inherits
|
|
1404
|
+
// the same labels. Reusing the captured tree (rather than wrapping it) ensures
|
|
1405
|
+
// revert-of-revert does not introduce new nesting.
|
|
1406
|
+
const previousLabelTreeNode = this.labelTreeNode;
|
|
1407
|
+
this.labelTreeNode = labelTree;
|
|
1408
|
+
try {
|
|
1409
|
+
this.#transaction.activeBranch.apply(
|
|
1410
|
+
change,
|
|
1411
|
+
kind === CommitKind.Default || kind === CommitKind.Redo
|
|
1412
|
+
? CommitKind.Undo
|
|
1413
|
+
: CommitKind.Redo,
|
|
1414
|
+
);
|
|
1415
|
+
} finally {
|
|
1416
|
+
this.labelTreeNode = previousLabelTreeNode;
|
|
1417
|
+
}
|
|
1375
1418
|
|
|
1376
1419
|
// Derive some stats about the reversion to return to the caller.
|
|
1377
1420
|
let revertAge = 0;
|
|
@@ -8,7 +8,7 @@ import type { MinimumVersionForCollab } from "@fluidframework/runtime-definition
|
|
|
8
8
|
import { lowestMinVersionForCollab } from "@fluidframework/runtime-utils/internal";
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
-
|
|
11
|
+
VersionDispatchingCodecBuilder,
|
|
12
12
|
type CodecTree,
|
|
13
13
|
type CodecVersion,
|
|
14
14
|
type DependentFormatVersion,
|
|
@@ -64,11 +64,9 @@ interface EditManagerCodecOptions<TChangeset> extends ICodecOptions {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* Creates a {@link
|
|
67
|
+
* Creates a {@link VersionDispatchingCodecBuilder} encoding for {@link SummaryData}.
|
|
68
68
|
*/
|
|
69
|
-
export function makeEditManagerCodecBuilder<
|
|
70
|
-
TChangeset,
|
|
71
|
-
>(): ClientVersionDispatchingCodecBuilder<
|
|
69
|
+
export function makeEditManagerCodecBuilder<TChangeset>(): VersionDispatchingCodecBuilder<
|
|
72
70
|
EditManagerCodecOptions<TChangeset>,
|
|
73
71
|
SummaryData<TChangeset>,
|
|
74
72
|
EditManagerEncodingContext,
|
|
@@ -137,7 +135,7 @@ export function makeEditManagerCodecBuilder<
|
|
|
137
135
|
},
|
|
138
136
|
];
|
|
139
137
|
|
|
140
|
-
return
|
|
138
|
+
return VersionDispatchingCodecBuilder.build(editManagerCodecName, versions);
|
|
141
139
|
}
|
|
142
140
|
|
|
143
141
|
/**
|
|
@@ -8,7 +8,7 @@ import type { MinimumVersionForCollab } from "@fluidframework/runtime-definition
|
|
|
8
8
|
import { lowestMinVersionForCollab } from "@fluidframework/runtime-utils/internal";
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
-
|
|
11
|
+
VersionDispatchingCodecBuilder,
|
|
12
12
|
type CodecTree,
|
|
13
13
|
type CodecVersion,
|
|
14
14
|
type DependentFormatVersion,
|
|
@@ -58,9 +58,9 @@ interface MessageCodecBuilderOptions<TChangeset> extends ICodecOptions {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
* Creates a {@link
|
|
61
|
+
* Creates a {@link VersionDispatchingCodecBuilder} for encoding/decoding messages.
|
|
62
62
|
*/
|
|
63
|
-
export function makeMessageCodecBuilder<TChangeset>():
|
|
63
|
+
export function makeMessageCodecBuilder<TChangeset>(): VersionDispatchingCodecBuilder<
|
|
64
64
|
MessageCodecBuilderOptions<TChangeset>,
|
|
65
65
|
DecodedMessage<TChangeset>,
|
|
66
66
|
MessageEncodingContext,
|
|
@@ -129,7 +129,7 @@ export function makeMessageCodecBuilder<TChangeset>(): ClientVersionDispatchingC
|
|
|
129
129
|
},
|
|
130
130
|
];
|
|
131
131
|
|
|
132
|
-
return
|
|
132
|
+
return VersionDispatchingCodecBuilder.build(messageCodecName, versions);
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
export function getCodecTreeForMessageFormatWithChange(
|
|
@@ -120,14 +120,16 @@ export class TreeNodeKernel {
|
|
|
120
120
|
#hydrationState: HydrationState;
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
|
-
*
|
|
123
|
+
* Handler for events listeners registered with the kernel.
|
|
124
|
+
*
|
|
124
125
|
* @remarks
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
126
|
+
* Supports event buffering via {@link withBufferedEvents}.
|
|
127
|
+
*
|
|
128
|
+
* Allocated lazily on first access to {@link TreeNodeKernel.events}.
|
|
129
|
+
* We expect the majority of nodes to never have event listeners registered, so
|
|
130
|
+
* deferring construction avoids per-kernel allocations.
|
|
129
131
|
*/
|
|
130
|
-
|
|
132
|
+
#eventBuffer: KernelEventBuffer | undefined;
|
|
131
133
|
|
|
132
134
|
/**
|
|
133
135
|
* Create a TreeNodeKernel which can be looked up with {@link getKernel}.
|
|
@@ -157,12 +159,9 @@ export class TreeNodeKernel {
|
|
|
157
159
|
this.#hydrationState = {
|
|
158
160
|
innerNode,
|
|
159
161
|
};
|
|
160
|
-
|
|
161
|
-
this.#eventBuffer = new KernelEventBuffer(innerNode.events);
|
|
162
162
|
} else {
|
|
163
163
|
// Hydrated case
|
|
164
164
|
this.#hydrationState = this.createHydratedState(innerNode);
|
|
165
|
-
this.#eventBuffer = new KernelEventBuffer(innerNode.anchorNode.events);
|
|
166
165
|
}
|
|
167
166
|
}
|
|
168
167
|
|
|
@@ -190,8 +189,10 @@ export class TreeNodeKernel {
|
|
|
190
189
|
|
|
191
190
|
this.#hydrationState = this.createHydratedState(inner);
|
|
192
191
|
|
|
193
|
-
// Lazily migrate existing event listeners to the anchor node
|
|
194
|
-
this
|
|
192
|
+
// Lazily migrate existing event listeners to the anchor node.
|
|
193
|
+
// If no one ever subscribed to this kernel's events, the buffer was never allocated
|
|
194
|
+
// and there is nothing to migrate.
|
|
195
|
+
this.#eventBuffer?.migrateEventSource(inner.anchorNode.events);
|
|
195
196
|
}
|
|
196
197
|
|
|
197
198
|
private createHydratedState(innerNode: HydratedFlexTreeNode): HydratedState {
|
|
@@ -233,6 +234,14 @@ export class TreeNodeKernel {
|
|
|
233
234
|
}
|
|
234
235
|
|
|
235
236
|
public get events(): Listenable<KernelEvents> {
|
|
237
|
+
assert(!this.disposed, 0xcfa /* Cannot register events on a disposed node */);
|
|
238
|
+
// Allocate the buffer on first access. See {@link TreeNodeKernel.#eventBuffer} for rationale.
|
|
239
|
+
if (this.#eventBuffer === undefined) {
|
|
240
|
+
const eventSource = isHydrated(this.#hydrationState)
|
|
241
|
+
? this.#hydrationState.innerNode.anchorNode.events
|
|
242
|
+
: this.#hydrationState.innerNode.events;
|
|
243
|
+
this.#eventBuffer = new KernelEventBuffer(eventSource);
|
|
244
|
+
}
|
|
236
245
|
return this.#eventBuffer;
|
|
237
246
|
}
|
|
238
247
|
|
|
@@ -244,7 +253,7 @@ export class TreeNodeKernel {
|
|
|
244
253
|
off();
|
|
245
254
|
}
|
|
246
255
|
}
|
|
247
|
-
this.#eventBuffer
|
|
256
|
+
this.#eventBuffer?.dispose();
|
|
248
257
|
// TODO: go to the context and remove myself from withAnchors
|
|
249
258
|
}
|
|
250
259
|
|
|
@@ -430,6 +439,8 @@ class KernelEventBuffer implements Listenable<KernelEvents> {
|
|
|
430
439
|
}
|
|
431
440
|
|
|
432
441
|
public on(eventName: keyof KernelEvents, listener: KernelEvents[typeof eventName]): Off {
|
|
442
|
+
this.#assertNotDisposed();
|
|
443
|
+
|
|
433
444
|
// Lazily bind event listeners to the source.
|
|
434
445
|
// If we do not have any existing listeners for this event, then we need to bind to the source.
|
|
435
446
|
if (!this.#events.hasListeners(eventName)) {
|
|
@@ -446,7 +457,10 @@ class KernelEventBuffer implements Listenable<KernelEvents> {
|
|
|
446
457
|
}
|
|
447
458
|
|
|
448
459
|
this.#events.on(eventName, listener);
|
|
449
|
-
|
|
460
|
+
// Return a bound method instead of an arrow closure. A bound function captures
|
|
461
|
+
// (target, thisArg, ...boundArgs) in a fixed shape that V8 can optimize more
|
|
462
|
+
// uniformly than a closure that captures its lexical context.
|
|
463
|
+
return this.off.bind(this, eventName, listener);
|
|
450
464
|
}
|
|
451
465
|
|
|
452
466
|
public off(eventName: keyof KernelEvents, listener: KernelEvents[typeof eventName]): void {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns the number of Unicode code points in `value`.
|
|
10
|
+
* @remarks
|
|
11
|
+
* Use this to translate a JavaScript string length (which is in UTF-16 code units) into
|
|
12
|
+
* the atom/code-point space used by {@link TextAsTree}.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* codePointCount(""); // 0
|
|
17
|
+
* codePointCount("abc"); // 3
|
|
18
|
+
* codePointCount("a😀b"); // 3 — emoji is one code point, but "a😀b".length === 4 (UTF-16 surrogate pair)
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export function codePointCount(value: string): number {
|
|
24
|
+
// Iterate instead of spreading to avoid allocating an intermediate array.
|
|
25
|
+
let count = 0;
|
|
26
|
+
for (const _ of value) {
|
|
27
|
+
count++;
|
|
28
|
+
}
|
|
29
|
+
return count;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns the number of UTF-16 code units occupied by the first `count` Unicode code points in `value`,
|
|
34
|
+
* starting at UTF-16 index `start`.
|
|
35
|
+
* @remarks
|
|
36
|
+
* Use this to translate {@link TextAsTree}-space counts (code points) into JavaScript string indices (UTF-16).
|
|
37
|
+
* One code point outside the Basic Multilingual Plane (e.g. most emoji) occupies two UTF-16 code units.
|
|
38
|
+
*
|
|
39
|
+
* Validates that the requested `count` code points are fully consumable from `start`; silent truncation
|
|
40
|
+
* would misalign delta offsets applied to strings rather than surface the drift to the caller.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* utf16LengthForCodePoints("abc", 0, 3); // 3 — three single-unit characters
|
|
45
|
+
* utf16LengthForCodePoints("a😀b", 0, 3); // 4 — a (1) + 😀 (2) + b (1)
|
|
46
|
+
* utf16LengthForCodePoints("a😀b", 1, 1); // 2 — just the emoji
|
|
47
|
+
* utf16LengthForCodePoints("abc", 0, 0); // 0 — no code points requested
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @param value - The string to measure.
|
|
51
|
+
* @param start - The UTF-16 index in `value` to start measuring from. Must be in `[0, value.length]`.
|
|
52
|
+
* @param count - The number of Unicode code points to measure. Must be non-negative, and there must
|
|
53
|
+
* be at least `count` code points available in `value` starting at `start`.
|
|
54
|
+
* @throws A {@link @fluidframework/telemetry-utils#UsageError} if `start` is out of range,
|
|
55
|
+
* `count` is negative, or fewer than `count` code points are available from `start`.
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
export function utf16LengthForCodePoints(value: string, start: number, count: number): number {
|
|
59
|
+
if (start < 0 || start > value.length) {
|
|
60
|
+
throw new UsageError(
|
|
61
|
+
`start (${start}) must be within [0, ${value.length}] (value.length).`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
if (count < 0) {
|
|
65
|
+
throw new UsageError(`count (${count}) must be non-negative.`);
|
|
66
|
+
}
|
|
67
|
+
let utf16 = 0;
|
|
68
|
+
let counted = 0;
|
|
69
|
+
while (counted < count && start + utf16 < value.length) {
|
|
70
|
+
// Code points above 0xFFFF are encoded in UTF-16 as a surrogate pair (2 units);
|
|
71
|
+
// everything else takes a single UTF-16 unit.
|
|
72
|
+
utf16 += (value.codePointAt(start + utf16) ?? 0) > 0xffff ? 2 : 1;
|
|
73
|
+
counted++;
|
|
74
|
+
}
|
|
75
|
+
if (counted !== count) {
|
|
76
|
+
throw new UsageError(
|
|
77
|
+
`count (${count}) exceeds the ${counted} code point(s) available from start (${start}) in a value of length ${value.length}.`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
return utf16;
|
|
81
|
+
}
|
package/src/text/index.ts
CHANGED