@fluidframework/tree 2.10.0-307060 → 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/dist/feature-libraries/modular-schema/discrepancies.d.ts +1 -1
- package/dist/feature-libraries/modular-schema/discrepancies.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/discrepancies.js +140 -181
- package/dist/feature-libraries/modular-schema/discrepancies.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/lib/feature-libraries/modular-schema/discrepancies.d.ts +1 -1
- package/lib/feature-libraries/modular-schema/discrepancies.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/discrepancies.js +139 -180
- package/lib/feature-libraries/modular-schema/discrepancies.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/package.json +23 -31
- package/src/feature-libraries/modular-schema/discrepancies.ts +165 -202
- package/src/packageVersion.ts +1 -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,
|
|
@@ -107,6 +107,17 @@ export interface NodeFieldsDiscrepancy {
|
|
|
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
|
*
|
|
@@ -124,165 +135,102 @@ type SchemaFactoryNodeKind = "object" | "leaf" | "map";
|
|
|
124
135
|
*
|
|
125
136
|
* @returns the discrepancies between two TreeStoredSchema objects
|
|
126
137
|
*/
|
|
127
|
-
export function getAllowedContentDiscrepancies(
|
|
138
|
+
export function* getAllowedContentDiscrepancies(
|
|
128
139
|
view: TreeStoredSchema,
|
|
129
140
|
stored: TreeStoredSchema,
|
|
130
|
-
): Discrepancy
|
|
131
|
-
const discrepancies: Discrepancy[] = [];
|
|
132
|
-
|
|
141
|
+
): Iterable<Discrepancy> {
|
|
133
142
|
// check root schema discrepancies
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (viewNodeSchema instanceof ObjectNodeStoredSchema) {
|
|
143
|
-
if (!stored.nodeSchema.has(key)) {
|
|
144
|
-
discrepancies.push({
|
|
145
|
-
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,
|
|
146
151
|
mismatch: "nodeKind",
|
|
147
|
-
view:
|
|
152
|
+
view: viewType,
|
|
148
153
|
stored: undefined,
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const storedNodeSchema = stored.nodeSchema.get(key);
|
|
152
|
-
assert(
|
|
153
|
-
storedNodeSchema !== undefined,
|
|
154
|
-
0x9be /* The storedNodeSchema in stored.nodeSchema should not be undefined */,
|
|
155
|
-
);
|
|
156
|
-
if (storedNodeSchema instanceof MapNodeStoredSchema) {
|
|
157
|
-
discrepancies.push({
|
|
158
|
-
identifier: key,
|
|
159
|
-
mismatch: "nodeKind",
|
|
160
|
-
view: "object",
|
|
161
|
-
stored: "map",
|
|
162
|
-
} satisfies NodeKindDiscrepancy);
|
|
163
|
-
} else if (storedNodeSchema instanceof LeafNodeStoredSchema) {
|
|
164
|
-
discrepancies.push({
|
|
165
|
-
identifier: key,
|
|
166
|
-
mismatch: "nodeKind",
|
|
167
|
-
view: "object",
|
|
168
|
-
stored: "leaf",
|
|
169
|
-
} satisfies NodeKindDiscrepancy);
|
|
170
|
-
} else if (storedNodeSchema instanceof ObjectNodeStoredSchema) {
|
|
171
|
-
const differences = trackObjectNodeDiscrepancies(viewNodeSchema, storedNodeSchema);
|
|
172
|
-
if (differences.length > 0) {
|
|
173
|
-
discrepancies.push({
|
|
174
|
-
identifier: key,
|
|
175
|
-
mismatch: "fields",
|
|
176
|
-
differences,
|
|
177
|
-
} satisfies NodeFieldsDiscrepancy);
|
|
178
|
-
}
|
|
179
|
-
} else {
|
|
180
|
-
throwUnsupportedNodeType(storedNodeSchema.constructor.name);
|
|
181
|
-
}
|
|
154
|
+
};
|
|
155
|
+
break;
|
|
182
156
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
identifier: key,
|
|
157
|
+
case "bExtra": {
|
|
158
|
+
const storedType = getNodeSchemaType(result.value);
|
|
159
|
+
yield {
|
|
160
|
+
identifier: result.key,
|
|
187
161
|
mismatch: "nodeKind",
|
|
188
|
-
view:
|
|
189
|
-
stored:
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const storedNodeSchema = stored.nodeSchema.get(key);
|
|
193
|
-
assert(
|
|
194
|
-
storedNodeSchema !== undefined,
|
|
195
|
-
0x9bf /* The storedNodeSchema in stored.nodeSchema should not be undefined */,
|
|
196
|
-
);
|
|
197
|
-
if (storedNodeSchema instanceof ObjectNodeStoredSchema) {
|
|
198
|
-
discrepancies.push({
|
|
199
|
-
identifier: key,
|
|
200
|
-
mismatch: "nodeKind",
|
|
201
|
-
view: "map",
|
|
202
|
-
stored: "object",
|
|
203
|
-
} satisfies NodeKindDiscrepancy);
|
|
204
|
-
} else if (storedNodeSchema instanceof LeafNodeStoredSchema) {
|
|
205
|
-
discrepancies.push({
|
|
206
|
-
identifier: key,
|
|
207
|
-
mismatch: "nodeKind",
|
|
208
|
-
view: "map",
|
|
209
|
-
stored: "leaf",
|
|
210
|
-
} satisfies NodeKindDiscrepancy);
|
|
211
|
-
} else if (storedNodeSchema instanceof MapNodeStoredSchema) {
|
|
212
|
-
discrepancies.push(
|
|
213
|
-
...trackFieldDiscrepancies(
|
|
214
|
-
viewNodeSchema.mapFields,
|
|
215
|
-
storedNodeSchema.mapFields,
|
|
216
|
-
key,
|
|
217
|
-
),
|
|
218
|
-
);
|
|
219
|
-
} else {
|
|
220
|
-
throwUnsupportedNodeType(storedNodeSchema.constructor.name);
|
|
221
|
-
}
|
|
162
|
+
view: undefined,
|
|
163
|
+
stored: storedType,
|
|
164
|
+
};
|
|
165
|
+
break;
|
|
222
166
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
identifier: key,
|
|
227
|
-
mismatch: "nodeKind",
|
|
228
|
-
view: "leaf",
|
|
229
|
-
stored: undefined,
|
|
230
|
-
});
|
|
231
|
-
} else {
|
|
232
|
-
const storedNodeSchema = stored.nodeSchema.get(key);
|
|
233
|
-
assert(
|
|
234
|
-
storedNodeSchema !== undefined,
|
|
235
|
-
0x9c0 /* The storedNodeSchema in stored.nodeSchema should not be undefined */,
|
|
236
|
-
);
|
|
237
|
-
if (storedNodeSchema instanceof MapNodeStoredSchema) {
|
|
238
|
-
discrepancies.push({
|
|
239
|
-
identifier: key,
|
|
240
|
-
mismatch: "nodeKind",
|
|
241
|
-
view: "leaf",
|
|
242
|
-
stored: "map",
|
|
243
|
-
} satisfies NodeKindDiscrepancy);
|
|
244
|
-
} else if (storedNodeSchema instanceof ObjectNodeStoredSchema) {
|
|
245
|
-
discrepancies.push({
|
|
246
|
-
identifier: key,
|
|
247
|
-
mismatch: "nodeKind",
|
|
248
|
-
view: "leaf",
|
|
249
|
-
stored: "object",
|
|
250
|
-
} satisfies NodeKindDiscrepancy);
|
|
251
|
-
} else if (storedNodeSchema instanceof LeafNodeStoredSchema) {
|
|
252
|
-
if (viewNodeSchema.leafValue !== storedNodeSchema.leafValue) {
|
|
253
|
-
discrepancies.push({
|
|
254
|
-
identifier: key,
|
|
255
|
-
mismatch: "valueSchema",
|
|
256
|
-
view: viewNodeSchema.leafValue,
|
|
257
|
-
stored: storedNodeSchema.leafValue,
|
|
258
|
-
} satisfies ValueSchemaDiscrepancy);
|
|
259
|
-
}
|
|
260
|
-
} else {
|
|
261
|
-
throwUnsupportedNodeType(storedNodeSchema.constructor.name);
|
|
262
|
-
}
|
|
167
|
+
case "both": {
|
|
168
|
+
yield* getNodeDiscrepancies(result.key, result.valueA, result.valueB);
|
|
169
|
+
break;
|
|
263
170
|
}
|
|
264
|
-
|
|
265
|
-
|
|
171
|
+
default:
|
|
172
|
+
break;
|
|
266
173
|
}
|
|
267
174
|
}
|
|
175
|
+
}
|
|
268
176
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
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;
|
|
283
192
|
}
|
|
284
193
|
|
|
285
|
-
|
|
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
|
+
}
|
|
286
234
|
}
|
|
287
235
|
|
|
288
236
|
/**
|
|
@@ -290,13 +238,11 @@ export function getAllowedContentDiscrepancies(
|
|
|
290
238
|
*
|
|
291
239
|
* @param keyOrRoot - If the key is missing, it indicates that this is the root field schema.
|
|
292
240
|
*/
|
|
293
|
-
function
|
|
241
|
+
function* getFieldDiscrepancies(
|
|
294
242
|
view: TreeFieldStoredSchema,
|
|
295
243
|
stored: TreeFieldStoredSchema,
|
|
296
244
|
keyOrRoot?: string,
|
|
297
|
-
): FieldDiscrepancy
|
|
298
|
-
const differences: FieldDiscrepancy[] = [];
|
|
299
|
-
|
|
245
|
+
): Iterable<FieldDiscrepancy> {
|
|
300
246
|
// Only track the symmetric differences of two sets.
|
|
301
247
|
const findSetDiscrepancies = (
|
|
302
248
|
a: TreeTypeSet,
|
|
@@ -307,34 +253,30 @@ function trackFieldDiscrepancies(
|
|
|
307
253
|
return [aDiff, bDiff];
|
|
308
254
|
};
|
|
309
255
|
|
|
310
|
-
const
|
|
311
|
-
if (
|
|
312
|
-
|
|
256
|
+
const [viewExtra, storedExtra] = findSetDiscrepancies(view.types, stored.types);
|
|
257
|
+
if (viewExtra.length > 0 || storedExtra.length > 0) {
|
|
258
|
+
yield {
|
|
313
259
|
identifier: keyOrRoot,
|
|
314
260
|
mismatch: "allowedTypes",
|
|
315
|
-
view:
|
|
316
|
-
stored:
|
|
317
|
-
} satisfies AllowedTypeDiscrepancy
|
|
261
|
+
view: viewExtra,
|
|
262
|
+
stored: storedExtra,
|
|
263
|
+
} satisfies AllowedTypeDiscrepancy;
|
|
318
264
|
}
|
|
319
265
|
|
|
320
266
|
if (view.kind !== stored.kind) {
|
|
321
|
-
|
|
267
|
+
yield {
|
|
322
268
|
identifier: keyOrRoot,
|
|
323
269
|
mismatch: "fieldKind",
|
|
324
270
|
view: view.kind,
|
|
325
271
|
stored: stored.kind,
|
|
326
|
-
} satisfies FieldKindDiscrepancy
|
|
272
|
+
} satisfies FieldKindDiscrepancy;
|
|
327
273
|
}
|
|
328
|
-
|
|
329
|
-
return differences;
|
|
330
274
|
}
|
|
331
275
|
|
|
332
|
-
function trackObjectNodeDiscrepancies(
|
|
276
|
+
function* trackObjectNodeDiscrepancies(
|
|
333
277
|
view: ObjectNodeStoredSchema,
|
|
334
278
|
stored: ObjectNodeStoredSchema,
|
|
335
|
-
): FieldDiscrepancy
|
|
336
|
-
const differences: FieldDiscrepancy[] = [];
|
|
337
|
-
const viewFieldKeys = new Set<FieldKey>();
|
|
279
|
+
): Iterable<FieldDiscrepancy> {
|
|
338
280
|
/**
|
|
339
281
|
* Similar to the logic used for tracking discrepancies between two node schemas, we will identify
|
|
340
282
|
* three types of differences:
|
|
@@ -346,47 +288,68 @@ function trackObjectNodeDiscrepancies(
|
|
|
346
288
|
* Then, the stored schema is iterated to find the third type.
|
|
347
289
|
*/
|
|
348
290
|
|
|
349
|
-
for (const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
)
|
|
368
|
-
|
|
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
|
+
}
|
|
369
329
|
}
|
|
370
330
|
}
|
|
331
|
+
}
|
|
371
332
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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 };
|
|
384
350
|
}
|
|
385
351
|
}
|
|
386
|
-
|
|
387
|
-
return differences;
|
|
388
352
|
}
|
|
389
|
-
|
|
390
353
|
/**
|
|
391
354
|
* @remarks
|
|
392
355
|
*
|
|
@@ -419,7 +382,7 @@ export function isRepoSuperset(view: TreeStoredSchema, stored: TreeStoredSchema)
|
|
|
419
382
|
case "valueSchema":
|
|
420
383
|
case "allowedTypes":
|
|
421
384
|
case "fieldKind": {
|
|
422
|
-
if (!
|
|
385
|
+
if (!isFieldDiscrepancyCompatible(discrepancy)) {
|
|
423
386
|
return false;
|
|
424
387
|
}
|
|
425
388
|
break;
|
|
@@ -427,7 +390,7 @@ export function isRepoSuperset(view: TreeStoredSchema, stored: TreeStoredSchema)
|
|
|
427
390
|
case "fields": {
|
|
428
391
|
if (
|
|
429
392
|
discrepancy.differences.some(
|
|
430
|
-
(difference) => !
|
|
393
|
+
(difference) => !isFieldDiscrepancyCompatible(difference),
|
|
431
394
|
)
|
|
432
395
|
) {
|
|
433
396
|
return false;
|
|
@@ -440,7 +403,7 @@ export function isRepoSuperset(view: TreeStoredSchema, stored: TreeStoredSchema)
|
|
|
440
403
|
return true;
|
|
441
404
|
}
|
|
442
405
|
|
|
443
|
-
function
|
|
406
|
+
function isFieldDiscrepancyCompatible(discrepancy: FieldDiscrepancy): boolean {
|
|
444
407
|
switch (discrepancy.mismatch) {
|
|
445
408
|
case "allowedTypes": {
|
|
446
409
|
// Since we only track the symmetric difference between the allowed types in the view and
|
package/src/packageVersion.ts
CHANGED