Skip to content

Commit e4dca8b

Browse files
committed
Merge remote-tracking branch 'microsoft/main' into schema-type
2 parents c6e40ba + 573e20e commit e4dca8b

File tree

12 files changed

+384
-156
lines changed

12 files changed

+384
-156
lines changed

.changeset/tricky-shirts-sleep.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
"@fluidframework/tree": minor
3+
"__section": feature
4+
---
5+
Added `Tree.ensureSchema`
6+
7+
This helper function allows content to be tagged with a schema type before being inserted into the tree.
8+
This allows content that would otherwise be ambiguous to be well-defined, without having to wrap it in a node constructor.
9+
10+
Example:
11+
12+
```typescript
13+
const sf = new SchemaFactory("example");
14+
class Dog extends sf.object("Dog", { name: sf.string() }) {}
15+
class Cat extends sf.object("Cat", { name: sf.string() }) {}
16+
class Root extends sf.object("Root", { pet: [Dog, Cat] }) {}
17+
// ...
18+
const pet = { name: "Max" };
19+
view.root.pet = pet; // Error: `pet` is ambiguous - is it a Dog or a Cat?
20+
view.root.pet = new Dog(pet); // This works, but has the overhead of creating a Dog node before the insertion actually happens.
21+
TreeAlpha.ensureSchema(Dog, pet); // Instead, this tags the `pet` object as a Dog...
22+
view.root.pet = pet; // So now there is no error for a normal insertion - it's a Dog.
23+
```
24+
25+
This function works by leveraging the new `schemaSymbol`, which is also available for use.
26+
See its documentation for more information.

packages/common/core-interfaces/api-report/core-interfaces.legacy.beta.api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
// @public
88
export type ConfigTypes = string | number | boolean | number[] | string[] | boolean[] | undefined;
99

10+
// @beta @sealed @system
11+
export abstract class ErasedBaseType<out Name = unknown> {
12+
protected constructor();
13+
protected abstract brand(dummy: never): Name;
14+
}
15+
1016
// @public @sealed
1117
export abstract class ErasedType<out Name = unknown> {
1218
static [Symbol.hasInstance](value: never): value is never;

packages/common/core-interfaces/src/erasedType.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,10 @@ export abstract class ErasedType<out Name = unknown> {
9696
*
9797
* This class should only be a `type` package export, preventing users from extending it directly.
9898
*
99-
* Since {@link ErasedTypeImplementation} is exported as `@internal`, this restricts implementations of the sealed interfaces to users of `@internal` APIs, which should be anything withing this release group.
99+
* Since {@link ErasedTypeImplementation} is exported as `@internal`, this restricts implementations of the sealed interfaces to users of `@internal` APIs, which should be anything within this release group.
100100
* Any finer grained restrictions can be done as documentation, but not type enforced.
101101
* @sealed
102-
* @alpha
102+
* @beta
103103
* @system
104104
*/
105105
export abstract class ErasedBaseType<out Name = unknown> {

packages/dds/tree/api-report/tree.alpha.api.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function adaptEnum<TScope extends string, const TEnum extends Record<stri
1515
}, Record<string, never>, true, Record<string, never>, undefined>; }[keyof TEnum]>;
1616
};
1717

