@fluidframework/tree 2.10.0-306579 → 2.10.0-307399
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/api-report/tree.alpha.api.md +11 -9
- package/api-report/tree.beta.api.md +2 -0
- package/api-report/tree.legacy.alpha.api.md +2 -0
- package/api-report/tree.legacy.public.api.md +2 -0
- package/api-report/tree.public.api.md +2 -0
- package/dist/feature-libraries/chunked-forest/basicChunk.d.ts +26 -5
- package/dist/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/basicChunk.js +15 -5
- package/dist/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkedForest.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/chunkedForest.js +5 -0
- package/dist/feature-libraries/chunked-forest/chunkedForest.js.map +1 -1
- package/dist/feature-libraries/index.d.ts +1 -1
- package/dist/feature-libraries/index.d.ts.map +1 -1
- package/dist/feature-libraries/index.js +2 -2
- package/dist/feature-libraries/index.js.map +1 -1
- package/dist/feature-libraries/modular-schema/discrepancies.d.ts +27 -27
- package/dist/feature-libraries/modular-schema/discrepancies.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/discrepancies.js +152 -193
- package/dist/feature-libraries/modular-schema/discrepancies.js.map +1 -1
- package/dist/feature-libraries/modular-schema/index.d.ts +1 -1
- package/dist/feature-libraries/modular-schema/index.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/index.js +2 -2
- package/dist/feature-libraries/modular-schema/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/treeApi.js +4 -1
- package/dist/shared-tree/treeApi.js.map +1 -1
- package/dist/simple-tree/api/schemaCreationUtilities.d.ts +12 -14
- package/dist/simple-tree/api/schemaCreationUtilities.d.ts.map +1 -1
- package/dist/simple-tree/api/schemaCreationUtilities.js +9 -7
- package/dist/simple-tree/api/schemaCreationUtilities.js.map +1 -1
- package/dist/simple-tree/api/schemaFactory.d.ts +2 -0
- package/dist/simple-tree/api/schemaFactory.d.ts.map +1 -1
- package/dist/simple-tree/api/schemaFactory.js +4 -1
- package/dist/simple-tree/api/schemaFactory.js.map +1 -1
- package/dist/simple-tree/api/schemaFactoryRecursive.js.map +1 -1
- package/dist/simple-tree/core/treeNodeKernel.d.ts +4 -5
- package/dist/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
- package/dist/simple-tree/core/treeNodeKernel.js +63 -67
- package/dist/simple-tree/core/treeNodeKernel.js.map +1 -1
- package/dist/simple-tree/objectNode.d.ts +1 -1
- package/dist/simple-tree/objectNode.js.map +1 -1
- package/dist/simple-tree/objectNodeTypes.d.ts +3 -0
- package/dist/simple-tree/objectNodeTypes.d.ts.map +1 -1
- package/dist/simple-tree/objectNodeTypes.js +3 -1
- package/dist/simple-tree/objectNodeTypes.js.map +1 -1
- package/docs/.attachments/object-merge-semantics.drawio +145 -0
- package/docs/user-facing/array-merge-semantics.md +344 -0
- package/docs/user-facing/map-merge-semantics.md +128 -0
- package/docs/user-facing/merge-semantics.md +7 -3
- package/docs/user-facing/object-merge-semantics.md +77 -0
- package/lib/feature-libraries/chunked-forest/basicChunk.d.ts +26 -5
- package/lib/feature-libraries/chunked-forest/basicChunk.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/basicChunk.js +15 -5
- package/lib/feature-libraries/chunked-forest/basicChunk.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkedForest.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/chunkedForest.js +5 -0
- package/lib/feature-libraries/chunked-forest/chunkedForest.js.map +1 -1
- package/lib/feature-libraries/index.d.ts +1 -1
- package/lib/feature-libraries/index.d.ts.map +1 -1
- package/lib/feature-libraries/index.js +1 -1
- package/lib/feature-libraries/index.js.map +1 -1
- package/lib/feature-libraries/modular-schema/discrepancies.d.ts +27 -27
- package/lib/feature-libraries/modular-schema/discrepancies.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/discrepancies.js +150 -191
- package/lib/feature-libraries/modular-schema/discrepancies.js.map +1 -1
- package/lib/feature-libraries/modular-schema/index.d.ts +1 -1
- package/lib/feature-libraries/modular-schema/index.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/index.js +1 -1
- package/lib/feature-libraries/modular-schema/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/treeApi.js +5 -2
- package/lib/shared-tree/treeApi.js.map +1 -1
- package/lib/simple-tree/api/schemaCreationUtilities.d.ts +12 -14
- package/lib/simple-tree/api/schemaCreationUtilities.d.ts.map +1 -1
- package/lib/simple-tree/api/schemaCreationUtilities.js +9 -7
- package/lib/simple-tree/api/schemaCreationUtilities.js.map +1 -1
- package/lib/simple-tree/api/schemaFactory.d.ts +2 -0
- package/lib/simple-tree/api/schemaFactory.d.ts.map +1 -1
- package/lib/simple-tree/api/schemaFactory.js +4 -1
- package/lib/simple-tree/api/schemaFactory.js.map +1 -1
- package/lib/simple-tree/api/schemaFactoryRecursive.js.map +1 -1
- package/lib/simple-tree/core/treeNodeKernel.d.ts +4 -5
- package/lib/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
- package/lib/simple-tree/core/treeNodeKernel.js +64 -68
- package/lib/simple-tree/core/treeNodeKernel.js.map +1 -1
- package/lib/simple-tree/objectNode.d.ts +1 -1
- package/lib/simple-tree/objectNode.js.map +1 -1
- package/lib/simple-tree/objectNodeTypes.d.ts +3 -0
- package/lib/simple-tree/objectNodeTypes.d.ts.map +1 -1
- package/lib/simple-tree/objectNodeTypes.js +3 -1
- package/lib/simple-tree/objectNodeTypes.js.map +1 -1
- package/package.json +23 -31
- package/src/feature-libraries/chunked-forest/basicChunk.ts +12 -4
- package/src/feature-libraries/chunked-forest/chunkedForest.ts +5 -0
- package/src/feature-libraries/index.ts +1 -1
- package/src/feature-libraries/modular-schema/discrepancies.ts +202 -241
- package/src/feature-libraries/modular-schema/index.ts +4 -1
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/treeApi.ts +7 -5
- package/src/simple-tree/api/schemaCreationUtilities.ts +29 -17
- package/src/simple-tree/api/schemaFactory.ts +25 -18
- package/src/simple-tree/api/schemaFactoryRecursive.ts +1 -1
- package/src/simple-tree/core/treeNodeKernel.ts +62 -64
- package/src/simple-tree/objectNode.ts +1 -1
- package/src/simple-tree/objectNodeTypes.ts +3 -1
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
-
type FieldKey,
|
|
10
9
|
type FieldKindIdentifier,
|
|
11
10
|
LeafNodeStoredSchema,
|
|
12
11
|
MapNodeStoredSchema,
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
storedEmptyFieldSchema,
|
|
15
14
|
type TreeFieldStoredSchema,
|
|
16
15
|
type TreeNodeSchemaIdentifier,
|
|
16
|
+
type TreeNodeStoredSchema,
|
|
17
17
|
type TreeStoredSchema,
|
|
18
18
|
type TreeTypeSet,
|
|
19
19
|
type ValueSchema,
|
|
@@ -27,45 +27,45 @@ import { brand } from "../../util/index.js";
|
|
|
27
27
|
/**
|
|
28
28
|
* @remarks
|
|
29
29
|
*
|
|
30
|
-
* 1.
|
|
30
|
+
* 1. FieldDiscrepancy
|
|
31
31
|
*
|
|
32
|
-
* `
|
|
32
|
+
* `FieldDiscrepancy` represents the differences between two `TreeFieldStoredSchema` objects. It consists of
|
|
33
33
|
* three types of incompatibilities:
|
|
34
34
|
*
|
|
35
|
-
* -
|
|
35
|
+
* - FieldKindDiscrepancy: Indicates the differences in `FieldKindIdentifier` between two `TreeFieldStoredSchema`
|
|
36
36
|
* objects (e.g., optional, required, sequence, etc.).
|
|
37
|
-
* -
|
|
38
|
-
* -
|
|
37
|
+
* - AllowedTypesDiscrepancy: Indicates the differences in the allowed child types between the two schemas.
|
|
38
|
+
* - ValueSchemaDiscrepancy: Specifically indicates the differences in the `ValueSchema` of two
|
|
39
39
|
* `LeafNodeStoredSchema` objects.
|
|
40
40
|
*
|
|
41
|
-
* 2.
|
|
41
|
+
* 2. NodeDiscrepancy
|
|
42
42
|
*
|
|
43
|
-
* `
|
|
43
|
+
* `NodeDiscrepancy` represents the differences between two `TreeNodeStoredSchema` objects and includes:
|
|
44
44
|
*
|
|
45
|
-
* -
|
|
45
|
+
* - NodeKindDiscrepancy: Indicates the differences in the types of `TreeNodeStoredSchema` (currently supports
|
|
46
46
|
* `ObjectNodeStoredSchema`, `MapNodeStoredSchema`, and `LeafNodeStoredSchema`).
|
|
47
|
-
* -
|
|
48
|
-
* `TreeNodeStoredSchema`. It includes an array of `
|
|
47
|
+
* - NodeFieldsDiscrepancy: Indicates the `FieldDiscrepancy` of `TreeFieldStoredSchema` within two
|
|
48
|
+
* `TreeNodeStoredSchema`. It includes an array of `FieldDiscrepancy` instances in the `differences` field.
|
|
49
49
|
*
|
|
50
50
|
* When comparing two nodes for compatibility, it only makes sense to compare their fields if the nodes are of
|
|
51
51
|
* the same kind (map, object, leaf).
|
|
52
52
|
*
|
|
53
|
-
* 3.
|
|
53
|
+
* 3. Discrepancy
|
|
54
54
|
*
|
|
55
|
-
*
|
|
56
|
-
* schema differences. See {@link
|
|
55
|
+
* Discrepancy consists of both `NodeDiscrepancy` and `FieldDiscrepancy`, representing any kind of
|
|
56
|
+
* schema differences. See {@link getAllowedContentDiscrepancies} for more details about how we process it
|
|
57
57
|
* and the ordering.
|
|
58
58
|
*/
|
|
59
|
-
export type
|
|
59
|
+
export type Discrepancy = FieldDiscrepancy | NodeDiscrepancy;
|
|
60
60
|
|
|
61
|
-
export type
|
|
61
|
+
export type NodeDiscrepancy = NodeKindDiscrepancy | NodeFieldsDiscrepancy;
|
|
62
62
|
|
|
63
|
-
export type
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
63
|
+
export type FieldDiscrepancy =
|
|
64
|
+
| AllowedTypeDiscrepancy
|
|
65
|
+
| FieldKindDiscrepancy
|
|
66
|
+
| ValueSchemaDiscrepancy;
|
|
67
67
|
|
|
68
|
-
export interface
|
|
68
|
+
export interface AllowedTypeDiscrepancy {
|
|
69
69
|
identifier: string | undefined; // undefined indicates root field schema
|
|
70
70
|
mismatch: "allowedTypes";
|
|
71
71
|
/**
|
|
@@ -78,213 +78,159 @@ export interface AllowedTypeIncompatibility {
|
|
|
78
78
|
stored: string[];
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
export interface
|
|
81
|
+
export interface FieldKindDiscrepancy {
|
|
82
82
|
identifier: string | undefined; // undefined indicates root field schema
|
|
83
83
|
mismatch: "fieldKind";
|
|
84
84
|
view: FieldKindIdentifier;
|
|
85
85
|
stored: FieldKindIdentifier;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
export interface
|
|
88
|
+
export interface ValueSchemaDiscrepancy {
|
|
89
89
|
identifier: string;
|
|
90
90
|
mismatch: "valueSchema";
|
|
91
91
|
view: ValueSchema | undefined;
|
|
92
92
|
stored: ValueSchema | undefined;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
export interface
|
|
95
|
+
export interface NodeKindDiscrepancy {
|
|
96
96
|
identifier: string;
|
|
97
97
|
mismatch: "nodeKind";
|
|
98
98
|
view: SchemaFactoryNodeKind | undefined;
|
|
99
99
|
stored: SchemaFactoryNodeKind | undefined;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
export interface
|
|
102
|
+
export interface NodeFieldsDiscrepancy {
|
|
103
103
|
identifier: string;
|
|
104
104
|
mismatch: "fields";
|
|
105
|
-
differences:
|
|
105
|
+
differences: FieldDiscrepancy[];
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
type SchemaFactoryNodeKind = "object" | "leaf" | "map";
|
|
109
109
|
|
|
110
|
+
function getNodeSchemaType(nodeSchema: TreeNodeStoredSchema): SchemaFactoryNodeKind {
|
|
111
|
+
if (nodeSchema instanceof ObjectNodeStoredSchema) {
|
|
112
|
+
return "object";
|
|
113
|
+
} else if (nodeSchema instanceof MapNodeStoredSchema) {
|
|
114
|
+
return "map";
|
|
115
|
+
} else if (nodeSchema instanceof LeafNodeStoredSchema) {
|
|
116
|
+
return "leaf";
|
|
117
|
+
}
|
|
118
|
+
throwUnsupportedNodeType(nodeSchema.constructor.name);
|
|
119
|
+
}
|
|
120
|
+
|
|
110
121
|
/**
|
|
111
|
-
*
|
|
122
|
+
* Finds and reports discrepancies between a view schema and a stored schema.
|
|
112
123
|
*
|
|
113
124
|
* The workflow for finding schema incompatibilities:
|
|
114
|
-
* 1. Compare the two root schemas to identify any `
|
|
125
|
+
* 1. Compare the two root schemas to identify any `FieldDiscrepancy`.
|
|
115
126
|
*
|
|
116
127
|
* 2. For each node schema in the `view`:
|
|
117
128
|
* - Verify if the node schema exists in the stored. If it does, ensure that the `SchemaFactoryNodeKind` are
|
|
118
|
-
* consistent. Otherwise this difference is treated as `
|
|
129
|
+
* consistent. Otherwise this difference is treated as `NodeKindDiscrepancy`
|
|
119
130
|
* - If a node schema with the same identifier exists in both view and stored, and their `SchemaFactoryNodeKind`
|
|
120
|
-
* are consistent, perform a exhaustive validation to identify all `
|
|
131
|
+
* are consistent, perform a exhaustive validation to identify all `FieldDiscrepancy`.
|
|
121
132
|
*
|
|
122
133
|
* 3. For each node schema in the stored, verify if it exists in the view. The overlapping parts were already
|
|
123
134
|
* addressed in the previous step.
|
|
124
135
|
*
|
|
125
136
|
* @returns the discrepancies between two TreeStoredSchema objects
|
|
126
137
|
*/
|
|
127
|
-
export function
|
|
138
|
+
export function* getAllowedContentDiscrepancies(
|
|
128
139
|
view: TreeStoredSchema,
|
|
129
140
|
stored: TreeStoredSchema,
|
|
130
|
-
):
|
|
131
|
-
const incompatibilities: Incompatibility[] = [];
|
|
132
|
-
|
|
141
|
+
): Iterable<Discrepancy> {
|
|
133
142
|
// check root schema discrepancies
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
viewNodeKeys.add(key);
|
|
143
|
-
|
|
144
|
-
if (viewNodeSchema instanceof ObjectNodeStoredSchema) {
|
|
145
|
-
if (!stored.nodeSchema.has(key)) {
|
|
146
|
-
incompatibilities.push({
|
|
147
|
-
identifier: key,
|
|
143
|
+
yield* getFieldDiscrepancies(view.rootFieldSchema, stored.rootFieldSchema);
|
|
144
|
+
|
|
145
|
+
for (const result of compareMaps(view.nodeSchema, stored.nodeSchema)) {
|
|
146
|
+
switch (result.type) {
|
|
147
|
+
case "aExtra": {
|
|
148
|
+
const viewType = getNodeSchemaType(result.value);
|
|
149
|
+
yield {
|
|
150
|
+
identifier: result.key,
|
|
148
151
|
mismatch: "nodeKind",
|
|
149
|
-
view:
|
|
152
|
+
view: viewType,
|
|
150
153
|
stored: undefined,
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const storedNodeSchema = stored.nodeSchema.get(key);
|
|
154
|
-
assert(
|
|
155
|
-
storedNodeSchema !== undefined,
|
|
156
|
-
0x9be /* The storedNodeSchema in stored.nodeSchema should not be undefined */,
|
|
157
|
-
);
|
|
158
|
-
if (storedNodeSchema instanceof MapNodeStoredSchema) {
|
|
159
|
-
incompatibilities.push({
|
|
160
|
-
identifier: key,
|
|
161
|
-
mismatch: "nodeKind",
|
|
162
|
-
view: "object",
|
|
163
|
-
stored: "map",
|
|
164
|
-
} satisfies NodeKindIncompatibility);
|
|
165
|
-
} else if (storedNodeSchema instanceof LeafNodeStoredSchema) {
|
|
166
|
-
incompatibilities.push({
|
|
167
|
-
identifier: key,
|
|
168
|
-
mismatch: "nodeKind",
|
|
169
|
-
view: "object",
|
|
170
|
-
stored: "leaf",
|
|
171
|
-
} satisfies NodeKindIncompatibility);
|
|
172
|
-
} else if (storedNodeSchema instanceof ObjectNodeStoredSchema) {
|
|
173
|
-
const differences = trackObjectNodeDiscrepancies(viewNodeSchema, storedNodeSchema);
|
|
174
|
-
if (differences.length > 0) {
|
|
175
|
-
incompatibilities.push({
|
|
176
|
-
identifier: key,
|
|
177
|
-
mismatch: "fields",
|
|
178
|
-
differences,
|
|
179
|
-
} satisfies NodeFieldsIncompatibility);
|
|
180
|
-
}
|
|
181
|
-
} else {
|
|
182
|
-
throwUnsupportedNodeType(storedNodeSchema.constructor.name);
|
|
183
|
-
}
|
|
154
|
+
};
|
|
155
|
+
break;
|
|
184
156
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
identifier: key,
|
|
157
|
+
case "bExtra": {
|
|
158
|
+
const storedType = getNodeSchemaType(result.value);
|
|
159
|
+
yield {
|
|
160
|
+
identifier: result.key,
|
|
189
161
|
mismatch: "nodeKind",
|
|
190
|
-
view:
|
|
191
|
-
stored:
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const storedNodeSchema = stored.nodeSchema.get(key);
|
|
195
|
-
assert(
|
|
196
|
-
storedNodeSchema !== undefined,
|
|
197
|
-
0x9bf /* The storedNodeSchema in stored.nodeSchema should not be undefined */,
|
|
198
|
-
);
|
|
199
|
-
if (storedNodeSchema instanceof ObjectNodeStoredSchema) {
|
|
200
|
-
incompatibilities.push({
|
|
201
|
-
identifier: key,
|
|
202
|
-
mismatch: "nodeKind",
|
|
203
|
-
view: "map",
|
|
204
|
-
stored: "object",
|
|
205
|
-
} satisfies NodeKindIncompatibility);
|
|
206
|
-
} else if (storedNodeSchema instanceof LeafNodeStoredSchema) {
|
|
207
|
-
incompatibilities.push({
|
|
208
|
-
identifier: key,
|
|
209
|
-
mismatch: "nodeKind",
|
|
210
|
-
view: "map",
|
|
211
|
-
stored: "leaf",
|
|
212
|
-
} satisfies NodeKindIncompatibility);
|
|
213
|
-
} else if (storedNodeSchema instanceof MapNodeStoredSchema) {
|
|
214
|
-
incompatibilities.push(
|
|
215
|
-
...trackFieldDiscrepancies(
|
|
216
|
-
viewNodeSchema.mapFields,
|
|
217
|
-
storedNodeSchema.mapFields,
|
|
218
|
-
key,
|
|
219
|
-
),
|
|
220
|
-
);
|
|
221
|
-
} else {
|
|
222
|
-
throwUnsupportedNodeType(storedNodeSchema.constructor.name);
|
|
223
|
-
}
|
|
162
|
+
view: undefined,
|
|
163
|
+
stored: storedType,
|
|
164
|
+
};
|
|
165
|
+
break;
|
|
224
166
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
identifier: key,
|
|
229
|
-
mismatch: "nodeKind",
|
|
230
|
-
view: "leaf",
|
|
231
|
-
stored: undefined,
|
|
232
|
-
});
|
|
233
|
-
} else {
|
|
234
|
-
const storedNodeSchema = stored.nodeSchema.get(key);
|
|
235
|
-
assert(
|
|
236
|
-
storedNodeSchema !== undefined,
|
|
237
|
-
0x9c0 /* The storedNodeSchema in stored.nodeSchema should not be undefined */,
|
|
238
|
-
);
|
|
239
|
-
if (storedNodeSchema instanceof MapNodeStoredSchema) {
|
|
240
|
-
incompatibilities.push({
|
|
241
|
-
identifier: key,
|
|
242
|
-
mismatch: "nodeKind",
|
|
243
|
-
view: "leaf",
|
|
244
|
-
stored: "map",
|
|
245
|
-
} satisfies NodeKindIncompatibility);
|
|
246
|
-
} else if (storedNodeSchema instanceof ObjectNodeStoredSchema) {
|
|
247
|
-
incompatibilities.push({
|
|
248
|
-
identifier: key,
|
|
249
|
-
mismatch: "nodeKind",
|
|
250
|
-
view: "leaf",
|
|
251
|
-
stored: "object",
|
|
252
|
-
} satisfies NodeKindIncompatibility);
|
|
253
|
-
} else if (storedNodeSchema instanceof LeafNodeStoredSchema) {
|
|
254
|
-
if (viewNodeSchema.leafValue !== storedNodeSchema.leafValue) {
|
|
255
|
-
incompatibilities.push({
|
|
256
|
-
identifier: key,
|
|
257
|
-
mismatch: "valueSchema",
|
|
258
|
-
view: viewNodeSchema.leafValue,
|
|
259
|
-
stored: storedNodeSchema.leafValue,
|
|
260
|
-
} satisfies ValueSchemaIncompatibility);
|
|
261
|
-
}
|
|
262
|
-
} else {
|
|
263
|
-
throwUnsupportedNodeType(storedNodeSchema.constructor.name);
|
|
264
|
-
}
|
|
167
|
+
case "both": {
|
|
168
|
+
yield* getNodeDiscrepancies(result.key, result.valueA, result.valueB);
|
|
169
|
+
break;
|
|
265
170
|
}
|
|
266
|
-
|
|
267
|
-
|
|
171
|
+
default:
|
|
172
|
+
break;
|
|
268
173
|
}
|
|
269
174
|
}
|
|
175
|
+
}
|
|
270
176
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
177
|
+
function* getNodeDiscrepancies(
|
|
178
|
+
identifier: TreeNodeSchemaIdentifier,
|
|
179
|
+
view: TreeNodeStoredSchema,
|
|
180
|
+
stored: TreeNodeStoredSchema,
|
|
181
|
+
): Iterable<Discrepancy> {
|
|
182
|
+
const viewType = getNodeSchemaType(view);
|
|
183
|
+
const storedType = getNodeSchemaType(stored);
|
|
184
|
+
if (viewType !== storedType) {
|
|
185
|
+
yield {
|
|
186
|
+
identifier,
|
|
187
|
+
mismatch: "nodeKind",
|
|
188
|
+
view: viewType,
|
|
189
|
+
stored: storedType,
|
|
190
|
+
};
|
|
191
|
+
return;
|
|
285
192
|
}
|
|
286
193
|
|
|
287
|
-
|
|
194
|
+
switch (viewType) {
|
|
195
|
+
case "object": {
|
|
196
|
+
const differences = Array.from(
|
|
197
|
+
trackObjectNodeDiscrepancies(
|
|
198
|
+
view as ObjectNodeStoredSchema,
|
|
199
|
+
stored as ObjectNodeStoredSchema,
|
|
200
|
+
),
|
|
201
|
+
);
|
|
202
|
+
if (differences.length > 0) {
|
|
203
|
+
yield {
|
|
204
|
+
identifier,
|
|
205
|
+
mismatch: "fields",
|
|
206
|
+
differences,
|
|
207
|
+
} satisfies NodeFieldsDiscrepancy;
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
case "map":
|
|
212
|
+
yield* getFieldDiscrepancies(
|
|
213
|
+
(view as MapNodeStoredSchema).mapFields,
|
|
214
|
+
(stored as MapNodeStoredSchema).mapFields,
|
|
215
|
+
identifier,
|
|
216
|
+
);
|
|
217
|
+
break;
|
|
218
|
+
case "leaf": {
|
|
219
|
+
const viewValue = (view as LeafNodeStoredSchema).leafValue;
|
|
220
|
+
const storedValue = (stored as LeafNodeStoredSchema).leafValue;
|
|
221
|
+
if (viewValue !== storedValue) {
|
|
222
|
+
yield {
|
|
223
|
+
identifier,
|
|
224
|
+
mismatch: "valueSchema",
|
|
225
|
+
view: viewValue,
|
|
226
|
+
stored: storedValue,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
default:
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
288
234
|
}
|
|
289
235
|
|
|
290
236
|
/**
|
|
@@ -292,13 +238,11 @@ export function getAllowedContentIncompatibilities(
|
|
|
292
238
|
*
|
|
293
239
|
* @param keyOrRoot - If the key is missing, it indicates that this is the root field schema.
|
|
294
240
|
*/
|
|
295
|
-
function
|
|
241
|
+
function* getFieldDiscrepancies(
|
|
296
242
|
view: TreeFieldStoredSchema,
|
|
297
243
|
stored: TreeFieldStoredSchema,
|
|
298
244
|
keyOrRoot?: string,
|
|
299
|
-
):
|
|
300
|
-
const differences: FieldIncompatibility[] = [];
|
|
301
|
-
|
|
245
|
+
): Iterable<FieldDiscrepancy> {
|
|
302
246
|
// Only track the symmetric differences of two sets.
|
|
303
247
|
const findSetDiscrepancies = (
|
|
304
248
|
a: TreeTypeSet,
|
|
@@ -309,34 +253,30 @@ function trackFieldDiscrepancies(
|
|
|
309
253
|
return [aDiff, bDiff];
|
|
310
254
|
};
|
|
311
255
|
|
|
312
|
-
const
|
|
313
|
-
if (
|
|
314
|
-
|
|
256
|
+
const [viewExtra, storedExtra] = findSetDiscrepancies(view.types, stored.types);
|
|
257
|
+
if (viewExtra.length > 0 || storedExtra.length > 0) {
|
|
258
|
+
yield {
|
|
315
259
|
identifier: keyOrRoot,
|
|
316
260
|
mismatch: "allowedTypes",
|
|
317
|
-
view:
|
|
318
|
-
stored:
|
|
319
|
-
} satisfies
|
|
261
|
+
view: viewExtra,
|
|
262
|
+
stored: storedExtra,
|
|
263
|
+
} satisfies AllowedTypeDiscrepancy;
|
|
320
264
|
}
|
|
321
265
|
|
|
322
266
|
if (view.kind !== stored.kind) {
|
|
323
|
-
|
|
267
|
+
yield {
|
|
324
268
|
identifier: keyOrRoot,
|
|
325
269
|
mismatch: "fieldKind",
|
|
326
270
|
view: view.kind,
|
|
327
271
|
stored: stored.kind,
|
|
328
|
-
} satisfies
|
|
272
|
+
} satisfies FieldKindDiscrepancy;
|
|
329
273
|
}
|
|
330
|
-
|
|
331
|
-
return differences;
|
|
332
274
|
}
|
|
333
275
|
|
|
334
|
-
function trackObjectNodeDiscrepancies(
|
|
276
|
+
function* trackObjectNodeDiscrepancies(
|
|
335
277
|
view: ObjectNodeStoredSchema,
|
|
336
278
|
stored: ObjectNodeStoredSchema,
|
|
337
|
-
):
|
|
338
|
-
const differences: FieldIncompatibility[] = [];
|
|
339
|
-
const viewFieldKeys = new Set<FieldKey>();
|
|
279
|
+
): Iterable<FieldDiscrepancy> {
|
|
340
280
|
/**
|
|
341
281
|
* Similar to the logic used for tracking discrepancies between two node schemas, we will identify
|
|
342
282
|
* three types of differences:
|
|
@@ -348,47 +288,68 @@ function trackObjectNodeDiscrepancies(
|
|
|
348
288
|
* Then, the stored schema is iterated to find the third type.
|
|
349
289
|
*/
|
|
350
290
|
|
|
351
|
-
for (const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
)
|
|
370
|
-
|
|
291
|
+
for (const result of compareMaps(view.objectNodeFields, stored.objectNodeFields)) {
|
|
292
|
+
const fieldKey = result.key;
|
|
293
|
+
switch (result.type) {
|
|
294
|
+
case "aExtra": {
|
|
295
|
+
if (result.value.kind === storedEmptyFieldSchema.kind) {
|
|
296
|
+
// In one of view/stored, this field is explicitly forbidden, but in the other it is implicitly forbidden
|
|
297
|
+
// (by way of omission). We treat these identically anyway.
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
yield {
|
|
301
|
+
identifier: fieldKey,
|
|
302
|
+
mismatch: "fieldKind",
|
|
303
|
+
view: result.value.kind,
|
|
304
|
+
stored: storedEmptyFieldSchema.kind,
|
|
305
|
+
} satisfies FieldKindDiscrepancy;
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
case "bExtra": {
|
|
309
|
+
if (result.value.kind === storedEmptyFieldSchema.kind) {
|
|
310
|
+
// In one of view/stored, this field is explicitly forbidden, but in the other it is implicitly forbidden
|
|
311
|
+
// (by way of omission). We treat these identically anyway.
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
yield {
|
|
315
|
+
identifier: fieldKey,
|
|
316
|
+
mismatch: "fieldKind",
|
|
317
|
+
view: storedEmptyFieldSchema.kind,
|
|
318
|
+
stored: result.value.kind,
|
|
319
|
+
} satisfies FieldKindDiscrepancy;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
case "both": {
|
|
323
|
+
yield* getFieldDiscrepancies(result.valueA, result.valueB, fieldKey);
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
default: {
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
371
329
|
}
|
|
372
330
|
}
|
|
331
|
+
}
|
|
373
332
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
333
|
+
function* compareMaps<K, V1, V2>(
|
|
334
|
+
a: ReadonlyMap<K, V1>,
|
|
335
|
+
b: ReadonlyMap<K, V2>,
|
|
336
|
+
): Iterable<
|
|
337
|
+
| { type: "aExtra"; key: K; value: V1 }
|
|
338
|
+
| { type: "bExtra"; key: K; value: V2 }
|
|
339
|
+
| { type: "both"; key: K; valueA: V1; valueB: V2 }
|
|
340
|
+
> {
|
|
341
|
+
for (const [key, valueA] of a) {
|
|
342
|
+
const valueB = b.get(key);
|
|
343
|
+
yield valueB === undefined
|
|
344
|
+
? { type: "aExtra", key, value: valueA }
|
|
345
|
+
: { type: "both", key, valueA, valueB };
|
|
346
|
+
}
|
|
347
|
+
for (const [key, valueB] of b) {
|
|
348
|
+
if (!a.has(key)) {
|
|
349
|
+
yield { type: "bExtra", key, value: valueB };
|
|
386
350
|
}
|
|
387
351
|
}
|
|
388
|
-
|
|
389
|
-
return differences;
|
|
390
352
|
}
|
|
391
|
-
|
|
392
353
|
/**
|
|
393
354
|
* @remarks
|
|
394
355
|
*
|
|
@@ -407,12 +368,12 @@ function trackObjectNodeDiscrepancies(
|
|
|
407
368
|
* validating internal fields.
|
|
408
369
|
*/
|
|
409
370
|
export function isRepoSuperset(view: TreeStoredSchema, stored: TreeStoredSchema): boolean {
|
|
410
|
-
const
|
|
371
|
+
const discrepancies = getAllowedContentDiscrepancies(view, stored);
|
|
411
372
|
|
|
412
|
-
for (const
|
|
413
|
-
switch (
|
|
373
|
+
for (const discrepancy of discrepancies) {
|
|
374
|
+
switch (discrepancy.mismatch) {
|
|
414
375
|
case "nodeKind": {
|
|
415
|
-
if (
|
|
376
|
+
if (discrepancy.stored !== undefined) {
|
|
416
377
|
// It's fine for the view schema to know of a node type that the stored schema doesn't know about.
|
|
417
378
|
return false;
|
|
418
379
|
}
|
|
@@ -421,15 +382,15 @@ export function isRepoSuperset(view: TreeStoredSchema, stored: TreeStoredSchema)
|
|
|
421
382
|
case "valueSchema":
|
|
422
383
|
case "allowedTypes":
|
|
423
384
|
case "fieldKind": {
|
|
424
|
-
if (!
|
|
385
|
+
if (!isFieldDiscrepancyCompatible(discrepancy)) {
|
|
425
386
|
return false;
|
|
426
387
|
}
|
|
427
388
|
break;
|
|
428
389
|
}
|
|
429
390
|
case "fields": {
|
|
430
391
|
if (
|
|
431
|
-
|
|
432
|
-
(difference) => !
|
|
392
|
+
discrepancy.differences.some(
|
|
393
|
+
(difference) => !isFieldDiscrepancyCompatible(difference),
|
|
433
394
|
)
|
|
434
395
|
) {
|
|
435
396
|
return false;
|
|
@@ -442,16 +403,16 @@ export function isRepoSuperset(view: TreeStoredSchema, stored: TreeStoredSchema)
|
|
|
442
403
|
return true;
|
|
443
404
|
}
|
|
444
405
|
|
|
445
|
-
function
|
|
446
|
-
switch (
|
|
406
|
+
function isFieldDiscrepancyCompatible(discrepancy: FieldDiscrepancy): boolean {
|
|
407
|
+
switch (discrepancy.mismatch) {
|
|
447
408
|
case "allowedTypes": {
|
|
448
409
|
// Since we only track the symmetric difference between the allowed types in the view and
|
|
449
410
|
// stored schemas, it's sufficient to check if any extra allowed types still exist in the
|
|
450
411
|
// stored schema.
|
|
451
|
-
return
|
|
412
|
+
return discrepancy.stored.length === 0;
|
|
452
413
|
}
|
|
453
414
|
case "fieldKind": {
|
|
454
|
-
return posetLte(
|
|
415
|
+
return posetLte(discrepancy.stored, discrepancy.view, fieldRealizer);
|
|
455
416
|
}
|
|
456
417
|
case "valueSchema": {
|
|
457
418
|
return false;
|
|
@@ -74,4 +74,7 @@ export type {
|
|
|
74
74
|
FieldKindConfiguration,
|
|
75
75
|
FieldKindConfigurationEntry,
|
|
76
76
|
} from "./fieldKindConfiguration.js";
|
|
77
|
-
export {
|
|
77
|
+
export {
|
|
78
|
+
getAllowedContentDiscrepancies,
|
|
79
|
+
isRepoSuperset,
|
|
80
|
+
} from "./discrepancies.js";
|
package/src/packageVersion.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { unreachableCase } from "@fluidframework/core-utils/internal";
|
|
7
7
|
import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
8
8
|
|
|
9
9
|
import { TreeStatus } from "../feature-libraries/index.js";
|
|
@@ -464,10 +464,12 @@ function runTransactionInCheckout<TResult>(
|
|
|
464
464
|
switch (constraint.type) {
|
|
465
465
|
case "nodeInDocument": {
|
|
466
466
|
const node = getOrCreateInnerNode(constraint.node);
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
467
|
+
const nodeStatus = treeApi.status(constraint.node);
|
|
468
|
+
if (nodeStatus !== TreeStatus.InDocument) {
|
|
469
|
+
throw new UsageError(
|
|
470
|
+
`Attempted to add a "nodeInDocument" constraint, but the node is not currently in the document. Node status: ${nodeStatus}`,
|
|
471
|
+
);
|
|
472
|
+
}
|
|
471
473
|
checkout.editor.addNodeExistsConstraint(node.anchorNode);
|
|
472
474
|
break;
|
|
473
475
|
}
|