@fluidframework/tree 2.117.0 → 2.118.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 +86 -0
- package/api-report/tree.alpha.api.md +44 -1
- package/api-report/tree.beta.api.md +38 -0
- package/api-report/tree.legacy.beta.api.md +38 -0
- package/dist/entrypoints/alpha.d.ts +1 -1
- package/dist/entrypoints/alpha.d.ts.map +1 -1
- package/dist/entrypoints/alpha.js.map +1 -1
- package/dist/entrypoints/beta.d.ts +1 -1
- package/dist/entrypoints/beta.d.ts.map +1 -1
- package/dist/entrypoints/beta.js.map +1 -1
- package/dist/entrypoints/legacy.d.ts +1 -1
- package/dist/entrypoints/legacy.d.ts.map +1 -1
- package/dist/entrypoints/legacy.js.map +1 -1
- package/dist/feature-libraries/index.d.ts +1 -1
- package/dist/feature-libraries/index.js.map +1 -1
- package/dist/feature-libraries/schemaChecker.d.ts +9 -19
- package/dist/feature-libraries/schemaChecker.d.ts.map +1 -1
- package/dist/feature-libraries/schemaChecker.js +130 -46
- package/dist/feature-libraries/schemaChecker.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/shared-tree/schematizingTreeView.d.ts +13 -3
- package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
- package/dist/shared-tree/schematizingTreeView.js +48 -11
- package/dist/shared-tree/schematizingTreeView.js.map +1 -1
- package/dist/simple-tree/api/configuration.d.ts +4 -4
- package/dist/simple-tree/api/configuration.d.ts.map +1 -1
- package/dist/simple-tree/api/configuration.js.map +1 -1
- package/dist/simple-tree/api/discrepancies.d.ts +36 -3
- package/dist/simple-tree/api/discrepancies.d.ts.map +1 -1
- package/dist/simple-tree/api/discrepancies.js +40 -14
- package/dist/simple-tree/api/discrepancies.js.map +1 -1
- package/dist/simple-tree/api/index.d.ts +3 -2
- package/dist/simple-tree/api/index.d.ts.map +1 -1
- package/dist/simple-tree/api/index.js +3 -2
- package/dist/simple-tree/api/index.js.map +1 -1
- package/dist/simple-tree/api/schemaCompatibilityTester.d.ts +22 -3
- package/dist/simple-tree/api/schemaCompatibilityTester.d.ts.map +1 -1
- package/dist/simple-tree/api/schemaCompatibilityTester.js +140 -10
- package/dist/simple-tree/api/schemaCompatibilityTester.js.map +1 -1
- package/dist/simple-tree/api/tree.d.ts +173 -7
- package/dist/simple-tree/api/tree.d.ts.map +1 -1
- package/dist/simple-tree/api/tree.js.map +1 -1
- package/dist/simple-tree/core/toStored.d.ts +7 -0
- package/dist/simple-tree/core/toStored.d.ts.map +1 -1
- package/dist/simple-tree/core/toStored.js.map +1 -1
- package/dist/simple-tree/core/treeNodeValid.d.ts.map +1 -1
- package/dist/simple-tree/core/treeNodeValid.js +2 -2
- package/dist/simple-tree/core/treeNodeValid.js.map +1 -1
- package/dist/simple-tree/index.d.ts +1 -1
- package/dist/simple-tree/index.d.ts.map +1 -1
- package/dist/simple-tree/index.js +4 -3
- package/dist/simple-tree/index.js.map +1 -1
- package/docs/main/glossary.md +163 -0
- package/lib/entrypoints/alpha.d.ts +1 -1
- package/lib/entrypoints/alpha.d.ts.map +1 -1
- package/lib/entrypoints/alpha.js.map +1 -1
- package/lib/entrypoints/beta.d.ts +1 -1
- package/lib/entrypoints/beta.d.ts.map +1 -1
- package/lib/entrypoints/beta.js.map +1 -1
- package/lib/entrypoints/legacy.d.ts +1 -1
- package/lib/entrypoints/legacy.d.ts.map +1 -1
- package/lib/entrypoints/legacy.js.map +1 -1
- package/lib/feature-libraries/index.d.ts +1 -1
- package/lib/feature-libraries/index.js.map +1 -1
- package/lib/feature-libraries/schemaChecker.d.ts +9 -19
- package/lib/feature-libraries/schemaChecker.d.ts.map +1 -1
- package/lib/feature-libraries/schemaChecker.js +133 -49
- package/lib/feature-libraries/schemaChecker.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/shared-tree/schematizingTreeView.d.ts +13 -3
- package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
- package/lib/shared-tree/schematizingTreeView.js +49 -12
- package/lib/shared-tree/schematizingTreeView.js.map +1 -1
- package/lib/simple-tree/api/configuration.d.ts +4 -4
- package/lib/simple-tree/api/configuration.d.ts.map +1 -1
- package/lib/simple-tree/api/configuration.js.map +1 -1
- package/lib/simple-tree/api/discrepancies.d.ts +36 -3
- package/lib/simple-tree/api/discrepancies.d.ts.map +1 -1
- package/lib/simple-tree/api/discrepancies.js +40 -14
- package/lib/simple-tree/api/discrepancies.js.map +1 -1
- package/lib/simple-tree/api/index.d.ts +3 -2
- package/lib/simple-tree/api/index.d.ts.map +1 -1
- package/lib/simple-tree/api/index.js +1 -1
- package/lib/simple-tree/api/index.js.map +1 -1
- package/lib/simple-tree/api/schemaCompatibilityTester.d.ts +22 -3
- package/lib/simple-tree/api/schemaCompatibilityTester.d.ts.map +1 -1
- package/lib/simple-tree/api/schemaCompatibilityTester.js +136 -7
- package/lib/simple-tree/api/schemaCompatibilityTester.js.map +1 -1
- package/lib/simple-tree/api/tree.d.ts +173 -7
- package/lib/simple-tree/api/tree.d.ts.map +1 -1
- package/lib/simple-tree/api/tree.js.map +1 -1
- package/lib/simple-tree/core/toStored.d.ts +7 -0
- package/lib/simple-tree/core/toStored.d.ts.map +1 -1
- package/lib/simple-tree/core/toStored.js.map +1 -1
- package/lib/simple-tree/core/treeNodeValid.d.ts.map +1 -1
- package/lib/simple-tree/core/treeNodeValid.js +3 -3
- package/lib/simple-tree/core/treeNodeValid.js.map +1 -1
- package/lib/simple-tree/index.d.ts +1 -1
- package/lib/simple-tree/index.d.ts.map +1 -1
- package/lib/simple-tree/index.js +1 -1
- package/lib/simple-tree/index.js.map +1 -1
- package/package.json +22 -22
- package/src/entrypoints/alpha.ts +3 -0
- package/src/entrypoints/beta.ts +2 -0
- package/src/entrypoints/legacy.ts +2 -0
- package/src/feature-libraries/index.ts +1 -1
- package/src/feature-libraries/schemaChecker.ts +198 -82
- package/src/index.ts +3 -0
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/schematizingTreeView.ts +75 -21
- package/src/simple-tree/api/configuration.ts +4 -4
- package/src/simple-tree/api/discrepancies.ts +100 -5
- package/src/simple-tree/api/index.ts +7 -1
- package/src/simple-tree/api/schemaCompatibilityTester.ts +185 -11
- package/src/simple-tree/api/tree.ts +185 -8
- package/src/simple-tree/core/toStored.ts +8 -0
- package/src/simple-tree/core/treeNodeValid.ts +3 -1
- package/src/simple-tree/index.ts +4 -0
- package/docs/main/runtime-schema-upgrade.md +0 -208
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
Listenable,
|
|
11
11
|
} from "@fluidframework/core-interfaces/internal";
|
|
12
12
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
13
|
-
import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
13
|
+
import { tagSchemaArtifacts, UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
14
14
|
|
|
15
15
|
import { anchorSlot, rootFieldKey, type RevertToOptionsAlpha } from "../core/index.js";
|
|
16
16
|
import {
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
} from "../feature-libraries/index.js";
|
|
28
28
|
import {
|
|
29
29
|
type ImplicitFieldSchema,
|
|
30
|
-
type
|
|
30
|
+
type SchemaCompatibilityStatusBeta,
|
|
31
31
|
type TreeView,
|
|
32
32
|
type TreeViewEvents,
|
|
33
33
|
tryGetTreeNodeForField,
|
|
@@ -61,6 +61,8 @@ import {
|
|
|
61
61
|
type TreeBranchHistory,
|
|
62
62
|
type UntypedTreeViewAlpha,
|
|
63
63
|
type TreeSchema,
|
|
64
|
+
type SchemaUpgrade,
|
|
65
|
+
type StagedUpgradeStatus,
|
|
64
66
|
} from "../simple-tree/index.js";
|
|
65
67
|
import {
|
|
66
68
|
type Breakable,
|
|
@@ -79,6 +81,27 @@ import type { TreeCheckout } from "./treeCheckout.js";
|
|
|
79
81
|
*/
|
|
80
82
|
export const ViewSlot = anchorSlot<TreeView<ImplicitFieldSchema>>();
|
|
81
83
|
|
|
84
|
+
function throwIfSchemaIsIncompatible(compatibility: SchemaCompatibilityStatusBeta): void {
|
|
85
|
+
if (compatibility.canView) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const resolution = compatibility.canInitialize
|
|
90
|
+
? "The document is uninitialized; call TreeView.initialize() before reading or writing TreeView.root."
|
|
91
|
+
: compatibility.canUpgrade
|
|
92
|
+
? "The stored schema can be upgraded; call TreeView.upgradeSchema() before reading or writing TreeView.root."
|
|
93
|
+
: "The schemas cannot be upgraded automatically. Use a compatible view schema or explicitly migrate the document schema and data.";
|
|
94
|
+
throw new UsageError(
|
|
95
|
+
`TreeView.root is unavailable because the view schema is incompatible with the stored schema. ${resolution}`,
|
|
96
|
+
tagSchemaArtifacts({
|
|
97
|
+
schemaIncompatibilityDetails:
|
|
98
|
+
compatibility.discrepancies === undefined
|
|
99
|
+
? undefined
|
|
100
|
+
: JSON.stringify(compatibility.discrepancies),
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
82
105
|
/**
|
|
83
106
|
* Implementation of TreeView wrapping a FlexTreeView.
|
|
84
107
|
*/
|
|
@@ -95,9 +118,14 @@ export class SchematizingSimpleTreeView<
|
|
|
95
118
|
private flexTreeContext: Context | undefined;
|
|
96
119
|
|
|
97
120
|
/**
|
|
98
|
-
* Undefined
|
|
121
|
+
* Undefined if and only if uninitialized or disposed.
|
|
99
122
|
*/
|
|
100
|
-
private currentCompatibility:
|
|
123
|
+
private currentCompatibility: SchemaCompatibilityStatusBeta | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* Cached map of upgrade statuses, computed alongside compatibility.
|
|
126
|
+
* @remarks Undefined if and only if uninitialized or disposed.
|
|
127
|
+
*/
|
|
128
|
+
private currentEnabledUpgrades: ReadonlyMap<SchemaUpgrade, StagedUpgradeStatus> | undefined;
|
|
101
129
|
public readonly events: Listenable<TreeViewEvents & TreeBranchEvents> &
|
|
102
130
|
IEmitter<TreeViewEvents & TreeBranchEvents> &
|
|
103
131
|
HasListeners<TreeViewEvents & TreeBranchEvents> = createEmitter();
|
|
@@ -155,9 +183,7 @@ export class SchematizingSimpleTreeView<
|
|
|
155
183
|
const stagedUpgradePolicy =
|
|
156
184
|
config instanceof TreeViewConfigurationAlpha ? config.stagedUpgradePolicy : undefined;
|
|
157
185
|
const configAlpha = new TreeViewConfigurationAlpha({
|
|
158
|
-
|
|
159
|
-
enableSchemaValidation: config.enableSchemaValidation,
|
|
160
|
-
preventAmbiguity: config.preventAmbiguity,
|
|
186
|
+
...config,
|
|
161
187
|
stagedUpgradePolicy,
|
|
162
188
|
});
|
|
163
189
|
this.stagedUpgradePolicy = configAlpha.stagedUpgradePolicy;
|
|
@@ -170,7 +196,9 @@ export class SchematizingSimpleTreeView<
|
|
|
170
196
|
canUpgrade: true,
|
|
171
197
|
isEquivalent: false,
|
|
172
198
|
canInitialize: true,
|
|
199
|
+
discrepancies: undefined,
|
|
173
200
|
};
|
|
201
|
+
this.currentEnabledUpgrades = new Map();
|
|
174
202
|
this.update();
|
|
175
203
|
|
|
176
204
|
this.unregisterCallbacks.add(
|
|
@@ -270,7 +298,7 @@ export class SchematizingSimpleTreeView<
|
|
|
270
298
|
public upgradeSchema(): void {
|
|
271
299
|
this.ensureUndisposed();
|
|
272
300
|
|
|
273
|
-
const newSchema = toUpgradeSchema(this.viewSchema.root, this.
|
|
301
|
+
const newSchema = toUpgradeSchema(this.viewSchema.root, this.effectiveUpgradePolicy);
|
|
274
302
|
const storedSchema = this.checkout.storedSchema.clone();
|
|
275
303
|
if (!allowsRepoSuperset(defaultSchemaPolicy, storedSchema, newSchema)) {
|
|
276
304
|
throw new UsageError(
|
|
@@ -285,6 +313,35 @@ export class SchematizingSimpleTreeView<
|
|
|
285
313
|
this.runSchemaEdit(() => this.checkout.updateSchema(newSchema));
|
|
286
314
|
}
|
|
287
315
|
|
|
316
|
+
public isStagedUpgradeEnabled(upgrade: SchemaUpgrade): StagedUpgradeStatus {
|
|
317
|
+
if (!this.currentEnabledUpgrades) {
|
|
318
|
+
this.failDisposed();
|
|
319
|
+
}
|
|
320
|
+
return this.currentEnabledUpgrades.get(upgrade) ?? "disabled";
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
private get effectiveUpgradePolicy(): StagedSchemaUpgradePolicy {
|
|
324
|
+
const configuredPolicy = this.stagedUpgradePolicy;
|
|
325
|
+
if (configuredPolicy.includeAlreadyEnabledUpgrades === false) {
|
|
326
|
+
return configuredPolicy;
|
|
327
|
+
}
|
|
328
|
+
const enabledUpgrades = this.currentEnabledUpgrades;
|
|
329
|
+
assert(
|
|
330
|
+
enabledUpgrades !== undefined,
|
|
331
|
+
0xd3e /* Enabled upgrades must be available for an active view */,
|
|
332
|
+
);
|
|
333
|
+
if (enabledUpgrades.size === 0) {
|
|
334
|
+
return configuredPolicy;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
includeStaged: (upgrade) =>
|
|
339
|
+
configuredPolicy.includeStaged(upgrade) || enabledUpgrades.has(upgrade),
|
|
340
|
+
includeStagedOptional: (upgrade) =>
|
|
341
|
+
configuredPolicy.includeStagedOptional(upgrade) || enabledUpgrades.has(upgrade),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
288
345
|
/**
|
|
289
346
|
* Gets the flex-tree context. Throws when disposed or out of schema.
|
|
290
347
|
*/
|
|
@@ -442,12 +499,16 @@ export class SchematizingSimpleTreeView<
|
|
|
442
499
|
}
|
|
443
500
|
}
|
|
444
501
|
|
|
445
|
-
|
|
446
|
-
|
|
502
|
+
/**
|
|
503
|
+
* Computes the current schema compatibility status and updates the cached enabled upgrades.
|
|
504
|
+
*/
|
|
505
|
+
private computeCompatibility(): SchemaCompatibilityStatusBeta {
|
|
506
|
+
const { enabledUpgrades, ...compatibility } = checkSchemaCompatibility(
|
|
447
507
|
this.viewSchema,
|
|
448
508
|
this.checkout.storedSchema,
|
|
449
509
|
this.stagedUpgradePolicy,
|
|
450
510
|
);
|
|
511
|
+
this.currentEnabledUpgrades = enabledUpgrades;
|
|
451
512
|
return {
|
|
452
513
|
...compatibility,
|
|
453
514
|
canInitialize: canInitialize(this.checkout),
|
|
@@ -486,7 +547,7 @@ export class SchematizingSimpleTreeView<
|
|
|
486
547
|
anchors.slots.delete(SimpleContextSlot);
|
|
487
548
|
}
|
|
488
549
|
|
|
489
|
-
public get compatibility():
|
|
550
|
+
public get compatibility(): SchemaCompatibilityStatusBeta {
|
|
490
551
|
if (!this.currentCompatibility) {
|
|
491
552
|
this.failDisposed();
|
|
492
553
|
}
|
|
@@ -501,6 +562,7 @@ export class SchematizingSimpleTreeView<
|
|
|
501
562
|
}
|
|
502
563
|
this.checkout.forest.anchors.slots.delete(ViewSlot);
|
|
503
564
|
this.currentCompatibility = undefined;
|
|
565
|
+
this.currentEnabledUpgrades = undefined;
|
|
504
566
|
this.onDispose?.();
|
|
505
567
|
if (!this.checkout.isSharedBranch && !this.checkout.disposed) {
|
|
506
568
|
// All non-shared branches are 1:1 with views, so if a user manually disposes a view, we should also dispose the checkout/branch.
|
|
@@ -510,11 +572,7 @@ export class SchematizingSimpleTreeView<
|
|
|
510
572
|
|
|
511
573
|
private get flexRoot(): FlexTreeOptionalField | FlexTreeRequiredField {
|
|
512
574
|
this.breaker.use();
|
|
513
|
-
|
|
514
|
-
throw new UsageError(
|
|
515
|
-
"Document is out of schema. Check TreeView.compatibility before accessing TreeView.root.",
|
|
516
|
-
);
|
|
517
|
-
}
|
|
575
|
+
throwIfSchemaIsIncompatible(this.compatibility);
|
|
518
576
|
const view = this.getFlexTreeContext();
|
|
519
577
|
assert(
|
|
520
578
|
view.root.is(FieldKinds.optional) ||
|
|
@@ -531,11 +589,7 @@ export class SchematizingSimpleTreeView<
|
|
|
531
589
|
|
|
532
590
|
public set root(newRoot: InsertableField<TRootSchema>) {
|
|
533
591
|
this.breaker.use();
|
|
534
|
-
|
|
535
|
-
throw new UsageError(
|
|
536
|
-
"Document is out of schema. Check TreeView.compatibility before accessing TreeView.root.",
|
|
537
|
-
);
|
|
538
|
-
}
|
|
592
|
+
throwIfSchemaIsIncompatible(this.compatibility);
|
|
539
593
|
const view = this.getFlexTreeContext();
|
|
540
594
|
setField(
|
|
541
595
|
view.root,
|
|
@@ -158,22 +158,22 @@ export interface ITreeViewConfiguration<
|
|
|
158
158
|
|
|
159
159
|
/**
|
|
160
160
|
* Property-bag configuration for {@link TreeViewConfigurationAlpha} construction.
|
|
161
|
+
* @input
|
|
161
162
|
* @alpha
|
|
162
163
|
*/
|
|
163
164
|
export interface ITreeViewConfigurationAlpha<
|
|
164
165
|
TSchema extends ImplicitFieldSchema = ImplicitFieldSchema,
|
|
165
166
|
> extends ITreeViewConfiguration<TSchema> {
|
|
166
167
|
/**
|
|
167
|
-
* Policy for generating stored schema from the view schema.
|
|
168
|
+
* Policy for generating stored schema from the view schema during staged schema upgrades.
|
|
168
169
|
*
|
|
169
170
|
* @remarks
|
|
170
|
-
* If omitted or `undefined`, defaults to {@link StagedSchemaUpgradePolicyFactory.restrictive}
|
|
171
|
-
* which does not enable any staged schema upgrades.
|
|
172
|
-
*
|
|
173
171
|
* If provided, this policy is used when generating stored schema to include in documents via
|
|
174
172
|
* `initialize` / `upgradeSchema` as well as in {@link snapshotSchemaCompatibility} to validate
|
|
175
173
|
* the compatibility of such documents.
|
|
176
174
|
*
|
|
175
|
+
* @defaultValue {@link StagedSchemaUpgradePolicyFactory.restrictive}
|
|
176
|
+
*
|
|
177
177
|
* @example Enabling specific staged upgrades
|
|
178
178
|
* ```typescript
|
|
179
179
|
* const config = new TreeViewConfigurationAlpha({
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
NodeKind,
|
|
28
28
|
normalizeAndEvaluateAnnotatedAllowedTypes,
|
|
29
29
|
type AnnotatedAllowedType,
|
|
30
|
+
type SchemaUpgrade,
|
|
30
31
|
type TreeNodeSchema,
|
|
31
32
|
} from "../core/index.js";
|
|
32
33
|
import {
|
|
@@ -48,6 +49,25 @@ import type { TreeSchema } from "../treeSchema.js";
|
|
|
48
49
|
|
|
49
50
|
import { tryStoredSchemaAsArray } from "./customTree.js";
|
|
50
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Collects upgrade location data during a schema walk.
|
|
54
|
+
* @remarks Called for each staged type or staged optional field encountered.
|
|
55
|
+
*/
|
|
56
|
+
export interface UpgradeLocationCollector {
|
|
57
|
+
/**
|
|
58
|
+
* Record a staged allowed type location.
|
|
59
|
+
* @param upgrade - The upgrade token guarding this type.
|
|
60
|
+
* @param isEnabled - Whether this type is present in stored schema.
|
|
61
|
+
*/
|
|
62
|
+
allowedType(upgrade: SchemaUpgrade, isEnabled: boolean): void;
|
|
63
|
+
/**
|
|
64
|
+
* Record a staged optional field location.
|
|
65
|
+
* @param upgrade - The upgrade token guarding this field.
|
|
66
|
+
* @param isEnabled - Whether the stored field is already optional.
|
|
67
|
+
*/
|
|
68
|
+
optionalField(upgrade: SchemaUpgrade, isEnabled: boolean): void;
|
|
69
|
+
}
|
|
70
|
+
|
|
51
71
|
/**
|
|
52
72
|
* Discriminated union (keyed on `mismatch`) of discrepancies between a view and stored schema which
|
|
53
73
|
* make it possible for content matching the stored schema to be incompatible with the view schema.
|
|
@@ -79,6 +99,11 @@ export interface FieldDiscrepancyLocation {
|
|
|
79
99
|
* - the discrepancy is for 'all fields' of a map node
|
|
80
100
|
*/
|
|
81
101
|
readonly fieldKey: FieldKey | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* Whether the view field is a staged optional field.
|
|
104
|
+
* Omitted when false.
|
|
105
|
+
*/
|
|
106
|
+
readonly viewIsStagedOptional?: true;
|
|
82
107
|
}
|
|
83
108
|
|
|
84
109
|
/**
|
|
@@ -94,6 +119,13 @@ export interface AllowedTypeDiscrepancy extends FieldDiscrepancyLocation {
|
|
|
94
119
|
* (excluding {@link SchemaStaticsBeta.staged | staged} schema) which are not allowed in stored schema.
|
|
95
120
|
*/
|
|
96
121
|
readonly view: readonly AnnotatedAllowedType<TreeNodeSchema>[];
|
|
122
|
+
/**
|
|
123
|
+
* Staged allowed types in the view schema which are not allowed in stored schema.
|
|
124
|
+
*
|
|
125
|
+
* @remarks
|
|
126
|
+
* These types do not cause the discrepancy and are omitted when there are none.
|
|
127
|
+
*/
|
|
128
|
+
readonly stagedView?: readonly AnnotatedAllowedType<TreeNodeSchema>[];
|
|
97
129
|
/**
|
|
98
130
|
* Allowed type identifiers in stored schema which are not allowed in view schema
|
|
99
131
|
* (including the view schema's {@link SchemaStaticsBeta.staged | staged} schema).
|
|
@@ -174,15 +206,25 @@ function doesNodeKindMatchStoredNodeKind(
|
|
|
174
206
|
|
|
175
207
|
/**
|
|
176
208
|
* Finds and reports discrepancies between a view schema and a stored schema which make "canView" false.
|
|
209
|
+
*
|
|
210
|
+
* Optionally collects upgrade location information for staged schema upgrades during the same walk.
|
|
211
|
+
*
|
|
177
212
|
* @remarks
|
|
178
213
|
* See documentation on {@link Discrepancy} and its subtypes for details of possible discrepancies.
|
|
179
214
|
*/
|
|
180
215
|
export function* getDiscrepanciesInAllowedContent(
|
|
181
216
|
view: TreeSchema,
|
|
182
217
|
stored: TreeStoredSchema,
|
|
218
|
+
upgradeCollector?: UpgradeLocationCollector,
|
|
183
219
|
): Iterable<Discrepancy> {
|
|
184
220
|
// check root field discrepancies
|
|
185
|
-
yield* getFieldDiscrepancies(
|
|
221
|
+
yield* getFieldDiscrepancies(
|
|
222
|
+
view.root,
|
|
223
|
+
stored.rootFieldSchema,
|
|
224
|
+
undefined,
|
|
225
|
+
undefined,
|
|
226
|
+
upgradeCollector,
|
|
227
|
+
);
|
|
186
228
|
|
|
187
229
|
// Check all of the stored nodes, including their fields for discrepancies.
|
|
188
230
|
for (const [identifier, storedSchema] of stored.nodeSchema) {
|
|
@@ -190,7 +232,7 @@ export function* getDiscrepanciesInAllowedContent(
|
|
|
190
232
|
|
|
191
233
|
// if the view schema has a node that's also in the stored schema, check it.
|
|
192
234
|
if (viewSchema !== undefined) {
|
|
193
|
-
yield* getNodeDiscrepancies(identifier, viewSchema, storedSchema);
|
|
235
|
+
yield* getNodeDiscrepancies(identifier, viewSchema, storedSchema, upgradeCollector);
|
|
194
236
|
}
|
|
195
237
|
// Note that nodes that are missing in the view schema are only a problem if other stored schema nodes actually reference them which will produce its own discrepancy, so we can rely on that to produce any needed discrepancies.
|
|
196
238
|
}
|
|
@@ -200,6 +242,7 @@ function* getNodeDiscrepancies(
|
|
|
200
242
|
identifier: TreeNodeSchemaIdentifier,
|
|
201
243
|
view: TreeNodeSchema,
|
|
202
244
|
stored: TreeNodeStoredSchema,
|
|
245
|
+
upgradeCollector?: UpgradeLocationCollector,
|
|
203
246
|
): Iterable<Discrepancy> {
|
|
204
247
|
if (!doesNodeKindMatchStoredNodeKind(view.kind, getStoredNodeSchemaType(stored))) {
|
|
205
248
|
yield {
|
|
@@ -221,6 +264,7 @@ function* getNodeDiscrepancies(
|
|
|
221
264
|
identifier,
|
|
222
265
|
view,
|
|
223
266
|
stored as ObjectNodeStoredSchema,
|
|
267
|
+
upgradeCollector,
|
|
224
268
|
);
|
|
225
269
|
break;
|
|
226
270
|
}
|
|
@@ -246,6 +290,8 @@ function* getNodeDiscrepancies(
|
|
|
246
290
|
arrayStoredSchema,
|
|
247
291
|
brand(view.identifier),
|
|
248
292
|
EmptyKey,
|
|
293
|
+
false,
|
|
294
|
+
upgradeCollector,
|
|
249
295
|
);
|
|
250
296
|
|
|
251
297
|
break;
|
|
@@ -261,6 +307,7 @@ function* getNodeDiscrepancies(
|
|
|
261
307
|
(stored as MapNodeStoredSchema).mapFields,
|
|
262
308
|
identifier,
|
|
263
309
|
undefined,
|
|
310
|
+
upgradeCollector,
|
|
264
311
|
);
|
|
265
312
|
break;
|
|
266
313
|
}
|
|
@@ -275,6 +322,7 @@ function* getNodeDiscrepancies(
|
|
|
275
322
|
(stored as MapNodeStoredSchema).mapFields,
|
|
276
323
|
identifier,
|
|
277
324
|
undefined,
|
|
325
|
+
upgradeCollector,
|
|
278
326
|
);
|
|
279
327
|
break;
|
|
280
328
|
}
|
|
@@ -308,7 +356,7 @@ function* getNodeDiscrepancies(
|
|
|
308
356
|
export function findExtraAllowedTypes(
|
|
309
357
|
viewAllowedTypes: readonly AnnotatedAllowedType<TreeNodeSchema>[],
|
|
310
358
|
storedAllowedTypes: TreeTypeSet,
|
|
311
|
-
): Pick<AllowedTypeDiscrepancy, "view" | "stored"> {
|
|
359
|
+
): Pick<AllowedTypeDiscrepancy, "view" | "stagedView" | "stored"> {
|
|
312
360
|
const viewNodeSchemaIdentifiers = new Set(
|
|
313
361
|
viewAllowedTypes.map((value) => value.type.identifier),
|
|
314
362
|
);
|
|
@@ -322,10 +370,19 @@ export function findExtraAllowedTypes(
|
|
|
322
370
|
!storedAllowedTypes.has(brand(value.type.identifier)) &&
|
|
323
371
|
value.metadata.stagedSchemaUpgrade === undefined,
|
|
324
372
|
);
|
|
373
|
+
const stagedView = viewAllowedTypes.filter(
|
|
374
|
+
(value) =>
|
|
375
|
+
!storedAllowedTypes.has(brand(value.type.identifier)) &&
|
|
376
|
+
value.metadata.stagedSchemaUpgrade !== undefined,
|
|
377
|
+
);
|
|
325
378
|
const stored = [...storedAllowedTypes].filter(
|
|
326
379
|
(value) => !viewNodeSchemaIdentifiers.has(value),
|
|
327
380
|
);
|
|
328
|
-
return {
|
|
381
|
+
return {
|
|
382
|
+
view,
|
|
383
|
+
...(stagedView.length === 0 ? {} : { stagedView }),
|
|
384
|
+
stored,
|
|
385
|
+
};
|
|
329
386
|
}
|
|
330
387
|
|
|
331
388
|
/**
|
|
@@ -346,16 +403,28 @@ function* getFieldDiscrepancies(
|
|
|
346
403
|
stored: TreeFieldStoredSchema,
|
|
347
404
|
identifier: TreeNodeSchemaIdentifier | undefined,
|
|
348
405
|
fieldKey: FieldKey | undefined,
|
|
406
|
+
upgradeCollector?: UpgradeLocationCollector,
|
|
349
407
|
): Iterable<FieldDiscrepancy> {
|
|
350
408
|
assert(
|
|
351
409
|
view instanceof FieldSchemaAlpha,
|
|
352
410
|
0xbee /* all field schema should be FieldSchemaAlpha */,
|
|
353
411
|
);
|
|
412
|
+
|
|
413
|
+
// Collect staged-optional upgrade location if present.
|
|
414
|
+
if (upgradeCollector !== undefined && view.isStagedOptional !== false) {
|
|
415
|
+
upgradeCollector.optionalField(
|
|
416
|
+
view.isStagedOptional,
|
|
417
|
+
stored.kind === FieldKinds.optional.identifier,
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
354
421
|
yield* getAllowedTypeDiscrepancies(
|
|
355
422
|
view.allowedTypesFull.evaluate().types,
|
|
356
423
|
stored.types,
|
|
357
424
|
identifier,
|
|
358
425
|
fieldKey,
|
|
426
|
+
view.isStagedOptional !== false,
|
|
427
|
+
upgradeCollector,
|
|
359
428
|
);
|
|
360
429
|
|
|
361
430
|
const viewKind =
|
|
@@ -375,6 +444,7 @@ function* getFieldDiscrepancies(
|
|
|
375
444
|
mismatch: "fieldKind",
|
|
376
445
|
view: viewKind.identifier,
|
|
377
446
|
stored: stored.kind,
|
|
447
|
+
...(view.isStagedOptional === false ? {} : { viewIsStagedOptional: true }),
|
|
378
448
|
} satisfies FieldKindDiscrepancy;
|
|
379
449
|
}
|
|
380
450
|
}
|
|
@@ -396,7 +466,21 @@ function* getAllowedTypeDiscrepancies(
|
|
|
396
466
|
stored: TreeTypeSet,
|
|
397
467
|
identifier: TreeNodeSchemaIdentifier | undefined,
|
|
398
468
|
fieldKey: FieldKey | undefined,
|
|
469
|
+
viewIsStagedOptional: boolean,
|
|
470
|
+
upgradeCollector?: UpgradeLocationCollector,
|
|
399
471
|
): Iterable<FieldDiscrepancy> {
|
|
472
|
+
// Collect staged allowed type upgrade locations if present.
|
|
473
|
+
if (upgradeCollector !== undefined) {
|
|
474
|
+
for (const allowedType of view) {
|
|
475
|
+
if (allowedType.metadata.stagedSchemaUpgrade !== undefined) {
|
|
476
|
+
upgradeCollector.allowedType(
|
|
477
|
+
allowedType.metadata.stagedSchemaUpgrade,
|
|
478
|
+
stored.has(brand(allowedType.type.identifier)),
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
400
484
|
const discrepancies = findExtraAllowedTypes(view, stored);
|
|
401
485
|
if (discrepancies.view.length > 0 || discrepancies.stored.length > 0) {
|
|
402
486
|
yield {
|
|
@@ -404,6 +488,7 @@ function* getAllowedTypeDiscrepancies(
|
|
|
404
488
|
identifier,
|
|
405
489
|
fieldKey,
|
|
406
490
|
mismatch: "allowedTypes",
|
|
491
|
+
...(viewIsStagedOptional ? { viewIsStagedOptional: true } : {}),
|
|
407
492
|
} satisfies AllowedTypeDiscrepancy;
|
|
408
493
|
}
|
|
409
494
|
}
|
|
@@ -424,6 +509,7 @@ function* computeObjectNodeDiscrepancies(
|
|
|
424
509
|
identifier: TreeNodeSchemaIdentifier,
|
|
425
510
|
view: ObjectNodeSchemaPrivate,
|
|
426
511
|
stored: ObjectNodeStoredSchema,
|
|
512
|
+
upgradeCollector?: UpgradeLocationCollector,
|
|
427
513
|
): Iterable<FieldDiscrepancy> {
|
|
428
514
|
/**
|
|
429
515
|
* Similar to the logic used for tracking discrepancies between two node schemas, we will identify
|
|
@@ -453,9 +539,18 @@ function* computeObjectNodeDiscrepancies(
|
|
|
453
539
|
mismatch: "fieldKind",
|
|
454
540
|
view: viewKind.identifier,
|
|
455
541
|
stored: storedEmptyFieldSchema.kind,
|
|
542
|
+
...(fieldSchema instanceof FieldSchemaAlpha && fieldSchema.isStagedOptional !== false
|
|
543
|
+
? { viewIsStagedOptional: true }
|
|
544
|
+
: {}),
|
|
456
545
|
} satisfies FieldKindDiscrepancy;
|
|
457
546
|
} else {
|
|
458
|
-
yield* getFieldDiscrepancies(
|
|
547
|
+
yield* getFieldDiscrepancies(
|
|
548
|
+
fieldSchema,
|
|
549
|
+
storedSchema,
|
|
550
|
+
identifier,
|
|
551
|
+
fieldKey,
|
|
552
|
+
upgradeCollector,
|
|
553
|
+
);
|
|
459
554
|
}
|
|
460
555
|
}
|
|
461
556
|
|
|
@@ -19,6 +19,8 @@ export type {
|
|
|
19
19
|
ViewableTree,
|
|
20
20
|
TreeViewEvents,
|
|
21
21
|
SchemaCompatibilityStatus,
|
|
22
|
+
SchemaCompatibilityStatusBeta,
|
|
23
|
+
SchemaDiscrepancy,
|
|
22
24
|
TreeViewAlpha,
|
|
23
25
|
TreeViewBeta,
|
|
24
26
|
UntypedTreeView,
|
|
@@ -105,7 +107,11 @@ export {
|
|
|
105
107
|
export type { TreeSchemaEncodingOptions } from "./getJsonSchema.js";
|
|
106
108
|
export { getJsonSchema } from "./getJsonSchema.js";
|
|
107
109
|
export { getSimpleSchema } from "./getSimpleSchema.js";
|
|
108
|
-
export {
|
|
110
|
+
export {
|
|
111
|
+
checkSchemaCompatibility,
|
|
112
|
+
getSchemaIncompatibilityDetails,
|
|
113
|
+
} from "./schemaCompatibilityTester.js";
|
|
114
|
+
export { type StagedUpgradeStatus } from "./schemaCompatibilityTester.js";
|
|
109
115
|
export type {
|
|
110
116
|
Unenforced,
|
|
111
117
|
FieldSchemaAlphaUnsafe,
|