18-
// @alpha @input
18+
// @beta @input
1919
export interface AllowedTypeMetadata {
2020
readonly custom?: unknown;
2121
readonly stagedSchemaUpgrade?: SchemaUpgrade;
@@ -24,13 +24,13 @@ export interface AllowedTypeMetadata {
2424
// @public @system
2525
export type AllowedTypes = readonly LazyItem<TreeNodeSchema>[];
2626

27-
// @alpha @sealed
27+
// @beta @sealed
2828
export type AllowedTypesFull<T extends readonly AnnotatedAllowedType[] = readonly AnnotatedAllowedType[]> = AnnotatedAllowedTypes<T> & UnannotateAllowedTypesList<T>;
2929

30-
// @alpha @sealed
30+
// @beta @sealed
3131
export type AllowedTypesFullEvaluated = AllowedTypesFull<readonly AnnotatedAllowedType<TreeNodeSchema>[]>;
3232

33-
// @alpha @sealed
33+
// @beta @sealed @system
3434
export type AllowedTypesFullFromMixed<T extends readonly (AnnotatedAllowedType | LazyItem<TreeNodeSchema>)[]> = UnannotateAllowedTypesList<T> & AnnotatedAllowedTypes<AnnotateAllowedTypesList<T>>;
3535

3636
// @alpha @sealed @system
@@ -39,15 +39,15 @@ export type AllowedTypesFullFromMixedUnsafe<T extends readonly Unenforced<Annota
3939
// @alpha @sealed @system
4040
export type AllowedTypesFullUnsafe<T extends readonly AnnotatedAllowedTypeUnsafe[] = readonly AnnotatedAllowedTypeUnsafe[]> = AnnotatedAllowedTypes<T> & UnannotateAllowedTypesListUnsafe<T>;
4141

42-
// @alpha @input
42+
// @beta @input
4343
export interface AllowedTypesMetadata {
4444
readonly custom?: unknown;
4545
}
4646

4747
// @alpha
4848
export function allowUnused<T>(t?: T): void;
4949

50-
// @alpha @system
50+
// @beta @system
5151
export type AnnotateAllowedTypesList<T extends readonly (AnnotatedAllowedType | LazyItem<TreeNodeSchema>)[]> = {
5252
[I in keyof T]: T[I] extends AnnotatedAllowedType<unknown> ? T[I] : AnnotatedAllowedType<T[I]>;
5353
};
@@ -57,13 +57,13 @@ export type AnnotateAllowedTypesListUnsafe<T extends readonly Unenforced<Annotat
5757
[I in keyof T]: T[I] extends AnnotatedAllowedTypeUnsafe ? T[I] : AnnotatedAllowedTypeUnsafe<T[I]>;
5858
};
5959

60-
// @alpha @sealed
60+
// @beta @sealed
6161
export interface AnnotatedAllowedType<T = LazyItem<TreeNodeSchema>> {
6262
readonly metadata: AllowedTypeMetadata;
6363
readonly type: T;
6464
}
6565

66-
// @alpha @sealed
66+
// @beta @sealed
6767
export interface AnnotatedAllowedTypes<T = readonly AnnotatedAllowedType[]> extends ErasedBaseType<"tree.AnnotatedAllowedTypes"> {
6868
evaluate(): AllowedTypesFullEvaluated;
6969
evaluateIdentifiers(): ReadonlySet<string>;
@@ -310,7 +310,7 @@ export namespace FluidSerializableAsTree {
310310
export type Data = JsonCompatible<IFluidHandle>;
311311
const // @system
312312
_APIExtractorWorkaroundObjectBase: TreeNodeSchemaClass_2<"com.fluidframework.serializable.object", NodeKind_2.Record, TreeRecordNodeUnsafe_2<readonly [() => typeof FluidSerializableObject, () => typeof Array, LeafSchema_2<"string", string>, LeafSchema_2<"number", number>, LeafSchema_2<"boolean", boolean>, LeafSchema_2<"null", null>, LeafSchema_2<"handle", IFluidHandle<unknown>>]> & WithType_2<"com.fluidframework.serializable.object", NodeKind_2.Record, unknown>, {
313-
readonly [x: string]: string | number | IFluidHandle<unknown> | System_Unsafe_2.InsertableTypedNodeUnsafe<LeafSchema_2<"boolean", boolean>, LeafSchema_2<"boolean", boolean>> | FluidSerializableObject | Array | null;
313+
readonly [x: string]: string | number | IFluidHandle<unknown> | FluidSerializableObject | Array | System_Unsafe_2.InsertableTypedNodeUnsafe<LeafSchema_2<"boolean", boolean>, LeafSchema_2<"boolean", boolean>> | null;
314314
}, false, readonly [() => typeof FluidSerializableObject, () => typeof Array, LeafSchema_2<"string", string>, LeafSchema_2<"number", number>, LeafSchema_2<"boolean", boolean>, LeafSchema_2<"null", null>, LeafSchema_2<"handle", IFluidHandle<unknown>>], undefined, unknown>;
315315
// @sealed
316316
export class FluidSerializableObject extends _APIExtractorWorkaroundObjectBase {
@@ -319,7 +319,7 @@ export namespace FluidSerializableAsTree {
319319
export type _RecursiveArrayWorkaroundJsonArray = FixRecursiveArraySchema<typeof Array>;
320320
const // @system
321321
_APIExtractorWorkaroundArrayBase: TreeNodeSchemaClass_2<"com.fluidframework.serializable.array", NodeKind_2.Array, System_Unsafe_2.TreeArrayNodeUnsafe<readonly [() => typeof FluidSerializableObject, () => typeof Array, LeafSchema_2<"string", string>, LeafSchema_2<"number", number>, LeafSchema_2<"boolean", boolean>, LeafSchema_2<"null", null>, LeafSchema_2<"handle", IFluidHandle<unknown>>]> & WithType_2<"com.fluidframework.serializable.array", NodeKind_2.Array, unknown>, {
322-
[Symbol.iterator](): Iterator<string | number | IFluidHandle<unknown> | System_Unsafe_2.InsertableTypedNodeUnsafe<LeafSchema_2<"boolean", boolean>, LeafSchema_2<"boolean", boolean>> | FluidSerializableObject | Array | null, any, undefined>;
322+
[Symbol.iterator](): Iterator<string | number | IFluidHandle<unknown> | FluidSerializableObject | Array | System_Unsafe_2.InsertableTypedNodeUnsafe<LeafSchema_2<"boolean", boolean>, LeafSchema_2<"boolean", boolean>> | null, any, undefined>;
323323
}, false, readonly [() => typeof FluidSerializableObject, () => typeof Array, LeafSchema_2<"string", string>, LeafSchema_2<"number", number>, LeafSchema_2<"boolean", boolean>, LeafSchema_2<"null", null>, LeafSchema_2<"handle", IFluidHandle<unknown>>], undefined>;
324324
// (undocumented)
325325
export type Tree = TreeNodeFromImplicitAllowedTypes<typeof Tree>;
@@ -512,7 +512,7 @@ export namespace JsonAsTree {
512512
}
513513
const // @system
514514
_APIExtractorWorkaroundObjectBase: TreeNodeSchemaClass<"com.fluidframework.json.object", NodeKind.Record, TreeRecordNodeUnsafe<readonly [LeafSchema<"null", null>, LeafSchema<"number", number>, LeafSchema<"string", string>, LeafSchema<"boolean", boolean>, () => typeof JsonObject, () => typeof Array]> & WithType<"com.fluidframework.json.object", NodeKind.Record, unknown>, {
515-
readonly [x: string]: string | number | JsonObject | Array | System_Unsafe.InsertableTypedNodeUnsafe<LeafSchema<"boolean", boolean>, LeafSchema<"boolean", boolean>> | null;
515+
readonly [x: string]: string | number | System_Unsafe.InsertableTypedNodeUnsafe<LeafSchema<"boolean", boolean>, LeafSchema<"boolean", boolean>> | JsonObject | Array | null;
516516
}, false, readonly [LeafSchema<"null", null>, LeafSchema<"number", number>, LeafSchema<"string", string>, LeafSchema<"boolean", boolean>, () => typeof JsonObject, () => typeof Array], undefined, unknown>;
517517
export type Primitive = TreeNodeFromImplicitAllowedTypes<typeof Primitive>;
518518
// @system
@@ -968,7 +968,7 @@ export interface SchemaStaticsAlpha {
968968
// @alpha
969969
export const schemaSymbol: unique symbol;
970970

971-
// @alpha @sealed
971+
// @beta @sealed
972972
export class SchemaUpgrade {
973973
// (undocumented)
974974
protected _typeCheck: MakeNominal;
@@ -1642,7 +1642,7 @@ const typeNameSymbol: unique symbol;
16421642
// @public @system
16431643
export const typeSchemaSymbol: unique symbol;
16441644

1645-
// @alpha @system
1645+
// @beta @system
16461646
export type UnannotateAllowedTypesList<T extends readonly (AnnotatedAllowedType | LazyItem<TreeNodeSchema>)[]> = {
16471647
[I in keyof T]: T[I] extends AnnotatedAllowedType<infer X> ? X : T[I];
16481648
};

packages/dds/tree/api-report/tree.beta.api.md

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,49 @@ export function adaptEnum<TScope extends string, const TEnum extends Record<stri
1515
}, Record<string, never>, true, Record<string, never>, undefined>; }[keyof TEnum]>;
1616
};
1717

18+
// @beta @input
19+
export interface AllowedTypeMetadata {
20+
readonly custom?: unknown;
21+
readonly stagedSchemaUpgrade?: SchemaUpgrade;
22+
}
23+
1824
// @public @system
1925
export type AllowedTypes = readonly LazyItem<TreeNodeSchema>[];
2026

27+
// @beta @sealed
28+
export type AllowedTypesFull<T extends readonly AnnotatedAllowedType[] = readonly AnnotatedAllowedType[]> = AnnotatedAllowedTypes<T> & UnannotateAllowedTypesList<T>;
29+
30+
// @beta @sealed
31+
export type AllowedTypesFullEvaluated = AllowedTypesFull<readonly AnnotatedAllowedType<TreeNodeSchema>[]>;
32+
33+
// @beta @sealed @system
34+
export type AllowedTypesFullFromMixed<T extends readonly (AnnotatedAllowedType | LazyItem<TreeNodeSchema>)[]> = UnannotateAllowedTypesList<T> & AnnotatedAllowedTypes<AnnotateAllowedTypesList<T>>;
35+
36+
// @beta @input
37+
export interface AllowedTypesMetadata {
38+
readonly custom?: unknown;
39+
}
40+
41+
// @beta @system
42+
export type AnnotateAllowedTypesList<T extends readonly (AnnotatedAllowedType | LazyItem<TreeNodeSchema>)[]> = {
43+
[I in keyof T]: T[I] extends AnnotatedAllowedType<unknown> ? T[I] : AnnotatedAllowedType<T[I]>;
44+
};
45+
46+
// @beta @sealed
47+
export interface AnnotatedAllowedType<T = LazyItem<TreeNodeSchema>> {
48+
readonly metadata: AllowedTypeMetadata;
49+
readonly type: T;
50+
}
51+
52+
// @beta @sealed
53+
export interface AnnotatedAllowedTypes<T = readonly AnnotatedAllowedType[]> extends ErasedBaseType<"tree.AnnotatedAllowedTypes"> {
54+
evaluate(): AllowedTypesFullEvaluated;
55+
evaluateIdentifiers(): ReadonlySet<string>;
56+
evaluateSet(): ReadonlySet<TreeNodeSchema>;
57+
readonly metadata: AllowedTypesMetadata;
58+
readonly types: T;
59+
}
60+
2161
// @public @system
2262
type ApplyKind<T, Kind extends FieldKind> = {
2363
[FieldKind.Required]: T;
@@ -132,7 +172,7 @@ export namespace FluidSerializableAsTree {
132172
export type Data = JsonCompatible<IFluidHandle>;
133173
const // @system
134174
_APIExtractorWorkaroundObjectBase: TreeNodeSchemaClass_2<"com.fluidframework.serializable.object", NodeKind_2.Record, TreeRecordNodeUnsafe_2<readonly [() => typeof FluidSerializableObject, () => typeof Array, LeafSchema_2<"string", string>, LeafSchema_2<"number", number>, LeafSchema_2<"boolean", boolean>, LeafSchema_2<"null", null>, LeafSchema_2<"handle", IFluidHandle<unknown>>]> & WithType_2<"com.fluidframework.serializable.object", NodeKind_2.Record, unknown>, {
135-
readonly [x: string]: string | number | IFluidHandle<unknown> | System_Unsafe_2.InsertableTypedNodeUnsafe<LeafSchema_2<"boolean", boolean>, LeafSchema_2<"boolean", boolean>> | FluidSerializableObject | Array | null;
175+
readonly [x: string]: string | number | IFluidHandle<unknown> | FluidSerializableObject | Array | System_Unsafe_2.InsertableTypedNodeUnsafe<LeafSchema_2<"boolean", boolean>, LeafSchema_2<"boolean", boolean>> | null;
136176
}, false, readonly [() => typeof FluidSerializableObject, () => typeof Array, LeafSchema_2<"string", string>, LeafSchema_2<"number", number>, LeafSchema_2<"boolean", boolean>, LeafSchema_2<"null", null>, LeafSchema_2<"handle", IFluidHandle<unknown>>], undefined, unknown>;
137177
// @sealed
138178
export class FluidSerializableObject extends _APIExtractorWorkaroundObjectBase {
@@ -141,7 +181,7 @@ export namespace FluidSerializableAsTree {
141181
export type _RecursiveArrayWorkaroundJsonArray = FixRecursiveArraySchema<typeof Array>;
142182
const // @system
143183
_APIExtractorWorkaroundArrayBase: TreeNodeSchemaClass_2<"com.fluidframework.serializable.array", NodeKind_2.Array, System_Unsafe_2.TreeArrayNodeUnsafe<readonly [() => typeof FluidSerializableObject, () => typeof Array, LeafSchema_2<"string", string>, LeafSchema_2<"number", number>, LeafSchema_2<"boolean", boolean>, LeafSchema_2<"null", null>, LeafSchema_2<"handle", IFluidHandle<unknown>>]> & WithType_2<"com.fluidframework.serializable.array", NodeKind_2.Array, unknown>, {
144-
[Symbol.iterator](): Iterator<string | number | IFluidHandle<unknown> | System_Unsafe_2.InsertableTypedNodeUnsafe<LeafSchema_2<"boolean", boolean>, LeafSchema_2<"boolean", boolean>> | FluidSerializableObject | Array | null, any, undefined>;
184+
[Symbol.iterator](): Iterator<string | number | IFluidHandle<unknown> | FluidSerializableObject | Array | System_Unsafe_2.InsertableTypedNodeUnsafe<LeafSchema_2<"boolean", boolean>, LeafSchema_2<"boolean", boolean>> | null, any, undefined>;
145185
}, false, readonly [() => typeof FluidSerializableObject, () => typeof Array, LeafSchema_2<"string", string>, LeafSchema_2<"number", number>, LeafSchema_2<"boolean", boolean>, LeafSchema_2<"null", null>, LeafSchema_2<"handle", IFluidHandle<unknown>>], undefined>;
146186
// (undocumented)
147187
export type Tree = TreeNodeFromImplicitAllowedTypes<typeof Tree>;
@@ -474,6 +514,12 @@ export interface SchemaStatics {
474514
readonly string: LeafSchema<"string", string>;
475515
}
476516

517+
// @beta @sealed
518+
export class SchemaUpgrade {
519+
// (undocumented)
520+
protected _typeCheck: MakeNominal;
521+
}
522+
477523
// @public @system
478524
type ScopedSchemaName<TScope extends string | undefined, TName extends number | string> = TScope extends undefined ? `${TName}` : `${TScope}.${TName}`;
479525

@@ -773,6 +819,11 @@ const typeNameSymbol: unique symbol;
773819
// @public @system
774820
export const typeSchemaSymbol: unique symbol;
775821

822+
// @beta @system
823+
export type UnannotateAllowedTypesList<T extends readonly (AnnotatedAllowedType | LazyItem<TreeNodeSchema>)[]> = {
824+
[I in keyof T]: T[I] extends AnnotatedAllowedType<infer X> ? X : T[I];
825+
};
826+
776827
// @public
777828
export type Unenforced<_DesiredExtendsConstraint> = unknown;
778829

0 commit comments

Comments
 (0)